DWARFDebugInfo.cpp revision 327952
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 DWARFCompileUnitSP cu_sp; 101 while ((cu_sp = DWARFCompileUnit::Extract(m_dwarf2Data, &offset))) { 102 m_compile_units.push_back(cu_sp); 103 104 offset = cu_sp->GetNextCompileUnitOffset(); 105 } 106 } 107 } 108} 109 110size_t DWARFDebugInfo::GetNumCompileUnits() { 111 ParseCompileUnitHeadersIfNeeded(); 112 return m_compile_units.size(); 113} 114 115DWARFCompileUnit *DWARFDebugInfo::GetCompileUnitAtIndex(uint32_t idx) { 116 DWARFCompileUnit *cu = NULL; 117 if (idx < GetNumCompileUnits()) 118 cu = m_compile_units[idx].get(); 119 return cu; 120} 121 122bool DWARFDebugInfo::ContainsCompileUnit(const DWARFCompileUnit *cu) const { 123 // Not a verify efficient function, but it is handy for use in assertions 124 // to make sure that a compile unit comes from a debug information file. 125 CompileUnitColl::const_iterator end_pos = m_compile_units.end(); 126 CompileUnitColl::const_iterator pos; 127 128 for (pos = m_compile_units.begin(); pos != end_pos; ++pos) { 129 if (pos->get() == cu) 130 return true; 131 } 132 return false; 133} 134 135bool DWARFDebugInfo::OffsetLessThanCompileUnitOffset( 136 dw_offset_t offset, const DWARFCompileUnitSP &cu_sp) { 137 return offset < cu_sp->GetOffset(); 138} 139 140DWARFCompileUnit *DWARFDebugInfo::GetCompileUnit(dw_offset_t cu_offset, 141 uint32_t *idx_ptr) { 142 DWARFCompileUnitSP cu_sp; 143 uint32_t cu_idx = DW_INVALID_INDEX; 144 if (cu_offset != DW_INVALID_OFFSET) { 145 ParseCompileUnitHeadersIfNeeded(); 146 147 // Watch out for single compile unit executable as they are pretty common 148 const size_t num_cus = m_compile_units.size(); 149 if (num_cus == 1) { 150 if (m_compile_units[0]->GetOffset() == cu_offset) { 151 cu_sp = m_compile_units[0]; 152 cu_idx = 0; 153 } 154 } else if (num_cus) { 155 CompileUnitColl::const_iterator end_pos = m_compile_units.end(); 156 CompileUnitColl::const_iterator begin_pos = m_compile_units.begin(); 157 CompileUnitColl::const_iterator pos = std::upper_bound( 158 begin_pos, end_pos, cu_offset, OffsetLessThanCompileUnitOffset); 159 if (pos != begin_pos) { 160 --pos; 161 if ((*pos)->GetOffset() == cu_offset) { 162 cu_sp = *pos; 163 cu_idx = std::distance(begin_pos, pos); 164 } 165 } 166 } 167 } 168 if (idx_ptr) 169 *idx_ptr = cu_idx; 170 return cu_sp.get(); 171} 172 173DWARFCompileUnit *DWARFDebugInfo::GetCompileUnit(const DIERef &die_ref) { 174 if (die_ref.cu_offset == DW_INVALID_OFFSET) 175 return GetCompileUnitContainingDIEOffset(die_ref.die_offset); 176 else 177 return GetCompileUnit(die_ref.cu_offset); 178} 179 180DWARFCompileUnit * 181DWARFDebugInfo::GetCompileUnitContainingDIEOffset(dw_offset_t die_offset) { 182 ParseCompileUnitHeadersIfNeeded(); 183 184 DWARFCompileUnitSP cu_sp; 185 186 // Watch out for single compile unit executable as they are pretty common 187 const size_t num_cus = m_compile_units.size(); 188 if (num_cus == 1) { 189 if (m_compile_units[0]->ContainsDIEOffset(die_offset)) 190 return m_compile_units[0].get(); 191 } else if (num_cus) { 192 CompileUnitColl::const_iterator end_pos = m_compile_units.end(); 193 CompileUnitColl::const_iterator begin_pos = m_compile_units.begin(); 194 CompileUnitColl::const_iterator pos = std::upper_bound( 195 begin_pos, end_pos, die_offset, OffsetLessThanCompileUnitOffset); 196 if (pos != begin_pos) { 197 --pos; 198 if ((*pos)->ContainsDIEOffset(die_offset)) 199 return (*pos).get(); 200 } 201 } 202 203 return nullptr; 204} 205 206DWARFDIE 207DWARFDebugInfo::GetDIEForDIEOffset(dw_offset_t die_offset) { 208 DWARFCompileUnit *cu = GetCompileUnitContainingDIEOffset(die_offset); 209 if (cu) 210 return cu->GetDIE(die_offset); 211 return DWARFDIE(); 212} 213 214//---------------------------------------------------------------------- 215// GetDIE() 216// 217// Get the DIE (Debug Information Entry) with the specified offset. 218//---------------------------------------------------------------------- 219DWARFDIE 220DWARFDebugInfo::GetDIE(const DIERef &die_ref) { 221 DWARFCompileUnit *cu = GetCompileUnit(die_ref); 222 if (cu) 223 return cu->GetDIE(die_ref.die_offset); 224 return DWARFDIE(); // Not found 225} 226 227//---------------------------------------------------------------------- 228// Parse 229// 230// Parses the .debug_info section and uses the .debug_abbrev section 231// and various other sections in the SymbolFileDWARF class and calls the 232// supplied callback function each time a compile unit header, or debug 233// information entry is successfully parsed. This function can be used 234// for different tasks such as parsing the file contents into a 235// structured data, dumping, verifying and much more. 236//---------------------------------------------------------------------- 237void DWARFDebugInfo::Parse(SymbolFileDWARF *dwarf2Data, Callback callback, 238 void *userData) { 239 if (dwarf2Data) { 240 lldb::offset_t offset = 0; 241 uint32_t depth = 0; 242 DWARFDebugInfoEntry die; 243 244 DWARFCompileUnitSP cu; 245 while ((cu = DWARFCompileUnit::Extract(dwarf2Data, &offset))) { 246 const dw_offset_t next_cu_offset = cu->GetNextCompileUnitOffset(); 247 248 depth = 0; 249 // Call the callback function with no DIE pointer for the compile unit 250 // and get the offset that we are to continue to parse from 251 offset = callback(dwarf2Data, cu.get(), NULL, offset, depth, userData); 252 253 // Make sure we are within our compile unit 254 if (offset < next_cu_offset) { 255 // We are in our compile unit, parse starting at the offset 256 // we were told to parse 257 bool done = false; 258 while (!done && die.Extract(dwarf2Data, cu.get(), &offset)) { 259 // Call the callback function with DIE pointer that falls within the 260 // compile unit 261 offset = 262 callback(dwarf2Data, cu.get(), &die, offset, depth, userData); 263 264 if (die.IsNULL()) { 265 if (depth) 266 --depth; 267 else 268 done = true; // We are done with this compile unit! 269 } else if (die.HasChildren()) 270 ++depth; 271 } 272 } 273 274 // Make sure the offset returned is valid, and if not stop parsing. 275 // Returning DW_INVALID_OFFSET from this callback is a good way to end 276 // all parsing 277 if (!dwarf2Data->get_debug_info_data().ValidOffset(offset)) 278 break; 279 280 // Make sure we start on a proper 281 offset = next_cu_offset; 282 } 283 } 284} 285 286typedef struct DumpInfo { 287 DumpInfo(Stream *init_strm, uint32_t off, uint32_t depth) 288 : strm(init_strm), die_offset(off), recurse_depth(depth), 289 found_depth(UINT32_MAX), found_die(false), ancestors() {} 290 Stream *strm; 291 const uint32_t die_offset; 292 const uint32_t recurse_depth; 293 uint32_t found_depth; 294 bool found_die; 295 std::vector<DWARFDebugInfoEntry> ancestors; 296 297 DISALLOW_COPY_AND_ASSIGN(DumpInfo); 298} DumpInfo; 299 300//---------------------------------------------------------------------- 301// DumpCallback 302// 303// A callback function for the static DWARFDebugInfo::Parse() function 304// that gets called each time a compile unit header or debug information 305// entry is successfully parsed. 306// 307// This function dump DWARF information and obey recurse depth and 308// whether a single DIE is to be dumped (or all of the data). 309//---------------------------------------------------------------------- 310static dw_offset_t DumpCallback(SymbolFileDWARF *dwarf2Data, 311 DWARFCompileUnit *cu, DWARFDebugInfoEntry *die, 312 const dw_offset_t next_offset, 313 const uint32_t curr_depth, void *userData) { 314 DumpInfo *dumpInfo = (DumpInfo *)userData; 315 Stream *s = dumpInfo->strm; 316 bool show_parents = 317 s->GetFlags().Test(DWARFDebugInfo::eDumpFlag_ShowAncestors); 318 319 if (die) { 320 // Are we dumping everything? 321 if (dumpInfo->die_offset == DW_INVALID_OFFSET) { 322 // Yes we are dumping everything. Obey our recurse level though 323 if (curr_depth < dumpInfo->recurse_depth) 324 die->Dump(dwarf2Data, cu, *s, 0); 325 } else { 326 // We are dumping a specific DIE entry by offset 327 if (dumpInfo->die_offset == die->GetOffset()) { 328 // We found the DIE we were looking for, dump it! 329 if (show_parents) { 330 s->SetIndentLevel(0); 331 const uint32_t num_ancestors = dumpInfo->ancestors.size(); 332 if (num_ancestors > 0) { 333 for (uint32_t i = 0; i < num_ancestors - 1; ++i) { 334 dumpInfo->ancestors[i].Dump(dwarf2Data, cu, *s, 0); 335 s->IndentMore(); 336 } 337 } 338 } 339 340 dumpInfo->found_depth = curr_depth; 341 342 die->Dump(dwarf2Data, cu, *s, 0); 343 344 // Note that we found the DIE we were looking for 345 dumpInfo->found_die = true; 346 347 // Since we are dumping a single DIE, if there are no children we are 348 // done! 349 if (!die->HasChildren() || dumpInfo->recurse_depth == 0) 350 return DW_INVALID_OFFSET; // Return an invalid address to end parsing 351 } else if (dumpInfo->found_die) { 352 // Are we done with all the children? 353 if (curr_depth <= dumpInfo->found_depth) 354 return DW_INVALID_OFFSET; 355 356 // We have already found our DIE and are printing it's children. Obey 357 // our recurse depth and return an invalid offset if we get done 358 // dumping all of the children 359 if (dumpInfo->recurse_depth == UINT32_MAX || 360 curr_depth <= dumpInfo->found_depth + dumpInfo->recurse_depth) 361 die->Dump(dwarf2Data, cu, *s, 0); 362 } else if (dumpInfo->die_offset > die->GetOffset()) { 363 if (show_parents) 364 dumpInfo->ancestors.back() = *die; 365 } 366 } 367 368 // Keep up with our indent level 369 if (die->IsNULL()) { 370 if (show_parents) 371 dumpInfo->ancestors.pop_back(); 372 373 if (curr_depth <= 1) 374 return cu->GetNextCompileUnitOffset(); 375 else 376 s->IndentLess(); 377 } else if (die->HasChildren()) { 378 if (show_parents) { 379 DWARFDebugInfoEntry null_die; 380 dumpInfo->ancestors.push_back(null_die); 381 } 382 s->IndentMore(); 383 } 384 } else { 385 if (cu == NULL) 386 s->PutCString("NULL - cu"); 387 // We have a compile unit, reset our indent level to zero just in case 388 s->SetIndentLevel(0); 389 390 // See if we are dumping everything? 391 if (dumpInfo->die_offset == DW_INVALID_OFFSET) { 392 // We are dumping everything 393 if (cu) { 394 cu->Dump(s); 395 return cu->GetFirstDIEOffset(); // Return true to parse all DIEs in this 396 // Compile Unit 397 } else { 398 return DW_INVALID_OFFSET; 399 } 400 } else { 401 if (show_parents) { 402 dumpInfo->ancestors.clear(); 403 dumpInfo->ancestors.resize(1); 404 } 405 406 // We are dumping only a single DIE possibly with it's children and 407 // we must find it's compile unit before we can dump it properly 408 if (cu && dumpInfo->die_offset < cu->GetFirstDIEOffset()) { 409 // Not found, maybe the DIE offset provided wasn't correct? 410 // *ostrm_ptr << "DIE at offset " << HEX32 << dumpInfo->die_offset << " 411 // was not found." << endl; 412 return DW_INVALID_OFFSET; 413 } else { 414 // See if the DIE is in this compile unit? 415 if (cu && dumpInfo->die_offset < cu->GetNextCompileUnitOffset()) { 416 return next_offset; 417 // // We found our compile unit that contains our DIE, just skip to 418 // dumping the requested DIE... 419 // return dumpInfo->die_offset; 420 } else { 421 // Skip to the next compile unit as the DIE isn't in the current one! 422 if (cu) { 423 return cu->GetNextCompileUnitOffset(); 424 } else { 425 return DW_INVALID_OFFSET; 426 } 427 } 428 } 429 } 430 } 431 432 // Just return the current offset to parse the next CU or DIE entry 433 return next_offset; 434} 435 436//---------------------------------------------------------------------- 437// Dump 438// 439// Dump the information in the .debug_info section to the specified 440// ostream. If die_offset is valid, a single DIE will be dumped. If the 441// die_offset is invalid, all the DWARF information will be dumped. Both 442// cases will obey a "recurse_depth" or how deep to traverse into the 443// children of each DIE entry. A recurse_depth of zero will dump all 444// compile unit headers. A recurse_depth of 1 will dump all compile unit 445// headers and the DW_TAG_compile unit tags. A depth of 2 will also 446// dump all types and functions. 447//---------------------------------------------------------------------- 448void DWARFDebugInfo::Dump(Stream *s, SymbolFileDWARF *dwarf2Data, 449 const uint32_t die_offset, 450 const uint32_t recurse_depth) { 451 DumpInfo dumpInfo(s, die_offset, recurse_depth); 452 s->PutCString(".debug_info contents"); 453 if (dwarf2Data->get_debug_info_data().GetByteSize() > 0) { 454 if (die_offset == DW_INVALID_OFFSET) 455 s->PutCString(":\n"); 456 else { 457 s->Printf(" for DIE entry at .debug_info[0x%8.8x]", die_offset); 458 if (recurse_depth != UINT32_MAX) 459 s->Printf(" recursing %u levels deep.", recurse_depth); 460 s->EOL(); 461 } 462 } else { 463 s->PutCString(": < EMPTY >\n"); 464 return; 465 } 466 DWARFDebugInfo::Parse(dwarf2Data, DumpCallback, &dumpInfo); 467} 468 469//---------------------------------------------------------------------- 470// Dump 471// 472// Dump the contents of this DWARFDebugInfo object as has been parsed 473// and/or modified after it has been parsed. 474//---------------------------------------------------------------------- 475void DWARFDebugInfo::Dump(Stream *s, const uint32_t die_offset, 476 const uint32_t recurse_depth) { 477 DumpInfo dumpInfo(s, die_offset, recurse_depth); 478 479 s->PutCString("Dumping .debug_info section from internal representation\n"); 480 481 CompileUnitColl::const_iterator pos; 482 uint32_t curr_depth = 0; 483 ParseCompileUnitHeadersIfNeeded(); 484 for (pos = m_compile_units.begin(); pos != m_compile_units.end(); ++pos) { 485 DWARFCompileUnit *cu = pos->get(); 486 DumpCallback(m_dwarf2Data, cu, NULL, 0, curr_depth, &dumpInfo); 487 488 const DWARFDIE die = cu->DIE(); 489 if (die) 490 die.Dump(s, recurse_depth); 491 } 492} 493