From 118bcd9ce247143ec7e66a68bfdcea7e8f8b2a92 Mon Sep 17 00:00:00 2001 From: Greg Clayton Date: Thu, 5 Apr 2018 15:52:39 +0000 Subject: [PATCH] Cleanup DWARFCompileUnit and DWARFUnit in preparation for adding DWARFTypeUnit Many things that were in DWARFCompileUnit actually need to be in DWARFUnit. This patch moves all DWARFUnit specific things over into DWARFUnit and fixes the layering. This is in preparation for adding DWARFTypeUnit for the .debug_types patch. Differential Revision: https://reviews.llvm.org/D45170 llvm-svn: 329305 --- .../Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp | 580 +------------------ .../Plugins/SymbolFile/DWARF/DWARFCompileUnit.h | 106 +--- .../SymbolFile/DWARF/DWARFDebugInfoEntry.cpp | 4 +- lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp | 622 +++++++++++++++++---- lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h | 69 ++- .../Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp | 12 +- .../Plugins/SymbolFile/DWARF/SymbolFileDWARF.h | 2 +- .../SymbolFile/DWARF/SymbolFileDWARFDebugMap.h | 2 +- 8 files changed, 569 insertions(+), 828 deletions(-) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp index 13e620b..0bff6e6 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp @@ -9,36 +9,15 @@ #include "DWARFCompileUnit.h" -#include "lldb/Core/DumpDataExtractor.h" -#include "lldb/Core/Mangled.h" -#include "lldb/Core/Module.h" -#include "lldb/Host/StringConvert.h" -#include "lldb/Symbol/CompileUnit.h" -#include "lldb/Symbol/LineTable.h" -#include "lldb/Symbol/ObjectFile.h" -#include "lldb/Utility/Stream.h" -#include "lldb/Utility/StreamString.h" -#include "lldb/Utility/Timer.h" - -#include "DWARFDIECollection.h" -#include "DWARFDebugAbbrev.h" -#include "DWARFDebugAranges.h" -#include "DWARFDebugInfo.h" -#include "DWARFFormValue.h" -#include "LogChannelDWARF.h" -#include "NameToDIE.h" #include "SymbolFileDWARF.h" -#include "SymbolFileDWARFDebugMap.h" -#include "SymbolFileDWARFDwo.h" using namespace lldb; using namespace lldb_private; -using namespace std; extern int g_verbose; DWARFCompileUnit::DWARFCompileUnit(SymbolFileDWARF *dwarf2Data) - : m_dwarf2Data(dwarf2Data) {} + : DWARFUnit(dwarf2Data) {} DWARFUnitSP DWARFCompileUnit::Extract(SymbolFileDWARF *dwarf2Data, lldb::offset_t *offset_ptr) { @@ -81,259 +60,6 @@ DWARFUnitSP DWARFCompileUnit::Extract(SymbolFileDWARF *dwarf2Data, return nullptr; } -void DWARFCompileUnit::ClearDIEs(bool keep_compile_unit_die) { - if (m_die_array.size() > 1) { - // std::vectors never get any smaller when resized to a smaller size, - // or when clear() or erase() are called, the size will report that it - // is smaller, but the memory allocated remains intact (call capacity() - // to see this). So we need to create a temporary vector and swap the - // contents which will cause just the internal pointers to be swapped - // so that when "tmp_array" goes out of scope, it will destroy the - // contents. - - // Save at least the compile unit DIE - DWARFDebugInfoEntry::collection tmp_array; - m_die_array.swap(tmp_array); - if (keep_compile_unit_die) - m_die_array.push_back(tmp_array.front()); - } - - if (m_dwo_symbol_file) - m_dwo_symbol_file->GetCompileUnit()->ClearDIEs(keep_compile_unit_die); -} - -//---------------------------------------------------------------------- -// ParseCompileUnitDIEsIfNeeded -// -// Parses a compile unit and indexes its DIEs if it hasn't already been -// done. -//---------------------------------------------------------------------- -size_t DWARFCompileUnit::ExtractDIEsIfNeeded(bool cu_die_only) { - const size_t initial_die_array_size = m_die_array.size(); - if ((cu_die_only && initial_die_array_size > 0) || initial_die_array_size > 1) - return 0; // Already parsed - - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer( - func_cat, - "%8.8x: DWARFCompileUnit::ExtractDIEsIfNeeded( cu_die_only = %i )", - m_offset, cu_die_only); - - // Set the offset to that of the first DIE and calculate the start of the - // next compilation unit header. - lldb::offset_t offset = GetFirstDIEOffset(); - lldb::offset_t next_cu_offset = GetNextCompileUnitOffset(); - - DWARFDebugInfoEntry die; - // Keep a flat array of the DIE for binary lookup by DIE offset - if (!cu_die_only) { - Log *log( - LogChannelDWARF::GetLogIfAny(DWARF_LOG_DEBUG_INFO | DWARF_LOG_LOOKUPS)); - if (log) { - m_dwarf2Data->GetObjectFile()->GetModule()->LogMessageVerboseBacktrace( - log, "DWARFCompileUnit::ExtractDIEsIfNeeded () for compile unit at " - ".debug_info[0x%8.8x]", - GetOffset()); - } - } - - uint32_t depth = 0; - // We are in our compile unit, parse starting at the offset - // we were told to parse - const DWARFDataExtractor &debug_info_data = - m_dwarf2Data->get_debug_info_data(); - std::vector die_index_stack; - die_index_stack.reserve(32); - die_index_stack.push_back(0); - bool prev_die_had_children = false; - DWARFFormValue::FixedFormSizes fixed_form_sizes = - DWARFFormValue::GetFixedFormSizesForAddressSize(GetAddressByteSize(), - m_is_dwarf64); - while (offset < next_cu_offset && - die.FastExtract(debug_info_data, this, fixed_form_sizes, &offset)) { - // if (log) - // log->Printf("0x%8.8x: %*.*s%s%s", - // die.GetOffset(), - // depth * 2, depth * 2, "", - // DW_TAG_value_to_name (die.Tag()), - // die.HasChildren() ? " *" : ""); - - const bool null_die = die.IsNULL(); - if (depth == 0) { - if (initial_die_array_size == 0) - AddCompileUnitDIE(die); - uint64_t base_addr = die.GetAttributeValueAsAddress( - m_dwarf2Data, this, DW_AT_low_pc, LLDB_INVALID_ADDRESS); - if (base_addr == LLDB_INVALID_ADDRESS) - base_addr = die.GetAttributeValueAsAddress(m_dwarf2Data, this, - DW_AT_entry_pc, 0); - SetBaseAddress(base_addr); - if (cu_die_only) - return 1; - } else { - if (null_die) { - if (prev_die_had_children) { - // This will only happen if a DIE says is has children - // but all it contains is a NULL tag. Since we are removing - // the NULL DIEs from the list (saves up to 25% in C++ code), - // we need a way to let the DIE know that it actually doesn't - // have children. - if (!m_die_array.empty()) - m_die_array.back().SetEmptyChildren(true); - } - } else { - die.SetParentIndex(m_die_array.size() - die_index_stack[depth - 1]); - - if (die_index_stack.back()) - m_die_array[die_index_stack.back()].SetSiblingIndex( - m_die_array.size() - die_index_stack.back()); - - // Only push the DIE if it isn't a NULL DIE - m_die_array.push_back(die); - } - } - - if (null_die) { - // NULL DIE. - if (!die_index_stack.empty()) - die_index_stack.pop_back(); - - if (depth > 0) - --depth; - if (depth == 0) - break; // We are done with this compile unit! - - prev_die_had_children = false; - } else { - die_index_stack.back() = m_die_array.size() - 1; - // Normal DIE - const bool die_has_children = die.HasChildren(); - if (die_has_children) { - die_index_stack.push_back(0); - ++depth; - } - prev_die_had_children = die_has_children; - } - } - - // Give a little bit of info if we encounter corrupt DWARF (our offset - // should always terminate at or before the start of the next compilation - // unit header). - if (offset > next_cu_offset) { - m_dwarf2Data->GetObjectFile()->GetModule()->ReportWarning( - "DWARF compile unit extends beyond its bounds cu 0x%8.8x at " - "0x%8.8" PRIx64 "\n", - GetOffset(), offset); - } - - // Since std::vector objects will double their size, we really need to - // make a new array with the perfect size so we don't end up wasting - // space. So here we copy and swap to make sure we don't have any extra - // memory taken up. - - if (m_die_array.size() < m_die_array.capacity()) { - DWARFDebugInfoEntry::collection exact_size_die_array(m_die_array.begin(), - m_die_array.end()); - exact_size_die_array.swap(m_die_array); - } - Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO)); - if (log && log->GetVerbose()) { - StreamString strm; - Dump(&strm); - if (m_die_array.empty()) - strm.Printf("error: no DIE for compile unit"); - else - m_die_array[0].Dump(m_dwarf2Data, this, strm, UINT32_MAX); - log->PutString(strm.GetString()); - } - - if (!m_dwo_symbol_file) - return m_die_array.size(); - - DWARFUnit *dwo_cu = m_dwo_symbol_file->GetCompileUnit(); - size_t dwo_die_count = dwo_cu->ExtractDIEsIfNeeded(cu_die_only); - return m_die_array.size() + dwo_die_count - - 1; // We have 2 CU die, but we want to count it only as one -} - -void DWARFCompileUnit::AddCompileUnitDIE(DWARFDebugInfoEntry &die) { - assert(m_die_array.empty() && "Compile unit DIE already added"); - AddDIE(die); - - const DWARFDebugInfoEntry &cu_die = m_die_array.front(); - std::unique_ptr dwo_symbol_file = - m_dwarf2Data->GetDwoSymbolFileForCompileUnit(*this, cu_die); - if (!dwo_symbol_file) - return; - - DWARFUnit *dwo_cu = dwo_symbol_file->GetCompileUnit(); - if (!dwo_cu) - return; // Can't fetch the compile unit from the dwo file. - - DWARFDIE dwo_cu_die = dwo_cu->GetCompileUnitDIEOnly(); - if (!dwo_cu_die.IsValid()) - return; // Can't fetch the compile unit DIE from the dwo file. - - uint64_t main_dwo_id = cu_die.GetAttributeValueAsUnsigned( - m_dwarf2Data, this, DW_AT_GNU_dwo_id, 0); - uint64_t sub_dwo_id = - dwo_cu_die.GetAttributeValueAsUnsigned(DW_AT_GNU_dwo_id, 0); - if (main_dwo_id != sub_dwo_id) - return; // The 2 dwo ID isn't match. Don't use the dwo file as it belongs to - // a differectn compilation. - - m_dwo_symbol_file = std::move(dwo_symbol_file); - - dw_addr_t addr_base = cu_die.GetAttributeValueAsUnsigned( - m_dwarf2Data, this, DW_AT_GNU_addr_base, 0); - dw_addr_t ranges_base = cu_die.GetAttributeValueAsUnsigned( - m_dwarf2Data, this, DW_AT_GNU_ranges_base, 0); - dwo_cu->SetAddrBase(addr_base, ranges_base, m_offset); -} - -dw_offset_t DWARFCompileUnit::GetAbbrevOffset() const { - return m_abbrevs ? m_abbrevs->GetOffset() : DW_INVALID_OFFSET; -} - -bool DWARFCompileUnit::Verify(Stream *s) const { - const DWARFDataExtractor &debug_info = m_dwarf2Data->get_debug_info_data(); - bool valid_offset = debug_info.ValidOffset(m_offset); - bool length_OK = debug_info.ValidOffset(GetNextCompileUnitOffset() - 1); - bool version_OK = SymbolFileDWARF::SupportedVersion(m_version); - bool abbr_offset_OK = - m_dwarf2Data->get_debug_abbrev_data().ValidOffset(GetAbbrevOffset()); - bool addr_size_OK = ((m_addr_size == 4) || (m_addr_size == 8)); - if (valid_offset && length_OK && version_OK && addr_size_OK && - abbr_offset_OK) { - return true; - } else { - s->Printf(" 0x%8.8x: ", m_offset); - DumpDataExtractor(m_dwarf2Data->get_debug_info_data(), s, m_offset, - lldb::eFormatHex, 1, Size(), 32, LLDB_INVALID_ADDRESS, 0, - 0); - s->EOL(); - if (valid_offset) { - if (!length_OK) - s->Printf(" The length (0x%8.8x) for this compile unit is too " - "large for the .debug_info provided.\n", - m_length); - if (!version_OK) - s->Printf(" The 16 bit compile unit header version is not " - "supported.\n"); - if (!abbr_offset_OK) - s->Printf(" The offset into the .debug_abbrev section (0x%8.8x) " - "is not valid.\n", - GetAbbrevOffset()); - if (!addr_size_OK) - s->Printf(" The address size is unsupported: 0x%2.2x\n", - m_addr_size); - } else - s->Printf(" The start offset of the compile unit header in the " - ".debug_info is invalid.\n"); - } - return false; -} - void DWARFCompileUnit::Dump(Stream *s) const { s->Printf("0x%8.8x: Compile Unit: length = 0x%8.8x, version = 0x%4.4x, " "abbr_offset = 0x%8.8x, addr_size = 0x%2.2x (next CU at " @@ -341,307 +67,3 @@ void DWARFCompileUnit::Dump(Stream *s) const { m_offset, m_length, m_version, GetAbbrevOffset(), m_addr_size, GetNextCompileUnitOffset()); } - -lldb::user_id_t DWARFCompileUnit::GetID() const { - dw_offset_t local_id = - m_base_obj_offset != DW_INVALID_OFFSET ? m_base_obj_offset : m_offset; - if (m_dwarf2Data) - return DIERef(local_id, local_id).GetUID(m_dwarf2Data); - else - return local_id; -} - -void DWARFCompileUnit::BuildAddressRangeTable( - SymbolFileDWARF *dwarf2Data, DWARFDebugAranges *debug_aranges) { - // This function is usually called if there in no .debug_aranges section - // in order to produce a compile unit level set of address ranges that - // is accurate. - - size_t num_debug_aranges = debug_aranges->GetNumRanges(); - - // First get the compile unit DIE only and check if it has a DW_AT_ranges - const DWARFDebugInfoEntry *die = GetCompileUnitDIEPtrOnly(); - - const dw_offset_t cu_offset = GetOffset(); - if (die) { - DWARFRangeList ranges; - const size_t num_ranges = - die->GetAttributeAddressRanges(dwarf2Data, this, ranges, false); - if (num_ranges > 0) { - // This compile unit has DW_AT_ranges, assume this is correct if it - // is present since clang no longer makes .debug_aranges by default - // and it emits DW_AT_ranges for DW_TAG_compile_units. GCC also does - // this with recent GCC builds. - for (size_t i = 0; i < num_ranges; ++i) { - const DWARFRangeList::Entry &range = ranges.GetEntryRef(i); - debug_aranges->AppendRange(cu_offset, range.GetRangeBase(), - range.GetRangeEnd()); - } - - return; // We got all of our ranges from the DW_AT_ranges attribute - } - } - // We don't have a DW_AT_ranges attribute, so we need to parse the DWARF - - // If the DIEs weren't parsed, then we don't want all dies for all compile - // units - // to stay loaded when they weren't needed. So we can end up parsing the DWARF - // and then throwing them all away to keep memory usage down. - const bool clear_dies = ExtractDIEsIfNeeded(false) > 1; - - die = DIEPtr(); - if (die) - die->BuildAddressRangeTable(dwarf2Data, this, debug_aranges); - - if (debug_aranges->GetNumRanges() == num_debug_aranges) { - // We got nothing from the functions, maybe we have a line tables only - // situation. Check the line tables and build the arange table from this. - SymbolContext sc; - sc.comp_unit = dwarf2Data->GetCompUnitForDWARFCompUnit(this); - if (sc.comp_unit) { - SymbolFileDWARFDebugMap *debug_map_sym_file = - m_dwarf2Data->GetDebugMapSymfile(); - if (debug_map_sym_file == NULL) { - LineTable *line_table = sc.comp_unit->GetLineTable(); - - if (line_table) { - LineTable::FileAddressRanges file_ranges; - const bool append = true; - const size_t num_ranges = - line_table->GetContiguousFileAddressRanges(file_ranges, append); - for (uint32_t idx = 0; idx < num_ranges; ++idx) { - const LineTable::FileAddressRanges::Entry &range = - file_ranges.GetEntryRef(idx); - debug_aranges->AppendRange(cu_offset, range.GetRangeBase(), - range.GetRangeEnd()); - } - } - } else - debug_map_sym_file->AddOSOARanges(dwarf2Data, debug_aranges); - } - } - - if (debug_aranges->GetNumRanges() == num_debug_aranges) { - // We got nothing from the functions, maybe we have a line tables only - // situation. Check the line tables and build the arange table from this. - SymbolContext sc; - sc.comp_unit = dwarf2Data->GetCompUnitForDWARFCompUnit(this); - if (sc.comp_unit) { - LineTable *line_table = sc.comp_unit->GetLineTable(); - - if (line_table) { - LineTable::FileAddressRanges file_ranges; - const bool append = true; - const size_t num_ranges = - line_table->GetContiguousFileAddressRanges(file_ranges, append); - for (uint32_t idx = 0; idx < num_ranges; ++idx) { - const LineTable::FileAddressRanges::Entry &range = - file_ranges.GetEntryRef(idx); - debug_aranges->AppendRange(GetOffset(), range.GetRangeBase(), - range.GetRangeEnd()); - } - } - } - } - - // Keep memory down by clearing DIEs if this generate function - // caused them to be parsed - if (clear_dies) - ClearDIEs(true); -} - -const DWARFDebugAranges &DWARFCompileUnit::GetFunctionAranges() { - if (m_func_aranges_ap.get() == NULL) { - m_func_aranges_ap.reset(new DWARFDebugAranges()); - Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_ARANGES)); - - if (log) { - m_dwarf2Data->GetObjectFile()->GetModule()->LogMessage( - log, "DWARFCompileUnit::GetFunctionAranges() for compile unit at " - ".debug_info[0x%8.8x]", - GetOffset()); - } - const DWARFDebugInfoEntry *die = DIEPtr(); - if (die) - die->BuildFunctionAddressRangeTable(m_dwarf2Data, this, - m_func_aranges_ap.get()); - - if (m_dwo_symbol_file) { - DWARFUnit *dwo_cu = m_dwo_symbol_file->GetCompileUnit(); - const DWARFDebugInfoEntry *dwo_die = dwo_cu->DIEPtr(); - if (dwo_die) - dwo_die->BuildFunctionAddressRangeTable(m_dwo_symbol_file.get(), dwo_cu, - m_func_aranges_ap.get()); - } - - const bool minimize = false; - m_func_aranges_ap->Sort(minimize); - } - return *m_func_aranges_ap.get(); -} - -DWARFDIE -DWARFCompileUnit::LookupAddress(const dw_addr_t address) { - if (DIE()) { - const DWARFDebugAranges &func_aranges = GetFunctionAranges(); - - // Re-check the aranges auto pointer contents in case it was created above - if (!func_aranges.IsEmpty()) - return GetDIE(func_aranges.FindAddress(address)); - } - return DWARFDIE(); -} - -size_t DWARFCompileUnit::AppendDIEsWithTag(const dw_tag_t tag, - DWARFDIECollection &dies, - uint32_t depth) const { - size_t old_size = dies.Size(); - DWARFDebugInfoEntry::const_iterator pos; - DWARFDebugInfoEntry::const_iterator end = m_die_array.end(); - for (pos = m_die_array.begin(); pos != end; ++pos) { - if (pos->Tag() == tag) - dies.Append(DWARFDIE(this, &(*pos))); - } - - // Return the number of DIEs added to the collection - return dies.Size() - old_size; -} - -// void -// DWARFCompileUnit::AddGlobalDIEByIndex (uint32_t die_idx) -//{ -// m_global_die_indexes.push_back (die_idx); -//} -// -// -// void -// DWARFCompileUnit::AddGlobal (const DWARFDebugInfoEntry* die) -//{ -// // Indexes to all file level global and static variables -// m_global_die_indexes; -// -// if (m_die_array.empty()) -// return; -// -// const DWARFDebugInfoEntry* first_die = &m_die_array[0]; -// const DWARFDebugInfoEntry* end = first_die + m_die_array.size(); -// if (first_die <= die && die < end) -// m_global_die_indexes.push_back (die - first_die); -//} - -void DWARFCompileUnit::ParseProducerInfo() { - m_producer_version_major = UINT32_MAX; - m_producer_version_minor = UINT32_MAX; - m_producer_version_update = UINT32_MAX; - - const DWARFDebugInfoEntry *die = GetCompileUnitDIEPtrOnly(); - if (die) { - - const char *producer_cstr = die->GetAttributeValueAsString( - m_dwarf2Data, this, DW_AT_producer, NULL); - if (producer_cstr) { - RegularExpression llvm_gcc_regex( - llvm::StringRef("^4\\.[012]\\.[01] \\(Based on Apple " - "Inc\\. build [0-9]+\\) \\(LLVM build " - "[\\.0-9]+\\)$")); - if (llvm_gcc_regex.Execute(llvm::StringRef(producer_cstr))) { - m_producer = eProducerLLVMGCC; - } else if (strstr(producer_cstr, "clang")) { - static RegularExpression g_clang_version_regex( - llvm::StringRef("clang-([0-9]+)\\.([0-9]+)\\.([0-9]+)")); - RegularExpression::Match regex_match(3); - if (g_clang_version_regex.Execute(llvm::StringRef(producer_cstr), - ®ex_match)) { - std::string str; - if (regex_match.GetMatchAtIndex(producer_cstr, 1, str)) - m_producer_version_major = - StringConvert::ToUInt32(str.c_str(), UINT32_MAX, 10); - if (regex_match.GetMatchAtIndex(producer_cstr, 2, str)) - m_producer_version_minor = - StringConvert::ToUInt32(str.c_str(), UINT32_MAX, 10); - if (regex_match.GetMatchAtIndex(producer_cstr, 3, str)) - m_producer_version_update = - StringConvert::ToUInt32(str.c_str(), UINT32_MAX, 10); - } - m_producer = eProducerClang; - } else if (strstr(producer_cstr, "GNU")) - m_producer = eProducerGCC; - } - } - if (m_producer == eProducerInvalid) - m_producer = eProcucerOther; -} - -DWARFProducer DWARFCompileUnit::GetProducer() { - if (m_producer == eProducerInvalid) - ParseProducerInfo(); - return m_producer; -} - -uint32_t DWARFCompileUnit::GetProducerVersionMajor() { - if (m_producer_version_major == 0) - ParseProducerInfo(); - return m_producer_version_major; -} - -uint32_t DWARFCompileUnit::GetProducerVersionMinor() { - if (m_producer_version_minor == 0) - ParseProducerInfo(); - return m_producer_version_minor; -} - -uint32_t DWARFCompileUnit::GetProducerVersionUpdate() { - if (m_producer_version_update == 0) - ParseProducerInfo(); - return m_producer_version_update; -} - -LanguageType DWARFCompileUnit::GetLanguageType() { - if (m_language_type != eLanguageTypeUnknown) - return m_language_type; - - const DWARFDebugInfoEntry *die = GetCompileUnitDIEPtrOnly(); - if (die) - m_language_type = LanguageTypeFromDWARF(die->GetAttributeValueAsUnsigned( - m_dwarf2Data, this, DW_AT_language, 0)); - return m_language_type; -} - -bool DWARFCompileUnit::GetIsOptimized() { - if (m_is_optimized == eLazyBoolCalculate) { - const DWARFDebugInfoEntry *die = GetCompileUnitDIEPtrOnly(); - if (die) { - m_is_optimized = eLazyBoolNo; - if (die->GetAttributeValueAsUnsigned(m_dwarf2Data, this, - DW_AT_APPLE_optimized, 0) == 1) { - m_is_optimized = eLazyBoolYes; - } - } - } - if (m_is_optimized == eLazyBoolYes) { - return true; - } else { - return false; - } -} - -TypeSystem *DWARFCompileUnit::GetTypeSystem() { - if (m_dwarf2Data) - return m_dwarf2Data->GetTypeSystemForLanguage(GetLanguageType()); - else - return nullptr; -} - -void DWARFCompileUnit::SetUserData(void *d) { - m_user_data = d; - if (m_dwo_symbol_file) - m_dwo_symbol_file->GetCompileUnit()->SetUserData(d); -} - -void DWARFCompileUnit::SetAddrBase(dw_addr_t addr_base, - dw_addr_t ranges_base, - dw_offset_t base_obj_offset) { - m_addr_base = addr_base; - m_ranges_base = ranges_base; - m_base_obj_offset = base_obj_offset; -} diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h index 978f173..1cf6a67 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h @@ -18,114 +18,10 @@ class DWARFCompileUnit : public DWARFUnit { public: static DWARFUnitSP Extract(SymbolFileDWARF *dwarf2Data, lldb::offset_t *offset_ptr); - - size_t ExtractDIEsIfNeeded(bool cu_die_only); - DWARFDIE LookupAddress(const dw_addr_t address); - size_t AppendDIEsWithTag(const dw_tag_t tag, - DWARFDIECollection &matching_dies, - uint32_t depth = UINT32_MAX) const; - bool Verify(lldb_private::Stream *s) const; - void Dump(lldb_private::Stream *s) const; - lldb::user_id_t GetID() const; - dw_offset_t GetAbbrevOffset() const; - void SetAddrBase(dw_addr_t addr_base, dw_addr_t ranges_base, dw_offset_t base_obj_offset); - void ClearDIEs(bool keep_compile_unit_die); - void BuildAddressRangeTable(SymbolFileDWARF *dwarf2Data, - DWARFDebugAranges *debug_aranges); - - lldb_private::TypeSystem *GetTypeSystem(); - - DWARFDIE - GetCompileUnitDIEOnly() { return DWARFDIE(this, GetCompileUnitDIEPtrOnly()); } - - DWARFDIE - DIE() { return DWARFDIE(this, DIEPtr()); } - - void AddDIE(DWARFDebugInfoEntry &die) { - // The average bytes per DIE entry has been seen to be - // around 14-20 so lets pre-reserve half of that since - // we are now stripping the NULL tags. - - // Only reserve the memory if we are adding children of - // the main compile unit DIE. The compile unit DIE is always - // the first entry, so if our size is 1, then we are adding - // the first compile unit child DIE and should reserve - // the memory. - if (m_die_array.empty()) - m_die_array.reserve(GetDebugInfoSize() / 24); - m_die_array.push_back(die); - } - - void AddCompileUnitDIE(DWARFDebugInfoEntry &die); - - void SetUserData(void *d); - - const DWARFDebugAranges &GetFunctionAranges(); - - DWARFProducer GetProducer(); - - uint32_t GetProducerVersionMajor(); - - uint32_t GetProducerVersionMinor(); - - uint32_t GetProducerVersionUpdate(); - - lldb::LanguageType GetLanguageType(); - - bool GetIsOptimized(); - -protected: - virtual DWARFCompileUnit &Data() override { return *this; } - virtual const DWARFCompileUnit &Data() const override { return *this; } - - SymbolFileDWARF *m_dwarf2Data; - std::unique_ptr m_dwo_symbol_file; - const DWARFAbbreviationDeclarationSet *m_abbrevs; - void *m_user_data = nullptr; - DWARFDebugInfoEntry::collection - m_die_array; // The compile unit debug information entry item - std::unique_ptr m_func_aranges_ap; // A table similar to - // the .debug_aranges - // table, but this one - // points to the exact - // DW_TAG_subprogram - // DIEs - dw_addr_t m_base_addr = 0; - dw_offset_t m_length; - uint16_t m_version; - uint8_t m_addr_size; - DWARFProducer m_producer = eProducerInvalid; - uint32_t m_producer_version_major = 0; - uint32_t m_producer_version_minor = 0; - uint32_t m_producer_version_update = 0; - lldb::LanguageType m_language_type = lldb::eLanguageTypeUnknown; - bool m_is_dwarf64; - lldb_private::LazyBool m_is_optimized = lldb_private::eLazyBoolCalculate; - dw_addr_t m_addr_base = 0; // Value of DW_AT_addr_base - dw_addr_t m_ranges_base = 0; // Value of DW_AT_ranges_base - // If this is a dwo compile unit this is the offset of the base compile unit - // in the main object file - dw_offset_t m_base_obj_offset = DW_INVALID_OFFSET; - - void ParseProducerInfo(); + void Dump(lldb_private::Stream *s) const override; private: DWARFCompileUnit(SymbolFileDWARF *dwarf2Data); - - const DWARFDebugInfoEntry *GetCompileUnitDIEPtrOnly() { - ExtractDIEsIfNeeded(true); - if (m_die_array.empty()) - return NULL; - return &m_die_array[0]; - } - - const DWARFDebugInfoEntry *DIEPtr() { - ExtractDIEsIfNeeded(false); - if (m_die_array.empty()) - return NULL; - return &m_die_array[0]; - } - DISALLOW_COPY_AND_ASSIGN(DWARFCompileUnit); }; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp index 4f07287..d3df28d 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp @@ -640,7 +640,7 @@ void DWARFDebugInfoEntry::Dump(SymbolFileDWARF *dwarf2Data, void DWARFDebugInfoEntry::DumpLocation(SymbolFileDWARF *dwarf2Data, DWARFUnit *cu, Stream &s) const { - const DWARFDIE cu_die = cu->GetCompileUnitDIEOnly(); + const DWARFDIE cu_die = cu->GetUnitDIEOnly(); const char *cu_name = NULL; if (cu_die) cu_name = cu_die.GetName(); @@ -916,7 +916,7 @@ dw_offset_t DWARFDebugInfoEntry::GetAttributeValue( if (!dwo_cu) return 0; - DWARFDIE dwo_cu_die = dwo_cu->GetCompileUnitDIEOnly(); + DWARFDIE dwo_cu_die = dwo_cu->GetUnitDIEOnly(); if (!dwo_cu_die.IsValid()) return 0; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp index 26b9900..a0af085 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -11,11 +11,18 @@ #include "Plugins/Language/ObjC/ObjCLanguage.h" #include "lldb/Core/Module.h" +#include "lldb/Host/StringConvert.h" +#include "lldb/Symbol/CompileUnit.h" +#include "lldb/Symbol/LineTable.h" #include "lldb/Symbol/ObjectFile.h" +#include "lldb/Utility/Timer.h" -#include "DWARFCompileUnit.h" +#include "DWARFDIECollection.h" +#include "DWARFDebugAbbrev.h" +#include "DWARFDebugAranges.h" #include "DWARFDebugInfo.h" #include "LogChannelDWARF.h" +#include "SymbolFileDWARFDebugMap.h" #include "SymbolFileDWARFDwo.h" using namespace lldb; @@ -24,34 +31,241 @@ using namespace std; extern int g_verbose; -DWARFUnit::DWARFUnit() {} +DWARFUnit::DWARFUnit(SymbolFileDWARF *dwarf) : m_dwarf(dwarf) {} DWARFUnit::~DWARFUnit() {} +//---------------------------------------------------------------------- +// ParseCompileUnitDIEsIfNeeded +// +// Parses a compile unit and indexes its DIEs if it hasn't already been +// done. +//---------------------------------------------------------------------- size_t DWARFUnit::ExtractDIEsIfNeeded(bool cu_die_only) { - return Data().ExtractDIEsIfNeeded(cu_die_only); + const size_t initial_die_array_size = m_die_array.size(); + if ((cu_die_only && initial_die_array_size > 0) || initial_die_array_size > 1) + return 0; // Already parsed + + static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); + Timer scoped_timer( + func_cat, "%8.8x: DWARFUnit::ExtractDIEsIfNeeded( cu_die_only = %i )", + m_offset, cu_die_only); + + // Set the offset to that of the first DIE and calculate the start of the + // next compilation unit header. + lldb::offset_t offset = GetFirstDIEOffset(); + lldb::offset_t next_cu_offset = GetNextCompileUnitOffset(); + + DWARFDebugInfoEntry die; + // Keep a flat array of the DIE for binary lookup by DIE offset + if (!cu_die_only) { + Log *log( + LogChannelDWARF::GetLogIfAny(DWARF_LOG_DEBUG_INFO | DWARF_LOG_LOOKUPS)); + if (log) { + m_dwarf->GetObjectFile()->GetModule()->LogMessageVerboseBacktrace( + log, + "DWARFUnit::ExtractDIEsIfNeeded () for compile unit at " + ".debug_info[0x%8.8x]", + GetOffset()); + } + } + + uint32_t depth = 0; + // We are in our compile unit, parse starting at the offset + // we were told to parse + const DWARFDataExtractor &debug_info_data = m_dwarf->get_debug_info_data(); + std::vector die_index_stack; + die_index_stack.reserve(32); + die_index_stack.push_back(0); + bool prev_die_had_children = false; + DWARFFormValue::FixedFormSizes fixed_form_sizes = + DWARFFormValue::GetFixedFormSizesForAddressSize(GetAddressByteSize(), + m_is_dwarf64); + while (offset < next_cu_offset && + die.FastExtract(debug_info_data, this, fixed_form_sizes, &offset)) { + // if (log) + // log->Printf("0x%8.8x: %*.*s%s%s", + // die.GetOffset(), + // depth * 2, depth * 2, "", + // DW_TAG_value_to_name (die.Tag()), + // die.HasChildren() ? " *" : ""); + + const bool null_die = die.IsNULL(); + if (depth == 0) { + if (initial_die_array_size == 0) + AddUnitDIE(die); + uint64_t base_addr = die.GetAttributeValueAsAddress( + m_dwarf, this, DW_AT_low_pc, LLDB_INVALID_ADDRESS); + if (base_addr == LLDB_INVALID_ADDRESS) + base_addr = + die.GetAttributeValueAsAddress(m_dwarf, this, DW_AT_entry_pc, 0); + SetBaseAddress(base_addr); + if (cu_die_only) + return 1; + } else { + if (null_die) { + if (prev_die_had_children) { + // This will only happen if a DIE says is has children + // but all it contains is a NULL tag. Since we are removing + // the NULL DIEs from the list (saves up to 25% in C++ code), + // we need a way to let the DIE know that it actually doesn't + // have children. + if (!m_die_array.empty()) + m_die_array.back().SetEmptyChildren(true); + } + } else { + die.SetParentIndex(m_die_array.size() - die_index_stack[depth - 1]); + + if (die_index_stack.back()) + m_die_array[die_index_stack.back()].SetSiblingIndex( + m_die_array.size() - die_index_stack.back()); + + // Only push the DIE if it isn't a NULL DIE + m_die_array.push_back(die); + } + } + + if (null_die) { + // NULL DIE. + if (!die_index_stack.empty()) + die_index_stack.pop_back(); + + if (depth > 0) + --depth; + if (depth == 0) + break; // We are done with this compile unit! + + prev_die_had_children = false; + } else { + die_index_stack.back() = m_die_array.size() - 1; + // Normal DIE + const bool die_has_children = die.HasChildren(); + if (die_has_children) { + die_index_stack.push_back(0); + ++depth; + } + prev_die_had_children = die_has_children; + } + } + + // Give a little bit of info if we encounter corrupt DWARF (our offset + // should always terminate at or before the start of the next compilation + // unit header). + if (offset > next_cu_offset) { + m_dwarf->GetObjectFile()->GetModule()->ReportWarning( + "DWARF compile unit extends beyond its bounds cu 0x%8.8x at " + "0x%8.8" PRIx64 "\n", + GetOffset(), offset); + } + + // Since std::vector objects will double their size, we really need to + // make a new array with the perfect size so we don't end up wasting + // space. So here we copy and swap to make sure we don't have any extra + // memory taken up. + + if (m_die_array.size() < m_die_array.capacity()) { + DWARFDebugInfoEntry::collection exact_size_die_array(m_die_array.begin(), + m_die_array.end()); + exact_size_die_array.swap(m_die_array); + } + Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO)); + if (log && log->GetVerbose()) { + StreamString strm; + Dump(&strm); + if (m_die_array.empty()) + strm.Printf("error: no DIE for compile unit"); + else + m_die_array[0].Dump(m_dwarf, this, strm, UINT32_MAX); + log->PutString(strm.GetString()); + } + + if (!m_dwo_symbol_file) + return m_die_array.size(); + + DWARFUnit *dwo_cu = m_dwo_symbol_file->GetCompileUnit(); + size_t dwo_die_count = dwo_cu->ExtractDIEsIfNeeded(cu_die_only); + return m_die_array.size() + dwo_die_count - + 1; // We have 2 CU die, but we want to count it only as one +} + +void DWARFUnit::AddUnitDIE(DWARFDebugInfoEntry &die) { + assert(m_die_array.empty() && "Compile unit DIE already added"); + + // The average bytes per DIE entry has been seen to be around 14-20 so lets + // pre-reserve half of that since we are now stripping the NULL tags. + + // Only reserve the memory if we are adding children of the main compile unit + // DIE. The compile unit DIE is always the first entry, so if our size is 1, + // then we are adding the first compile unit child DIE and should reserve + // the memory. + m_die_array.reserve(GetDebugInfoSize() / 24); + m_die_array.push_back(die); + + const DWARFDebugInfoEntry &cu_die = m_die_array.front(); + std::unique_ptr dwo_symbol_file = + m_dwarf->GetDwoSymbolFileForCompileUnit(*this, cu_die); + if (!dwo_symbol_file) + return; + + DWARFUnit *dwo_cu = dwo_symbol_file->GetCompileUnit(); + if (!dwo_cu) + return; // Can't fetch the compile unit from the dwo file. + + DWARFDIE dwo_cu_die = dwo_cu->GetUnitDIEOnly(); + if (!dwo_cu_die.IsValid()) + return; // Can't fetch the compile unit DIE from the dwo file. + + uint64_t main_dwo_id = + cu_die.GetAttributeValueAsUnsigned(m_dwarf, this, DW_AT_GNU_dwo_id, 0); + uint64_t sub_dwo_id = + dwo_cu_die.GetAttributeValueAsUnsigned(DW_AT_GNU_dwo_id, 0); + if (main_dwo_id != sub_dwo_id) + return; // The 2 dwo ID isn't match. Don't use the dwo file as it belongs to + // a differectn compilation. + + m_dwo_symbol_file = std::move(dwo_symbol_file); + + dw_addr_t addr_base = + cu_die.GetAttributeValueAsUnsigned(m_dwarf, this, DW_AT_GNU_addr_base, 0); + dw_addr_t ranges_base = cu_die.GetAttributeValueAsUnsigned( + m_dwarf, this, DW_AT_GNU_ranges_base, 0); + dwo_cu->SetAddrBase(addr_base, ranges_base, m_offset); } DWARFDIE DWARFUnit::LookupAddress(const dw_addr_t address) { - return Data().LookupAddress(address); + if (DIE()) { + const DWARFDebugAranges &func_aranges = GetFunctionAranges(); + + // Re-check the aranges auto pointer contents in case it was created above + if (!func_aranges.IsEmpty()) + return GetDIE(func_aranges.FindAddress(address)); + } + return DWARFDIE(); } size_t DWARFUnit::AppendDIEsWithTag(const dw_tag_t tag, DWARFDIECollection &dies, uint32_t depth) const { - return Data().AppendDIEsWithTag(tag, dies, depth); -} + size_t old_size = dies.Size(); + DWARFDebugInfoEntry::const_iterator pos; + DWARFDebugInfoEntry::const_iterator end = m_die_array.end(); + for (pos = m_die_array.begin(); pos != end; ++pos) { + if (pos->Tag() == tag) + dies.Append(DWARFDIE(this, &(*pos))); + } -bool DWARFUnit::Verify(Stream *s) const { - return Data().Verify(s); + // Return the number of DIEs added to the collection + return dies.Size() - old_size; } -void DWARFUnit::Dump(Stream *s) const { - Data().Dump(s); -} lldb::user_id_t DWARFUnit::GetID() const { - return Data().GetID(); + dw_offset_t local_id = + m_base_obj_offset != DW_INVALID_OFFSET ? m_base_obj_offset : m_offset; + if (m_dwarf) + return DIERef(local_id, local_id).GetUID(m_dwarf); + else + return local_id; } uint32_t DWARFUnit::Size() const { return IsDWARF64() ? 23 : 11; } @@ -64,46 +278,162 @@ size_t DWARFUnit::GetDebugInfoSize() const { return (IsDWARF64() ? 12 : 4) + GetLength() - Size(); } -uint32_t DWARFUnit::GetLength() const { return Data().m_length; } -uint16_t DWARFUnit::GetVersion() const { return Data().m_version; } +uint32_t DWARFUnit::GetLength() const { return m_length; } +uint16_t DWARFUnit::GetVersion() const { return m_version; } const DWARFAbbreviationDeclarationSet *DWARFUnit::GetAbbreviations() const { - return Data().m_abbrevs; + return m_abbrevs; } dw_offset_t DWARFUnit::GetAbbrevOffset() const { - return Data().GetAbbrevOffset(); + return m_abbrevs ? m_abbrevs->GetOffset() : DW_INVALID_OFFSET; } -uint8_t DWARFUnit::GetAddressByteSize() const { return Data().m_addr_size; } +uint8_t DWARFUnit::GetAddressByteSize() const { return m_addr_size; } -dw_addr_t DWARFUnit::GetBaseAddress() const { return Data().m_base_addr; } +dw_addr_t DWARFUnit::GetBaseAddress() const { return m_base_addr; } -dw_addr_t DWARFUnit::GetAddrBase() const { return Data().m_addr_base; } +dw_addr_t DWARFUnit::GetAddrBase() const { return m_addr_base; } -dw_addr_t DWARFUnit::GetRangesBase() const { return Data().m_ranges_base; } +dw_addr_t DWARFUnit::GetRangesBase() const { return m_ranges_base; } void DWARFUnit::SetAddrBase(dw_addr_t addr_base, dw_addr_t ranges_base, dw_offset_t base_obj_offset) { - Data().SetAddrBase(addr_base, ranges_base, base_obj_offset); + m_addr_base = addr_base; + m_ranges_base = ranges_base; + m_base_obj_offset = base_obj_offset; } void DWARFUnit::ClearDIEs(bool keep_compile_unit_die) { - Data().ClearDIEs(keep_compile_unit_die); + if (m_die_array.size() > 1) { + // std::vectors never get any smaller when resized to a smaller size, + // or when clear() or erase() are called, the size will report that it + // is smaller, but the memory allocated remains intact (call capacity() + // to see this). So we need to create a temporary vector and swap the + // contents which will cause just the internal pointers to be swapped + // so that when "tmp_array" goes out of scope, it will destroy the + // contents. + + // Save at least the compile unit DIE + DWARFDebugInfoEntry::collection tmp_array; + m_die_array.swap(tmp_array); + if (keep_compile_unit_die) + m_die_array.push_back(tmp_array.front()); + } + + if (m_dwo_symbol_file) + m_dwo_symbol_file->GetCompileUnit()->ClearDIEs(keep_compile_unit_die); } -void DWARFUnit::BuildAddressRangeTable(SymbolFileDWARF *dwarf2Data, +void DWARFUnit::BuildAddressRangeTable(SymbolFileDWARF *dwarf, DWARFDebugAranges *debug_aranges) { - Data().BuildAddressRangeTable(dwarf2Data, debug_aranges); + // This function is usually called if there in no .debug_aranges section + // in order to produce a compile unit level set of address ranges that + // is accurate. + + size_t num_debug_aranges = debug_aranges->GetNumRanges(); + + // First get the compile unit DIE only and check if it has a DW_AT_ranges + const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly(); + + const dw_offset_t cu_offset = GetOffset(); + if (die) { + DWARFRangeList ranges; + const size_t num_ranges = + die->GetAttributeAddressRanges(dwarf, this, ranges, false); + if (num_ranges > 0) { + // This compile unit has DW_AT_ranges, assume this is correct if it + // is present since clang no longer makes .debug_aranges by default + // and it emits DW_AT_ranges for DW_TAG_compile_units. GCC also does + // this with recent GCC builds. + for (size_t i = 0; i < num_ranges; ++i) { + const DWARFRangeList::Entry &range = ranges.GetEntryRef(i); + debug_aranges->AppendRange(cu_offset, range.GetRangeBase(), + range.GetRangeEnd()); + } + + return; // We got all of our ranges from the DW_AT_ranges attribute + } + } + // We don't have a DW_AT_ranges attribute, so we need to parse the DWARF + + // If the DIEs weren't parsed, then we don't want all dies for all compile + // units + // to stay loaded when they weren't needed. So we can end up parsing the DWARF + // and then throwing them all away to keep memory usage down. + const bool clear_dies = ExtractDIEsIfNeeded(false) > 1; + + die = DIEPtr(); + if (die) + die->BuildAddressRangeTable(dwarf, this, debug_aranges); + + if (debug_aranges->GetNumRanges() == num_debug_aranges) { + // We got nothing from the functions, maybe we have a line tables only + // situation. Check the line tables and build the arange table from this. + SymbolContext sc; + sc.comp_unit = dwarf->GetCompUnitForDWARFCompUnit(this); + if (sc.comp_unit) { + SymbolFileDWARFDebugMap *debug_map_sym_file = + m_dwarf->GetDebugMapSymfile(); + if (debug_map_sym_file == NULL) { + LineTable *line_table = sc.comp_unit->GetLineTable(); + + if (line_table) { + LineTable::FileAddressRanges file_ranges; + const bool append = true; + const size_t num_ranges = + line_table->GetContiguousFileAddressRanges(file_ranges, append); + for (uint32_t idx = 0; idx < num_ranges; ++idx) { + const LineTable::FileAddressRanges::Entry &range = + file_ranges.GetEntryRef(idx); + debug_aranges->AppendRange(cu_offset, range.GetRangeBase(), + range.GetRangeEnd()); + } + } + } else + debug_map_sym_file->AddOSOARanges(dwarf, debug_aranges); + } + } + + if (debug_aranges->GetNumRanges() == num_debug_aranges) { + // We got nothing from the functions, maybe we have a line tables only + // situation. Check the line tables and build the arange table from this. + SymbolContext sc; + sc.comp_unit = dwarf->GetCompUnitForDWARFCompUnit(this); + if (sc.comp_unit) { + LineTable *line_table = sc.comp_unit->GetLineTable(); + + if (line_table) { + LineTable::FileAddressRanges file_ranges; + const bool append = true; + const size_t num_ranges = + line_table->GetContiguousFileAddressRanges(file_ranges, append); + for (uint32_t idx = 0; idx < num_ranges; ++idx) { + const LineTable::FileAddressRanges::Entry &range = + file_ranges.GetEntryRef(idx); + debug_aranges->AppendRange(GetOffset(), range.GetRangeBase(), + range.GetRangeEnd()); + } + } + } + } + + // Keep memory down by clearing DIEs if this generate function + // caused them to be parsed + if (clear_dies) + ClearDIEs(true); } lldb::ByteOrder DWARFUnit::GetByteOrder() const { - return Data().m_dwarf2Data->GetObjectFile()->GetByteOrder(); + return m_dwarf->GetObjectFile()->GetByteOrder(); } TypeSystem *DWARFUnit::GetTypeSystem() { - return Data().GetTypeSystem(); + if (m_dwarf) + return m_dwarf->GetTypeSystemForLanguage(GetLanguageType()); + else + return nullptr; } DWARFFormValue::FixedFormSizes DWARFUnit::GetFixedFormSizes() { @@ -111,19 +441,9 @@ DWARFFormValue::FixedFormSizes DWARFUnit::GetFixedFormSizes() { IsDWARF64()); } -void DWARFUnit::SetBaseAddress(dw_addr_t base_addr) { - Data().m_base_addr = base_addr; -} +void DWARFUnit::SetBaseAddress(dw_addr_t base_addr) { m_base_addr = base_addr; } -DWARFDIE DWARFUnit::GetCompileUnitDIEOnly() { - return Data().GetCompileUnitDIEOnly(); -} - -DWARFDIE DWARFUnit::DIE() { - return Data().DIE(); -} - -bool DWARFUnit::HasDIEsParsed() const { return Data().m_die_array.size() > 1; } +bool DWARFUnit::HasDIEsParsed() const { return m_die_array.size() > 1; } //---------------------------------------------------------------------- // Compare function DWARFDebugAranges::Range structures @@ -149,9 +469,9 @@ DWARFUnit::GetDIE(dw_offset_t die_offset) { if (ContainsDIEOffset(die_offset)) { ExtractDIEsIfNeeded(false); - DWARFDebugInfoEntry::iterator end = Data().m_die_array.end(); - DWARFDebugInfoEntry::iterator pos = lower_bound( - Data().m_die_array.begin(), end, die_offset, CompareDIEOffset); + DWARFDebugInfoEntry::iterator end = m_die_array.end(); + DWARFDebugInfoEntry::iterator pos = + lower_bound(m_die_array.begin(), end, die_offset, CompareDIEOffset); if (pos != end) { if (die_offset == (*pos).GetOffset()) return DWARFDIE(this, &(*pos)); @@ -160,18 +480,16 @@ DWARFUnit::GetDIE(dw_offset_t die_offset) { // Don't specify the compile unit offset as we don't know it because the // DIE belongs to // a different compile unit in the same symbol file. - return Data().m_dwarf2Data->DebugInfo()->GetDIEForDIEOffset(die_offset); + return m_dwarf->DebugInfo()->GetDIEForDIEOffset(die_offset); } } return DWARFDIE(); // Not found } -static uint8_t g_default_addr_size = 4; - uint8_t DWARFUnit::GetAddressByteSize(const DWARFUnit *cu) { if (cu) return cu->GetAddressByteSize(); - return DWARFCompileUnit::GetDefaultAddressSize(); + return DWARFUnit::GetDefaultAddressSize(); } bool DWARFUnit::IsDWARF64(const DWARFUnit *cu) { @@ -180,18 +498,14 @@ bool DWARFUnit::IsDWARF64(const DWARFUnit *cu) { return false; } -uint8_t DWARFUnit::GetDefaultAddressSize() { - return g_default_addr_size; -} +uint8_t DWARFUnit::GetDefaultAddressSize() { return 4; } -void DWARFUnit::SetDefaultAddressSize(uint8_t addr_size) { - g_default_addr_size = addr_size; -} - -void *DWARFUnit::GetUserData() const { return Data().m_user_data; } +void *DWARFUnit::GetUserData() const { return m_user_data; } void DWARFUnit::SetUserData(void *d) { - Data().SetUserData(d); + m_user_data = d; + if (m_dwo_symbol_file) + m_dwo_symbol_file->GetCompileUnit()->SetUserData(d); } bool DWARFUnit::Supports_DW_AT_APPLE_objc_complete_type() { @@ -219,26 +533,74 @@ bool DWARFUnit::Supports_unnamed_objc_bitfields() { // info } -SymbolFileDWARF *DWARFUnit::GetSymbolFileDWARF() const { - return Data().m_dwarf2Data; +SymbolFileDWARF *DWARFUnit::GetSymbolFileDWARF() const { return m_dwarf; } + +void DWARFUnit::ParseProducerInfo() { + m_producer_version_major = UINT32_MAX; + m_producer_version_minor = UINT32_MAX; + m_producer_version_update = UINT32_MAX; + + const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly(); + if (die) { + + const char *producer_cstr = + die->GetAttributeValueAsString(m_dwarf, this, DW_AT_producer, NULL); + if (producer_cstr) { + RegularExpression llvm_gcc_regex( + llvm::StringRef("^4\\.[012]\\.[01] \\(Based on Apple " + "Inc\\. build [0-9]+\\) \\(LLVM build " + "[\\.0-9]+\\)$")); + if (llvm_gcc_regex.Execute(llvm::StringRef(producer_cstr))) { + m_producer = eProducerLLVMGCC; + } else if (strstr(producer_cstr, "clang")) { + static RegularExpression g_clang_version_regex( + llvm::StringRef("clang-([0-9]+)\\.([0-9]+)\\.([0-9]+)")); + RegularExpression::Match regex_match(3); + if (g_clang_version_regex.Execute(llvm::StringRef(producer_cstr), + ®ex_match)) { + std::string str; + if (regex_match.GetMatchAtIndex(producer_cstr, 1, str)) + m_producer_version_major = + StringConvert::ToUInt32(str.c_str(), UINT32_MAX, 10); + if (regex_match.GetMatchAtIndex(producer_cstr, 2, str)) + m_producer_version_minor = + StringConvert::ToUInt32(str.c_str(), UINT32_MAX, 10); + if (regex_match.GetMatchAtIndex(producer_cstr, 3, str)) + m_producer_version_update = + StringConvert::ToUInt32(str.c_str(), UINT32_MAX, 10); + } + m_producer = eProducerClang; + } else if (strstr(producer_cstr, "GNU")) + m_producer = eProducerGCC; + } + } + if (m_producer == eProducerInvalid) + m_producer = eProcucerOther; } DWARFProducer DWARFUnit::GetProducer() { - return Data().GetProducer(); + if (m_producer == eProducerInvalid) + ParseProducerInfo(); + return m_producer; } uint32_t DWARFUnit::GetProducerVersionMajor() { - return Data().GetProducerVersionMajor(); + if (m_producer_version_major == 0) + ParseProducerInfo(); + return m_producer_version_major; } uint32_t DWARFUnit::GetProducerVersionMinor() { - return Data().GetProducerVersionMinor(); + if (m_producer_version_minor == 0) + ParseProducerInfo(); + return m_producer_version_minor; } uint32_t DWARFUnit::GetProducerVersionUpdate() { - return Data().GetProducerVersionUpdate(); + if (m_producer_version_update == 0) + ParseProducerInfo(); + return m_producer_version_update; } - LanguageType DWARFUnit::LanguageTypeFromDWARF(uint64_t val) { // Note: user languages between lo_user and hi_user // must be handled explicitly here. @@ -253,47 +615,51 @@ LanguageType DWARFUnit::LanguageTypeFromDWARF(uint64_t val) { } LanguageType DWARFUnit::GetLanguageType() { - return Data().GetLanguageType(); + if (m_language_type != eLanguageTypeUnknown) + return m_language_type; + + const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly(); + if (die) + m_language_type = LanguageTypeFromDWARF( + die->GetAttributeValueAsUnsigned(m_dwarf, this, DW_AT_language, 0)); + return m_language_type; } -bool DWARFUnit::IsDWARF64() const { return Data().m_is_dwarf64; } +bool DWARFUnit::IsDWARF64() const { return m_is_dwarf64; } bool DWARFUnit::GetIsOptimized() { - return Data().GetIsOptimized(); + if (m_is_optimized == eLazyBoolCalculate) { + const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly(); + if (die) { + m_is_optimized = eLazyBoolNo; + if (die->GetAttributeValueAsUnsigned(m_dwarf, this, DW_AT_APPLE_optimized, + 0) == 1) { + m_is_optimized = eLazyBoolYes; + } + } + } + return m_is_optimized == eLazyBoolYes; } SymbolFileDWARFDwo *DWARFUnit::GetDwoSymbolFile() const { - return Data().m_dwo_symbol_file.get(); -} - -dw_offset_t DWARFUnit::GetBaseObjOffset() const { - return Data().m_base_obj_offset; -} - -const DWARFDebugInfoEntry *DWARFUnit::GetCompileUnitDIEPtrOnly() { - return Data().GetCompileUnitDIEPtrOnly(); + return m_dwo_symbol_file.get(); } -const DWARFDebugInfoEntry *DWARFUnit::DIEPtr() { - return Data().DIEPtr(); -} +dw_offset_t DWARFUnit::GetBaseObjOffset() const { return m_base_obj_offset; } -void DWARFUnit::Index(NameToDIE &func_basenames, - NameToDIE &func_fullnames, NameToDIE &func_methods, - NameToDIE &func_selectors, - NameToDIE &objc_class_selectors, - NameToDIE &globals, NameToDIE &types, - NameToDIE &namespaces) { - assert(!Data().m_dwarf2Data->GetBaseCompileUnit() && +void DWARFUnit::Index(NameToDIE &func_basenames, NameToDIE &func_fullnames, + NameToDIE &func_methods, NameToDIE &func_selectors, + NameToDIE &objc_class_selectors, NameToDIE &globals, + NameToDIE &types, NameToDIE &namespaces) { + assert(!m_dwarf->GetBaseCompileUnit() && "DWARFUnit associated with .dwo or .dwp " "should not be indexed directly"); Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS)); if (log) { - Data().m_dwarf2Data->GetObjectFile()->GetModule()->LogMessage( - log, - "DWARFUnit::Index() for compile unit at .debug_info[0x%8.8x]", + m_dwarf->GetObjectFile()->GetModule()->LogMessage( + log, "DWARFUnit::Index() for compile unit at .debug_info[0x%8.8x]", GetOffset()); } @@ -323,9 +689,8 @@ void DWARFUnit::IndexPrivate( NameToDIE &func_selectors, NameToDIE &objc_class_selectors, NameToDIE &globals, NameToDIE &types, NameToDIE &namespaces) { DWARFDebugInfoEntry::const_iterator pos; - DWARFDebugInfoEntry::const_iterator begin = - dwarf_cu->Data().m_die_array.begin(); - DWARFDebugInfoEntry::const_iterator end = dwarf_cu->Data().m_die_array.end(); + DWARFDebugInfoEntry::const_iterator begin = dwarf_cu->m_die_array.begin(); + DWARFDebugInfoEntry::const_iterator end = dwarf_cu->m_die_array.end(); for (pos = begin; pos != end; ++pos) { const DWARFDebugInfoEntry &die = *pos; @@ -413,37 +778,25 @@ void DWARFUnit::IndexPrivate( case DW_TAG_lexical_block: case DW_TAG_inlined_subroutine: // Even if this is a function level static, we don't add it. We - // could theoretically - // add these if we wanted to by introspecting into the - // DW_AT_location and seeing - // if the location describes a hard coded address, but we dont - // want the performance - // penalty of that right now. + // could theoretically add these if we wanted to by + // introspecting into the DW_AT_location and seeing if the + // location describes a hard coded address, but we don't want + // the performance penalty of that right now. is_global_or_static_variable = false; - // if - // (attributes.ExtractFormValueAtIndex(dwarf2Data, - // i, form_value)) - // { - // // If we have valid block - // data, then we have location - // expression bytes - // // that are fixed (not a - // location list). - // const uint8_t *block_data = - // form_value.BlockData(); - // if (block_data) - // { - // uint32_t block_length = - // form_value.Unsigned(); - // if (block_length == 1 + - // attributes.CompileUnitAtIndex(i)->GetAddressByteSize()) - // { - // if (block_data[0] == - // DW_OP_addr) - // add_die = true; - // } - // } - // } + // if (attributes.ExtractFormValueAtIndex(dwarf, i, + // form_value)) { + // // If we have valid block data, then we have location + // // expression bytesthat are fixed (not a location list). + // const uint8_t *block_data = form_value.BlockData(); + // if (block_data) { + // uint32_t block_length = form_value.Unsigned(); + // if (block_length == 1 + + // attributes.CompileUnitAtIndex(i)->GetAddressByteSize()) { + // if (block_data[0] == DW_OP_addr) + // add_die = true; + // } + // } + // } parent_die = NULL; // Terminate the while loop. break; @@ -628,3 +981,34 @@ void DWARFUnit::IndexPrivate( } } } + +const DWARFDebugAranges &DWARFUnit::GetFunctionAranges() { + if (m_func_aranges_ap.get() == NULL) { + m_func_aranges_ap.reset(new DWARFDebugAranges()); + Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_ARANGES)); + + if (log) { + m_dwarf->GetObjectFile()->GetModule()->LogMessage( + log, + "DWARFUnit::GetFunctionAranges() for compile unit at " + ".debug_info[0x%8.8x]", + GetOffset()); + } + const DWARFDebugInfoEntry *die = DIEPtr(); + if (die) + die->BuildFunctionAddressRangeTable(m_dwarf, this, + m_func_aranges_ap.get()); + + if (m_dwo_symbol_file) { + DWARFUnit *dwo_cu = m_dwo_symbol_file->GetCompileUnit(); + const DWARFDebugInfoEntry *dwo_die = dwo_cu->DIEPtr(); + if (dwo_die) + dwo_die->BuildFunctionAddressRangeTable(m_dwo_symbol_file.get(), dwo_cu, + m_func_aranges_ap.get()); + } + + const bool minimize = false; + m_func_aranges_ap->Sort(minimize); + } + return *m_func_aranges_ap.get(); +} diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h index feeb785..9be0f42 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h @@ -42,7 +42,7 @@ public: DWARFDIECollection &matching_dies, uint32_t depth = UINT32_MAX) const; bool Verify(lldb_private::Stream *s) const; - void Dump(lldb_private::Stream *s) const; + virtual void Dump(lldb_private::Stream *s) const = 0; // Offset of the initial length field. dw_offset_t GetOffset() const { return m_offset; } lldb::user_id_t GetID() const; @@ -65,24 +65,25 @@ public: dw_addr_t GetBaseAddress() const; dw_addr_t GetAddrBase() const; dw_addr_t GetRangesBase() const; - void SetAddrBase(dw_addr_t addr_base, dw_addr_t ranges_base, dw_offset_t base_obj_offset); + void SetAddrBase(dw_addr_t addr_base, dw_addr_t ranges_base, + dw_offset_t base_obj_offset); void ClearDIEs(bool keep_compile_unit_die); - void BuildAddressRangeTable(SymbolFileDWARF *dwarf2Data, + void BuildAddressRangeTable(SymbolFileDWARF *dwarf, DWARFDebugAranges *debug_aranges); lldb::ByteOrder GetByteOrder() const; lldb_private::TypeSystem *GetTypeSystem(); + const DWARFDebugAranges &GetFunctionAranges(); + DWARFFormValue::FixedFormSizes GetFixedFormSizes(); void SetBaseAddress(dw_addr_t base_addr); - DWARFDIE - GetCompileUnitDIEOnly(); + DWARFDIE GetUnitDIEOnly() { return DWARFDIE(this, GetUnitDIEPtrOnly()); } - DWARFDIE - DIE(); + DWARFDIE DIE() { return DWARFDIE(this, DIEPtr()); } bool HasDIEsParsed() const; @@ -94,8 +95,6 @@ public: static uint8_t GetDefaultAddressSize(); - static void SetDefaultAddressSize(uint8_t addr_size); - void *GetUserData() const; void SetUserData(void *d); @@ -134,10 +133,33 @@ public: dw_offset_t GetBaseObjOffset() const; protected: - virtual DWARFCompileUnit &Data() = 0; - virtual const DWARFCompileUnit &Data() const = 0; - - DWARFUnit(); + DWARFUnit(SymbolFileDWARF *dwarf); + + SymbolFileDWARF *m_dwarf = nullptr; + std::unique_ptr m_dwo_symbol_file; + const DWARFAbbreviationDeclarationSet *m_abbrevs = nullptr; + void *m_user_data = nullptr; + // The compile unit debug information entry item + DWARFDebugInfoEntry::collection m_die_array; + // A table similar to the .debug_aranges table, but this one points to the + // exact DW_TAG_subprogram DIEs + std::unique_ptr m_func_aranges_ap; + dw_addr_t m_base_addr = 0; + dw_offset_t m_length = 0; + uint16_t m_version = 0; + uint8_t m_addr_size = 0; + DWARFProducer m_producer = eProducerInvalid; + uint32_t m_producer_version_major = 0; + uint32_t m_producer_version_minor = 0; + uint32_t m_producer_version_update = 0; + lldb::LanguageType m_language_type = lldb::eLanguageTypeUnknown; + bool m_is_dwarf64 = false; + lldb_private::LazyBool m_is_optimized = lldb_private::eLazyBoolCalculate; + dw_addr_t m_addr_base = 0; // Value of DW_AT_addr_base + dw_addr_t m_ranges_base = 0; // Value of DW_AT_ranges_base + // If this is a dwo compile unit this is the offset of the base compile unit + // in the main object file + dw_offset_t m_base_obj_offset = DW_INVALID_OFFSET; static void IndexPrivate(DWARFUnit *dwarf_cu, const lldb::LanguageType cu_language, @@ -151,9 +173,26 @@ protected: dw_offset_t m_offset; private: - const DWARFDebugInfoEntry *GetCompileUnitDIEPtrOnly(); + void ParseProducerInfo(); + + // Get the DWARF unit DWARF debug informration entry. Parse the single DIE + // if needed. + const DWARFDebugInfoEntry *GetUnitDIEPtrOnly() { + ExtractDIEsIfNeeded(true); + if (m_die_array.empty()) + return NULL; + return &m_die_array[0]; + } + + // Get all DWARF debug informration entries. Parse all DIEs if needed. + const DWARFDebugInfoEntry *DIEPtr() { + ExtractDIEsIfNeeded(false); + if (m_die_array.empty()) + return NULL; + return &m_die_array[0]; + } - const DWARFDebugInfoEntry *DIEPtr(); + void AddUnitDIE(DWARFDebugInfoEntry &die); DISALLOW_COPY_AND_ASSIGN(DWARFUnit); }; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 077f06c..422a007 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -772,7 +772,7 @@ lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFUnit *dwarf_cu, } else { ModuleSP module_sp(m_obj_file->GetModule()); if (module_sp) { - const DWARFDIE cu_die = dwarf_cu->GetCompileUnitDIEOnly(); + const DWARFDIE cu_die = dwarf_cu->GetUnitDIEOnly(); if (cu_die) { FileSpec cu_file_spec{cu_die.GetName(), false}; if (cu_file_spec) { @@ -909,7 +909,7 @@ bool SymbolFileDWARF::ParseCompileUnitSupportFiles( assert(sc.comp_unit); DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); if (dwarf_cu) { - const DWARFDIE cu_die = dwarf_cu->GetCompileUnitDIEOnly(); + const DWARFDIE cu_die = dwarf_cu->GetUnitDIEOnly(); if (cu_die) { const char *cu_comp_dir = resolveCompDir( @@ -948,7 +948,7 @@ bool SymbolFileDWARF::ParseImportedModules( UpdateExternalModuleListIfNeeded(); if (sc.comp_unit) { - const DWARFDIE die = dwarf_cu->GetCompileUnitDIEOnly(); + const DWARFDIE die = dwarf_cu->GetUnitDIEOnly(); if (die) { for (DWARFDIE child_die = die.GetFirstChild(); child_die; @@ -1024,7 +1024,7 @@ bool SymbolFileDWARF::ParseCompileUnitLineTable(const SymbolContext &sc) { DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); if (dwarf_cu) { - const DWARFDIE dwarf_cu_die = dwarf_cu->GetCompileUnitDIEOnly(); + const DWARFDIE dwarf_cu_die = dwarf_cu->GetUnitDIEOnly(); if (dwarf_cu_die) { const dw_offset_t cu_line_offset = dwarf_cu_die.GetAttributeValueAsUnsigned(DW_AT_stmt_list, @@ -1109,7 +1109,7 @@ bool SymbolFileDWARF::ParseCompileUnitDebugMacros(const SymbolContext &sc) { if (dwarf_cu == nullptr) return false; - const DWARFDIE dwarf_cu_die = dwarf_cu->GetCompileUnitDIEOnly(); + const DWARFDIE dwarf_cu_die = dwarf_cu->GetUnitDIEOnly(); if (!dwarf_cu_die) return false; @@ -1620,7 +1620,7 @@ void SymbolFileDWARF::UpdateExternalModuleListIfNeeded() { for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) { DWARFUnit *dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx); - const DWARFDIE die = dwarf_cu->GetCompileUnitDIEOnly(); + const DWARFDIE die = dwarf_cu->GetUnitDIEOnly(); if (die && die.HasChildren() == false) { const char *name = die.GetAttributeValueAsString(DW_AT_name, nullptr); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index 49501aa..148facd 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -71,7 +71,7 @@ public: friend class SymbolFileDWARFDwo; friend class DebugMapModule; friend struct DIERef; - friend class DWARFCompileUnit; + friend class DWARFUnit; friend class DWARFDIE; friend class DWARFASTParserClang; friend class DWARFASTParserGo; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h index dcca426..04599eb 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h @@ -136,7 +136,7 @@ protected: friend class DebugMapModule; friend struct DIERef; friend class DWARFASTParserClang; - friend class DWARFCompileUnit; + friend class DWARFUnit; friend class SymbolFileDWARF; struct OSOInfo { lldb::ModuleSP module_sp; -- 2.7.4