[DWARF parser] Refactor fetching DIE address ranges.

Add a helper method to get address ranges specified in a DIE
(either by DW_AT_low_pc/DW_AT_high_pc, or by DW_AT_ranges). Use it
to untangle and simplify the code.

No functionality change.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@206624 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Alexey Samsonov
2014-04-18 17:25:46 +00:00
parent 54850bedf2
commit fe030f3dcd
7 changed files with 72 additions and 64 deletions

View File

@ -58,8 +58,13 @@ void DWARFDebugAranges::generate(DWARFContext *CTX) {
// manually build aranges for the rest of them. // manually build aranges for the rest of them.
for (const auto &CU : CTX->compile_units()) { for (const auto &CU : CTX->compile_units()) {
uint32_t CUOffset = CU->getOffset(); uint32_t CUOffset = CU->getOffset();
if (ParsedCUOffsets.insert(CUOffset).second) if (ParsedCUOffsets.insert(CUOffset).second) {
CU->buildAddressRangeTable(this, true, CUOffset); DWARFAddressRangesVector CURanges;
CU->collectAddressRanges(CURanges);
for (const auto &R : CURanges) {
appendRange(CUOffset, R.first, R.second);
}
}
} }
sortAndMinimize(); sortAndMinimize();

View File

@ -226,39 +226,47 @@ bool DWARFDebugInfoEntryMinimal::getLowAndHighPC(const DWARFUnit *U,
return (HighPC != -1ULL); return (HighPC != -1ULL);
} }
void DWARFDebugInfoEntryMinimal::buildAddressRangeTable( DWARFAddressRangesVector
const DWARFUnit *U, DWARFDebugAranges *DebugAranges, DWARFDebugInfoEntryMinimal::getAddressRanges(const DWARFUnit *U) const {
uint32_t UOffsetInAranges) const {
if (AbbrevDecl) {
if (isSubprogramDIE()) {
uint64_t LowPC, HighPC;
if (getLowAndHighPC(U, LowPC, HighPC))
DebugAranges->appendRange(UOffsetInAranges, LowPC, HighPC);
// FIXME: try to append ranges from .debug_ranges section.
}
const DWARFDebugInfoEntryMinimal *Child = getFirstChild();
while (Child) {
Child->buildAddressRangeTable(U, DebugAranges, UOffsetInAranges);
Child = Child->getSibling();
}
}
}
bool DWARFDebugInfoEntryMinimal::addressRangeContainsAddress(
const DWARFUnit *U, const uint64_t Address) const {
if (isNULL()) if (isNULL())
return false; return DWARFAddressRangesVector{};
// Single range specified by low/high PC.
uint64_t LowPC, HighPC; uint64_t LowPC, HighPC;
if (getLowAndHighPC(U, LowPC, HighPC)) if (getLowAndHighPC(U, LowPC, HighPC)) {
return (LowPC <= Address && Address <= HighPC); return DWARFAddressRangesVector{std::make_pair(LowPC, HighPC)};
// Try to get address ranges from .debug_ranges section. }
// Multiple ranges from .debug_ranges section.
uint32_t RangesOffset = uint32_t RangesOffset =
getAttributeValueAsSectionOffset(U, DW_AT_ranges, -1U); getAttributeValueAsSectionOffset(U, DW_AT_ranges, -1U);
if (RangesOffset != -1U) { if (RangesOffset != -1U) {
DWARFDebugRangeList RangeList; DWARFDebugRangeList RangeList;
if (U->extractRangeList(RangesOffset, RangeList)) if (U->extractRangeList(RangesOffset, RangeList))
return RangeList.containsAddress(U->getBaseAddress(), Address); return RangeList.getAbsoluteRanges(U->getBaseAddress());
}
return DWARFAddressRangesVector{};
}
void DWARFDebugInfoEntryMinimal::collectChildrenAddressRanges(
const DWARFUnit *U, DWARFAddressRangesVector& Ranges) const {
if (isNULL())
return;
if (isSubprogramDIE()) {
const auto &DIERanges = getAddressRanges(U);
Ranges.insert(Ranges.end(), DIERanges.begin(), DIERanges.end());
}
const DWARFDebugInfoEntryMinimal *Child = getFirstChild();
while (Child) {
Child->collectChildrenAddressRanges(U, Ranges);
Child = Child->getSibling();
}
}
bool DWARFDebugInfoEntryMinimal::addressRangeContainsAddress(
const DWARFUnit *U, const uint64_t Address) const {
for (const auto& R : getAddressRanges(U)) {
if (R.first <= Address && Address < R.second)
return true;
} }
return false; return false;
} }

View File

@ -11,6 +11,7 @@
#define LLVM_DEBUGINFO_DWARFDEBUGINFOENTRY_H #define LLVM_DEBUGINFO_DWARFDEBUGINFOENTRY_H
#include "DWARFAbbreviationDeclaration.h" #include "DWARFAbbreviationDeclaration.h"
#include "DWARFDebugRangeList.h"
#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallVector.h"
#include "llvm/Support/DataTypes.h" #include "llvm/Support/DataTypes.h"
@ -135,9 +136,10 @@ public:
bool getLowAndHighPC(const DWARFUnit *U, uint64_t &LowPC, bool getLowAndHighPC(const DWARFUnit *U, uint64_t &LowPC,
uint64_t &HighPC) const; uint64_t &HighPC) const;
void buildAddressRangeTable(const DWARFUnit *U, DWARFAddressRangesVector getAddressRanges(const DWARFUnit *U) const;
DWARFDebugAranges *DebugAranges,
uint32_t CUOffsetInAranges) const; void collectChildrenAddressRanges(const DWARFUnit *U,
DWARFAddressRangesVector &Ranges) const;
bool addressRangeContainsAddress(const DWARFUnit *U, bool addressRangeContainsAddress(const DWARFUnit *U,
const uint64_t Address) const; const uint64_t Address) const;

View File

@ -54,13 +54,16 @@ void DWARFDebugRangeList::dump(raw_ostream &OS) const {
OS << format("%08x <End of list>\n", Offset); OS << format("%08x <End of list>\n", Offset);
} }
bool DWARFDebugRangeList::containsAddress(uint64_t BaseAddress, DWARFAddressRangesVector
uint64_t Address) const { DWARFDebugRangeList::getAbsoluteRanges(uint64_t BaseAddress) const {
DWARFAddressRangesVector Res;
for (const RangeListEntry &RLE : Entries) { for (const RangeListEntry &RLE : Entries) {
if (RLE.isBaseAddressSelectionEntry(AddressSize)) if (RLE.isBaseAddressSelectionEntry(AddressSize)) {
BaseAddress = RLE.EndAddress; BaseAddress = RLE.EndAddress;
else if (RLE.containsAddress(BaseAddress, Address)) } else {
return true; Res.push_back(std::make_pair(BaseAddress + RLE.StartAddress,
BaseAddress + RLE.EndAddress));
}
} }
return false; return Res;
} }

