range_map-inl.h
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> 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> 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> 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> 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> 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> 282 int RangeMap<AddressType, EntryType>::GetCount() const { 283 return static_cast<int>(map_.size()); 284 } 285 286 287 template<typename AddressType, typename EntryType> 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__