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)
debugAbbrev_(getSection(".debug_abbrev")),
debugLine_(getSection(".debug_line")),
debugStr_(getSection(".debug_str")),
debugAranges_(getSection(".debug_aranges")) {
// NOTE: debugAranges_ is for fast address range lookup.
// If missing .debug_info can be used - but it's much slower (linear scan).
debugAranges_(getSection(".debug_aranges")),
debugRanges_(getSection(".debug_ranges")) {
// 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() ||
debugStr_.empty()) {
elf_ = nullptr;
......@@ -457,6 +462,7 @@ bool Dwarf::findLocation(
LocationInfo& locationInfo,
folly::Range<SymbolizedFrame*> inlineFrames) const {
detail::Die die = getDieAtOffset(cu, cu.firstDie);
// Partial compilation unit (DW_TAG_partial_unit) is not supported.
FOLLY_SAFE_CHECK(
die.abbr.tag == DW_TAG_compile_unit, "expecting compile unit entry");
......@@ -734,6 +740,40 @@ folly::Optional<T> Dwarf::getAttribute(
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(
const detail::CompilationUnit& cu,
const detail::Die& die,
......@@ -744,10 +784,12 @@ void Dwarf::findSubProgramDieForAddress(
folly::Optional<uint64_t> lowPc;
folly::Optional<uint64_t> highPc;
folly::Optional<bool> isHighPcAddr;
folly::Optional<uint64_t> rangeOffset;
forEachAttribute(cu, childDie, [&](const detail::Attribute& attr) {
switch (attr.spec.name) {
// Here DW_AT_ranges is not supported since it requires looking up
// in a different section (.debug_ranges).
case DW_AT_ranges:
rangeOffset = boost::get<uint64_t>(attr.attrValue);
break;
case DW_AT_low_pc:
lowPc = boost::get<uint64_t>(attr.attrValue);
break;
......@@ -761,12 +803,10 @@ void Dwarf::findSubProgramDieForAddress(
// Iterate through all attributes until find all above.
return true;
});
if (!lowPc || !highPc || !isHighPcAddr) {
// Missing required fields. Keep searching other children.
return true;
}
if (address >= *lowPc &&
address < (*isHighPcAddr ? *highPc : *lowPc + *highPc)) {
if ((lowPc && highPc && isHighPcAddr && address >= *lowPc &&
address < (*isHighPcAddr ? *highPc : *lowPc + *highPc)) ||
(rangeOffset &&
isAddrInRangeList(address, *rangeOffset, cu.addrSize))) {
subprogram = childDie;
return false;
}
......@@ -798,10 +838,12 @@ void Dwarf::findInlinedSubroutineDieForAddress(
folly::Optional<uint64_t> origin;
folly::Optional<uint64_t> originRefType;
folly::Optional<uint64_t> callLine;
folly::Optional<uint64_t> rangeOffset;
forEachAttribute(cu, childDie, [&](const detail::Attribute& attr) {
switch (attr.spec.name) {
// Here DW_AT_ranges is not supported since it requires looking up
// in a different section (.debug_ranges).
case DW_AT_ranges:
rangeOffset = boost::get<uint64_t>(attr.attrValue);
break;
case DW_AT_low_pc:
lowPc = boost::get<uint64_t>(attr.attrValue);
break;
......@@ -822,13 +864,14 @@ void Dwarf::findInlinedSubroutineDieForAddress(
// Iterate through all until find all above attributes.
return true;
});
if (!lowPc || !highPc || !isHighPcAddr || !origin || !originRefType ||
!callLine) {
if (!origin || !originRefType || !callLine) {
// Missing required fields. Keep searching other children.
return true;
}
if (address < *lowPc ||
address >= (*isHighPcAddr ? *highPc : *lowPc + *highPc)) {
if ((!lowPc || !highPc || !isHighPcAddr || address < *lowPc ||
address >= (*isHighPcAddr ? *highPc : *lowPc + *highPc)) &&
(!rangeOffset ||
!isAddrInRangeList(address, rangeOffset.value(), cu.addrSize))) {
// Address doesn't match. Keep searching other children.
return true;
}
......
......@@ -188,6 +188,12 @@ class Dwarf {
const detail::CompilationUnit& cu,
const detail::Die& die,
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 folly::StringPiece debugInfo_; // .debug_info
......@@ -195,6 +201,7 @@ class Dwarf {
const folly::StringPiece debugLine_; // .debug_line
const folly::StringPiece debugStr_; // .debug_str
const folly::StringPiece debugAranges_; // .debug_aranges
const folly::StringPiece debugRanges_; // .debug_ranges
};
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