View File

@ -17,6 +17,9 @@ namespace llvm {
class raw_ostream; class raw_ostream;
/// DWARFAddressRangesVector - represents a set of absolute address ranges.
typedef std::vector<std::pair<uint64_t, uint64_t>> DWARFAddressRangesVector;
class DWARFDebugRangeList { class DWARFDebugRangeList {
public: public:
struct RangeListEntry { struct RangeListEntry {
@ -50,10 +53,6 @@ public:
else else
return StartAddress == -1ULL; return StartAddress == -1ULL;
} }
bool containsAddress(uint64_t BaseAddress, uint64_t Address) const {
return (BaseAddress + StartAddress <= Address) &&
(Address < BaseAddress + EndAddress);
}
}; };
private: private:
@ -67,10 +66,10 @@ public:
void clear(); void clear();
void dump(raw_ostream &OS) const; void dump(raw_ostream &OS) const;
bool extract(DataExtractor data, uint32_t *offset_ptr); bool extract(DataExtractor data, uint32_t *offset_ptr);
/// containsAddress - Returns true if range list contains the given /// getAbsoluteRanges - Returns absolute address ranges defined by this range
/// address. Has to be passed base address of the compile unit that /// list. Has to be passed base address of the compile unit referencing this
/// references this range list. /// range list.
bool containsAddress(uint64_t BaseAddress, uint64_t Address) const; DWARFAddressRangesVector getAbsoluteRanges(uint64_t BaseAddress) const;
}; };
} // namespace llvm } // namespace llvm

View File

@ -298,33 +298,26 @@ void DWARFUnit::clearDIEs(bool KeepCUDie) {
} }
} }
void void DWARFUnit::collectAddressRanges(DWARFAddressRangesVector &CURanges) {
DWARFUnit::buildAddressRangeTable(DWARFDebugAranges *debug_aranges,
bool clear_dies_if_already_not_parsed,
uint32_t CUOffsetInAranges) {
// This function is usually called if there in no .debug_aranges section // 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 // 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 // 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 // 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 // up parsing the DWARF and then throwing them all away to keep memory usage
// down. // down.
const bool clear_dies = extractDIEsIfNeeded(false) > 1 && const bool ClearDIEs = extractDIEsIfNeeded(false) > 1;
clear_dies_if_already_not_parsed; DieArray[0].collectChildrenAddressRanges(this, CURanges);
DieArray[0].buildAddressRangeTable(this, debug_aranges, CUOffsetInAranges);
// Collect address ranges from DIEs in .dwo if necessary.
bool DWOCreated = parseDWO(); bool DWOCreated = parseDWO();
if (DWO.get()) { if (DWO.get())
// If there is a .dwo file for this compile unit, then skeleton CU DIE DWO->getUnit()->collectAddressRanges(CURanges);
// doesn't have children, and we should instead build address range table if (DWOCreated)
// from DIEs in the .debug_info.dwo section of .dwo file.
DWO->getUnit()->buildAddressRangeTable(
debug_aranges, clear_dies_if_already_not_parsed, CUOffsetInAranges);
}
if (DWOCreated && clear_dies_if_already_not_parsed)
DWO.reset(); DWO.reset();
// Keep memory down by clearing DIEs if this generate function // Keep memory down by clearing DIEs if this generate function
// caused them to be parsed. // caused them to be parsed.
if (clear_dies) if (ClearDIEs)
clearDIEs(true); clearDIEs(true);
} }

View File

@ -129,9 +129,7 @@ public:
const char *getCompilationDir(); const char *getCompilationDir();
uint64_t getDWOId(); uint64_t getDWOId();
void buildAddressRangeTable(DWARFDebugAranges *debug_aranges, void collectAddressRanges(DWARFAddressRangesVector &CURanges);
bool clear_dies_if_already_not_parsed,
uint32_t CUOffsetInAranges);
/// getInlinedChainForAddress - fetches inlined chain for a given address. /// getInlinedChainForAddress - fetches inlined chain for a given address.
/// Returns empty chain if there is no subprogram containing address. The /// Returns empty chain if there is no subprogram containing address. The