rel32_utils.h 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. // Copyright 2017 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef COMPONENTS_ZUCCHINI_REL32_UTILS_H_
  5. #define COMPONENTS_ZUCCHINI_REL32_UTILS_H_
  6. #include <algorithm>
  7. #include <array>
  8. #include <deque>
  9. #include <memory>
  10. #include "base/logging.h"
  11. #include "components/zucchini/address_translator.h"
  12. #include "components/zucchini/arm_utils.h"
  13. #include "components/zucchini/buffer_view.h"
  14. #include "components/zucchini/image_utils.h"
  15. #include "components/zucchini/io_utils.h"
  16. #include "third_party/abseil-cpp/absl/types/optional.h"
  17. namespace zucchini {
  18. // Reader that emits x86 / x64 References (locations and target) from a list of
  19. // valid locations, constrained by a portion of an image.
  20. class Rel32ReaderX86 : public ReferenceReader {
  21. public:
  22. // |image| is an image containing x86 / x64 code in [|lo|, |hi|).
  23. // |locations| is a sorted list of offsets of rel32 reference locations.
  24. // |translator| (for |image|) is embedded into |target_rva_to_offset_| and
  25. // |location_offset_to_rva_| for address translation, and therefore must
  26. // outlive |*this|.
  27. Rel32ReaderX86(ConstBufferView image,
  28. offset_t lo,
  29. offset_t hi,
  30. const std::deque<offset_t>* locations,
  31. const AddressTranslator& translator);
  32. Rel32ReaderX86(const Rel32ReaderX86&) = delete;
  33. const Rel32ReaderX86& operator=(const Rel32ReaderX86&) = delete;
  34. ~Rel32ReaderX86() override;
  35. // Returns the next reference, or absl::nullopt if exhausted.
  36. absl::optional<Reference> GetNext() override;
  37. private:
  38. ConstBufferView image_;
  39. AddressTranslator::RvaToOffsetCache target_rva_to_offset_;
  40. AddressTranslator::OffsetToRvaCache location_offset_to_rva_;
  41. const offset_t hi_;
  42. const std::deque<offset_t>::const_iterator last_;
  43. std::deque<offset_t>::const_iterator current_;
  44. };
  45. // Writer for x86 / x64 rel32 References.
  46. class Rel32WriterX86 : public ReferenceWriter {
  47. public:
  48. // |image| wraps the raw bytes of a binary in which rel32 references will be
  49. // written. |translator| (for |image|) is embedded into
  50. // |target_offset_to_rva_| and |location_offset_to_rva_| for address
  51. // translation, and therefore must outlive |*this|.
  52. Rel32WriterX86(MutableBufferView image, const AddressTranslator& translator);
  53. Rel32WriterX86(const Rel32WriterX86&) = delete;
  54. const Rel32WriterX86& operator=(const Rel32WriterX86&) = delete;
  55. ~Rel32WriterX86() override;
  56. void PutNext(Reference ref) override;
  57. private:
  58. MutableBufferView image_;
  59. AddressTranslator::OffsetToRvaCache target_offset_to_rva_;
  60. AddressTranslator::OffsetToRvaCache location_offset_to_rva_;
  61. };
  62. // Reader that emits x86 / x64 References (locations and target) of a spcific
  63. // type from a list of valid locations, constrained by a portion of an image.
  64. template <class ADDR_TRAITS>
  65. class Rel32ReaderArm : public ReferenceReader {
  66. public:
  67. using CODE_T = typename ADDR_TRAITS::code_t;
  68. Rel32ReaderArm(const AddressTranslator& translator,
  69. ConstBufferView view,
  70. const std::deque<offset_t>& rel32_locations,
  71. offset_t lo,
  72. offset_t hi)
  73. : view_(view),
  74. offset_to_rva_(translator),
  75. rva_to_offset_(translator),
  76. hi_(hi) {
  77. cur_it_ =
  78. std::lower_bound(rel32_locations.begin(), rel32_locations.end(), lo);
  79. rel32_end_ = rel32_locations.end();
  80. }
  81. Rel32ReaderArm(const Rel32ReaderArm&) = delete;
  82. const Rel32ReaderArm& operator=(const Rel32ReaderArm&) = delete;
  83. absl::optional<Reference> GetNext() override {
  84. while (cur_it_ < rel32_end_ && *cur_it_ < hi_) {
  85. offset_t location = *(cur_it_++);
  86. CODE_T code = ADDR_TRAITS::Fetch(view_, location);
  87. rva_t instr_rva = offset_to_rva_.Convert(location);
  88. rva_t target_rva = kInvalidRva;
  89. if (ADDR_TRAITS::Read(instr_rva, code, &target_rva)) {
  90. offset_t target = rva_to_offset_.Convert(target_rva);
  91. if (target != kInvalidOffset)
  92. return Reference{location, target};
  93. }
  94. }
  95. return absl::nullopt;
  96. }
  97. private:
  98. ConstBufferView view_;
  99. AddressTranslator::OffsetToRvaCache offset_to_rva_;
  100. AddressTranslator::RvaToOffsetCache rva_to_offset_;
  101. std::deque<offset_t>::const_iterator cur_it_;
  102. std::deque<offset_t>::const_iterator rel32_end_;
  103. offset_t hi_;
  104. };
  105. // Writer for ARM rel32 References of a specific type.
  106. template <class ADDR_TRAITS>
  107. class Rel32WriterArm : public ReferenceWriter {
  108. public:
  109. using CODE_T = typename ADDR_TRAITS::code_t;
  110. Rel32WriterArm(const AddressTranslator& translator,
  111. MutableBufferView mutable_view)
  112. : mutable_view_(mutable_view), offset_to_rva_(translator) {}
  113. Rel32WriterArm(const Rel32WriterArm&) = delete;
  114. const Rel32WriterArm& operator=(const Rel32WriterArm&) = delete;
  115. void PutNext(Reference ref) override {
  116. CODE_T code = ADDR_TRAITS::Fetch(mutable_view_, ref.location);
  117. rva_t instr_rva = offset_to_rva_.Convert(ref.location);
  118. rva_t target_rva = offset_to_rva_.Convert(ref.target);
  119. if (ADDR_TRAITS::Write(instr_rva, target_rva, &code)) {
  120. ADDR_TRAITS::Store(mutable_view_, ref.location, code);
  121. } else {
  122. LOG(ERROR) << "Write error: " << AsHex<8>(ref.location) << ": "
  123. << AsHex<static_cast<int>(sizeof(CODE_T)) * 2>(code)
  124. << " <= " << AsHex<8>(target_rva) << ".";
  125. }
  126. }
  127. private:
  128. MutableBufferView mutable_view_;
  129. AddressTranslator::OffsetToRvaCache offset_to_rva_;
  130. };
  131. // Copier that makes |*dst_it| similar to |*src_it| (both assumed to point to
  132. // rel32 instructions of type ADDR_TRAITS) by copying the displacement (i.e.,
  133. // payload bits) from |src_it| to |dst_it|. If successful, updates |*dst_it|,
  134. // and returns true. Otherwise returns false. Note that alignment is not an
  135. // issue since the displacement is not translated to target RVA!
  136. template <class ADDR_TRAITS>
  137. bool ArmCopyDisp(ConstBufferView src_view,
  138. offset_t src_idx,
  139. MutableBufferView dst_view,
  140. offset_t dst_idx) {
  141. using CODE_T = typename ADDR_TRAITS::code_t;
  142. CODE_T src_code = ADDR_TRAITS::Fetch(src_view, src_idx);
  143. arm_disp_t disp = 0;
  144. if (ADDR_TRAITS::Decode(src_code, &disp)) {
  145. CODE_T dst_code = ADDR_TRAITS::Fetch(dst_view, dst_idx);
  146. if (ADDR_TRAITS::Encode(disp, &dst_code)) {
  147. ADDR_TRAITS::Store(dst_view, dst_idx, dst_code);
  148. return true;
  149. }
  150. }
  151. return false;
  152. }
  153. // Outputs error message (throttled) on ArmCopyDisp failure.
  154. void OutputArmCopyDispFailure(uint32_t addr_type);
  155. // Mixer for ARM rel32 References of a specific type.
  156. template <class ADDR_TRAITS>
  157. class Rel32MixerArm : public ReferenceMixer {
  158. using code_t = typename ADDR_TRAITS::code_t;
  159. static constexpr size_t kCodeWidth = sizeof(code_t);
  160. public:
  161. Rel32MixerArm(ConstBufferView src_image, ConstBufferView dst_image)
  162. : src_image_(src_image), dst_image_(dst_image) {}
  163. ~Rel32MixerArm() override = default;
  164. ConstBufferView Mix(offset_t src_offset, offset_t dst_offset) override {
  165. ConstBufferView::const_iterator new_it = dst_image_.begin() + dst_offset;
  166. MutableBufferView out_buffer_view(out_buffer_.data(), kCodeWidth);
  167. std::copy(new_it, new_it + kCodeWidth, out_buffer_view.begin());
  168. if (!ArmCopyDisp<ADDR_TRAITS>(src_image_, src_offset, out_buffer_view,
  169. 0U)) {
  170. OutputArmCopyDispFailure(static_cast<uint32_t>(ADDR_TRAITS::addr_type));
  171. // Fall back to direct copy.
  172. std::copy(new_it, new_it + kCodeWidth, out_buffer_.begin());
  173. }
  174. return ConstBufferView(out_buffer_.data(), kCodeWidth);
  175. }
  176. private:
  177. ConstBufferView src_image_;
  178. ConstBufferView dst_image_;
  179. std::array<uint8_t, sizeof(code_t)> out_buffer_;
  180. };
  181. } // namespace zucchini
  182. #endif // COMPONENTS_ZUCCHINI_REL32_UTILS_H_