1 //===-- DWARFUnit.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 "DWARFUnit.h" 11 12 #include "lldb/Core/Module.h" 13 #include "lldb/Host/StringConvert.h" 14 #include "lldb/Symbol/CompileUnit.h" 15 #include "lldb/Symbol/LineTable.h" 16 #include "lldb/Symbol/ObjectFile.h" 17 #include "lldb/Utility/LLDBAssert.h" 18 #include "lldb/Utility/StreamString.h" 19 #include "lldb/Utility/Timer.h" 20 21 #include "DWARFDIECollection.h" 22 #include "DWARFDebugAranges.h" 23 #include "DWARFDebugInfo.h" 24 #include "LogChannelDWARF.h" 25 #include "SymbolFileDWARFDebugMap.h" 26 #include "SymbolFileDWARFDwo.h" 27 28 using namespace lldb; 29 using namespace lldb_private; 30 using namespace std; 31 32 extern int g_verbose; 33 34 DWARFUnit::DWARFUnit(SymbolFileDWARF *dwarf) : m_dwarf(dwarf) {} 35 36 DWARFUnit::~DWARFUnit() {} 37 38 //---------------------------------------------------------------------- 39 // Parses first DIE of a compile unit. 40 //---------------------------------------------------------------------- 41 void DWARFUnit::ExtractUnitDIEIfNeeded() { 42 if (m_first_die) 43 return; // Already parsed 44 45 static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); 46 Timer scoped_timer( 47 func_cat, "%8.8x: DWARFUnit::ExtractUnitDIEIfNeeded()", m_offset); 48 49 // Set the offset to that of the first DIE and calculate the start of the 50 // next compilation unit header. 51 lldb::offset_t offset = GetFirstDIEOffset(); 52 53 // We are in our compile unit, parse starting at the offset we were told to 54 // parse 55 const DWARFDataExtractor &data = GetData(); 56 DWARFFormValue::FixedFormSizes fixed_form_sizes = 57 DWARFFormValue::GetFixedFormSizesForAddressSize(GetAddressByteSize(), 58 IsDWARF64()); 59 if (offset < GetNextCompileUnitOffset() && 60 m_first_die.FastExtract(data, this, fixed_form_sizes, &offset)) { 61 AddUnitDIE(m_first_die); 62 return; 63 } 64 65 ExtractDIEsEndCheck(offset); 66 } 67 68 //---------------------------------------------------------------------- 69 // Parses a compile unit and indexes its DIEs if it hasn't already been done. 70 //---------------------------------------------------------------------- 71 bool DWARFUnit::ExtractDIEsIfNeeded() { 72 if (!m_die_array.empty()) 73 return 0; // Already parsed 74 75 static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); 76 Timer scoped_timer( 77 func_cat, "%8.8x: DWARFUnit::ExtractDIEsIfNeeded()", m_offset); 78 79 // Set the offset to that of the first DIE and calculate the start of the 80 // next compilation unit header. 81 lldb::offset_t offset = GetFirstDIEOffset(); 82 lldb::offset_t next_cu_offset = GetNextCompileUnitOffset(); 83 84 DWARFDebugInfoEntry die; 85 // Keep a flat array of the DIE for binary lookup by DIE offset 86 Log *log( 87 LogChannelDWARF::GetLogIfAny(DWARF_LOG_DEBUG_INFO | DWARF_LOG_LOOKUPS)); 88 if (log) { 89 m_dwarf->GetObjectFile()->GetModule()->LogMessageVerboseBacktrace( 90 log, 91 "DWARFUnit::ExtractDIEsIfNeeded () for compile unit at " 92 ".debug_info[0x%8.8x]", 93 GetOffset()); 94 } 95 96 uint32_t depth = 0; 97 // We are in our compile unit, parse starting at the offset we were told to 98 // parse 99 const DWARFDataExtractor &data = GetData(); 100 std::vector<uint32_t> die_index_stack; 101 die_index_stack.reserve(32); 102 die_index_stack.push_back(0); 103 bool prev_die_had_children = false; 104 DWARFFormValue::FixedFormSizes fixed_form_sizes = 105 DWARFFormValue::GetFixedFormSizesForAddressSize(GetAddressByteSize(), 106 IsDWARF64()); 107 while (offset < next_cu_offset && 108 die.FastExtract(data, this, fixed_form_sizes, &offset)) { 109 // if (log) 110 // log->Printf("0x%8.8x: %*.*s%s%s", 111 // die.GetOffset(), 112 // depth * 2, depth * 2, "", 113 // DW_TAG_value_to_name (die.Tag()), 114 // die.HasChildren() ? " *" : ""); 115 116 const bool null_die = die.IsNULL(); 117 if (depth == 0) { 118 assert(m_die_array.empty() && "Compile unit DIE already added"); 119 120 // The average bytes per DIE entry has been seen to be around 14-20 so 121 // lets pre-reserve half of that since we are now stripping the NULL 122 // tags. 123 124 // Only reserve the memory if we are adding children of the main 125 // compile unit DIE. The compile unit DIE is always the first entry, so 126 // if our size is 1, then we are adding the first compile unit child 127 // DIE and should reserve the memory. 128 m_die_array.reserve(GetDebugInfoSize() / 24); 129 m_die_array.push_back(die); 130 131 if (!m_first_die) 132 AddUnitDIE(m_die_array.front()); 133 } else { 134 if (null_die) { 135 if (prev_die_had_children) { 136 // This will only happen if a DIE says is has children but all it 137 // contains is a NULL tag. Since we are removing the NULL DIEs from 138 // the list (saves up to 25% in C++ code), we need a way to let the 139 // DIE know that it actually doesn't have children. 140 if (!m_die_array.empty()) 141 m_die_array.back().SetEmptyChildren(true); 142 } 143 } else { 144 die.SetParentIndex(m_die_array.size() - die_index_stack[depth - 1]); 145 146 if (die_index_stack.back()) 147 m_die_array[die_index_stack.back()].SetSiblingIndex( 148 m_die_array.size() - die_index_stack.back()); 149 150 // Only push the DIE if it isn't a NULL DIE 151 m_die_array.push_back(die); 152 } 153 } 154 155 if (null_die) { 156 // NULL DIE. 157 if (!die_index_stack.empty()) 158 die_index_stack.pop_back(); 159 160 if (depth > 0) 161 --depth; 162 if (depth == 0) 163 break; // We are done with this compile unit! 164 165 prev_die_had_children = false; 166 } else { 167 die_index_stack.back() = m_die_array.size() - 1; 168 // Normal DIE 169 const bool die_has_children = die.HasChildren(); 170 if (die_has_children) { 171 die_index_stack.push_back(0); 172 ++depth; 173 } 174 prev_die_had_children = die_has_children; 175 } 176 } 177 178 if (!m_die_array.empty()) { 179 lldbassert(!m_first_die || m_first_die == m_die_array.front()); 180 m_first_die = m_die_array.front(); 181 } 182 183 // Since std::vector objects will double their size, we really need to make a 184 // new array with the perfect size so we don't end up wasting space. So here 185 // we copy and swap to make sure we don't have any extra memory taken up. 186 187 if (m_die_array.size() < m_die_array.capacity()) { 188 DWARFDebugInfoEntry::collection exact_size_die_array(m_die_array.begin(), 189 m_die_array.end()); 190 exact_size_die_array.swap(m_die_array); 191 } 192 193 ExtractDIEsEndCheck(offset); 194 195 if (!m_dwo_symbol_file) 196 return m_die_array.size(); 197 198 DWARFUnit *dwo_cu = m_dwo_symbol_file->GetCompileUnit(); 199 size_t dwo_die_count = dwo_cu->ExtractDIEsIfNeeded(); 200 return m_die_array.size() + dwo_die_count - 201 1; // We have 2 CU die, but we want to count it only as one 202 } 203 204 //-------------------------------------------------------------------------- 205 // Final checks for both ExtractUnitDIEIfNeeded() and ExtractDIEsIfNeeded(). 206 //-------------------------------------------------------------------------- 207 void DWARFUnit::ExtractDIEsEndCheck(lldb::offset_t offset) const { 208 // Give a little bit of info if we encounter corrupt DWARF (our offset should 209 // always terminate at or before the start of the next compilation unit 210 // header). 211 if (offset > GetNextCompileUnitOffset()) { 212 m_dwarf->GetObjectFile()->GetModule()->ReportWarning( 213 "DWARF compile unit extends beyond its bounds cu 0x%8.8x at " 214 "0x%8.8" PRIx64 "\n", 215 GetOffset(), offset); 216 } 217 218 Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO)); 219 if (log && log->GetVerbose()) { 220 StreamString strm; 221 Dump(&strm); 222 if (m_die_array.empty()) 223 strm.Printf("error: no DIE for compile unit"); 224 else 225 m_die_array[0].Dump(m_dwarf, this, strm, UINT32_MAX); 226 log->PutString(strm.GetString()); 227 } 228 } 229 230 void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) { 231 uint64_t base_addr = cu_die.GetAttributeValueAsAddress( 232 m_dwarf, this, DW_AT_low_pc, LLDB_INVALID_ADDRESS); 233 if (base_addr == LLDB_INVALID_ADDRESS) 234 base_addr = cu_die.GetAttributeValueAsAddress( 235 m_dwarf, this, DW_AT_entry_pc, 0); 236 SetBaseAddress(base_addr); 237 238 std::unique_ptr<SymbolFileDWARFDwo> dwo_symbol_file = 239 m_dwarf->GetDwoSymbolFileForCompileUnit(*this, cu_die); 240 if (!dwo_symbol_file) 241 return; 242 243 DWARFUnit *dwo_cu = dwo_symbol_file->GetCompileUnit(); 244 if (!dwo_cu) 245 return; // Can't fetch the compile unit from the dwo file. 246 247 DWARFBaseDIE dwo_cu_die = dwo_cu->GetUnitDIEOnly(); 248 if (!dwo_cu_die.IsValid()) 249 return; // Can't fetch the compile unit DIE from the dwo file. 250 251 uint64_t main_dwo_id = 252 cu_die.GetAttributeValueAsUnsigned(m_dwarf, this, DW_AT_GNU_dwo_id, 0); 253 uint64_t sub_dwo_id = 254 dwo_cu_die.GetAttributeValueAsUnsigned(DW_AT_GNU_dwo_id, 0); 255 if (main_dwo_id != sub_dwo_id) 256 return; // The 2 dwo ID isn't match. Don't use the dwo file as it belongs to 257 // a differectn compilation. 258 259 m_dwo_symbol_file = std::move(dwo_symbol_file); 260 261 dw_addr_t addr_base = 262 cu_die.GetAttributeValueAsUnsigned(m_dwarf, this, DW_AT_GNU_addr_base, 0); 263 dw_addr_t ranges_base = cu_die.GetAttributeValueAsUnsigned( 264 m_dwarf, this, DW_AT_GNU_ranges_base, 0); 265 dwo_cu->SetAddrBase(addr_base, ranges_base, m_offset); 266 } 267 268 DWARFDIE DWARFUnit::LookupAddress(const dw_addr_t address) { 269 if (DIE()) { 270 const DWARFDebugAranges &func_aranges = GetFunctionAranges(); 271 272 // Re-check the aranges auto pointer contents in case it was created above 273 if (!func_aranges.IsEmpty()) 274 return GetDIE(func_aranges.FindAddress(address)); 275 } 276 return DWARFDIE(); 277 } 278 279 size_t DWARFUnit::AppendDIEsWithTag(const dw_tag_t tag, 280 DWARFDIECollection &dies, 281 uint32_t depth) const { 282 size_t old_size = dies.Size(); 283 DWARFDebugInfoEntry::const_iterator pos; 284 DWARFDebugInfoEntry::const_iterator end = m_die_array.end(); 285 for (pos = m_die_array.begin(); pos != end; ++pos) { 286 if (pos->Tag() == tag) 287 dies.Append(DWARFDIE(this, &(*pos))); 288 } 289 290 // Return the number of DIEs added to the collection 291 return dies.Size() - old_size; 292 } 293 294 295 lldb::user_id_t DWARFUnit::GetID() const { 296 dw_offset_t local_id = 297 m_base_obj_offset != DW_INVALID_OFFSET ? m_base_obj_offset : m_offset; 298 if (m_dwarf) 299 return DIERef(local_id, local_id).GetUID(m_dwarf); 300 else 301 return local_id; 302 } 303 304 dw_offset_t DWARFUnit::GetNextCompileUnitOffset() const { 305 return m_offset + GetLengthByteSize() + GetLength(); 306 } 307 308 size_t DWARFUnit::GetDebugInfoSize() const { 309 return GetLengthByteSize() + GetLength() - GetHeaderByteSize(); 310 } 311 312 const DWARFAbbreviationDeclarationSet *DWARFUnit::GetAbbreviations() const { 313 return m_abbrevs; 314 } 315 316 dw_offset_t DWARFUnit::GetAbbrevOffset() const { 317 return m_abbrevs ? m_abbrevs->GetOffset() : DW_INVALID_OFFSET; 318 } 319 320 void DWARFUnit::SetAddrBase(dw_addr_t addr_base, 321 dw_addr_t ranges_base, 322 dw_offset_t base_obj_offset) { 323 m_addr_base = addr_base; 324 m_ranges_base = ranges_base; 325 m_base_obj_offset = base_obj_offset; 326 } 327 328 void DWARFUnit::ClearDIEs() { 329 m_die_array.clear(); 330 m_die_array.shrink_to_fit(); 331 332 if (m_dwo_symbol_file) 333 m_dwo_symbol_file->GetCompileUnit()->ClearDIEs(); 334 } 335 336 void DWARFUnit::BuildAddressRangeTable(SymbolFileDWARF *dwarf, 337 DWARFDebugAranges *debug_aranges) { 338 // This function is usually called if there in no .debug_aranges section in 339 // order to produce a compile unit level set of address ranges that is 340 // accurate. 341 342 size_t num_debug_aranges = debug_aranges->GetNumRanges(); 343 344 // First get the compile unit DIE only and check if it has a DW_AT_ranges 345 const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly(); 346 347 const dw_offset_t cu_offset = GetOffset(); 348 if (die) { 349 DWARFRangeList ranges; 350 const size_t num_ranges = 351 die->GetAttributeAddressRanges(dwarf, this, ranges, false); 352 if (num_ranges > 0) { 353 // This compile unit has DW_AT_ranges, assume this is correct if it is 354 // present since clang no longer makes .debug_aranges by default and it 355 // emits DW_AT_ranges for DW_TAG_compile_units. GCC also does this with 356 // recent GCC builds. 357 for (size_t i = 0; i < num_ranges; ++i) { 358 const DWARFRangeList::Entry &range = ranges.GetEntryRef(i); 359 debug_aranges->AppendRange(cu_offset, range.GetRangeBase(), 360 range.GetRangeEnd()); 361 } 362 363 return; // We got all of our ranges from the DW_AT_ranges attribute 364 } 365 } 366 // We don't have a DW_AT_ranges attribute, so we need to parse the DWARF 367 368 // If the DIEs weren't parsed, then we don't want all dies for all compile 369 // units to stay loaded when they weren't needed. So we can end up parsing 370 // the DWARF and then throwing them all away to keep memory usage down. 371 const bool clear_dies = ExtractDIEsIfNeeded(); 372 373 die = DIEPtr(); 374 if (die) 375 die->BuildAddressRangeTable(dwarf, this, debug_aranges); 376 377 if (debug_aranges->GetNumRanges() == num_debug_aranges) { 378 // We got nothing from the functions, maybe we have a line tables only 379 // situation. Check the line tables and build the arange table from this. 380 SymbolContext sc; 381 sc.comp_unit = dwarf->GetCompUnitForDWARFCompUnit(this); 382 if (sc.comp_unit) { 383 SymbolFileDWARFDebugMap *debug_map_sym_file = 384 m_dwarf->GetDebugMapSymfile(); 385 if (debug_map_sym_file == NULL) { 386 LineTable *line_table = sc.comp_unit->GetLineTable(); 387 388 if (line_table) { 389 LineTable::FileAddressRanges file_ranges; 390 const bool append = true; 391 const size_t num_ranges = 392 line_table->GetContiguousFileAddressRanges(file_ranges, append); 393 for (uint32_t idx = 0; idx < num_ranges; ++idx) { 394 const LineTable::FileAddressRanges::Entry &range = 395 file_ranges.GetEntryRef(idx); 396 debug_aranges->AppendRange(cu_offset, range.GetRangeBase(), 397 range.GetRangeEnd()); 398 } 399 } 400 } else 401 debug_map_sym_file->AddOSOARanges(dwarf, debug_aranges); 402 } 403 } 404 405 if (debug_aranges->GetNumRanges() == num_debug_aranges) { 406 // We got nothing from the functions, maybe we have a line tables only 407 // situation. Check the line tables and build the arange table from this. 408 SymbolContext sc; 409 sc.comp_unit = dwarf->GetCompUnitForDWARFCompUnit(this); 410 if (sc.comp_unit) { 411 LineTable *line_table = sc.comp_unit->GetLineTable(); 412 413 if (line_table) { 414 LineTable::FileAddressRanges file_ranges; 415 const bool append = true; 416 const size_t num_ranges = 417 line_table->GetContiguousFileAddressRanges(file_ranges, append); 418 for (uint32_t idx = 0; idx < num_ranges; ++idx) { 419 const LineTable::FileAddressRanges::Entry &range = 420 file_ranges.GetEntryRef(idx); 421 debug_aranges->AppendRange(GetOffset(), range.GetRangeBase(), 422 range.GetRangeEnd()); 423 } 424 } 425 } 426 } 427 428 // Keep memory down by clearing DIEs if this generate function caused them to 429 // be parsed 430 if (clear_dies) 431 ClearDIEs(); 432 } 433 434 lldb::ByteOrder DWARFUnit::GetByteOrder() const { 435 return m_dwarf->GetObjectFile()->GetByteOrder(); 436 } 437 438 TypeSystem *DWARFUnit::GetTypeSystem() { 439 if (m_dwarf) 440 return m_dwarf->GetTypeSystemForLanguage(GetLanguageType()); 441 else 442 return nullptr; 443 } 444 445 DWARFFormValue::FixedFormSizes DWARFUnit::GetFixedFormSizes() { 446 return DWARFFormValue::GetFixedFormSizesForAddressSize(GetAddressByteSize(), 447 IsDWARF64()); 448 } 449 450 void DWARFUnit::SetBaseAddress(dw_addr_t base_addr) { m_base_addr = base_addr; } 451 452 //---------------------------------------------------------------------- 453 // Compare function DWARFDebugAranges::Range structures 454 //---------------------------------------------------------------------- 455 static bool CompareDIEOffset(const DWARFDebugInfoEntry &die, 456 const dw_offset_t die_offset) { 457 return die.GetOffset() < die_offset; 458 } 459 460 //---------------------------------------------------------------------- 461 // GetDIE() 462 // 463 // Get the DIE (Debug Information Entry) with the specified offset by first 464 // checking if the DIE is contained within this compile unit and grabbing the 465 // DIE from this compile unit. Otherwise we grab the DIE from the DWARF file. 466 //---------------------------------------------------------------------- 467 DWARFDIE 468 DWARFUnit::GetDIE(dw_offset_t die_offset) { 469 if (die_offset != DW_INVALID_OFFSET) { 470 if (GetDwoSymbolFile()) 471 return GetDwoSymbolFile()->GetCompileUnit()->GetDIE(die_offset); 472 473 if (ContainsDIEOffset(die_offset)) { 474 ExtractDIEsIfNeeded(); 475 DWARFDebugInfoEntry::const_iterator end = m_die_array.cend(); 476 DWARFDebugInfoEntry::const_iterator pos = 477 lower_bound(m_die_array.cbegin(), end, die_offset, CompareDIEOffset); 478 if (pos != end) { 479 if (die_offset == (*pos).GetOffset()) 480 return DWARFDIE(this, &(*pos)); 481 } 482 } else { 483 // Don't specify the compile unit offset as we don't know it because the 484 // DIE belongs to 485 // a different compile unit in the same symbol file. 486 return m_dwarf->DebugInfo()->GetDIEForDIEOffset(die_offset); 487 } 488 } 489 return DWARFDIE(); // Not found 490 } 491 492 uint8_t DWARFUnit::GetAddressByteSize(const DWARFUnit *cu) { 493 if (cu) 494 return cu->GetAddressByteSize(); 495 return DWARFUnit::GetDefaultAddressSize(); 496 } 497 498 bool DWARFUnit::IsDWARF64(const DWARFUnit *cu) { 499 if (cu) 500 return cu->IsDWARF64(); 501 return false; 502 } 503 504 uint8_t DWARFUnit::GetDefaultAddressSize() { return 4; } 505 506 void *DWARFUnit::GetUserData() const { return m_user_data; } 507 508 void DWARFUnit::SetUserData(void *d) { 509 m_user_data = d; 510 if (m_dwo_symbol_file) 511 m_dwo_symbol_file->GetCompileUnit()->SetUserData(d); 512 } 513 514 bool DWARFUnit::Supports_DW_AT_APPLE_objc_complete_type() { 515 if (GetProducer() == eProducerLLVMGCC) 516 return false; 517 return true; 518 } 519 520 bool DWARFUnit::DW_AT_decl_file_attributes_are_invalid() { 521 // llvm-gcc makes completely invalid decl file attributes and won't ever be 522 // fixed, so we need to know to ignore these. 523 return GetProducer() == eProducerLLVMGCC; 524 } 525 526 bool DWARFUnit::Supports_unnamed_objc_bitfields() { 527 if (GetProducer() == eProducerClang) { 528 const uint32_t major_version = GetProducerVersionMajor(); 529 if (major_version > 425 || 530 (major_version == 425 && GetProducerVersionUpdate() >= 13)) 531 return true; 532 else 533 return false; 534 } 535 return true; // Assume all other compilers didn't have incorrect ObjC bitfield 536 // info 537 } 538 539 SymbolFileDWARF *DWARFUnit::GetSymbolFileDWARF() const { return m_dwarf; } 540 541 void DWARFUnit::ParseProducerInfo() { 542 m_producer_version_major = UINT32_MAX; 543 m_producer_version_minor = UINT32_MAX; 544 m_producer_version_update = UINT32_MAX; 545 546 const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly(); 547 if (die) { 548 549 const char *producer_cstr = 550 die->GetAttributeValueAsString(m_dwarf, this, DW_AT_producer, NULL); 551 if (producer_cstr) { 552 RegularExpression llvm_gcc_regex( 553 llvm::StringRef("^4\\.[012]\\.[01] \\(Based on Apple " 554 "Inc\\. build [0-9]+\\) \\(LLVM build " 555 "[\\.0-9]+\\)$")); 556 if (llvm_gcc_regex.Execute(llvm::StringRef(producer_cstr))) { 557 m_producer = eProducerLLVMGCC; 558 } else if (strstr(producer_cstr, "clang")) { 559 static RegularExpression g_clang_version_regex( 560 llvm::StringRef("clang-([0-9]+)\\.([0-9]+)\\.([0-9]+)")); 561 RegularExpression::Match regex_match(3); 562 if (g_clang_version_regex.Execute(llvm::StringRef(producer_cstr), 563 ®ex_match)) { 564 std::string str; 565 if (regex_match.GetMatchAtIndex(producer_cstr, 1, str)) 566 m_producer_version_major = 567 StringConvert::ToUInt32(str.c_str(), UINT32_MAX, 10); 568 if (regex_match.GetMatchAtIndex(producer_cstr, 2, str)) 569 m_producer_version_minor = 570 StringConvert::ToUInt32(str.c_str(), UINT32_MAX, 10); 571 if (regex_match.GetMatchAtIndex(producer_cstr, 3, str)) 572 m_producer_version_update = 573 StringConvert::ToUInt32(str.c_str(), UINT32_MAX, 10); 574 } 575 m_producer = eProducerClang; 576 } else if (strstr(producer_cstr, "GNU")) 577 m_producer = eProducerGCC; 578 } 579 } 580 if (m_producer == eProducerInvalid) 581 m_producer = eProcucerOther; 582 } 583 584 DWARFProducer DWARFUnit::GetProducer() { 585 if (m_producer == eProducerInvalid) 586 ParseProducerInfo(); 587 return m_producer; 588 } 589 590 uint32_t DWARFUnit::GetProducerVersionMajor() { 591 if (m_producer_version_major == 0) 592 ParseProducerInfo(); 593 return m_producer_version_major; 594 } 595 596 uint32_t DWARFUnit::GetProducerVersionMinor() { 597 if (m_producer_version_minor == 0) 598 ParseProducerInfo(); 599 return m_producer_version_minor; 600 } 601 602 uint32_t DWARFUnit::GetProducerVersionUpdate() { 603 if (m_producer_version_update == 0) 604 ParseProducerInfo(); 605 return m_producer_version_update; 606 } 607 LanguageType DWARFUnit::LanguageTypeFromDWARF(uint64_t val) { 608 // Note: user languages between lo_user and hi_user must be handled 609 // explicitly here. 610 switch (val) { 611 case DW_LANG_Mips_Assembler: 612 return eLanguageTypeMipsAssembler; 613 case DW_LANG_GOOGLE_RenderScript: 614 return eLanguageTypeExtRenderScript; 615 default: 616 return static_cast<LanguageType>(val); 617 } 618 } 619 620 LanguageType DWARFUnit::GetLanguageType() { 621 if (m_language_type != eLanguageTypeUnknown) 622 return m_language_type; 623 624 const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly(); 625 if (die) 626 m_language_type = LanguageTypeFromDWARF( 627 die->GetAttributeValueAsUnsigned(m_dwarf, this, DW_AT_language, 0)); 628 return m_language_type; 629 } 630 631 bool DWARFUnit::GetIsOptimized() { 632 if (m_is_optimized == eLazyBoolCalculate) { 633 const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly(); 634 if (die) { 635 m_is_optimized = eLazyBoolNo; 636 if (die->GetAttributeValueAsUnsigned(m_dwarf, this, DW_AT_APPLE_optimized, 637 0) == 1) { 638 m_is_optimized = eLazyBoolYes; 639 } 640 } 641 } 642 return m_is_optimized == eLazyBoolYes; 643 } 644 645 SymbolFileDWARFDwo *DWARFUnit::GetDwoSymbolFile() const { 646 return m_dwo_symbol_file.get(); 647 } 648 649 dw_offset_t DWARFUnit::GetBaseObjOffset() const { return m_base_obj_offset; } 650 651 const DWARFDebugAranges &DWARFUnit::GetFunctionAranges() { 652 if (m_func_aranges_ap.get() == NULL) { 653 m_func_aranges_ap.reset(new DWARFDebugAranges()); 654 Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_ARANGES)); 655 656 if (log) { 657 m_dwarf->GetObjectFile()->GetModule()->LogMessage( 658 log, 659 "DWARFUnit::GetFunctionAranges() for compile unit at " 660 ".debug_info[0x%8.8x]", 661 GetOffset()); 662 } 663 const DWARFDebugInfoEntry *die = DIEPtr(); 664 if (die) 665 die->BuildFunctionAddressRangeTable(m_dwarf, this, 666 m_func_aranges_ap.get()); 667 668 if (m_dwo_symbol_file) { 669 DWARFUnit *dwo_cu = m_dwo_symbol_file->GetCompileUnit(); 670 const DWARFDebugInfoEntry *dwo_die = dwo_cu->DIEPtr(); 671 if (dwo_die) 672 dwo_die->BuildFunctionAddressRangeTable(m_dwo_symbol_file.get(), dwo_cu, 673 m_func_aranges_ap.get()); 674 } 675 676 const bool minimize = false; 677 m_func_aranges_ap->Sort(minimize); 678 } 679 return *m_func_aranges_ap.get(); 680 } 681 682