Commit 416bc6ef authored by Matt Ma's avatar Matt Ma Committed by Facebook Github Bot

Support debug_ranges lookup when matching address for inline functions.

Summary:
Range lists are contained in a separate object file section called .debug_ranges. A range list is
indicated by a DW_AT_ranges attribute whose value is represented as an offset from the
beginning of the .debug_ranges section to the beginning of the range list.
Each entry in a range list is either:
a range list entry,
a base address selection entry, or
an end of list entry.

Reviewed By: luciang

Differential Revision: D19658819

fbshipit-source-id: ed70915465f0ac6bb8ab6f7efe415a3d8c5b04ee
parent 4c872d1c
...@@ -344,9 +344,14 @@ Dwarf::Dwarf(const ElfFile* elf) ...@@ -344,9 +344,14 @@ Dwarf::Dwarf(const ElfFile* elf)
debugAbbrev_(getSection(".debug_abbrev")), debugAbbrev_(getSection(".debug_abbrev")),
debugLine_(getSection(".debug_line")), debugLine_(getSection(".debug_line")),
debugStr_(getSection(".debug_str")), debugStr_(getSection(".debug_str")),
debugAranges_(getSection(".debug_aranges")) { debugAranges_(getSection(".debug_aranges")),
// NOTE: debugAranges_ is for fast address range lookup. debugRanges_(getSection(".debug_ranges")) {
// If missing .debug_info can be used - but it's much slower (linear scan). // Optional sections:
// - debugAranges_: for fast address range lookup.
// If missing .debug_info can be used - but it's much slower (linear
// scan).
// - debugRanges_: contains non-contiguous address ranges of debugging
// information entries. Used for inline function address lookup.
if (debugInfo_.empty() || debugAbbrev_.empty() || debugLine_.empty() || if (debugInfo_.empty() || debugAbbrev_.empty() || debugLine_.empty() ||
debugStr_.empty()) { debugStr_.empty()) {
elf_ = nullptr; elf_ = nullptr;
...@@ -457,6 +462,7 @@ bool Dwarf::findLocation( ...@@ -457,6 +462,7 @@ bool Dwarf::findLocation(
LocationInfo& locationInfo, LocationInfo& locationInfo,
folly::Range<SymbolizedFrame*> inlineFrames) const { folly::Range<SymbolizedFrame*> inlineFrames) const {
detail::Die die = getDieAtOffset(cu, cu.firstDie); detail::Die die = getDieAtOffset(cu, cu.firstDie);
// Partial compilation unit (DW_TAG_partial_unit) is not supported.
FOLLY_SAFE_CHECK( FOLLY_SAFE_CHECK(
die.abbr.tag == DW_TAG_compile_unit, "expecting compile unit entry"); die.abbr.tag == DW_TAG_compile_unit, "expecting compile unit entry");
...@@ -734,6 +740,40 @@ folly::Optional<T> Dwarf::getAttribute( ...@@ -734,6 +740,40 @@ folly::Optional<T> Dwarf::getAttribute(
return result; return result;
} }
bool Dwarf::isAddrInRangeList(uint64_t address, size_t offset, uint8_t addrSize)
const {
FOLLY_SAFE_CHECK(addrSize == 4 || addrSize == 8, "wrong address size");
if (debugRanges_.empty()) {
return false;
}
const bool is64BitAddr = addrSize == 8;
folly::StringPiece sp = debugRanges_;
sp.advance(offset);
const uint64_t maxAddr = is64BitAddr ? std::numeric_limits<uint64_t>::max()
: std::numeric_limits<uint32_t>::max();
uint64_t baseAddr = 0;
while (!sp.empty()) {
uint64_t begin = readOffset(sp, is64BitAddr);
uint64_t end = readOffset(sp, is64BitAddr);
// The range list entry is a base address selection entry.
if (begin == maxAddr) {
baseAddr = end;
continue;
}
// The range list entry is an end of list entry.
if (begin == 0 && end == 0) {
break;
}
// Check if the given address falls in the range list entry.
if (address >= begin + baseAddr && address < end + baseAddr) {
return true;
}
};
return false;
}
void Dwarf::findSubProgramDieForAddress( void Dwarf::findSubProgramDieForAddress(
const detail::CompilationUnit& cu, const detail::CompilationUnit& cu,
const detail::Die& die, const detail::Die& die,
...@@ -744,10 +784,12 @@ void Dwarf::findSubProgramDieForAddress( ...@@ -744,10 +784,12 @@ void Dwarf::findSubProgramDieForAddress(
folly::Optional<uint64_t> lowPc; folly::Optional<uint64_t> lowPc;
folly::Optional<uint64_t> highPc; folly::Optional<uint64_t> highPc;
folly::Optional<bool> isHighPcAddr; folly::Optional<bool> isHighPcAddr;
folly::Optional<uint64_t> rangeOffset;
forEachAttribute(cu, childDie, [&](const detail::Attribute& attr) { forEachAttribute(cu, childDie, [&](const detail::Attribute& attr) {
switch (attr.spec.name) { switch (attr.spec.name) {
// Here DW_AT_ranges is not supported since it requires looking up case DW_AT_ranges:
// in a different section (.debug_ranges). rangeOffset = boost::get<uint64_t>(attr.attrValue);
break;
case DW_AT_low_pc: case DW_AT_low_pc:
lowPc = boost::get<uint64_t>(attr.attrValue); lowPc = boost::get<uint64_t>(attr.attrValue);
break; break;
...@@ -761,12 +803,10 @@ void Dwarf::findSubProgramDieForAddress( ...@@ -761,12 +803,10 @@ void Dwarf::findSubProgramDieForAddress(
// Iterate through all attributes until find all above. // Iterate through all attributes until find all above.
return true; return true;
}); });
if (!lowPc || !highPc || !isHighPcAddr) { if ((lowPc && highPc && isHighPcAddr && address >= *lowPc &&
// Missing required fields. Keep searching other children. address < (*isHighPcAddr ? *highPc : *lowPc + *highPc)) ||
return true; (rangeOffset &&
} isAddrInRangeList(address, *rangeOffset, cu.addrSize))) {
if (address >= *lowPc &&
address < (*isHighPcAddr ? *highPc : *lowPc + *highPc)) {
subprogram = childDie; subprogram = childDie;
return false; return false;
} }
...@@ -798,10 +838,12 @@ void Dwarf::findInlinedSubroutineDieForAddress( ...@@ -798,10 +838,12 @@ void Dwarf::findInlinedSubroutineDieForAddress(
folly::Optional<uint64_t> origin; folly::Optional<uint64_t> origin;
folly::Optional<uint64_t> originRefType; folly::Optional<uint64_t> originRefType;
folly::Optional<uint64_t> callLine; folly::Optional<uint64_t> callLine;
folly::Optional<uint64_t> rangeOffset;
forEachAttribute(cu, childDie, [&](const detail::Attribute& attr) { forEachAttribute(cu, childDie, [&](const detail::Attribute& attr) {
switch (attr.spec.name) { switch (attr.spec.name) {
// Here DW_AT_ranges is not supported since it requires looking up case DW_AT_ranges:
// in a different section (.debug_ranges). rangeOffset = boost::get<uint64_t>(attr.attrValue);
break;
case DW_AT_low_pc: case DW_AT_low_pc:
lowPc = boost::get<uint64_t>(attr.attrValue); lowPc = boost::get<uint64_t>(attr.attrValue);
break; break;
...@@ -822,13 +864,14 @@ void Dwarf::findInlinedSubroutineDieForAddress( ...@@ -822,13 +864,14 @@ void Dwarf::findInlinedSubroutineDieForAddress(
// Iterate through all until find all above attributes. // Iterate through all until find all above attributes.
return true; return true;
}); });
if (!lowPc || !highPc || !isHighPcAddr || !origin || !originRefType || if (!origin || !originRefType || !callLine) {
!callLine) {
// Missing required fields. Keep searching other children. // Missing required fields. Keep searching other children.
return true; return true;
} }
if (address < *lowPc || if ((!lowPc || !highPc || !isHighPcAddr || address < *lowPc ||
address >= (*isHighPcAddr ? *highPc : *lowPc + *highPc)) { address >= (*isHighPcAddr ? *highPc : *lowPc + *highPc)) &&
(!rangeOffset ||
!isAddrInRangeList(address, rangeOffset.value(), cu.addrSize))) {
// Address doesn't match. Keep searching other children. // Address doesn't match. Keep searching other children.
return true; return true;
} }
......
...@@ -188,6 +188,12 @@ class Dwarf { ...@@ -188,6 +188,12 @@ class Dwarf {
const detail::CompilationUnit& cu, const detail::CompilationUnit& cu,
const detail::Die& die, const detail::Die& die,
uint64_t attrName) const; uint64_t attrName) const;
/**
* Check if the given address is in the range list at the given offset in
* .debug_ranges.
*/
bool isAddrInRangeList(uint64_t address, size_t offset, uint8_t addrSize)
const;
const ElfFile* elf_; const ElfFile* elf_;
const folly::StringPiece debugInfo_; // .debug_info const folly::StringPiece debugInfo_; // .debug_info
...@@ -195,6 +201,7 @@ class Dwarf { ...@@ -195,6 +201,7 @@ class Dwarf {
const folly::StringPiece debugLine_; // .debug_line const folly::StringPiece debugLine_; // .debug_line
const folly::StringPiece debugStr_; // .debug_str const folly::StringPiece debugStr_; // .debug_str
const folly::StringPiece debugAranges_; // .debug_aranges const folly::StringPiece debugAranges_; // .debug_aranges
const folly::StringPiece debugRanges_; // .debug_ranges
}; };
class Dwarf::Section { class Dwarf::Section {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment