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