1 //===-- DWARFDebugInfo.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 "SymbolFileDWARF.h" 11 12 #include <algorithm> 13 #include <set> 14 15 #include "lldb/Core/RegularExpression.h" 16 #include "lldb/Core/Stream.h" 17 #include "lldb/Symbol/ObjectFile.h" 18 19 #include "DWARFDebugAranges.h" 20 #include "DWARFDebugInfo.h" 21 #include "DWARFCompileUnit.h" 22 #include "DWARFDebugAranges.h" 23 #include "DWARFDebugInfoEntry.h" 24 #include "DWARFFormValue.h" 25 #include "LogChannelDWARF.h" 26 27 using namespace lldb; 28 using namespace lldb_private; 29 using namespace std; 30 31 //---------------------------------------------------------------------- 32 // Constructor 33 //---------------------------------------------------------------------- 34 DWARFDebugInfo::DWARFDebugInfo() : 35 m_dwarf2Data(NULL), 36 m_compile_units(), 37 m_cu_aranges_ap () 38 { 39 } 40 41 //---------------------------------------------------------------------- 42 // SetDwarfData 43 //---------------------------------------------------------------------- 44 void 45 DWARFDebugInfo::SetDwarfData(SymbolFileDWARF* dwarf2Data) 46 { 47 m_dwarf2Data = dwarf2Data; 48 m_compile_units.clear(); 49 } 50 51 52 DWARFDebugAranges & 53 DWARFDebugInfo::GetCompileUnitAranges () 54 { 55 if (m_cu_aranges_ap.get() == NULL && m_dwarf2Data) 56 { 57 Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_ARANGES)); 58 59 m_cu_aranges_ap.reset (new DWARFDebugAranges()); 60 const DataExtractor &debug_aranges_data = m_dwarf2Data->get_debug_aranges_data(); 61 if (debug_aranges_data.GetByteSize() > 0) 62 { 63 if (log) 64 log->Printf ("DWARFDebugInfo::GetCompileUnitAranges() for \"%s\" from .debug_aranges", 65 m_dwarf2Data->GetObjectFile()->GetFileSpec().GetPath().c_str()); 66 m_cu_aranges_ap->Extract (debug_aranges_data); 67 68 } 69 else 70 { 71 if (log) 72 log->Printf ("DWARFDebugInfo::GetCompileUnitAranges() for \"%s\" by parsing", 73 m_dwarf2Data->GetObjectFile()->GetFileSpec().GetPath().c_str()); 74 const size_t num_compile_units = GetNumCompileUnits(); 75 const bool clear_dies_if_already_not_parsed = true; 76 for (size_t idx = 0; idx < num_compile_units; ++idx) 77 { 78 DWARFCompileUnit* cu = GetCompileUnitAtIndex(idx); 79 if (cu) 80 cu->BuildAddressRangeTable (m_dwarf2Data, m_cu_aranges_ap.get(), clear_dies_if_already_not_parsed); 81 } 82 } 83 84 const bool minimize = true; 85 m_cu_aranges_ap->Sort (minimize); 86 } 87 return *m_cu_aranges_ap.get(); 88 } 89 90 91 //---------------------------------------------------------------------- 92 // LookupAddress 93 //---------------------------------------------------------------------- 94 bool 95 DWARFDebugInfo::LookupAddress 96 ( 97 const dw_addr_t address, 98 const dw_offset_t hint_die_offset, 99 DWARFCompileUnitSP& cu_sp, 100 DWARFDebugInfoEntry** function_die, 101 DWARFDebugInfoEntry** block_die 102 ) 103 { 104 105 if (hint_die_offset != DW_INVALID_OFFSET) 106 cu_sp = GetCompileUnit(hint_die_offset); 107 else 108 { 109 DWARFDebugAranges &cu_aranges = GetCompileUnitAranges (); 110 const dw_offset_t cu_offset = cu_aranges.FindAddress (address); 111 cu_sp = GetCompileUnit(cu_offset); 112 } 113 114 if (cu_sp.get()) 115 { 116 if (cu_sp->LookupAddress(address, function_die, block_die)) 117 return true; 118 cu_sp.reset(); 119 } 120 else 121 { 122 // The hint_die_offset may have been a pointer to the actual item that 123 // we are looking for 124 DWARFDebugInfoEntry* die_ptr = GetDIEPtr(hint_die_offset, &cu_sp); 125 if (die_ptr) 126 { 127 if (cu_sp.get()) 128 { 129 if (function_die || block_die) 130 return die_ptr->LookupAddress(address, m_dwarf2Data, cu_sp.get(), function_die, block_die); 131 132 // We only wanted the compile unit that contained this address 133 return true; 134 } 135 } 136 } 137 return false; 138 } 139 140 141 void 142 DWARFDebugInfo::ParseCompileUnitHeadersIfNeeded() 143 { 144 if (m_compile_units.empty()) 145 { 146 if (m_dwarf2Data != NULL) 147 { 148 lldb::offset_t offset = 0; 149 const DataExtractor &debug_info_data = m_dwarf2Data->get_debug_info_data(); 150 while (debug_info_data.ValidOffset(offset)) 151 { 152 DWARFCompileUnitSP cu_sp(new DWARFCompileUnit(m_dwarf2Data)); 153 // Out of memory? 154 if (cu_sp.get() == NULL) 155 break; 156 157 if (cu_sp->Extract(debug_info_data, &offset) == false) 158 break; 159 160 m_compile_units.push_back(cu_sp); 161 162 offset = cu_sp->GetNextCompileUnitOffset(); 163 } 164 } 165 } 166 } 167 168 size_t 169 DWARFDebugInfo::GetNumCompileUnits() 170 { 171 ParseCompileUnitHeadersIfNeeded(); 172 return m_compile_units.size(); 173 } 174 175 DWARFCompileUnit* 176 DWARFDebugInfo::GetCompileUnitAtIndex(uint32_t idx) 177 { 178 DWARFCompileUnit* cu = NULL; 179 if (idx < GetNumCompileUnits()) 180 cu = m_compile_units[idx].get(); 181 return cu; 182 } 183 184 bool 185 DWARFDebugInfo::ContainsCompileUnit (const DWARFCompileUnit *cu) const 186 { 187 // Not a verify efficient function, but it is handy for use in assertions 188 // to make sure that a compile unit comes from a debug information file. 189 CompileUnitColl::const_iterator end_pos = m_compile_units.end(); 190 CompileUnitColl::const_iterator pos; 191 192 for (pos = m_compile_units.begin(); pos != end_pos; ++pos) 193 { 194 if (pos->get() == cu) 195 return true; 196 } 197 return false; 198 } 199 200 201 static bool CompileUnitOffsetLessThan (const DWARFCompileUnitSP& a, const DWARFCompileUnitSP& b) 202 { 203 return a->GetOffset() < b->GetOffset(); 204 } 205 206 207 static int 208 CompareDWARFCompileUnitSPOffset (const void *key, const void *arrmem) 209 { 210 const dw_offset_t key_cu_offset = *(dw_offset_t*) key; 211 const dw_offset_t cu_offset = ((DWARFCompileUnitSP *)arrmem)->get()->GetOffset(); 212 if (key_cu_offset < cu_offset) 213 return -1; 214 if (key_cu_offset > cu_offset) 215 return 1; 216 return 0; 217 } 218 219 DWARFCompileUnitSP 220 DWARFDebugInfo::GetCompileUnit(dw_offset_t cu_offset, uint32_t* idx_ptr) 221 { 222 DWARFCompileUnitSP cu_sp; 223 uint32_t cu_idx = DW_INVALID_INDEX; 224 if (cu_offset != DW_INVALID_OFFSET) 225 { 226 ParseCompileUnitHeadersIfNeeded(); 227 228 DWARFCompileUnitSP* match = (DWARFCompileUnitSP*)bsearch(&cu_offset, &m_compile_units[0], m_compile_units.size(), sizeof(DWARFCompileUnitSP), CompareDWARFCompileUnitSPOffset); 229 if (match) 230 { 231 cu_sp = *match; 232 cu_idx = match - &m_compile_units[0]; 233 } 234 } 235 if (idx_ptr) 236 *idx_ptr = cu_idx; 237 return cu_sp; 238 } 239 240 DWARFCompileUnitSP 241 DWARFDebugInfo::GetCompileUnitContainingDIE(dw_offset_t die_offset) 242 { 243 DWARFCompileUnitSP cu_sp; 244 if (die_offset != DW_INVALID_OFFSET) 245 { 246 ParseCompileUnitHeadersIfNeeded(); 247 248 CompileUnitColl::const_iterator end_pos = m_compile_units.end(); 249 CompileUnitColl::const_iterator pos; 250 251 for (pos = m_compile_units.begin(); pos != end_pos; ++pos) 252 { 253 dw_offset_t cu_start_offset = (*pos)->GetOffset(); 254 dw_offset_t cu_end_offset = (*pos)->GetNextCompileUnitOffset(); 255 if (cu_start_offset <= die_offset && die_offset < cu_end_offset) 256 { 257 cu_sp = *pos; 258 break; 259 } 260 } 261 } 262 return cu_sp; 263 } 264 265 //---------------------------------------------------------------------- 266 // Compare function DWARFDebugAranges::Range structures 267 //---------------------------------------------------------------------- 268 static bool CompareDIEOffset (const DWARFDebugInfoEntry& die1, const DWARFDebugInfoEntry& die2) 269 { 270 return die1.GetOffset() < die2.GetOffset(); 271 } 272 273 274 //---------------------------------------------------------------------- 275 // GetDIE() 276 // 277 // Get the DIE (Debug Information Entry) with the specified offset. 278 //---------------------------------------------------------------------- 279 DWARFDebugInfoEntry* 280 DWARFDebugInfo::GetDIEPtr(dw_offset_t die_offset, DWARFCompileUnitSP* cu_sp_ptr) 281 { 282 DWARFCompileUnitSP cu_sp(GetCompileUnitContainingDIE(die_offset)); 283 if (cu_sp_ptr) 284 *cu_sp_ptr = cu_sp; 285 if (cu_sp.get()) 286 return cu_sp->GetDIEPtr(die_offset); 287 return NULL; // Not found in any compile units 288 } 289 290 DWARFDebugInfoEntry* 291 DWARFDebugInfo::GetDIEPtrWithCompileUnitHint (dw_offset_t die_offset, DWARFCompileUnit**cu_handle) 292 { 293 assert (cu_handle); 294 DWARFDebugInfoEntry* die = NULL; 295 if (*cu_handle) 296 die = (*cu_handle)->GetDIEPtr(die_offset); 297 298 if (die == NULL) 299 { 300 DWARFCompileUnitSP cu_sp (GetCompileUnitContainingDIE(die_offset)); 301 if (cu_sp.get()) 302 { 303 *cu_handle = cu_sp.get(); 304 die = cu_sp->GetDIEPtr(die_offset); 305 } 306 } 307 if (die == NULL) 308 *cu_handle = NULL; 309 return die; 310 } 311 312 313 const DWARFDebugInfoEntry* 314 DWARFDebugInfo::GetDIEPtrContainingOffset(dw_offset_t die_offset, DWARFCompileUnitSP* cu_sp_ptr) 315 { 316 DWARFCompileUnitSP cu_sp(GetCompileUnitContainingDIE(die_offset)); 317 if (cu_sp_ptr) 318 *cu_sp_ptr = cu_sp; 319 if (cu_sp.get()) 320 return cu_sp->GetDIEPtrContainingOffset(die_offset); 321 322 return NULL; // Not found in any compile units 323 324 } 325 326 //---------------------------------------------------------------------- 327 // DWARFDebugInfo_ParseCallback 328 // 329 // A callback function for the static DWARFDebugInfo::Parse() function 330 // that gets parses all compile units and DIE's into an internate 331 // representation for further modification. 332 //---------------------------------------------------------------------- 333 334 static dw_offset_t 335 DWARFDebugInfo_ParseCallback 336 ( 337 SymbolFileDWARF* dwarf2Data, 338 DWARFCompileUnitSP& cu_sp, 339 DWARFDebugInfoEntry* die, 340 const dw_offset_t next_offset, 341 const uint32_t curr_depth, 342 void* userData 343 ) 344 { 345 DWARFDebugInfo* debug_info = (DWARFDebugInfo*)userData; 346 DWARFCompileUnit* cu = cu_sp.get(); 347 if (die) 348 { 349 cu->AddDIE(*die); 350 } 351 else if (cu) 352 { 353 debug_info->AddCompileUnit(cu_sp); 354 } 355 356 // Just return the current offset to parse the next CU or DIE entry 357 return next_offset; 358 } 359 360 //---------------------------------------------------------------------- 361 // AddCompileUnit 362 //---------------------------------------------------------------------- 363 void 364 DWARFDebugInfo::AddCompileUnit(DWARFCompileUnitSP& cu) 365 { 366 m_compile_units.push_back(cu); 367 } 368 369 /* 370 void 371 DWARFDebugInfo::AddDIE(DWARFDebugInfoEntry& die) 372 { 373 m_die_array.push_back(die); 374 } 375 */ 376 377 378 379 380 //---------------------------------------------------------------------- 381 // Parse 382 // 383 // Parses the .debug_info section and uses the .debug_abbrev section 384 // and various other sections in the SymbolFileDWARF class and calls the 385 // supplied callback function each time a compile unit header, or debug 386 // information entry is successfully parsed. This function can be used 387 // for different tasks such as parsing the file contents into a 388 // structured data, dumping, verifying and much more. 389 //---------------------------------------------------------------------- 390 void 391 DWARFDebugInfo::Parse(SymbolFileDWARF* dwarf2Data, Callback callback, void* userData) 392 { 393 if (dwarf2Data) 394 { 395 lldb::offset_t offset = 0; 396 uint32_t depth = 0; 397 DWARFCompileUnitSP cu(new DWARFCompileUnit(dwarf2Data)); 398 if (cu.get() == NULL) 399 return; 400 DWARFDebugInfoEntry die; 401 402 while (cu->Extract(dwarf2Data->get_debug_info_data(), &offset)) 403 { 404 const dw_offset_t next_cu_offset = cu->GetNextCompileUnitOffset(); 405 406 depth = 0; 407 // Call the callback function with no DIE pointer for the compile unit 408 // and get the offset that we are to continue to parse from 409 offset = callback(dwarf2Data, cu, NULL, offset, depth, userData); 410 411 // Make sure we are within our compile unit 412 if (offset < next_cu_offset) 413 { 414 // We are in our compile unit, parse starting at the offset 415 // we were told to parse 416 bool done = false; 417 while (!done && die.Extract(dwarf2Data, cu.get(), &offset)) 418 { 419 // Call the callback function with DIE pointer that falls within the compile unit 420 offset = callback(dwarf2Data, cu, &die, offset, depth, userData); 421 422 if (die.IsNULL()) 423 { 424 if (depth) 425 --depth; 426 else 427 done = true; // We are done with this compile unit! 428 } 429 else if (die.HasChildren()) 430 ++depth; 431 } 432 } 433 434 // Make sure the offset returned is valid, and if not stop parsing. 435 // Returning DW_INVALID_OFFSET from this callback is a good way to end 436 // all parsing 437 if (!dwarf2Data->get_debug_info_data().ValidOffset(offset)) 438 break; 439 440 // See if during the callback anyone retained a copy of the compile 441 // unit other than ourselves and if so, let whomever did own the object 442 // and create a new one for our own use! 443 if (!cu.unique()) 444 cu.reset(new DWARFCompileUnit(dwarf2Data)); 445 446 447 // Make sure we start on a proper 448 offset = next_cu_offset; 449 } 450 } 451 } 452 453 typedef struct DumpInfo 454 { 455 DumpInfo(Stream* init_strm, uint32_t off, uint32_t depth) : 456 strm(init_strm), 457 die_offset(off), 458 recurse_depth(depth), 459 found_depth(UINT32_MAX), 460 found_die(false), 461 ancestors() 462 { 463 } 464 Stream* strm; 465 const uint32_t die_offset; 466 const uint32_t recurse_depth; 467 uint32_t found_depth; 468 bool found_die; 469 std::vector<DWARFDebugInfoEntry> ancestors; 470 471 DISALLOW_COPY_AND_ASSIGN(DumpInfo); 472 } DumpInfo; 473 474 //---------------------------------------------------------------------- 475 // DumpCallback 476 // 477 // A callback function for the static DWARFDebugInfo::Parse() function 478 // that gets called each time a compile unit header or debug information 479 // entry is successfully parsed. 480 // 481 // This function dump DWARF information and obey recurse depth and 482 // whether a single DIE is to be dumped (or all of the data). 483 //---------------------------------------------------------------------- 484 static dw_offset_t DumpCallback 485 ( 486 SymbolFileDWARF* dwarf2Data, 487 DWARFCompileUnitSP& cu_sp, 488 DWARFDebugInfoEntry* die, 489 const dw_offset_t next_offset, 490 const uint32_t curr_depth, 491 void* userData 492 ) 493 { 494 DumpInfo* dumpInfo = (DumpInfo*)userData; 495 496 const DWARFCompileUnit* cu = cu_sp.get(); 497 498 Stream *s = dumpInfo->strm; 499 bool show_parents = s->GetFlags().Test(DWARFDebugInfo::eDumpFlag_ShowAncestors); 500 501 if (die) 502 { 503 // Are we dumping everything? 504 if (dumpInfo->die_offset == DW_INVALID_OFFSET) 505 { 506 // Yes we are dumping everything. Obey our recurse level though 507 if (curr_depth < dumpInfo->recurse_depth) 508 die->Dump(dwarf2Data, cu, *s, 0); 509 } 510 else 511 { 512 // We are dumping a specific DIE entry by offset 513 if (dumpInfo->die_offset == die->GetOffset()) 514 { 515 // We found the DIE we were looking for, dump it! 516 if (show_parents) 517 { 518 s->SetIndentLevel(0); 519 const uint32_t num_ancestors = dumpInfo->ancestors.size(); 520 if (num_ancestors > 0) 521 { 522 for (uint32_t i=0; i<num_ancestors-1; ++i) 523 { 524 dumpInfo->ancestors[i].Dump(dwarf2Data, cu, *s, 0); 525 s->IndentMore(); 526 } 527 } 528 } 529 530 dumpInfo->found_depth = curr_depth; 531 532 die->Dump(dwarf2Data, cu, *s, 0); 533 534 // Note that we found the DIE we were looking for 535 dumpInfo->found_die = true; 536 537 // Since we are dumping a single DIE, if there are no children we are done! 538 if (!die->HasChildren() || dumpInfo->recurse_depth == 0) 539 return DW_INVALID_OFFSET; // Return an invalid address to end parsing 540 } 541 else if (dumpInfo->found_die) 542 { 543 // Are we done with all the children? 544 if (curr_depth <= dumpInfo->found_depth) 545 return DW_INVALID_OFFSET; 546 547 // We have already found our DIE and are printing it's children. Obey 548 // our recurse depth and return an invalid offset if we get done 549 // dumping all the the children 550 if (dumpInfo->recurse_depth == UINT32_MAX || curr_depth <= dumpInfo->found_depth + dumpInfo->recurse_depth) 551 die->Dump(dwarf2Data, cu, *s, 0); 552 } 553 else if (dumpInfo->die_offset > die->GetOffset()) 554 { 555 if (show_parents) 556 dumpInfo->ancestors.back() = *die; 557 } 558 } 559 560 // Keep up with our indent level 561 if (die->IsNULL()) 562 { 563 if (show_parents) 564 dumpInfo->ancestors.pop_back(); 565 566 if (curr_depth <= 1) 567 return cu->GetNextCompileUnitOffset(); 568 else 569 s->IndentLess(); 570 } 571 else if (die->HasChildren()) 572 { 573 if (show_parents) 574 { 575 DWARFDebugInfoEntry null_die; 576 dumpInfo->ancestors.push_back(null_die); 577 } 578 s->IndentMore(); 579 } 580 } 581 else 582 { 583 if (cu == NULL) 584 s->PutCString("NULL - cu"); 585 // We have a compile unit, reset our indent level to zero just in case 586 s->SetIndentLevel(0); 587 588 // See if we are dumping everything? 589 if (dumpInfo->die_offset == DW_INVALID_OFFSET) 590 { 591 // We are dumping everything 592 cu->Dump(s); 593 return cu->GetFirstDIEOffset(); // Return true to parse all DIEs in this Compile Unit 594 } 595 else 596 { 597 if (show_parents) 598 { 599 dumpInfo->ancestors.clear(); 600 dumpInfo->ancestors.resize(1); 601 } 602 603 // We are dumping only a single DIE possibly with it's children and 604 // we must find it's compile unit before we can dump it properly 605 if (dumpInfo->die_offset < cu->GetFirstDIEOffset()) 606 { 607 // Not found, maybe the DIE offset provided wasn't correct? 608 // *ostrm_ptr << "DIE at offset " << HEX32 << dumpInfo->die_offset << " was not found." << endl; 609 return DW_INVALID_OFFSET; 610 } 611 else 612 { 613 // See if the DIE is in this compile unit? 614 if (dumpInfo->die_offset < cu->GetNextCompileUnitOffset()) 615 { 616 // This DIE is in this compile unit! 617 if (s->GetVerbose()) 618 cu->Dump(s); // Dump the compile unit for the DIE in verbose mode 619 620 return next_offset; 621 // // We found our compile unit that contains our DIE, just skip to dumping the requested DIE... 622 // return dumpInfo->die_offset; 623 } 624 else 625 { 626 // Skip to the next compile unit as the DIE isn't in the current one! 627 return cu->GetNextCompileUnitOffset(); 628 } 629 } 630 } 631 } 632 633 // Just return the current offset to parse the next CU or DIE entry 634 return next_offset; 635 } 636 637 //---------------------------------------------------------------------- 638 // Dump 639 // 640 // Dump the information in the .debug_info section to the specified 641 // ostream. If die_offset is valid, a single DIE will be dumped. If the 642 // die_offset is invalid, all the DWARF information will be dumped. Both 643 // cases will obey a "recurse_depth" or how deep to traverse into the 644 // children of each DIE entry. A recurse_depth of zero will dump all 645 // compile unit headers. A recurse_depth of 1 will dump all compile unit 646 // headers and the DW_TAG_compile unit tags. A depth of 2 will also 647 // dump all types and functions. 648 //---------------------------------------------------------------------- 649 void 650 DWARFDebugInfo::Dump 651 ( 652 Stream *s, 653 SymbolFileDWARF* dwarf2Data, 654 const uint32_t die_offset, 655 const uint32_t recurse_depth 656 ) 657 { 658 DumpInfo dumpInfo(s, die_offset, recurse_depth); 659 s->PutCString(".debug_info contents"); 660 if (dwarf2Data->get_debug_info_data().GetByteSize() > 0) 661 { 662 if (die_offset == DW_INVALID_OFFSET) 663 s->PutCString(":\n"); 664 else 665 { 666 s->Printf(" for DIE entry at .debug_info[0x%8.8x]", die_offset); 667 if (recurse_depth != UINT32_MAX) 668 s->Printf(" recursing %u levels deep.", recurse_depth); 669 s->EOL(); 670 } 671 } 672 else 673 { 674 s->PutCString(": < EMPTY >\n"); 675 return; 676 } 677 DWARFDebugInfo::Parse(dwarf2Data, DumpCallback, &dumpInfo); 678 } 679 680 681 //---------------------------------------------------------------------- 682 // Dump 683 // 684 // Dump the contents of this DWARFDebugInfo object as has been parsed 685 // and/or modified after it has been parsed. 686 //---------------------------------------------------------------------- 687 void 688 DWARFDebugInfo::Dump (Stream *s, const uint32_t die_offset, const uint32_t recurse_depth) 689 { 690 DumpInfo dumpInfo(s, die_offset, recurse_depth); 691 692 s->PutCString("Dumping .debug_info section from internal representation\n"); 693 694 CompileUnitColl::const_iterator pos; 695 uint32_t curr_depth = 0; 696 ParseCompileUnitHeadersIfNeeded(); 697 for (pos = m_compile_units.begin(); pos != m_compile_units.end(); ++pos) 698 { 699 const DWARFCompileUnitSP& cu_sp = *pos; 700 DumpCallback(m_dwarf2Data, (DWARFCompileUnitSP&)cu_sp, NULL, 0, curr_depth, &dumpInfo); 701 702 const DWARFDebugInfoEntry* die = cu_sp->DIE(); 703 if (die) 704 die->Dump(m_dwarf2Data, cu_sp.get(), *s, recurse_depth); 705 } 706 } 707 708 709 //---------------------------------------------------------------------- 710 // FindCallbackString 711 // 712 // A callback function for the static DWARFDebugInfo::Parse() function 713 // that gets called each time a compile unit header or debug information 714 // entry is successfully parsed. 715 // 716 // This function will find the die_offset of any items whose DW_AT_name 717 // matches the given string 718 //---------------------------------------------------------------------- 719 typedef struct FindCallbackStringInfoTag 720 { 721 const char* name; 722 bool ignore_case; 723 RegularExpression* regex; 724 vector<dw_offset_t>& die_offsets; 725 } FindCallbackStringInfo; 726 727 static dw_offset_t FindCallbackString 728 ( 729 SymbolFileDWARF* dwarf2Data, 730 DWARFCompileUnitSP& cu_sp, 731 DWARFDebugInfoEntry* die, 732 const dw_offset_t next_offset, 733 const uint32_t curr_depth, 734 void* userData 735 ) 736 { 737 FindCallbackStringInfo* info = (FindCallbackStringInfo*)userData; 738 const DWARFCompileUnit* cu = cu_sp.get(); 739 740 if (die) 741 { 742 const char* die_name = die->GetName(dwarf2Data, cu); 743 if (die_name) 744 { 745 if (info->regex) 746 { 747 if (info->regex->Execute(die_name)) 748 info->die_offsets.push_back(die->GetOffset()); 749 } 750 else 751 { 752 if ((info->ignore_case ? strcasecmp(die_name, info->name) : strcmp(die_name, info->name)) == 0) 753 info->die_offsets.push_back(die->GetOffset()); 754 } 755 } 756 } 757 758 // Just return the current offset to parse the next CU or DIE entry 759 return next_offset; 760 } 761 762 //---------------------------------------------------------------------- 763 // Find 764 // 765 // Finds all DIE that have a specific DW_AT_name attribute by manually 766 // searching through the debug information (not using the 767 // .debug_pubnames section). The string must match the entire name 768 // and case sensitive searches are an option. 769 //---------------------------------------------------------------------- 770 bool 771 DWARFDebugInfo::Find(const char* name, bool ignore_case, vector<dw_offset_t>& die_offsets) const 772 { 773 die_offsets.clear(); 774 if (name && name[0]) 775 { 776 FindCallbackStringInfo info = { name, ignore_case, NULL, die_offsets }; 777 DWARFDebugInfo::Parse(m_dwarf2Data, FindCallbackString, &info); 778 } 779 return !die_offsets.empty(); 780 } 781 782 //---------------------------------------------------------------------- 783 // Find 784 // 785 // Finds all DIE that have a specific DW_AT_name attribute by manually 786 // searching through the debug information (not using the 787 // .debug_pubnames section). The string must match the supplied regular 788 // expression. 789 //---------------------------------------------------------------------- 790 bool 791 DWARFDebugInfo::Find(RegularExpression& re, vector<dw_offset_t>& die_offsets) const 792 { 793 die_offsets.clear(); 794 FindCallbackStringInfo info = { NULL, false, &re, die_offsets }; 795 DWARFDebugInfo::Parse(m_dwarf2Data, FindCallbackString, &info); 796 return !die_offsets.empty(); 797 } 798