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