xref: /aosp_15_r20/external/zucchini/abs32_utils.cc (revision a03ca8b91e029cd15055c20c78c2e087c84792e4)
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