1 //===-- DWARFDebugAranges.cpp -----------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "DWARFDebugAranges.h" 11 12 #include <assert.h> 13 #include <stdio.h> 14 15 #include <algorithm> 16 17 #include "lldb/Core/Log.h" 18 #include "lldb/Core/Stream.h" 19 #include "lldb/Core/Timer.h" 20 21 #include "LogChannelDWARF.h" 22 #include "SymbolFileDWARF.h" 23 #include "DWARFDebugInfo.h" 24 #include "DWARFCompileUnit.h" 25 26 using namespace lldb_private; 27 28 //---------------------------------------------------------------------- 29 // Constructor 30 //---------------------------------------------------------------------- 31 DWARFDebugAranges::DWARFDebugAranges() : 32 m_aranges() 33 { 34 } 35 36 37 //---------------------------------------------------------------------- 38 // Compare function DWARFDebugAranges::Range structures 39 //---------------------------------------------------------------------- 40 static bool RangeLessThan (const DWARFDebugAranges::Range& range1, const DWARFDebugAranges::Range& range2) 41 { 42 return range1.lo_pc < range2.lo_pc; 43 } 44 45 //---------------------------------------------------------------------- 46 // CountArangeDescriptors 47 //---------------------------------------------------------------------- 48 class CountArangeDescriptors 49 { 50 public: 51 CountArangeDescriptors (uint32_t& count_ref) : count(count_ref) 52 { 53 // printf("constructor CountArangeDescriptors()\n"); 54 } 55 void operator() (const DWARFDebugArangeSet& set) 56 { 57 count += set.NumDescriptors(); 58 } 59 uint32_t& count; 60 }; 61 62 //---------------------------------------------------------------------- 63 // AddArangeDescriptors 64 //---------------------------------------------------------------------- 65 class AddArangeDescriptors 66 { 67 public: 68 AddArangeDescriptors (DWARFDebugAranges::RangeColl& ranges) : range_collection(ranges) {} 69 void operator() (const DWARFDebugArangeSet& set) 70 { 71 const DWARFDebugArangeSet::Descriptor* arange_desc_ptr; 72 DWARFDebugAranges::Range range; 73 range.offset = set.GetCompileUnitDIEOffset(); 74 75 for (uint32_t i=0; (arange_desc_ptr = set.GetDescriptor(i)) != NULL; ++i) 76 { 77 range.lo_pc = arange_desc_ptr->address; 78 range.length = arange_desc_ptr->length; 79 80 // Insert each item in increasing address order so binary searching 81 // can later be done! 82 DWARFDebugAranges::RangeColl::iterator insert_pos = lower_bound(range_collection.begin(), range_collection.end(), range, RangeLessThan); 83 range_collection.insert(insert_pos, range); 84 } 85 } 86 DWARFDebugAranges::RangeColl& range_collection; 87 }; 88 89 //---------------------------------------------------------------------- 90 // PrintRange 91 //---------------------------------------------------------------------- 92 static void PrintRange(const DWARFDebugAranges::Range& range) 93 { 94 // Cast the address values in case the address type is compiled as 32 bit 95 printf("0x%8.8x: [0x%8.8llx - 0x%8.8llx)\n", range.offset, (long long)range.lo_pc, (long long)range.hi_pc()); 96 } 97 98 //---------------------------------------------------------------------- 99 // Extract 100 //---------------------------------------------------------------------- 101 bool 102 DWARFDebugAranges::Extract(const DataExtractor &debug_aranges_data) 103 { 104 if (debug_aranges_data.ValidOffset(0)) 105 { 106 uint32_t offset = 0; 107 108 typedef std::vector<DWARFDebugArangeSet> SetCollection; 109 typedef SetCollection::const_iterator SetCollectionIter; 110 SetCollection sets; 111 112 DWARFDebugArangeSet set; 113 Range range; 114 while (set.Extract(debug_aranges_data, &offset)) 115 sets.push_back(set); 116 117 uint32_t count = 0; 118 119 for_each(sets.begin(), sets.end(), CountArangeDescriptors(count)); 120 121 if (count > 0) 122 { 123 m_aranges.reserve(count); 124 AddArangeDescriptors range_adder(m_aranges); 125 for_each(sets.begin(), sets.end(), range_adder); 126 } 127 128 // puts("\n\nDWARFDebugAranges list is:\n"); 129 // for_each(m_aranges.begin(), m_aranges.end(), PrintRange); 130 } 131 return false; 132 } 133 134 //---------------------------------------------------------------------- 135 // Generate 136 //---------------------------------------------------------------------- 137 bool 138 DWARFDebugAranges::Generate(SymbolFileDWARF* dwarf2Data) 139 { 140 Clear(); 141 DWARFDebugInfo* debug_info = dwarf2Data->DebugInfo(); 142 if (debug_info) 143 { 144 const bool clear_dies_if_already_not_parsed = true; 145 uint32_t cu_idx = 0; 146 const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits(); 147 for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) 148 { 149 DWARFCompileUnit* cu = debug_info->GetCompileUnitAtIndex(cu_idx); 150 if (cu) 151 cu->BuildAddressRangeTable(dwarf2Data, this, clear_dies_if_already_not_parsed); 152 } 153 } 154 return !IsEmpty(); 155 } 156 157 158 void 159 DWARFDebugAranges::Dump (Log *log) const 160 { 161 if (log == NULL) 162 return; 163 const uint32_t num_ranges = NumRanges(); 164 for (uint32_t i = 0; i < num_ranges; ++i) 165 { 166 const Range &range = m_aranges[i]; 167 log->Printf ("0x%8.8x: [0x%8.8llx - 0x%8.8llx)", range.offset, (uint64_t)range.lo_pc, (uint64_t)range.hi_pc()); 168 } 169 } 170 171 172 void 173 DWARFDebugAranges::Range::Dump(Stream *s) const 174 { 175 s->Printf("{0x%8.8x}: [0x%8.8llx - 0x%8.8llx)\n", offset, lo_pc, hi_pc()); 176 } 177 178 //---------------------------------------------------------------------- 179 // Dump 180 //---------------------------------------------------------------------- 181 //void 182 //DWARFDebugAranges::Dump(SymbolFileDWARF* dwarf2Data, Stream *s) 183 //{ 184 // const DataExtractor &debug_aranges_data = dwarf2Data->get_debug_aranges_data(); 185 // if (debug_aranges_data.ValidOffset(0)) 186 // { 187 // uint32_t offset = 0; 188 // 189 // DWARFDebugArangeSet set; 190 // while (set.Extract(debug_aranges_data, &offset)) 191 // set.Dump(s); 192 // } 193 // else 194 // s->PutCString("< EMPTY >\n"); 195 //} 196 // 197 198 //---------------------------------------------------------------------- 199 // AppendDebugRanges 200 //---------------------------------------------------------------------- 201 //void 202 //DWARFDebugAranges::AppendDebugRanges(BinaryStreamBuf& debug_ranges, dw_addr_t cu_base_addr, uint32_t addr_size) const 203 //{ 204 // if (!m_aranges.empty()) 205 // { 206 // RangeCollIterator end = m_aranges.end(); 207 // RangeCollIterator pos; 208 // RangeCollIterator lo_pos = end; 209 // for (pos = m_aranges.begin(); pos != end; ++pos) 210 // { 211 // if (lo_pos == end) 212 // lo_pos = pos; 213 // 214 // RangeCollIterator next = pos + 1; 215 // if (next != end) 216 // { 217 // // Check to see if we can combine two consecutive ranges? 218 // if (pos->hi_pc == next->lo_pc) 219 // continue; // We can combine them! 220 // } 221 // 222 // if (cu_base_addr == 0 || cu_base_addr == DW_INVALID_ADDRESS) 223 // { 224 // debug_ranges.AppendMax64(lo_pos->lo_pc, addr_size); 225 // debug_ranges.AppendMax64(pos->hi_pc, addr_size); 226 // } 227 // else 228 // { 229 // assert(lo_pos->lo_pc >= cu_base_addr); 230 // assert(pos->hi_pc >= cu_base_addr); 231 // debug_ranges.AppendMax64(lo_pos->lo_pc - cu_base_addr, addr_size); 232 // debug_ranges.AppendMax64(pos->hi_pc - cu_base_addr, addr_size); 233 // } 234 // 235 // // Reset the low part of the next address range 236 // lo_pos = end; 237 // } 238 // } 239 // // Terminate the .debug_ranges with two zero addresses 240 // debug_ranges.AppendMax64(0, addr_size); 241 // debug_ranges.AppendMax64(0, addr_size); 242 // 243 //} 244 void 245 DWARFDebugAranges::AppendRange (dw_offset_t offset, dw_addr_t low_pc, dw_addr_t high_pc) 246 { 247 if (!m_aranges.empty()) 248 { 249 if (m_aranges.back().offset == offset && m_aranges.back().hi_pc() == low_pc) 250 { 251 m_aranges.back().set_hi_pc(high_pc); 252 return; 253 } 254 } 255 m_aranges.push_back (DWARFDebugAranges::Range(low_pc, high_pc, offset)); 256 } 257 258 void 259 DWARFDebugAranges::Sort (bool minimize, uint32_t n) 260 { 261 Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p", 262 __PRETTY_FUNCTION__, this); 263 264 Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_ARANGES); 265 const size_t orig_arange_size = m_aranges.size(); 266 if (log) 267 { 268 log->Printf ("DWARFDebugAranges::Sort(minimize = %u, n = %u) with %zu entries", minimize, n, orig_arange_size); 269 Dump (log); 270 } 271 272 // Size of one? If so, no sorting is needed 273 if (orig_arange_size <= 1) 274 return; 275 // Sort our address range entries 276 std::stable_sort (m_aranges.begin(), m_aranges.end(), RangeLessThan); 277 278 279 if (!minimize) 280 return; 281 282 // Most address ranges are contiguous from function to function 283 // so our new ranges will likely be smaller. We calculate the size 284 // of the new ranges since although std::vector objects can be resized, 285 // the will never reduce their allocated block size and free any excesss 286 // memory, so we might as well start a brand new collection so it is as 287 // small as possible. 288 289 // First calculate the size of the new minimal arange vector 290 // so we don't have to do a bunch of re-allocations as we 291 // copy the new minimal stuff over to the new collection 292 size_t minimal_size = 1; 293 size_t i; 294 for (i=1; i<orig_arange_size; ++i) 295 { 296 if (!DWARFDebugAranges::Range::SortedOverlapCheck (m_aranges[i-1], m_aranges[i], n)) 297 ++minimal_size; 298 } 299 300 // If the sizes are the same, then no consecutive aranges can be 301 // combined, we are done 302 if (minimal_size == orig_arange_size) 303 return; 304 305 // Else, make a new RangeColl that _only_ contains what we need. 306 RangeColl minimal_aranges; 307 minimal_aranges.resize(minimal_size); 308 uint32_t j=0; 309 minimal_aranges[j] = m_aranges[0]; 310 for (i=1; i<orig_arange_size; ++i) 311 { 312 if (DWARFDebugAranges::Range::SortedOverlapCheck (minimal_aranges[j], m_aranges[i], n)) 313 { 314 minimal_aranges[j].set_hi_pc (m_aranges[i].hi_pc()); 315 } 316 else 317 { 318 // Only increment j if we aren't merging 319 minimal_aranges[++j] = m_aranges[i]; 320 } 321 } 322 assert (j+1 == minimal_size); 323 324 // Now swap our new minimal aranges into place. The local 325 // minimal_aranges will then contian the old big collection 326 // which will get freed. 327 minimal_aranges.swap(m_aranges); 328 329 if (log) 330 { 331 size_t delta = orig_arange_size - m_aranges.size(); 332 log->Printf ("DWARFDebugAranges::Sort() %zu entries after minimizing (%zu entries combined for %zu bytes saved)", 333 m_aranges.size(), delta, delta * sizeof(Range)); 334 Dump (log); 335 } 336 } 337 338 //---------------------------------------------------------------------- 339 // FindAddress 340 //---------------------------------------------------------------------- 341 dw_offset_t 342 DWARFDebugAranges::FindAddress(dw_addr_t address) const 343 { 344 if ( !m_aranges.empty() ) 345 { 346 DWARFDebugAranges::Range range(address); 347 DWARFDebugAranges::RangeCollIterator begin = m_aranges.begin(); 348 DWARFDebugAranges::RangeCollIterator end = m_aranges.end(); 349 DWARFDebugAranges::RangeCollIterator pos = lower_bound(begin, end, range, RangeLessThan); 350 351 if ((pos != end) && (pos->lo_pc <= address && address < pos->hi_pc())) 352 { 353 // printf("FindAddress(1) found 0x%8.8x in compile unit: 0x%8.8x\n", address, pos->offset); 354 return pos->offset; 355 } 356 else if (pos != begin) 357 { 358 --pos; 359 if ((pos->lo_pc <= address) && (address < pos->hi_pc())) 360 { 361 // printf("FindAddress(2) found 0x%8.8x in compile unit: 0x%8.8x\n", address, pos->offset); 362 return (*pos).offset; 363 } 364 } 365 } 366 return DW_INVALID_OFFSET; 367 } 368 369 //---------------------------------------------------------------------- 370 // AllRangesAreContiguous 371 //---------------------------------------------------------------------- 372 bool 373 DWARFDebugAranges::AllRangesAreContiguous(dw_addr_t& lo_pc, dw_addr_t& hi_pc) const 374 { 375 if (m_aranges.empty()) 376 return false; 377 378 DWARFDebugAranges::RangeCollIterator begin = m_aranges.begin(); 379 DWARFDebugAranges::RangeCollIterator end = m_aranges.end(); 380 DWARFDebugAranges::RangeCollIterator pos; 381 dw_addr_t next_addr = 0; 382 383 for (pos = begin; pos != end; ++pos) 384 { 385 if ((pos != begin) && (pos->lo_pc != next_addr)) 386 return false; 387 next_addr = pos->hi_pc(); 388 } 389 lo_pc = m_aranges.front().lo_pc; // We checked for empty at the start of function so front() will be valid 390 hi_pc = m_aranges.back().hi_pc(); // We checked for empty at the start of function so back() will be valid 391 return true; 392 } 393 394 bool 395 DWARFDebugAranges::GetMaxRange(dw_addr_t& lo_pc, dw_addr_t& hi_pc) const 396 { 397 if (m_aranges.empty()) 398 return false; 399 400 lo_pc = m_aranges.front().lo_pc; // We checked for empty at the start of function so front() will be valid 401 hi_pc = m_aranges.back().hi_pc(); // We checked for empty at the start of function so back() will be valid 402 return true; 403 } 404 405