Index: source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h +++ source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h @@ -18,114 +18,10 @@ public: static DWARFUnitSP Extract(SymbolFileDWARF *dwarf2Data, lldb::offset_t *offset_ptr); + void Dump(lldb_private::Stream *s) const override; - 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(); - 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); }; Index: source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp +++ 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 @@ 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 @@ 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; -} Index: source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp @@ -640,7 +640,7 @@ 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 @@ 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; Index: source/Plugins/SymbolFile/DWARF/DWARFUnit.h =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFUnit.h +++ source/Plugins/SymbolFile/DWARF/DWARFUnit.h @@ -42,7 +42,7 @@ 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 @@ 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 @@ static uint8_t GetDefaultAddressSize(); - static void SetDefaultAddressSize(uint8_t addr_size); - void *GetUserData() const; void SetUserData(void *d); @@ -134,10 +133,33 @@ dw_offset_t GetBaseObjOffset() const; protected: - virtual DWARFCompileUnit &Data() = 0; - virtual const DWARFCompileUnit &Data() const = 0; + DWARFUnit(SymbolFileDWARF *dwarf); - DWARFUnit(); + 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,10 +173,27 @@ dw_offset_t m_offset; private: - const DWARFDebugInfoEntry *GetCompileUnitDIEPtrOnly(); + void ParseProducerInfo(); - const DWARFDebugInfoEntry *DIEPtr(); + // 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]; + } + + void AddUnitDIE(DWARFDebugInfoEntry &die); + DISALLOW_COPY_AND_ASSIGN(DWARFUnit); }; Index: source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ 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 @@ 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 @@ 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,20 +441,10 @@ 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(); -} +bool DWARFUnit::HasDIEsParsed() const { return m_die_array.size() > 1; } -DWARFDIE DWARFUnit::DIE() { - return Data().DIE(); -} - -bool DWARFUnit::HasDIEsParsed() const { return Data().m_die_array.size() > 1; } - //---------------------------------------------------------------------- // Compare function DWARFDebugAranges::Range structures //---------------------------------------------------------------------- @@ -149,9 +469,9 @@ 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 @@ // 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 @@ 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 m_user_data; } -void *DWARFUnit::GetUserData() const { return Data().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 @@ // 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::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(); + return m_dwo_symbol_file.get(); } -dw_offset_t DWARFUnit::GetBaseObjOffset() const { - return Data().m_base_obj_offset; -} +dw_offset_t DWARFUnit::GetBaseObjOffset() const { return m_base_obj_offset; } -const DWARFDebugInfoEntry *DWARFUnit::GetCompileUnitDIEPtrOnly() { - return Data().GetCompileUnitDIEPtrOnly(); -} - -const DWARFDebugInfoEntry *DWARFUnit::DIEPtr() { - return Data().DIEPtr(); -} - -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 @@ 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 @@ 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 @@ } } } + +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(); +} Index: source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h =================================================================== --- source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -71,7 +71,7 @@ friend class SymbolFileDWARFDwo; friend class DebugMapModule; friend struct DIERef; - friend class DWARFCompileUnit; + friend class DWARFUnit; friend class DWARFDIE; friend class DWARFASTParserClang; friend class DWARFASTParserGo; Index: source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -772,7 +772,7 @@ } 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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); Index: source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h =================================================================== --- source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h +++ source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h @@ -136,7 +136,7 @@ friend class DebugMapModule; friend struct DIERef; friend class DWARFASTParserClang; - friend class DWARFCompileUnit; + friend class DWARFUnit; friend class SymbolFileDWARF; struct OSOInfo { lldb::ModuleSP module_sp;