xref: /aosp_15_r20/external/google-breakpad/src/processor/range_map-inl.h (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
1 // Copyright 2010 Google LLC
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are
5 // met:
6 //
7 //     * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 //     * Redistributions in binary form must reproduce the above
10 // copyright notice, this list of conditions and the following disclaimer
11 // in the documentation and/or other materials provided with the
12 // distribution.
13 //     * Neither the name of Google LLC nor the names of its
14 // contributors may be used to endorse or promote products derived from
15 // this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 
29 // range_map-inl.h: Range map implementation.
30 //
31 // See range_map.h for documentation.
32 //
33 // Author: Mark Mentovai
34 
35 #ifndef PROCESSOR_RANGE_MAP_INL_H__
36 #define PROCESSOR_RANGE_MAP_INL_H__
37 
38 
39 #include <assert.h>
40 
41 #include "common/safe_math.h"
42 #include "processor/range_map.h"
43 #include "processor/linked_ptr.h"
44 #include "processor/logging.h"
45 
46 
47 namespace google_breakpad {
48 
49 template<typename AddressType, typename EntryType>
StoreRange(const AddressType & base,const AddressType & size,const EntryType & entry)50 bool RangeMap<AddressType, EntryType>::StoreRange(const AddressType& base,
51                                                   const AddressType& size,
52                                                   const EntryType& entry) {
53   return StoreRangeInternal(base, 0 /* delta */, size, entry);
54 }
55 
56 template<typename AddressType, typename EntryType>
StoreRangeInternal(const AddressType & base,const AddressType & delta,const AddressType & size,const EntryType & entry)57 bool RangeMap<AddressType, EntryType>::StoreRangeInternal(
58     const AddressType& base, const AddressType& delta,
59     const AddressType& size, const EntryType& entry) {
60   AddressType high;
61   bool high_ok = false;
62   if (size > 0) {
63     std::pair<AddressType, bool> result = AddWithOverflowCheck(base, size - 1);
64     high = result.first;
65     high_ok = !result.second;
66   }
67   // Check for undersize or overflow.
68   if (!high_ok) {
69     // The processor will hit this case too frequently with common symbol
70     // files in the size == 0 case, which is more suited to a DEBUG channel.
71     // Filter those out since there's no DEBUG channel at the moment.
72     BPLOG_IF(INFO, size != 0) << "StoreRangeInternal failed, "
73                               << HexString(base) << "+" << HexString(size)
74                               << ", " << HexString(high)
75                               << ", delta: " << HexString(delta);
76     return false;
77   }
78 
79   // Ensure that this range does not overlap with another one already in the
80   // map.
81   MapConstIterator iterator_base = map_.lower_bound(base);
82   MapConstIterator iterator_high = map_.lower_bound(high);
83 
84   if (iterator_base != iterator_high) {
85     // Some other range ends in the space used by this range.  It may be
86     // contained within the space used by this range, or it may extend lower.
87     if (merge_strategy_ == MergeRangeStrategy::kTruncateLower) {
88       // kTruncate the range with the lower base address.
89       AddressType other_base = iterator_base->second.base();
90       if (base < other_base) {
91         return StoreRangeInternal(base, delta, other_base - base, entry);
92       } else if (other_base < base) {
93         EntryType other_entry;
94         AddressType other_high, other_size, other_delta;
95         other_high = iterator_base->first;
96         RetrieveRange(other_high, &other_entry, &other_base, &other_delta,
97                       &other_size);
98         map_.erase(iterator_base);
99         map_.insert(
100             MapValue(base - 1, Range(other_base, other_delta, other_entry)));
101         return StoreRangeInternal(base, delta, size, entry);
102       } else {
103         return false;
104       }
105     } else if (merge_strategy_ == MergeRangeStrategy::kTruncateUpper) {
106       // Truncate the lower portion of this range.
107       AddressType additional_delta = iterator_base->first - base + 1;
108       return StoreRangeInternal(base + additional_delta,
109                                 delta + additional_delta,
110                                 size - additional_delta, entry);
111     } else {
112       // The processor hits this case too frequently with common symbol files.
113       // This is most appropriate for a DEBUG channel, but since none exists
114       // now simply comment out this logging.
115       // AddressType other_base = iterator_base->second.base();
116       // AddressType other_size = iterator_base->first - other_base + 1;
117       // BPLOG(INFO) << "StoreRangeInternal failed, an existing range is "
118       //             << "overlapping with the new range: new "
119       //             << HexString(base) << "+" << HexString(size)
120       //             << ", existing " << HexString(other_base) << "+"
121       //             << HexString(other_size);
122       return false;
123     }
124   }
125 
126   if (iterator_high != map_.end() && iterator_high->second.base() <= high) {
127     // The range above this one overlaps with this one.  It may fully
128     // contain this range, or it may begin within this range and extend
129     // higher.
130     if (merge_strategy_ == MergeRangeStrategy::kTruncateLower) {
131       AddressType other_base = iterator_high->second.base();
132       if (base < other_base) {
133         return StoreRangeInternal(base, delta, other_base - base, entry);
134       } else if (other_base < base) {
135         EntryType other_entry;
136         AddressType other_high, other_size, other_delta;
137         other_high = iterator_high->first;
138         RetrieveRange(other_high, &other_entry, &other_base, &other_delta,
139                       &other_size);
140         map_.erase(iterator_high);
141         map_.insert(
142             MapValue(base - 1, Range(other_base, other_delta, other_entry)));
143         return StoreRangeInternal(base, delta, size, entry);
144       } else {
145         return false;
146       }
147     } else if (merge_strategy_ == MergeRangeStrategy::kTruncateUpper &&
148                iterator_high->first > high) {
149       // Shrink the other range down.
150       AddressType other_high = iterator_high->first;
151       AddressType additional_delta = high - iterator_high->second.base() + 1;
152       EntryType other_entry;
153       AddressType other_base = AddressType();
154       AddressType other_size = AddressType();
155       AddressType other_delta = AddressType();
156       RetrieveRange(other_high, &other_entry, &other_base, &other_delta,
157                     &other_size);
158       map_.erase(iterator_high);
159       map_.insert(MapValue(other_high,
160                            Range(other_base + additional_delta,
161                                  other_delta + additional_delta, other_entry)));
162       // Retry to store this range.
163       return StoreRangeInternal(base, delta, size, entry);
164     } else {
165       // The processor hits this case too frequently with common symbol files.
166       // This is most appropriate for a DEBUG channel, but since none exists
167       // now simply comment out this logging.
168       //
169       // AddressType other_base = iterator_high->second.base();
170       // AddressType other_size = iterator_high->first - other_base + 1;
171       // BPLOG(INFO) << "StoreRangeInternal failed, an existing range "
172       //             << "contains or extends higher than the new range: new "
173       //             << HexString(base) << "+" << HexString(size)
174       //             << ", existing " << HexString(other_base) << "+"
175       //             << HexString(other_size);
176       return false;
177     }
178   }
179 
180   // Store the range in the map by its high address, so that lower_bound can
181   // be used to quickly locate a range by address.
182   map_.insert(MapValue(high, Range(base, delta, entry)));
183   return true;
184 }
185 
186 
187 template<typename AddressType, typename EntryType>
RetrieveRange(const AddressType & address,EntryType * entry,AddressType * entry_base,AddressType * entry_delta,AddressType * entry_size)188 bool RangeMap<AddressType, EntryType>::RetrieveRange(
189     const AddressType& address, EntryType* entry, AddressType* entry_base,
190     AddressType* entry_delta, AddressType* entry_size) const {
191   BPLOG_IF(ERROR, !entry) << "RangeMap::RetrieveRange requires |entry|";
192   assert(entry);
193 
194   MapConstIterator iterator = map_.lower_bound(address);
195   if (iterator == map_.end())
196     return false;
197 
198   // The map is keyed by the high address of each range, so |address| is
199   // guaranteed to be lower than the range's high address.  If |range| is
200   // not directly preceded by another range, it's possible for address to
201   // be below the range's low address, though.  When that happens, address
202   // references something not within any range, so return false.
203   if (address < iterator->second.base())
204     return false;
205 
206   *entry = iterator->second.entry();
207   if (entry_base)
208     *entry_base = iterator->second.base();
209   if (entry_delta)
210     *entry_delta = iterator->second.delta();
211   if (entry_size)
212     *entry_size = iterator->first - iterator->second.base() + 1;
213 
214   return true;
215 }
216 
217 
218 template<typename AddressType, typename EntryType>
RetrieveNearestRange(const AddressType & address,EntryType * entry,AddressType * entry_base,AddressType * entry_delta,AddressType * entry_size)219 bool RangeMap<AddressType, EntryType>::RetrieveNearestRange(
220     const AddressType& address, EntryType* entry, AddressType* entry_base,
221     AddressType* entry_delta, AddressType* entry_size) const {
222   BPLOG_IF(ERROR, !entry) << "RangeMap::RetrieveNearestRange requires |entry|";
223   assert(entry);
224 
225   // If address is within a range, RetrieveRange can handle it.
226   if (RetrieveRange(address, entry, entry_base, entry_delta, entry_size))
227     return true;
228 
229   // upper_bound gives the first element whose key is greater than address,
230   // but we want the first element whose key is less than or equal to address.
231   // Decrement the iterator to get there, but not if the upper_bound already
232   // points to the beginning of the map - in that case, address is lower than
233   // the lowest stored key, so return false.
234   MapConstIterator iterator = map_.upper_bound(address);
235   if (iterator == map_.begin())
236     return false;
237   --iterator;
238 
239   *entry = iterator->second.entry();
240   if (entry_base)
241     *entry_base = iterator->second.base();
242   if (entry_delta)
243     *entry_delta = iterator->second.delta();
244   if (entry_size)
245     *entry_size = iterator->first - iterator->second.base() + 1;
246 
247   return true;
248 }
249 
250 
251 template<typename AddressType, typename EntryType>
RetrieveRangeAtIndex(int index,EntryType * entry,AddressType * entry_base,AddressType * entry_delta,AddressType * entry_size)252 bool RangeMap<AddressType, EntryType>::RetrieveRangeAtIndex(
253     int index, EntryType* entry, AddressType* entry_base,
254     AddressType* entry_delta, AddressType* entry_size) const {
255   BPLOG_IF(ERROR, !entry) << "RangeMap::RetrieveRangeAtIndex requires |entry|";
256   assert(entry);
257 
258   if (index >= GetCount()) {
259     BPLOG(ERROR) << "Index out of range: " << index << "/" << GetCount();
260     return false;
261   }
262 
263   // Walk through the map.  Although it's ordered, it's not a vector, so it
264   // can't be addressed directly by index.
265   MapConstIterator iterator = map_.begin();
266   for (int this_index = 0; this_index < index; ++this_index)
267     ++iterator;
268 
269   *entry = iterator->second.entry();
270   if (entry_base)
271     *entry_base = iterator->second.base();
272   if (entry_delta)
273     *entry_delta = iterator->second.delta();
274   if (entry_size)
275     *entry_size = iterator->first - iterator->second.base() + 1;
276 
277   return true;
278 }
279 
280 
281 template<typename AddressType, typename EntryType>
GetCount()282 int RangeMap<AddressType, EntryType>::GetCount() const {
283   return static_cast<int>(map_.size());
284 }
285 
286 
287 template<typename AddressType, typename EntryType>
Clear()288 void RangeMap<AddressType, EntryType>::Clear() {
289   map_.clear();
290 }
291 
292 
293 }  // namespace google_breakpad
294 
295 
296 #endif  // PROCESSOR_RANGE_MAP_INL_H__
297