xref: /aosp_15_r20/external/zucchini/address_translator.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/address_translator.h"
6*a03ca8b9SKrzysztof Kosiński 
7*a03ca8b9SKrzysztof Kosiński #include <algorithm>
8*a03ca8b9SKrzysztof Kosiński #include <utility>
9*a03ca8b9SKrzysztof Kosiński 
10*a03ca8b9SKrzysztof Kosiński #include "base/containers/cxx20_erase.h"
11*a03ca8b9SKrzysztof Kosiński 
12*a03ca8b9SKrzysztof Kosiński namespace zucchini {
13*a03ca8b9SKrzysztof Kosiński 
14*a03ca8b9SKrzysztof Kosiński /******** AddressTranslator::OffsetToRvaCache ********/
15*a03ca8b9SKrzysztof Kosiński 
OffsetToRvaCache(const AddressTranslator & translator)16*a03ca8b9SKrzysztof Kosiński AddressTranslator::OffsetToRvaCache::OffsetToRvaCache(
17*a03ca8b9SKrzysztof Kosiński     const AddressTranslator& translator)
18*a03ca8b9SKrzysztof Kosiński     : translator_(translator) {}
19*a03ca8b9SKrzysztof Kosiński 
Convert(offset_t offset) const20*a03ca8b9SKrzysztof Kosiński rva_t AddressTranslator::OffsetToRvaCache::Convert(offset_t offset) const {
21*a03ca8b9SKrzysztof Kosiński   if (offset >= translator_.fake_offset_begin_) {
22*a03ca8b9SKrzysztof Kosiński     // Rely on |translator_| to handle this special case.
23*a03ca8b9SKrzysztof Kosiński     return translator_.OffsetToRva(offset);
24*a03ca8b9SKrzysztof Kosiński   }
25*a03ca8b9SKrzysztof Kosiński   if (cached_unit_ && cached_unit_->CoversOffset(offset))
26*a03ca8b9SKrzysztof Kosiński     return cached_unit_->OffsetToRvaUnsafe(offset);
27*a03ca8b9SKrzysztof Kosiński   const AddressTranslator::Unit* unit = translator_.OffsetToUnit(offset);
28*a03ca8b9SKrzysztof Kosiński   if (!unit)
29*a03ca8b9SKrzysztof Kosiński     return kInvalidRva;
30*a03ca8b9SKrzysztof Kosiński   cached_unit_ = unit;
31*a03ca8b9SKrzysztof Kosiński   return unit->OffsetToRvaUnsafe(offset);
32*a03ca8b9SKrzysztof Kosiński }
33*a03ca8b9SKrzysztof Kosiński 
34*a03ca8b9SKrzysztof Kosiński /******** AddressTranslator::RvaToOffsetCache ********/
35*a03ca8b9SKrzysztof Kosiński 
RvaToOffsetCache(const AddressTranslator & translator)36*a03ca8b9SKrzysztof Kosiński AddressTranslator::RvaToOffsetCache::RvaToOffsetCache(
37*a03ca8b9SKrzysztof Kosiński     const AddressTranslator& translator)
38*a03ca8b9SKrzysztof Kosiński     : translator_(translator) {}
39*a03ca8b9SKrzysztof Kosiński 
IsValid(rva_t rva) const40*a03ca8b9SKrzysztof Kosiński bool AddressTranslator::RvaToOffsetCache::IsValid(rva_t rva) const {
41*a03ca8b9SKrzysztof Kosiński   if (rva == kInvalidRva)
42*a03ca8b9SKrzysztof Kosiński     return false;
43*a03ca8b9SKrzysztof Kosiński   if (!cached_unit_ || !cached_unit_->CoversRva(rva)) {
44*a03ca8b9SKrzysztof Kosiński     const AddressTranslator::Unit* unit = translator_.RvaToUnit(rva);
45*a03ca8b9SKrzysztof Kosiński     if (!unit)
46*a03ca8b9SKrzysztof Kosiński       return false;
47*a03ca8b9SKrzysztof Kosiński     cached_unit_ = unit;
48*a03ca8b9SKrzysztof Kosiński   }
49*a03ca8b9SKrzysztof Kosiński   return true;
50*a03ca8b9SKrzysztof Kosiński }
51*a03ca8b9SKrzysztof Kosiński 
Convert(rva_t rva) const52*a03ca8b9SKrzysztof Kosiński offset_t AddressTranslator::RvaToOffsetCache::Convert(rva_t rva) const {
53*a03ca8b9SKrzysztof Kosiński   if (!cached_unit_ || !cached_unit_->CoversRva(rva)) {
54*a03ca8b9SKrzysztof Kosiński     const AddressTranslator::Unit* unit = translator_.RvaToUnit(rva);
55*a03ca8b9SKrzysztof Kosiński     if (!unit)
56*a03ca8b9SKrzysztof Kosiński       return kInvalidOffset;
57*a03ca8b9SKrzysztof Kosiński     cached_unit_ = unit;
58*a03ca8b9SKrzysztof Kosiński   }
59*a03ca8b9SKrzysztof Kosiński   return cached_unit_->RvaToOffsetUnsafe(rva, translator_.fake_offset_begin_);
60*a03ca8b9SKrzysztof Kosiński }
61*a03ca8b9SKrzysztof Kosiński 
62*a03ca8b9SKrzysztof Kosiński /******** AddressTranslator ********/
63*a03ca8b9SKrzysztof Kosiński 
64*a03ca8b9SKrzysztof Kosiński AddressTranslator::AddressTranslator() = default;
65*a03ca8b9SKrzysztof Kosiński 
66*a03ca8b9SKrzysztof Kosiński AddressTranslator::AddressTranslator(AddressTranslator&&) = default;
67*a03ca8b9SKrzysztof Kosiński 
68*a03ca8b9SKrzysztof Kosiński AddressTranslator::~AddressTranslator() = default;
69*a03ca8b9SKrzysztof Kosiński 
Initialize(std::vector<Unit> && units)70*a03ca8b9SKrzysztof Kosiński AddressTranslator::Status AddressTranslator::Initialize(
71*a03ca8b9SKrzysztof Kosiński     std::vector<Unit>&& units) {
72*a03ca8b9SKrzysztof Kosiński   for (Unit& unit : units) {
73*a03ca8b9SKrzysztof Kosiński     // Check for overflows and fail if found.
74*a03ca8b9SKrzysztof Kosiński     if (!RangeIsBounded<offset_t>(unit.offset_begin, unit.offset_size,
75*a03ca8b9SKrzysztof Kosiński                                   kOffsetBound) ||
76*a03ca8b9SKrzysztof Kosiński         !RangeIsBounded<rva_t>(unit.rva_begin, unit.rva_size, kRvaBound)) {
77*a03ca8b9SKrzysztof Kosiński       return kErrorOverflow;
78*a03ca8b9SKrzysztof Kosiński     }
79*a03ca8b9SKrzysztof Kosiński     // If |rva_size < offset_size|: Just shrink |offset_size| to accommodate.
80*a03ca8b9SKrzysztof Kosiński     unit.offset_size = std::min(unit.offset_size, unit.rva_size);
81*a03ca8b9SKrzysztof Kosiński     // Now |rva_size >= offset_size|. Note that |rva_size > offset_size| is
82*a03ca8b9SKrzysztof Kosiński     // allowed; these lead to dangling RVA.
83*a03ca8b9SKrzysztof Kosiński   }
84*a03ca8b9SKrzysztof Kosiński 
85*a03ca8b9SKrzysztof Kosiński   // Remove all empty units.
86*a03ca8b9SKrzysztof Kosiński   base::EraseIf(units, [](const Unit& unit) { return unit.IsEmpty(); });
87*a03ca8b9SKrzysztof Kosiński 
88*a03ca8b9SKrzysztof Kosiński   // Sort |units| by RVA, then uniquefy.
89*a03ca8b9SKrzysztof Kosiński   std::sort(units.begin(), units.end(), [](const Unit& a, const Unit& b) {
90*a03ca8b9SKrzysztof Kosiński     return std::tie(a.rva_begin, a.rva_size) <
91*a03ca8b9SKrzysztof Kosiński            std::tie(b.rva_begin, b.rva_size);
92*a03ca8b9SKrzysztof Kosiński   });
93*a03ca8b9SKrzysztof Kosiński   units.erase(std::unique(units.begin(), units.end()), units.end());
94*a03ca8b9SKrzysztof Kosiński 
95*a03ca8b9SKrzysztof Kosiński   // Scan for RVA range overlaps, validate, and merge wherever possible.
96*a03ca8b9SKrzysztof Kosiński   if (units.size() > 1) {
97*a03ca8b9SKrzysztof Kosiński     // Traverse with two iterators: |slow| stays behind and modifies Units that
98*a03ca8b9SKrzysztof Kosiński     // absorb all overlapping (or tangent if suitable) Units; |fast| explores
99*a03ca8b9SKrzysztof Kosiński     // new Units as candidates for consistency checks and potential merge into
100*a03ca8b9SKrzysztof Kosiński     // |slow|.
101*a03ca8b9SKrzysztof Kosiński     auto slow = units.begin();
102*a03ca8b9SKrzysztof Kosiński 
103*a03ca8b9SKrzysztof Kosiński     // All |it| with |slow| < |it| < |fast| contain garbage.
104*a03ca8b9SKrzysztof Kosiński     for (auto fast = slow + 1; fast != units.end(); ++fast) {
105*a03ca8b9SKrzysztof Kosiński       // Comment notation: S = slow offset, F = fast offset, O = overlap offset,
106*a03ca8b9SKrzysztof Kosiński       // s = slow RVA, f = fast RVA, o = overlap RVA.
107*a03ca8b9SKrzysztof Kosiński       DCHECK_GE(fast->rva_begin, slow->rva_begin);
108*a03ca8b9SKrzysztof Kosiński       if (slow->rva_end() < fast->rva_begin) {
109*a03ca8b9SKrzysztof Kosiński         // ..ssssss..ffffff..: Disjoint: Can advance |slow|.
110*a03ca8b9SKrzysztof Kosiński         *(++slow) = *fast;
111*a03ca8b9SKrzysztof Kosiński         continue;
112*a03ca8b9SKrzysztof Kosiński       }
113*a03ca8b9SKrzysztof Kosiński 
114*a03ca8b9SKrzysztof Kosiński       // ..ssssffff..: Tangent: Merge is optional.
115*a03ca8b9SKrzysztof Kosiński       // ..sssooofff.. / ..sssooosss..: Overlap: Merge is required.
116*a03ca8b9SKrzysztof Kosiński       bool merge_is_optional = slow->rva_end() == fast->rva_begin;
117*a03ca8b9SKrzysztof Kosiński 
118*a03ca8b9SKrzysztof Kosiński       // Check whether |fast| and |slow| have identical RVA -> offset shift.
119*a03ca8b9SKrzysztof Kosiński       // If not, then merge cannot be resolved. Examples:
120*a03ca8b9SKrzysztof Kosiński       // ..ssssffff.. -> ..SSSSFFFF..: Good, can merge.
121*a03ca8b9SKrzysztof Kosiński       // ..ssssffff.. -> ..SSSS..FFFF..: Non-fatal: don't merge.
122*a03ca8b9SKrzysztof Kosiński       // ..ssssffff.. -> ..FFFF..SSSS..: Non-fatal: don't merge.
123*a03ca8b9SKrzysztof Kosiński       // ..ssssffff.. -> ..SSOOFF..: Fatal: Ignore for now (handled later).
124*a03ca8b9SKrzysztof Kosiński       // ..sssooofff.. -> ..SSSOOOFFF..: Good, can merge.
125*a03ca8b9SKrzysztof Kosiński       // ..sssooofff.. -> ..SSSSSOFFFFF..: Fatal.
126*a03ca8b9SKrzysztof Kosiński       // ..sssooofff.. -> ..FFOOOOSS..: Fatal.
127*a03ca8b9SKrzysztof Kosiński       // ..sssooofff.. -> ..SSSOOOF..: Good, notice |fast| has dangling RVAs.
128*a03ca8b9SKrzysztof Kosiński       // ..oooooo.. -> ..OOOOOO..: Good, can merge.
129*a03ca8b9SKrzysztof Kosiński       if (fast->offset_begin < slow->offset_begin ||
130*a03ca8b9SKrzysztof Kosiński           fast->offset_begin - slow->offset_begin !=
131*a03ca8b9SKrzysztof Kosiński               fast->rva_begin - slow->rva_begin) {
132*a03ca8b9SKrzysztof Kosiński         if (merge_is_optional) {
133*a03ca8b9SKrzysztof Kosiński           *(++slow) = *fast;
134*a03ca8b9SKrzysztof Kosiński           continue;
135*a03ca8b9SKrzysztof Kosiński         }
136*a03ca8b9SKrzysztof Kosiński         return kErrorBadOverlap;
137*a03ca8b9SKrzysztof Kosiński       }
138*a03ca8b9SKrzysztof Kosiński 
139*a03ca8b9SKrzysztof Kosiński       // Check whether dangling RVAs (if they exist) are consistent. Examples:
140*a03ca8b9SKrzysztof Kosiński       // ..sssooofff.. -> ..SSSOOOF..: Good, can merge.
141*a03ca8b9SKrzysztof Kosiński       // ..sssooosss.. -> ..SSSOOOS..: Good, can merge.
142*a03ca8b9SKrzysztof Kosiński       // ..sssooofff.. -> ..SSSOO..: Good, can merge.
143*a03ca8b9SKrzysztof Kosiński       // ..sssooofff.. -> ..SSSOFFF..: Fatal.
144*a03ca8b9SKrzysztof Kosiński       // ..sssooosss.. -> ..SSSOOFFFF..: Fatal.
145*a03ca8b9SKrzysztof Kosiński       // ..oooooo.. -> ..OOO..: Good, can merge.
146*a03ca8b9SKrzysztof Kosiński       // Idea of check: Suppose |fast| has dangling RVA, then
147*a03ca8b9SKrzysztof Kosiński       // |[fast->rva_start, fast->rva_start + fast->offset_start)| ->
148*a03ca8b9SKrzysztof Kosiński       // |[fast->offset_start, **fast->offset_end()**)|, with remaining RVA
149*a03ca8b9SKrzysztof Kosiński       // mapping to fake offsets. This means |fast->offset_end()| must be >=
150*a03ca8b9SKrzysztof Kosiński       // |slow->offset_end()|, and failure to do so resluts in error. The
151*a03ca8b9SKrzysztof Kosiński       // argument for |slow| havng dangling RVA is symmetric.
152*a03ca8b9SKrzysztof Kosiński       if ((fast->HasDanglingRva() && fast->offset_end() < slow->offset_end()) ||
153*a03ca8b9SKrzysztof Kosiński           (slow->HasDanglingRva() && slow->offset_end() < fast->offset_end())) {
154*a03ca8b9SKrzysztof Kosiński         if (merge_is_optional) {
155*a03ca8b9SKrzysztof Kosiński           *(++slow) = *fast;
156*a03ca8b9SKrzysztof Kosiński           continue;
157*a03ca8b9SKrzysztof Kosiński         }
158*a03ca8b9SKrzysztof Kosiński         return kErrorBadOverlapDanglingRva;
159*a03ca8b9SKrzysztof Kosiński       }
160*a03ca8b9SKrzysztof Kosiński 
161*a03ca8b9SKrzysztof Kosiński       // Merge |fast| into |slow|.
162*a03ca8b9SKrzysztof Kosiński       slow->rva_size =
163*a03ca8b9SKrzysztof Kosiński           std::max(slow->rva_size, fast->rva_end() - slow->rva_begin);
164*a03ca8b9SKrzysztof Kosiński       slow->offset_size =
165*a03ca8b9SKrzysztof Kosiński           std::max(slow->offset_size, fast->offset_end() - slow->offset_begin);
166*a03ca8b9SKrzysztof Kosiński     }
167*a03ca8b9SKrzysztof Kosiński     ++slow;
168*a03ca8b9SKrzysztof Kosiński     units.erase(slow, units.end());
169*a03ca8b9SKrzysztof Kosiński   }
170*a03ca8b9SKrzysztof Kosiński 
171*a03ca8b9SKrzysztof Kosiński   // After resolving RVA overlaps, any offset overlap would imply error.
172*a03ca8b9SKrzysztof Kosiński   std::sort(units.begin(), units.end(), [](const Unit& a, const Unit& b) {
173*a03ca8b9SKrzysztof Kosiński     return a.offset_begin < b.offset_begin;
174*a03ca8b9SKrzysztof Kosiński   });
175*a03ca8b9SKrzysztof Kosiński 
176*a03ca8b9SKrzysztof Kosiński   if (units.size() > 1) {
177*a03ca8b9SKrzysztof Kosiński     auto previous = units.begin();
178*a03ca8b9SKrzysztof Kosiński     for (auto current = previous + 1; current != units.end(); ++current) {
179*a03ca8b9SKrzysztof Kosiński       if (previous->offset_end() > current->offset_begin)
180*a03ca8b9SKrzysztof Kosiński         return kErrorBadOverlap;
181*a03ca8b9SKrzysztof Kosiński       previous = current;
182*a03ca8b9SKrzysztof Kosiński     }
183*a03ca8b9SKrzysztof Kosiński   }
184*a03ca8b9SKrzysztof Kosiński 
185*a03ca8b9SKrzysztof Kosiński   // For to fake offset heuristics: Compute exclusive upper bounds for offsets
186*a03ca8b9SKrzysztof Kosiński   // and RVAs.
187*a03ca8b9SKrzysztof Kosiński   offset_t offset_bound = 0;
188*a03ca8b9SKrzysztof Kosiński   rva_t rva_bound = 0;
189*a03ca8b9SKrzysztof Kosiński   for (const Unit& unit : units) {
190*a03ca8b9SKrzysztof Kosiński     offset_bound = std::max(offset_bound, unit.offset_end());
191*a03ca8b9SKrzysztof Kosiński     rva_bound = std::max(rva_bound, unit.rva_end());
192*a03ca8b9SKrzysztof Kosiński   }
193*a03ca8b9SKrzysztof Kosiński 
194*a03ca8b9SKrzysztof Kosiński   // Compute pessimistic range and see if it still fits within space of valid
195*a03ca8b9SKrzysztof Kosiński   // offsets. This limits image size to one half of |kOffsetBound|, and is a
196*a03ca8b9SKrzysztof Kosiński   // main drawback for the current heuristic to convert dangling RVA to fake
197*a03ca8b9SKrzysztof Kosiński   // offsets.
198*a03ca8b9SKrzysztof Kosiński   if (!RangeIsBounded(offset_bound, rva_bound, kOffsetBound))
199*a03ca8b9SKrzysztof Kosiński     return kErrorFakeOffsetBeginTooLarge;
200*a03ca8b9SKrzysztof Kosiński 
201*a03ca8b9SKrzysztof Kosiński   // Success. Store results. |units| is currently sorted by offset, so assign.
202*a03ca8b9SKrzysztof Kosiński   units_sorted_by_offset_.assign(units.begin(), units.end());
203*a03ca8b9SKrzysztof Kosiński 
204*a03ca8b9SKrzysztof Kosiński   // Sort |units| by RVA, and just store it directly
205*a03ca8b9SKrzysztof Kosiński   std::sort(units.begin(), units.end(), [](const Unit& a, const Unit& b) {
206*a03ca8b9SKrzysztof Kosiński     return a.rva_begin < b.rva_begin;
207*a03ca8b9SKrzysztof Kosiński   });
208*a03ca8b9SKrzysztof Kosiński   units_sorted_by_rva_ = std::move(units);
209*a03ca8b9SKrzysztof Kosiński 
210*a03ca8b9SKrzysztof Kosiński   fake_offset_begin_ = offset_bound;
211*a03ca8b9SKrzysztof Kosiński   return kSuccess;
212*a03ca8b9SKrzysztof Kosiński }
213*a03ca8b9SKrzysztof Kosiński 
OffsetToRva(offset_t offset) const214*a03ca8b9SKrzysztof Kosiński rva_t AddressTranslator::OffsetToRva(offset_t offset) const {
215*a03ca8b9SKrzysztof Kosiński   if (offset >= fake_offset_begin_) {
216*a03ca8b9SKrzysztof Kosiński     // Handle dangling RVA: First shift it to regular RVA space.
217*a03ca8b9SKrzysztof Kosiński     rva_t rva = offset - fake_offset_begin_;
218*a03ca8b9SKrzysztof Kosiński     // If result is indeed a dangling RVA, return it; else return |kInvalidRva|.
219*a03ca8b9SKrzysztof Kosiński     const Unit* unit = RvaToUnit(rva);
220*a03ca8b9SKrzysztof Kosiński     return (unit && unit->HasDanglingRva() && unit->CoversDanglingRva(rva))
221*a03ca8b9SKrzysztof Kosiński                ? rva
222*a03ca8b9SKrzysztof Kosiński                : kInvalidRva;
223*a03ca8b9SKrzysztof Kosiński   }
224*a03ca8b9SKrzysztof Kosiński   const Unit* unit = OffsetToUnit(offset);
225*a03ca8b9SKrzysztof Kosiński   return unit ? unit->OffsetToRvaUnsafe(offset) : kInvalidRva;
226*a03ca8b9SKrzysztof Kosiński }
227*a03ca8b9SKrzysztof Kosiński 
RvaToOffset(rva_t rva) const228*a03ca8b9SKrzysztof Kosiński offset_t AddressTranslator::RvaToOffset(rva_t rva) const {
229*a03ca8b9SKrzysztof Kosiński   const Unit* unit = RvaToUnit(rva);
230*a03ca8b9SKrzysztof Kosiński   // This also handles dangling RVA.
231*a03ca8b9SKrzysztof Kosiński   return unit ? unit->RvaToOffsetUnsafe(rva, fake_offset_begin_)
232*a03ca8b9SKrzysztof Kosiński               : kInvalidOffset;
233*a03ca8b9SKrzysztof Kosiński }
234*a03ca8b9SKrzysztof Kosiński 
OffsetToUnit(offset_t offset) const235*a03ca8b9SKrzysztof Kosiński const AddressTranslator::Unit* AddressTranslator::OffsetToUnit(
236*a03ca8b9SKrzysztof Kosiński     offset_t offset) const {
237*a03ca8b9SKrzysztof Kosiński   // Finds first Unit with |offset_begin| > |offset|, rewind by 1 to find the
238*a03ca8b9SKrzysztof Kosiński   // last Unit with |offset_begin| >= |offset| (if it exists).
239*a03ca8b9SKrzysztof Kosiński   auto it = std::upper_bound(
240*a03ca8b9SKrzysztof Kosiński       units_sorted_by_offset_.begin(), units_sorted_by_offset_.end(), offset,
241*a03ca8b9SKrzysztof Kosiński       [](offset_t a, const Unit& b) { return a < b.offset_begin; });
242*a03ca8b9SKrzysztof Kosiński   if (it == units_sorted_by_offset_.begin())
243*a03ca8b9SKrzysztof Kosiński     return nullptr;
244*a03ca8b9SKrzysztof Kosiński   --it;
245*a03ca8b9SKrzysztof Kosiński   return it->CoversOffset(offset) ? &(*it) : nullptr;
246*a03ca8b9SKrzysztof Kosiński }
247*a03ca8b9SKrzysztof Kosiński 
RvaToUnit(rva_t rva) const248*a03ca8b9SKrzysztof Kosiński const AddressTranslator::Unit* AddressTranslator::RvaToUnit(rva_t rva) const {
249*a03ca8b9SKrzysztof Kosiński   auto it = std::upper_bound(
250*a03ca8b9SKrzysztof Kosiński       units_sorted_by_rva_.begin(), units_sorted_by_rva_.end(), rva,
251*a03ca8b9SKrzysztof Kosiński       [](rva_t a, const Unit& b) { return a < b.rva_begin; });
252*a03ca8b9SKrzysztof Kosiński   if (it == units_sorted_by_rva_.begin())
253*a03ca8b9SKrzysztof Kosiński     return nullptr;
254*a03ca8b9SKrzysztof Kosiński   --it;
255*a03ca8b9SKrzysztof Kosiński   return it->CoversRva(rva) ? &(*it) : nullptr;
256*a03ca8b9SKrzysztof Kosiński }
257*a03ca8b9SKrzysztof Kosiński 
258*a03ca8b9SKrzysztof Kosiński }  // namespace zucchini
259