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