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 #include "components/zucchini/abs32_utils.h"
6*a03ca8b9SKrzysztof Kosiński
7*a03ca8b9SKrzysztof Kosiński #include <algorithm>
8*a03ca8b9SKrzysztof Kosiński #include <type_traits>
9*a03ca8b9SKrzysztof Kosiński #include <utility>
10*a03ca8b9SKrzysztof Kosiński
11*a03ca8b9SKrzysztof Kosiński #include "base/check_op.h"
12*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/io_utils.h"
13*a03ca8b9SKrzysztof Kosiński
14*a03ca8b9SKrzysztof Kosiński namespace zucchini {
15*a03ca8b9SKrzysztof Kosiński
16*a03ca8b9SKrzysztof Kosiński namespace {
17*a03ca8b9SKrzysztof Kosiński
18*a03ca8b9SKrzysztof Kosiński // Templated helper for AbsoluteAddress::Read().
19*a03ca8b9SKrzysztof Kosiński template <typename T>
ReadAbs(ConstBufferView image,offset_t offset,uint64_t * value)20*a03ca8b9SKrzysztof Kosiński bool ReadAbs(ConstBufferView image, offset_t offset, uint64_t* value) {
21*a03ca8b9SKrzysztof Kosiński static_assert(std::is_unsigned<T>::value, "Value type must be unsigned.");
22*a03ca8b9SKrzysztof Kosiński if (!image.can_access<T>(offset))
23*a03ca8b9SKrzysztof Kosiński return false;
24*a03ca8b9SKrzysztof Kosiński *value = static_cast<uint64_t>(image.read<T>(offset));
25*a03ca8b9SKrzysztof Kosiński return true;
26*a03ca8b9SKrzysztof Kosiński }
27*a03ca8b9SKrzysztof Kosiński
28*a03ca8b9SKrzysztof Kosiński // Templated helper for AbsoluteAddress::Write().
29*a03ca8b9SKrzysztof Kosiński template <typename T>
WriteAbs(offset_t offset,T value,MutableBufferView * image)30*a03ca8b9SKrzysztof Kosiński bool WriteAbs(offset_t offset, T value, MutableBufferView* image) {
31*a03ca8b9SKrzysztof Kosiński static_assert(std::is_unsigned<T>::value, "Value type must be unsigned.");
32*a03ca8b9SKrzysztof Kosiński if (!image->can_access<T>(offset))
33*a03ca8b9SKrzysztof Kosiński return false;
34*a03ca8b9SKrzysztof Kosiński image->write<T>(offset, value);
35*a03ca8b9SKrzysztof Kosiński return true;
36*a03ca8b9SKrzysztof Kosiński }
37*a03ca8b9SKrzysztof Kosiński
38*a03ca8b9SKrzysztof Kosiński } // namespace
39*a03ca8b9SKrzysztof Kosiński
40*a03ca8b9SKrzysztof Kosiński /******** AbsoluteAddress ********/
41*a03ca8b9SKrzysztof Kosiński
AbsoluteAddress(Bitness bitness,uint64_t image_base)42*a03ca8b9SKrzysztof Kosiński AbsoluteAddress::AbsoluteAddress(Bitness bitness, uint64_t image_base)
43*a03ca8b9SKrzysztof Kosiński : bitness_(bitness), image_base_(image_base), value_(image_base) {
44*a03ca8b9SKrzysztof Kosiński CHECK(bitness_ == kBit64 || image_base_ < 0x100000000ULL);
45*a03ca8b9SKrzysztof Kosiński }
46*a03ca8b9SKrzysztof Kosiński
47*a03ca8b9SKrzysztof Kosiński AbsoluteAddress::AbsoluteAddress(AbsoluteAddress&&) = default;
48*a03ca8b9SKrzysztof Kosiński
49*a03ca8b9SKrzysztof Kosiński AbsoluteAddress::~AbsoluteAddress() = default;
50*a03ca8b9SKrzysztof Kosiński
FromRva(rva_t rva)51*a03ca8b9SKrzysztof Kosiński bool AbsoluteAddress::FromRva(rva_t rva) {
52*a03ca8b9SKrzysztof Kosiński if (rva >= kRvaBound)
53*a03ca8b9SKrzysztof Kosiński return false;
54*a03ca8b9SKrzysztof Kosiński uint64_t value = image_base_ + rva;
55*a03ca8b9SKrzysztof Kosiński // Check overflow, which manifests as |value| "wrapping around", resulting in
56*a03ca8b9SKrzysztof Kosiński // |value| less than |image_base_| (preprocessing needed for 32-bit).
57*a03ca8b9SKrzysztof Kosiński if (((bitness_ == kBit32) ? (value & 0xFFFFFFFFU) : value) < image_base_)
58*a03ca8b9SKrzysztof Kosiński return false;
59*a03ca8b9SKrzysztof Kosiński value_ = value;
60*a03ca8b9SKrzysztof Kosiński return true;
61*a03ca8b9SKrzysztof Kosiński }
62*a03ca8b9SKrzysztof Kosiński
ToRva() const63*a03ca8b9SKrzysztof Kosiński rva_t AbsoluteAddress::ToRva() const {
64*a03ca8b9SKrzysztof Kosiński if (value_ < image_base_)
65*a03ca8b9SKrzysztof Kosiński return kInvalidRva;
66*a03ca8b9SKrzysztof Kosiński uint64_t raw_rva = value_ - image_base_;
67*a03ca8b9SKrzysztof Kosiński if (raw_rva >= kRvaBound)
68*a03ca8b9SKrzysztof Kosiński return kInvalidRva;
69*a03ca8b9SKrzysztof Kosiński return static_cast<rva_t>(raw_rva);
70*a03ca8b9SKrzysztof Kosiński }
71*a03ca8b9SKrzysztof Kosiński
Read(offset_t offset,const ConstBufferView & image)72*a03ca8b9SKrzysztof Kosiński bool AbsoluteAddress::Read(offset_t offset, const ConstBufferView& image) {
73*a03ca8b9SKrzysztof Kosiński // Read raw data; |value_| is not guaranteed to represent a valid RVA.
74*a03ca8b9SKrzysztof Kosiński if (bitness_ == kBit32)
75*a03ca8b9SKrzysztof Kosiński return ReadAbs<uint32_t>(image, offset, &value_);
76*a03ca8b9SKrzysztof Kosiński DCHECK_EQ(kBit64, bitness_);
77*a03ca8b9SKrzysztof Kosiński return ReadAbs<uint64_t>(image, offset, &value_);
78*a03ca8b9SKrzysztof Kosiński }
79*a03ca8b9SKrzysztof Kosiński
Write(offset_t offset,MutableBufferView * image)80*a03ca8b9SKrzysztof Kosiński bool AbsoluteAddress::Write(offset_t offset, MutableBufferView* image) {
81*a03ca8b9SKrzysztof Kosiński if (bitness_ == kBit32)
82*a03ca8b9SKrzysztof Kosiński return WriteAbs<uint32_t>(offset, static_cast<uint32_t>(value_), image);
83*a03ca8b9SKrzysztof Kosiński DCHECK_EQ(kBit64, bitness_);
84*a03ca8b9SKrzysztof Kosiński return WriteAbs<uint64_t>(offset, value_, image);
85*a03ca8b9SKrzysztof Kosiński }
86*a03ca8b9SKrzysztof Kosiński
87*a03ca8b9SKrzysztof Kosiński /******** Abs32RvaExtractorWin32 ********/
88*a03ca8b9SKrzysztof Kosiński
Abs32RvaExtractorWin32(ConstBufferView image,AbsoluteAddress && addr,const std::vector<offset_t> & abs32_locations,offset_t lo,offset_t hi)89*a03ca8b9SKrzysztof Kosiński Abs32RvaExtractorWin32::Abs32RvaExtractorWin32(
90*a03ca8b9SKrzysztof Kosiński ConstBufferView image,
91*a03ca8b9SKrzysztof Kosiński AbsoluteAddress&& addr,
92*a03ca8b9SKrzysztof Kosiński const std::vector<offset_t>& abs32_locations,
93*a03ca8b9SKrzysztof Kosiński offset_t lo,
94*a03ca8b9SKrzysztof Kosiński offset_t hi)
95*a03ca8b9SKrzysztof Kosiński : image_(image), addr_(std::move(addr)) {
96*a03ca8b9SKrzysztof Kosiński CHECK_LE(lo, hi);
97*a03ca8b9SKrzysztof Kosiński auto find_and_check = [this](const std::vector<offset_t>& locations,
98*a03ca8b9SKrzysztof Kosiński offset_t offset) {
99*a03ca8b9SKrzysztof Kosiński auto it = std::lower_bound(locations.begin(), locations.end(), offset);
100*a03ca8b9SKrzysztof Kosiński // Ensure that |offset| does not straddle a reference body.
101*a03ca8b9SKrzysztof Kosiński CHECK(it == locations.begin() || offset - *(it - 1) >= addr_.width());
102*a03ca8b9SKrzysztof Kosiński return it;
103*a03ca8b9SKrzysztof Kosiński };
104*a03ca8b9SKrzysztof Kosiński cur_abs32_ = find_and_check(abs32_locations, lo);
105*a03ca8b9SKrzysztof Kosiński end_abs32_ = find_and_check(abs32_locations, hi);
106*a03ca8b9SKrzysztof Kosiński }
107*a03ca8b9SKrzysztof Kosiński
108*a03ca8b9SKrzysztof Kosiński Abs32RvaExtractorWin32::Abs32RvaExtractorWin32(Abs32RvaExtractorWin32&&) =
109*a03ca8b9SKrzysztof Kosiński default;
110*a03ca8b9SKrzysztof Kosiński
111*a03ca8b9SKrzysztof Kosiński Abs32RvaExtractorWin32::~Abs32RvaExtractorWin32() = default;
112*a03ca8b9SKrzysztof Kosiński
GetNext()113*a03ca8b9SKrzysztof Kosiński std::optional<Abs32RvaExtractorWin32::Unit> Abs32RvaExtractorWin32::GetNext() {
114*a03ca8b9SKrzysztof Kosiński while (cur_abs32_ < end_abs32_) {
115*a03ca8b9SKrzysztof Kosiński offset_t location = *(cur_abs32_++);
116*a03ca8b9SKrzysztof Kosiński if (!addr_.Read(location, image_))
117*a03ca8b9SKrzysztof Kosiński continue;
118*a03ca8b9SKrzysztof Kosiński rva_t target_rva = addr_.ToRva();
119*a03ca8b9SKrzysztof Kosiński if (target_rva == kInvalidRva)
120*a03ca8b9SKrzysztof Kosiński continue;
121*a03ca8b9SKrzysztof Kosiński return Unit{location, target_rva};
122*a03ca8b9SKrzysztof Kosiński }
123*a03ca8b9SKrzysztof Kosiński return std::nullopt;
124*a03ca8b9SKrzysztof Kosiński }
125*a03ca8b9SKrzysztof Kosiński
126*a03ca8b9SKrzysztof Kosiński /******** Abs32ReaderWin32 ********/
127*a03ca8b9SKrzysztof Kosiński
Abs32ReaderWin32(Abs32RvaExtractorWin32 && abs32_rva_extractor,const AddressTranslator & translator)128*a03ca8b9SKrzysztof Kosiński Abs32ReaderWin32::Abs32ReaderWin32(Abs32RvaExtractorWin32&& abs32_rva_extractor,
129*a03ca8b9SKrzysztof Kosiński const AddressTranslator& translator)
130*a03ca8b9SKrzysztof Kosiński : abs32_rva_extractor_(std::move(abs32_rva_extractor)),
131*a03ca8b9SKrzysztof Kosiński target_rva_to_offset_(translator) {}
132*a03ca8b9SKrzysztof Kosiński
133*a03ca8b9SKrzysztof Kosiński Abs32ReaderWin32::~Abs32ReaderWin32() = default;
134*a03ca8b9SKrzysztof Kosiński
GetNext()135*a03ca8b9SKrzysztof Kosiński std::optional<Reference> Abs32ReaderWin32::GetNext() {
136*a03ca8b9SKrzysztof Kosiński for (auto unit = abs32_rva_extractor_.GetNext(); unit.has_value();
137*a03ca8b9SKrzysztof Kosiński unit = abs32_rva_extractor_.GetNext()) {
138*a03ca8b9SKrzysztof Kosiński offset_t location = unit->location;
139*a03ca8b9SKrzysztof Kosiński offset_t unsafe_target = target_rva_to_offset_.Convert(unit->target_rva);
140*a03ca8b9SKrzysztof Kosiński if (unsafe_target != kInvalidOffset)
141*a03ca8b9SKrzysztof Kosiński return Reference{location, unsafe_target};
142*a03ca8b9SKrzysztof Kosiński }
143*a03ca8b9SKrzysztof Kosiński return std::nullopt;
144*a03ca8b9SKrzysztof Kosiński }
145*a03ca8b9SKrzysztof Kosiński
146*a03ca8b9SKrzysztof Kosiński /******** Abs32WriterWin32 ********/
147*a03ca8b9SKrzysztof Kosiński
Abs32WriterWin32(MutableBufferView image,AbsoluteAddress && addr,const AddressTranslator & translator)148*a03ca8b9SKrzysztof Kosiński Abs32WriterWin32::Abs32WriterWin32(MutableBufferView image,
149*a03ca8b9SKrzysztof Kosiński AbsoluteAddress&& addr,
150*a03ca8b9SKrzysztof Kosiński const AddressTranslator& translator)
151*a03ca8b9SKrzysztof Kosiński : image_(image),
152*a03ca8b9SKrzysztof Kosiński addr_(std::move(addr)),
153*a03ca8b9SKrzysztof Kosiński target_offset_to_rva_(translator) {}
154*a03ca8b9SKrzysztof Kosiński
155*a03ca8b9SKrzysztof Kosiński Abs32WriterWin32::~Abs32WriterWin32() = default;
156*a03ca8b9SKrzysztof Kosiński
PutNext(Reference ref)157*a03ca8b9SKrzysztof Kosiński void Abs32WriterWin32::PutNext(Reference ref) {
158*a03ca8b9SKrzysztof Kosiński rva_t target_rva = target_offset_to_rva_.Convert(ref.target);
159*a03ca8b9SKrzysztof Kosiński if (target_rva != kInvalidRva) {
160*a03ca8b9SKrzysztof Kosiński addr_.FromRva(target_rva);
161*a03ca8b9SKrzysztof Kosiński addr_.Write(ref.location, &image_);
162*a03ca8b9SKrzysztof Kosiński }
163*a03ca8b9SKrzysztof Kosiński }
164*a03ca8b9SKrzysztof Kosiński
165*a03ca8b9SKrzysztof Kosiński /******** Exported Functions ********/
166*a03ca8b9SKrzysztof Kosiński
RemoveUntranslatableAbs32(ConstBufferView image,AbsoluteAddress && addr,const AddressTranslator & translator,std::vector<offset_t> * locations)167*a03ca8b9SKrzysztof Kosiński size_t RemoveUntranslatableAbs32(ConstBufferView image,
168*a03ca8b9SKrzysztof Kosiński AbsoluteAddress&& addr,
169*a03ca8b9SKrzysztof Kosiński const AddressTranslator& translator,
170*a03ca8b9SKrzysztof Kosiński std::vector<offset_t>* locations) {
171*a03ca8b9SKrzysztof Kosiński AddressTranslator::RvaToOffsetCache target_rva_checker(translator);
172*a03ca8b9SKrzysztof Kosiński Abs32RvaExtractorWin32 extractor(image, std::move(addr), *locations, 0,
173*a03ca8b9SKrzysztof Kosiński image.size());
174*a03ca8b9SKrzysztof Kosiński Abs32ReaderWin32 reader(std::move(extractor), translator);
175*a03ca8b9SKrzysztof Kosiński std::vector<offset_t>::iterator write_it = locations->begin();
176*a03ca8b9SKrzysztof Kosiński // |reader| reads |locations| while |write_it| modifies it. However, there's
177*a03ca8b9SKrzysztof Kosiński // no conflict since read occurs before write, and can skip ahead.
178*a03ca8b9SKrzysztof Kosiński for (auto ref = reader.GetNext(); ref.has_value(); ref = reader.GetNext())
179*a03ca8b9SKrzysztof Kosiński *(write_it++) = ref->location;
180*a03ca8b9SKrzysztof Kosiński DCHECK(write_it <= locations->end());
181*a03ca8b9SKrzysztof Kosiński size_t num_removed = locations->end() - write_it;
182*a03ca8b9SKrzysztof Kosiński locations->erase(write_it, locations->end());
183*a03ca8b9SKrzysztof Kosiński return num_removed;
184*a03ca8b9SKrzysztof Kosiński }
185*a03ca8b9SKrzysztof Kosiński
RemoveOverlappingAbs32Locations(uint32_t width,std::vector<offset_t> * locations)186*a03ca8b9SKrzysztof Kosiński size_t RemoveOverlappingAbs32Locations(uint32_t width,
187*a03ca8b9SKrzysztof Kosiński std::vector<offset_t>* locations) {
188*a03ca8b9SKrzysztof Kosiński if (locations->size() <= 1)
189*a03ca8b9SKrzysztof Kosiński return 0;
190*a03ca8b9SKrzysztof Kosiński
191*a03ca8b9SKrzysztof Kosiński auto slow = locations->begin();
192*a03ca8b9SKrzysztof Kosiński auto fast = locations->begin() + 1;
193*a03ca8b9SKrzysztof Kosiński for (;;) {
194*a03ca8b9SKrzysztof Kosiński // Find next good location.
195*a03ca8b9SKrzysztof Kosiński while (fast != locations->end() && *fast - *slow < width)
196*a03ca8b9SKrzysztof Kosiński ++fast;
197*a03ca8b9SKrzysztof Kosiński // Advance |slow|. For the last iteration this becomes the new sentinel.
198*a03ca8b9SKrzysztof Kosiński ++slow;
199*a03ca8b9SKrzysztof Kosiński if (fast == locations->end())
200*a03ca8b9SKrzysztof Kosiński break;
201*a03ca8b9SKrzysztof Kosiński // Compactify good locations (potentially overwrite bad locations).
202*a03ca8b9SKrzysztof Kosiński if (slow != fast)
203*a03ca8b9SKrzysztof Kosiński *slow = *fast;
204*a03ca8b9SKrzysztof Kosiński ++fast;
205*a03ca8b9SKrzysztof Kosiński }
206*a03ca8b9SKrzysztof Kosiński size_t num_removed = locations->end() - slow;
207*a03ca8b9SKrzysztof Kosiński locations->erase(slow, locations->end());
208*a03ca8b9SKrzysztof Kosiński return num_removed;
209*a03ca8b9SKrzysztof Kosiński }
210*a03ca8b9SKrzysztof Kosiński
211*a03ca8b9SKrzysztof Kosiński } // namespace zucchini
212