DWARFDebugInfo.cpp revision 321369
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/Host/PosixApi.h" 16#include "lldb/Symbol/ObjectFile.h" 17#include "lldb/Utility/RegularExpression.h" 18#include "lldb/Utility/Stream.h" 19 20#include "DWARFCompileUnit.h" 21#include "DWARFDebugAranges.h" 22#include "DWARFDebugAranges.h" 23#include "DWARFDebugInfo.h" 24#include "DWARFDebugInfoEntry.h" 25#include "DWARFFormValue.h" 26#include "LogChannelDWARF.h" 27 28using namespace lldb; 29using namespace lldb_private; 30using namespace std; 31 32//---------------------------------------------------------------------- 33// Constructor 34//---------------------------------------------------------------------- 35DWARFDebugInfo::DWARFDebugInfo() 36 : m_dwarf2Data(NULL), m_compile_units(), m_cu_aranges_ap() {} 37 38//---------------------------------------------------------------------- 39// SetDwarfData 40//---------------------------------------------------------------------- 41void DWARFDebugInfo::SetDwarfData(SymbolFileDWARF *dwarf2Data) { 42 m_dwarf2Data = dwarf2Data; 43 m_compile_units.clear(); 44} 45 46DWARFDebugAranges &DWARFDebugInfo::GetCompileUnitAranges() { 47 if (m_cu_aranges_ap.get() == NULL && m_dwarf2Data) { 48 Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_ARANGES)); 49 50 m_cu_aranges_ap.reset(new DWARFDebugAranges()); 51 const DWARFDataExtractor &debug_aranges_data = 52 m_dwarf2Data->get_debug_aranges_data(); 53 if (debug_aranges_data.GetByteSize() > 0) { 54 if (log) 55 log->Printf( 56 "DWARFDebugInfo::GetCompileUnitAranges() for \"%s\" from " 57 ".debug_aranges", 58 m_dwarf2Data->GetObjectFile()->GetFileSpec().GetPath().c_str()); 59 m_cu_aranges_ap->Extract(debug_aranges_data); 60 } 61 62 // Make a list of all CUs represented by the arange data in the file. 63 std::set<dw_offset_t> cus_with_data; 64 for (size_t n = 0; n < m_cu_aranges_ap.get()->GetNumRanges(); n++) { 65 dw_offset_t offset = m_cu_aranges_ap.get()->OffsetAtIndex(n); 66 if (offset != DW_INVALID_OFFSET) 67 cus_with_data.insert(offset); 68 } 69 70 // Manually build arange data for everything that wasn't in the 71 // .debug_aranges table. 72 bool printed = false; 73 const size_t num_compile_units = GetNumCompileUnits(); 74 for (size_t idx = 0; idx < num_compile_units; ++idx) { 75 DWARFCompileUnit *cu = GetCompileUnitAtIndex(idx); 76 77 dw_offset_t offset = cu->GetOffset(); 78 if (cus_with_data.find(offset) == cus_with_data.end()) { 79 if (log) { 80 if (!printed) 81 log->Printf( 82 "DWARFDebugInfo::GetCompileUnitAranges() for \"%s\" by parsing", 83 m_dwarf2Data->GetObjectFile()->GetFileSpec().GetPath().c_str()); 84 printed = true; 85 } 86 cu->BuildAddressRangeTable(m_dwarf2Data, m_cu_aranges_ap.get()); 87 } 88 } 89 90 const bool minimize = true; 91 m_cu_aranges_ap->Sort(minimize); 92 } 93 return *m_cu_aranges_ap.get(); 94} 95 96void DWARFDebugInfo::ParseCompileUnitHeadersIfNeeded() { 97 if (m_compile_units.empty()) { 98 if (m_dwarf2Data != NULL) { 99 lldb::offset_t offset = 0; 100 const DWARFDataExtractor &debug_info_data = 101 m_dwarf2Data->get_debug_info_data(); 102 while (debug_info_data.ValidOffset(offset)) { 103 DWARFCompileUnitSP cu_sp(new DWARFCompileUnit(m_dwarf2Data)); 104 // Out of memory? 105 if (cu_sp.get() == NULL) 106 break; 107 108 if (cu_sp->Extract(debug_info_data, &offset) == false) 109 break; 110 111 m_compile_units.push_back(cu_sp); 112 113 offset = cu_sp->GetNextCompileUnitOffset(); 114 } 115 } 116 } 117} 118 119size_t DWARFDebugInfo::GetNumCompileUnits() { 120 ParseCompileUnitHeadersIfNeeded(); 121 return m_compile_units.size(); 122} 123 124DWARFCompileUnit *DWARFDebugInfo::GetCompileUnitAtIndex(uint32_t idx) { 125 DWARFCompileUnit *cu = NULL; 126 if (idx < GetNumCompileUnits()) 127 cu = m_compile_units[idx].get(); 128 return cu; 129} 130 131bool DWARFDebugInfo::ContainsCompileUnit(const DWARFCompileUnit *cu) const { 132 // Not a verify efficient function, but it is handy for use in assertions 133 // to make sure that a compile unit comes from a debug information file. 134 CompileUnitColl::const_iterator end_pos = m_compile_units.end(); 135 CompileUnitColl::const_iterator pos; 136 137 for (pos = m_compile_units.begin(); pos != end_pos; ++pos) { 138 if (pos->get() == cu) 139 return true; 140 } 141 return false; 142} 143 144bool DWARFDebugInfo::OffsetLessThanCompileUnitOffset( 145 dw_offset_t offset, const DWARFCompileUnitSP &cu_sp) { 146 return offset < cu_sp->GetOffset(); 147} 148 149DWARFCompileUnit *DWARFDebugInfo::GetCompileUnit(dw_offset_t cu_offset, 150 uint32_t *idx_ptr) { 151 DWARFCompileUnitSP cu_sp; 152 uint32_t cu_idx = DW_INVALID_INDEX; 153 if (cu_offset != DW_INVALID_OFFSET) { 154 ParseCompileUnitHeadersIfNeeded(); 155 156 // Watch out for single compile unit executable as they are pretty common 157 const size_t num_cus = m_compile_units.size(); 158 if (num_cus == 1) { 159 if (m_compile_units[0]->GetOffset() == cu_offset) { 160 cu_sp = m_compile_units[0]; 161 cu_idx = 0; 162 } 163 } else if (num_cus) { 164 CompileUnitColl::const_iterator end_pos = m_compile_units.end(); 165 CompileUnitColl::const_iterator begin_pos = m_compile_units.begin(); 166 CompileUnitColl::const_iterator pos = std::upper_bound( 167 begin_pos, end_pos, cu_offset, OffsetLessThanCompileUnitOffset); 168 if (pos != begin_pos) { 169 --pos; 170 if ((*pos)->GetOffset() == cu_offset) { 171 cu_sp = *pos; 172 cu_idx = std::distance(begin_pos, pos); 173 } 174 } 175 } 176 } 177 if (idx_ptr) 178 *idx_ptr = cu_idx; 179 return cu_sp.get(); 180} 181 182DWARFCompileUnit *DWARFDebugInfo::GetCompileUnit(const DIERef &die_ref) { 183 if (die_ref.cu_offset == DW_INVALID_OFFSET) 184 return GetCompileUnitContainingDIEOffset(die_ref.die_offset); 185 else 186 return GetCompileUnit(die_ref.cu_offset); 187} 188 189DWARFCompileUnit * 190DWARFDebugInfo::GetCompileUnitContainingDIEOffset(dw_offset_t die_offset) { 191 ParseCompileUnitHeadersIfNeeded(); 192 193 DWARFCompileUnitSP cu_sp; 194 195 // Watch out for single compile unit executable as they are pretty common 196 const size_t num_cus = m_compile_units.size(); 197 if (num_cus == 1) { 198 if (m_compile_units[0]->ContainsDIEOffset(die_offset)) 199 return m_compile_units[0].get(); 200 } else if (num_cus) { 201 CompileUnitColl::const_iterator end_pos = m_compile_units.end(); 202 CompileUnitColl::const_iterator begin_pos = m_compile_units.begin(); 203 CompileUnitColl::const_iterator pos = std::upper_bound( 204 begin_pos, end_pos, die_offset, OffsetLessThanCompileUnitOffset); 205 if (pos != begin_pos) { 206 --pos; 207 if ((*pos)->ContainsDIEOffset(die_offset)) 208 return (*pos).get(); 209 } 210 } 211 212 return nullptr; 213} 214 215DWARFDIE 216DWARFDebugInfo::GetDIEForDIEOffset(dw_offset_t die_offset) { 217 DWARFCompileUnit *cu = GetCompileUnitContainingDIEOffset(die_offset); 218 if (cu) 219 return cu->GetDIE(die_offset); 220 return DWARFDIE(); 221} 222 223//---------------------------------------------------------------------- 224// GetDIE() 225// 226// Get the DIE (Debug Information Entry) with the specified offset. 227//---------------------------------------------------------------------- 228DWARFDIE 229DWARFDebugInfo::GetDIE(const DIERef &die_ref) { 230 DWARFCompileUnit *cu = GetCompileUnit(die_ref); 231 if (cu) 232 return cu->GetDIE(die_ref.die_offset); 233 return DWARFDIE(); // Not found 234} 235 236//---------------------------------------------------------------------- 237// Parse 238// 239// Parses the .debug_info section and uses the .debug_abbrev section 240// and various other sections in the SymbolFileDWARF class and calls the 241// supplied callback function each time a compile unit header, or debug 242// information entry is successfully parsed. This function can be used 243// for different tasks such as parsing the file contents into a 244// structured data, dumping, verifying and much more. 245//---------------------------------------------------------------------- 246void DWARFDebugInfo::Parse(SymbolFileDWARF *dwarf2Data, Callback callback, 247 void *userData) { 248 if (dwarf2Data) { 249 lldb::offset_t offset = 0; 250 uint32_t depth = 0; 251 DWARFCompileUnitSP cu(new DWARFCompileUnit(dwarf2Data)); 252 if (cu.get() == NULL) 253 return; 254 DWARFDebugInfoEntry die; 255 256 while (cu->Extract(dwarf2Data->get_debug_info_data(), &offset)) { 257 const dw_offset_t next_cu_offset = cu->GetNextCompileUnitOffset(); 258 259 depth = 0; 260 // Call the callback function with no DIE pointer for the compile unit 261 // and get the offset that we are to continue to parse from 262 offset = callback(dwarf2Data, cu.get(), NULL, offset, depth, userData); 263 264 // Make sure we are within our compile unit 265 if (offset < next_cu_offset) { 266 // We are in our compile unit, parse starting at the offset 267 // we were told to parse 268 bool done = false; 269 while (!done && die.Extract(dwarf2Data, cu.get(), &offset)) { 270 // Call the callback function with DIE pointer that falls within the 271 // compile unit 272 offset = 273 callback(dwarf2Data, cu.get(), &die, offset, depth, userData); 274 275 if (die.IsNULL()) { 276 if (depth) 277 --depth; 278 else 279 done = true; // We are done with this compile unit! 280 } else if (die.HasChildren()) 281 ++depth; 282 } 283 } 284 285 // Make sure the offset returned is valid, and if not stop parsing. 286 // Returning DW_INVALID_OFFSET from this callback is a good way to end 287 // all parsing 288 if (!dwarf2Data->get_debug_info_data().ValidOffset(offset)) 289 break; 290 291 // See if during the callback anyone retained a copy of the compile 292 // unit other than ourselves and if so, let whomever did own the object 293 // and create a new one for our own use! 294 if (!cu.unique()) 295 cu.reset(new DWARFCompileUnit(dwarf2Data)); 296 297 // Make sure we start on a proper 298 offset = next_cu_offset; 299 } 300 } 301} 302 303typedef struct DumpInfo { 304 DumpInfo(Stream *init_strm, uint32_t off, uint32_t depth) 305 : strm(init_strm), die_offset(off), recurse_depth(depth), 306 found_depth(UINT32_MAX), found_die(false), ancestors() {} 307 Stream *strm; 308 const uint32_t die_offset; 309 const uint32_t recurse_depth; 310 uint32_t found_depth; 311 bool found_die; 312 std::vector<DWARFDebugInfoEntry> ancestors; 313 314 DISALLOW_COPY_AND_ASSIGN(DumpInfo); 315} DumpInfo; 316 317//---------------------------------------------------------------------- 318// DumpCallback 319// 320// A callback function for the static DWARFDebugInfo::Parse() function 321// that gets called each time a compile unit header or debug information 322// entry is successfully parsed. 323// 324// This function dump DWARF information and obey recurse depth and 325// whether a single DIE is to be dumped (or all of the data). 326//---------------------------------------------------------------------- 327static dw_offset_t DumpCallback(SymbolFileDWARF *dwarf2Data, 328 DWARFCompileUnit *cu, DWARFDebugInfoEntry *die, 329 const dw_offset_t next_offset, 330 const uint32_t curr_depth, void *userData) { 331 DumpInfo *dumpInfo = (DumpInfo *)userData; 332 Stream *s = dumpInfo->strm; 333 bool show_parents = 334 s->GetFlags().Test(DWARFDebugInfo::eDumpFlag_ShowAncestors); 335 336 if (die) { 337 // Are we dumping everything? 338 if (dumpInfo->die_offset == DW_INVALID_OFFSET) { 339 // Yes we are dumping everything. Obey our recurse level though 340 if (curr_depth < dumpInfo->recurse_depth) 341 die->Dump(dwarf2Data, cu, *s, 0); 342 } else { 343 // We are dumping a specific DIE entry by offset 344 if (dumpInfo->die_offset == die->GetOffset()) { 345 // We found the DIE we were looking for, dump it! 346 if (show_parents) { 347 s->SetIndentLevel(0); 348 const uint32_t num_ancestors = dumpInfo->ancestors.size(); 349 if (num_ancestors > 0) { 350 for (uint32_t i = 0; i < num_ancestors - 1; ++i) { 351 dumpInfo->ancestors[i].Dump(dwarf2Data, cu, *s, 0); 352 s->IndentMore(); 353 } 354 } 355 } 356 357 dumpInfo->found_depth = curr_depth; 358 359 die->Dump(dwarf2Data, cu, *s, 0); 360 361 // Note that we found the DIE we were looking for 362 dumpInfo->found_die = true; 363 364 // Since we are dumping a single DIE, if there are no children we are 365 // done! 366 if (!die->HasChildren() || dumpInfo->recurse_depth == 0) 367 return DW_INVALID_OFFSET; // Return an invalid address to end parsing 368 } else if (dumpInfo->found_die) { 369 // Are we done with all the children? 370 if (curr_depth <= dumpInfo->found_depth) 371 return DW_INVALID_OFFSET; 372 373 // We have already found our DIE and are printing it's children. Obey 374 // our recurse depth and return an invalid offset if we get done 375 // dumping all of the children 376 if (dumpInfo->recurse_depth == UINT32_MAX || 377 curr_depth <= dumpInfo->found_depth + dumpInfo->recurse_depth) 378 die->Dump(dwarf2Data, cu, *s, 0); 379 } else if (dumpInfo->die_offset > die->GetOffset()) { 380 if (show_parents) 381 dumpInfo->ancestors.back() = *die; 382 } 383 } 384 385 // Keep up with our indent level 386 if (die->IsNULL()) { 387 if (show_parents) 388 dumpInfo->ancestors.pop_back(); 389 390 if (curr_depth <= 1) 391 return cu->GetNextCompileUnitOffset(); 392 else 393 s->IndentLess(); 394 } else if (die->HasChildren()) { 395 if (show_parents) { 396 DWARFDebugInfoEntry null_die; 397 dumpInfo->ancestors.push_back(null_die); 398 } 399 s->IndentMore(); 400 } 401 } else { 402 if (cu == NULL) 403 s->PutCString("NULL - cu"); 404 // We have a compile unit, reset our indent level to zero just in case 405 s->SetIndentLevel(0); 406 407 // See if we are dumping everything? 408 if (dumpInfo->die_offset == DW_INVALID_OFFSET) { 409 // We are dumping everything 410 if (cu) { 411 cu->Dump(s); 412 return cu->GetFirstDIEOffset(); // Return true to parse all DIEs in this 413 // Compile Unit 414 } else { 415 return DW_INVALID_OFFSET; 416 } 417 } else { 418 if (show_parents) { 419 dumpInfo->ancestors.clear(); 420 dumpInfo->ancestors.resize(1); 421 } 422 423 // We are dumping only a single DIE possibly with it's children and 424 // we must find it's compile unit before we can dump it properly 425 if (cu && dumpInfo->die_offset < cu->GetFirstDIEOffset()) { 426 // Not found, maybe the DIE offset provided wasn't correct? 427 // *ostrm_ptr << "DIE at offset " << HEX32 << dumpInfo->die_offset << " 428 // was not found." << endl; 429 return DW_INVALID_OFFSET; 430 } else { 431 // See if the DIE is in this compile unit? 432 if (cu && dumpInfo->die_offset < cu->GetNextCompileUnitOffset()) { 433 return next_offset; 434 // // We found our compile unit that contains our DIE, just skip to 435 // dumping the requested DIE... 436 // return dumpInfo->die_offset; 437 } else { 438 // Skip to the next compile unit as the DIE isn't in the current one! 439 if (cu) { 440 return cu->GetNextCompileUnitOffset(); 441 } else { 442 return DW_INVALID_OFFSET; 443 } 444 } 445 } 446 } 447 } 448 449 // Just return the current offset to parse the next CU or DIE entry 450 return next_offset; 451} 452 453//---------------------------------------------------------------------- 454// Dump 455// 456// Dump the information in the .debug_info section to the specified 457// ostream. If die_offset is valid, a single DIE will be dumped. If the 458// die_offset is invalid, all the DWARF information will be dumped. Both 459// cases will obey a "recurse_depth" or how deep to traverse into the 460// children of each DIE entry. A recurse_depth of zero will dump all 461// compile unit headers. A recurse_depth of 1 will dump all compile unit 462// headers and the DW_TAG_compile unit tags. A depth of 2 will also 463// dump all types and functions. 464//---------------------------------------------------------------------- 465void DWARFDebugInfo::Dump(Stream *s, SymbolFileDWARF *dwarf2Data, 466 const uint32_t die_offset, 467 const uint32_t recurse_depth) { 468 DumpInfo dumpInfo(s, die_offset, recurse_depth); 469 s->PutCString(".debug_info contents"); 470 if (dwarf2Data->get_debug_info_data().GetByteSize() > 0) { 471 if (die_offset == DW_INVALID_OFFSET) 472 s->PutCString(":\n"); 473 else { 474 s->Printf(" for DIE entry at .debug_info[0x%8.8x]", die_offset); 475 if (recurse_depth != UINT32_MAX) 476 s->Printf(" recursing %u levels deep.", recurse_depth); 477 s->EOL(); 478 } 479 } else { 480 s->PutCString(": < EMPTY >\n"); 481 return; 482 } 483 DWARFDebugInfo::Parse(dwarf2Data, DumpCallback, &dumpInfo); 484} 485 486//---------------------------------------------------------------------- 487// Dump 488// 489// Dump the contents of this DWARFDebugInfo object as has been parsed 490// and/or modified after it has been parsed. 491//---------------------------------------------------------------------- 492void DWARFDebugInfo::Dump(Stream *s, const uint32_t die_offset, 493 const uint32_t recurse_depth) { 494 DumpInfo dumpInfo(s, die_offset, recurse_depth); 495 496 s->PutCString("Dumping .debug_info section from internal representation\n"); 497 498 CompileUnitColl::const_iterator pos; 499 uint32_t curr_depth = 0; 500 ParseCompileUnitHeadersIfNeeded(); 501 for (pos = m_compile_units.begin(); pos != m_compile_units.end(); ++pos) { 502 DWARFCompileUnit *cu = pos->get(); 503 DumpCallback(m_dwarf2Data, cu, NULL, 0, curr_depth, &dumpInfo); 504 505 const DWARFDIE die = cu->DIE(); 506 if (die) 507 die.Dump(s, recurse_depth); 508 } 509} 510 511//---------------------------------------------------------------------- 512// FindCallbackString 513// 514// A callback function for the static DWARFDebugInfo::Parse() function 515// that gets called each time a compile unit header or debug information 516// entry is successfully parsed. 517// 518// This function will find the die_offset of any items whose DW_AT_name 519// matches the given string 520//---------------------------------------------------------------------- 521typedef struct FindCallbackStringInfoTag { 522 const char *name; 523 bool ignore_case; 524 RegularExpression *regex; 525 vector<dw_offset_t> &die_offsets; 526} FindCallbackStringInfo; 527 528static dw_offset_t 529FindCallbackString(SymbolFileDWARF *dwarf2Data, DWARFCompileUnit *cu, 530 DWARFDebugInfoEntry *die, const dw_offset_t next_offset, 531 const uint32_t curr_depth, void *userData) { 532 FindCallbackStringInfo *info = (FindCallbackStringInfo *)userData; 533 534 if (!die) 535 return next_offset; 536 537 const char *die_name = die->GetName(dwarf2Data, cu); 538 if (!die_name) 539 return next_offset; 540 541 if (info->regex) { 542 if (info->regex->Execute(llvm::StringRef(die_name))) 543 info->die_offsets.push_back(die->GetOffset()); 544 } else { 545 if ((info->ignore_case ? strcasecmp(die_name, info->name) 546 : strcmp(die_name, info->name)) == 0) 547 info->die_offsets.push_back(die->GetOffset()); 548 } 549 550 // Just return the current offset to parse the next CU or DIE entry 551 return next_offset; 552} 553 554//---------------------------------------------------------------------- 555// Find 556// 557// Finds all DIE that have a specific DW_AT_name attribute by manually 558// searching through the debug information (not using the 559// .debug_pubnames section). The string must match the entire name 560// and case sensitive searches are an option. 561//---------------------------------------------------------------------- 562bool DWARFDebugInfo::Find(const char *name, bool ignore_case, 563 vector<dw_offset_t> &die_offsets) const { 564 die_offsets.clear(); 565 if (name && name[0]) { 566 FindCallbackStringInfo info = {name, ignore_case, NULL, die_offsets}; 567 DWARFDebugInfo::Parse(m_dwarf2Data, FindCallbackString, &info); 568 } 569 return !die_offsets.empty(); 570} 571 572//---------------------------------------------------------------------- 573// Find 574// 575// Finds all DIE that have a specific DW_AT_name attribute by manually 576// searching through the debug information (not using the 577// .debug_pubnames section). The string must match the supplied regular 578// expression. 579//---------------------------------------------------------------------- 580bool DWARFDebugInfo::Find(RegularExpression &re, 581 vector<dw_offset_t> &die_offsets) const { 582 die_offsets.clear(); 583 FindCallbackStringInfo info = {NULL, false, &re, die_offsets}; 584 DWARFDebugInfo::Parse(m_dwarf2Data, FindCallbackString, &info); 585 return !die_offsets.empty(); 586} 587