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