From 10df80692cc1594fb06fc02cae6eba177123cfd9 Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Wed, 14 Sep 2011 20:52:27 +0000 Subject: DWARF: Generate the address lookup table from the DIE tree if .debug_aranges is not available. Ported from LLDB. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@139732 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/DebugInfo/DWARFCompileUnit.cpp | 37 +++++++++++++++++++++++++++++++++++ lib/DebugInfo/DWARFCompileUnit.h | 5 +++++ lib/DebugInfo/DWARFContext.cpp | 2 ++ lib/DebugInfo/DWARFDebugAranges.cpp | 13 ++++++++++++ lib/DebugInfo/DWARFDebugAranges.h | 1 + lib/DebugInfo/DWARFDebugInfoEntry.cpp | 26 +++++++++++++++++++++++- lib/DebugInfo/DWARFDebugInfoEntry.h | 4 ++++ 7 files changed, 87 insertions(+), 1 deletion(-) diff --git a/lib/DebugInfo/DWARFCompileUnit.cpp b/lib/DebugInfo/DWARFCompileUnit.cpp index 224ae925c2..d535df05d3 100644 --- a/lib/DebugInfo/DWARFCompileUnit.cpp +++ b/lib/DebugInfo/DWARFCompileUnit.cpp @@ -200,3 +200,40 @@ size_t DWARFCompileUnit::extractDIEsIfNeeded(bool cu_die_only) { setDIERelations(); return DieArray.size(); } + +void DWARFCompileUnit::clearDIEs(bool keep_compile_unit_die) { + if (DieArray.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 + std::vector tmpArray; + DieArray.swap(tmpArray); + if (keep_compile_unit_die) + DieArray.push_back(tmpArray.front()); + } +} + +void +DWARFCompileUnit::buildAddressRangeTable(DWARFDebugAranges *debug_aranges, + bool clear_dies_if_already_not_parsed){ + // 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. 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; + + DieArray[0].buildAddressRangeTable(this, debug_aranges); + + // Keep memory down by clearing DIEs if this generate function + // caused them to be parsed. + if (clear_dies) + clearDIEs(true); +} diff --git a/lib/DebugInfo/DWARFCompileUnit.h b/lib/DebugInfo/DWARFCompileUnit.h index 0c082ad337..378b6ced8c 100644 --- a/lib/DebugInfo/DWARFCompileUnit.h +++ b/lib/DebugInfo/DWARFCompileUnit.h @@ -91,6 +91,11 @@ public: DieArray.reserve(getDebugInfoSize() / 14); DieArray.push_back(die); } + + void clearDIEs(bool keep_compile_unit_die); + + void buildAddressRangeTable(DWARFDebugAranges *debug_aranges, + bool clear_dies_if_already_not_parsed); }; } diff --git a/lib/DebugInfo/DWARFContext.cpp b/lib/DebugInfo/DWARFContext.cpp index c034bb3696..3359ae3b90 100644 --- a/lib/DebugInfo/DWARFContext.cpp +++ b/lib/DebugInfo/DWARFContext.cpp @@ -46,6 +46,8 @@ const DWARFDebugAranges *DWARFContext::getDebugAranges() { Aranges.reset(new DWARFDebugAranges()); Aranges->extract(arangesData); + if (Aranges->isEmpty()) // No aranges in file, generate them from the DIEs. + Aranges->generate(this); return Aranges.get(); } diff --git a/lib/DebugInfo/DWARFDebugAranges.cpp b/lib/DebugInfo/DWARFDebugAranges.cpp index b116f8f7d8..5053e19b71 100644 --- a/lib/DebugInfo/DWARFDebugAranges.cpp +++ b/lib/DebugInfo/DWARFDebugAranges.cpp @@ -83,6 +83,19 @@ bool DWARFDebugAranges::extract(DataExtractor debug_aranges_data) { return false; } +bool DWARFDebugAranges::generate(DWARFContext *ctx) { + clear(); + if (ctx) { + const uint32_t num_compile_units = ctx->getNumCompileUnits(); + for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) { + DWARFCompileUnit *cu = ctx->getCompileUnitAtIndex(cu_idx); + if (cu) + cu->buildAddressRangeTable(this, true); + } + } + return !isEmpty(); +} + void DWARFDebugAranges::dump(raw_ostream &OS) const { const uint32_t num_ranges = getNumRanges(); for (uint32_t i = 0; i < num_ranges; ++i) { diff --git a/lib/DebugInfo/DWARFDebugAranges.h b/lib/DebugInfo/DWARFDebugAranges.h index 8fe70e4aa4..12afb60beb 100644 --- a/lib/DebugInfo/DWARFDebugAranges.h +++ b/lib/DebugInfo/DWARFDebugAranges.h @@ -64,6 +64,7 @@ public: bool allRangesAreContiguous(uint64_t& LoPC, uint64_t& HiPC) const; bool getMaxRange(uint64_t& LoPC, uint64_t& HiPC) const; bool extract(DataExtractor debug_aranges_data); + bool generate(DWARFContext *ctx); // Use append range multiple times and then call sort void appendRange(uint32_t cu_offset, uint64_t low_pc, uint64_t high_pc); diff --git a/lib/DebugInfo/DWARFDebugInfoEntry.cpp b/lib/DebugInfo/DWARFDebugInfoEntry.cpp index 627fad5afc..0bf8b69611 100644 --- a/lib/DebugInfo/DWARFDebugInfoEntry.cpp +++ b/lib/DebugInfo/DWARFDebugInfoEntry.cpp @@ -397,7 +397,8 @@ DWARFDebugInfoEntryMinimal::getAttributeValueAsSigned( } uint64_t -DWARFDebugInfoEntryMinimal::getAttributeValueAsReference(const DWARFCompileUnit* cu, +DWARFDebugInfoEntryMinimal::getAttributeValueAsReference( + const DWARFCompileUnit* cu, const uint16_t attr, uint64_t fail_value) const { DWARFFormValue form_value; @@ -405,3 +406,26 @@ DWARFDebugInfoEntryMinimal::getAttributeValueAsReference(const DWARFCompileUnit* return form_value.getReference(cu); return fail_value; } + +void +DWARFDebugInfoEntryMinimal::buildAddressRangeTable(const DWARFCompileUnit *cu, + DWARFDebugAranges *debug_aranges) + const { + if (AbbrevDecl) { + uint16_t tag = AbbrevDecl->getTag(); + if (tag == DW_TAG_subprogram) { + uint64_t hi_pc = -1ULL; + uint64_t lo_pc = getAttributeValueAsUnsigned(cu, DW_AT_low_pc, -1ULL); + if (lo_pc != -1ULL) + hi_pc = getAttributeValueAsUnsigned(cu, DW_AT_high_pc, -1ULL); + if (hi_pc != -1ULL) + debug_aranges->appendRange(cu->getOffset(), lo_pc, hi_pc); + } + + const DWARFDebugInfoEntryMinimal *child = getFirstChild(); + while (child) { + child->buildAddressRangeTable(cu, debug_aranges); + child = child->getSibling(); + } + } +} diff --git a/lib/DebugInfo/DWARFDebugInfoEntry.h b/lib/DebugInfo/DWARFDebugInfoEntry.h index 5e7b89b5a6..aff2e85567 100644 --- a/lib/DebugInfo/DWARFDebugInfoEntry.h +++ b/lib/DebugInfo/DWARFDebugInfoEntry.h @@ -15,6 +15,7 @@ namespace llvm { +class DWARFDebugAranges; class DWARFCompileUnit; class DWARFContext; class DWARFFormValue; @@ -124,6 +125,9 @@ public: int64_t getAttributeValueAsSigned(const DWARFCompileUnit* cu, const uint16_t attr, int64_t fail_value) const; + + void buildAddressRangeTable(const DWARFCompileUnit *cu, + DWARFDebugAranges *debug_aranges) const; }; } -- cgit v1.2.3