Commit 5c4c45a4 authored by Tudor Bosman's avatar Tudor Bosman Committed by Facebook GitHub Bot

Speed up findLocation in the absence of .debug_aranges (#1607)

Summary:
If we don't find `.debug_aranges`, we used to jump directly to running the line number VM for every single compilation unit (CU). This is obviously not great.

Instead, every CU lists one (or multiple) address ranges that make up its `.text`, so do that first. I think (but haven't benchmarked) that this shouldn't be significantly slower than `.debug_aranges` (probably why clang doesn't emit `.debug_aranges` by default) -- both `.debug_aranges` and this approach suffer from the same drawback: they're grouped by CU instead of being sorted by address, so we still need to iterate for all CUs.

Pull Request resolved: https://github.com/facebook/folly/pull/1607

Reviewed By: yfeldblum

Differential Revision: D29175717

Pulled By: luciang

fbshipit-source-id: d626babdbb7f9a2f7dd51aefd914f6659124eb4e
parent 852cd96d
...@@ -451,6 +451,9 @@ bool Dwarf::findDebugInfoOffset( ...@@ -451,6 +451,9 @@ bool Dwarf::findDebugInfoOffset(
* Best effort: * Best effort:
* - fills @inlineFrames if mode == FULL_WITH_INLINE, * - fills @inlineFrames if mode == FULL_WITH_INLINE,
* - calls @eachParameterName on the function parameters. * - calls @eachParameterName on the function parameters.
*
* if @checkAddress is true, we verify that the address is mapped to
* a range in this CU before running the line number VM
*/ */
bool Dwarf::findLocation( bool Dwarf::findLocation(
uintptr_t address, uintptr_t address,
...@@ -458,7 +461,8 @@ bool Dwarf::findLocation( ...@@ -458,7 +461,8 @@ bool Dwarf::findLocation(
detail::CompilationUnit& cu, detail::CompilationUnit& cu,
LocationInfo& locationInfo, LocationInfo& locationInfo,
folly::Range<SymbolizedFrame*> inlineFrames, folly::Range<SymbolizedFrame*> inlineFrames,
folly::FunctionRef<void(folly::StringPiece)> eachParameterName) const { folly::FunctionRef<void(folly::StringPiece)> eachParameterName,
bool checkAddress) 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. // Partial compilation unit (DW_TAG_partial_unit) is not supported.
FOLLY_SAFE_CHECK( FOLLY_SAFE_CHECK(
...@@ -470,41 +474,98 @@ bool Dwarf::findLocation( ...@@ -470,41 +474,98 @@ bool Dwarf::findLocation(
folly::StringPiece compilationDirectory; folly::StringPiece compilationDirectory;
folly::Optional<folly::StringPiece> mainFileName; folly::Optional<folly::StringPiece> mainFileName;
folly::Optional<uint64_t> baseAddrCU; folly::Optional<uint64_t> baseAddrCU;
folly::Optional<uint64_t> rangesOffset;
bool seenLowPC = false;
bool seenHighPC = false;
enum : unsigned {
kStmtList = 1U << 0,
kCompDir = 1U << 1,
kName = 1U << 2,
kLowPC = 1U << 3,
kHighPCOrRanges = 1U << 4,
};
unsigned expectedAttributes = kStmtList | kCompDir | kName | kLowPC;
bool foundAddress = !checkAddress;
if (!foundAddress) {
expectedAttributes |= kHighPCOrRanges;
}
forEachAttribute(cu, die, [&](const detail::Attribute& attr) { forEachAttribute(cu, die, [&](const detail::Attribute& attr) {
switch (attr.spec.name) { switch (attr.spec.name) {
case DW_AT_stmt_list: case DW_AT_stmt_list:
expectedAttributes &= ~kStmtList;
// Offset in .debug_line for the line number VM program for this // Offset in .debug_line for the line number VM program for this
// compilation unit // compilation unit
lineOffset = boost::get<uint64_t>(attr.attrValue); lineOffset = boost::get<uint64_t>(attr.attrValue);
break; break;
case DW_AT_comp_dir: case DW_AT_comp_dir:
expectedAttributes &= ~kCompDir;
// Compilation directory // Compilation directory
compilationDirectory = boost::get<folly::StringPiece>(attr.attrValue); compilationDirectory = boost::get<folly::StringPiece>(attr.attrValue);
break; break;
case DW_AT_name: case DW_AT_name:
expectedAttributes &= ~kName;
// File name of main file being compiled // File name of main file being compiled
mainFileName = boost::get<folly::StringPiece>(attr.attrValue); mainFileName = boost::get<folly::StringPiece>(attr.attrValue);
break; break;
case DW_AT_low_pc: case DW_AT_low_pc:
case DW_AT_entry_pc: expectedAttributes &= ~kLowPC;
// 2.17.1: historically DW_AT_low_pc was used. DW_AT_entry_pc was
// introduced in DWARF3. Support either to determine the base address of
// the CU.
baseAddrCU = boost::get<uint64_t>(attr.attrValue); baseAddrCU = boost::get<uint64_t>(attr.attrValue);
if (!foundAddress) {
if (address < *baseAddrCU) {
return false;
}
seenLowPC = true;
if (seenHighPC) {
foundAddress = true;
} else if (rangesOffset) {
if (!isAddrInRangeList(
address, baseAddrCU, *rangesOffset, cu.addrSize)) {
return false;
}
foundAddress = true;
}
}
break; break;
case DW_AT_high_pc:
expectedAttributes &= ~kHighPCOrRanges;
if (!foundAddress) {
if (address >= boost::get<uint64_t>(attr.attrValue)) {
return false;
} }
return true; // continue forEachAttribute seenHighPC = true;
foundAddress = seenLowPC;
}
break;
case DW_AT_ranges:
// 3.1.1: CU entries have:
// - either DW_AT_low_pc and DW_AT_high_pc
// OR
// - DW_AT_ranges and optional DW_AT_low_pc
expectedAttributes &= ~kHighPCOrRanges;
if (!foundAddress) {
rangesOffset = boost::get<uint64_t>(attr.attrValue);
if (seenLowPC) {
if (!isAddrInRangeList(
address, baseAddrCU, *rangesOffset, cu.addrSize)) {
return false;
}
foundAddress = true;
}
}
break;
}
return (expectedAttributes != 0); // continue forEachAttribute
}); });
if (!foundAddress || !lineOffset) {
return false;
}
if (mainFileName) { if (mainFileName) {
locationInfo.hasMainFile = true; locationInfo.hasMainFile = true;
locationInfo.mainFile = Path(compilationDirectory, "", *mainFileName); locationInfo.mainFile = Path(compilationDirectory, "", *mainFileName);
} }
if (!lineOffset) {
return false;
}
folly::StringPiece lineSection(debugLine_); folly::StringPiece lineSection(debugLine_);
lineSection.advance(*lineOffset); lineSection.advance(*lineOffset);
LineNumberVM lineVM(lineSection, compilationDirectory); LineNumberVM lineVM(lineSection, compilationDirectory);
...@@ -653,7 +714,13 @@ bool Dwarf::findAddress( ...@@ -653,7 +714,13 @@ bool Dwarf::findAddress(
// Read compilation unit header from .debug_info // Read compilation unit header from .debug_info
auto unit = getCompilationUnit(debugInfo_, offset); auto unit = getCompilationUnit(debugInfo_, offset);
return findLocation( return findLocation(
address, mode, unit, locationInfo, inlineFrames, eachParameterName); address,
mode,
unit,
locationInfo,
inlineFrames,
eachParameterName,
false /*checkAddress*/);
} else if (mode == LocationInfoMode::FAST) { } else if (mode == LocationInfoMode::FAST) {
// NOTE: Clang (when using -gdwarf-aranges) doesn't generate entries // NOTE: Clang (when using -gdwarf-aranges) doesn't generate entries
// in .debug_aranges for some functions, but always generates // in .debug_aranges for some functions, but always generates
...@@ -681,7 +748,8 @@ bool Dwarf::findAddress( ...@@ -681,7 +748,8 @@ bool Dwarf::findAddress(
unit, unit,
locationInfo, locationInfo,
inlineFrames, inlineFrames,
eachParameterName)) { eachParameterName,
true /*checkAddress*/)) {
return true; return true;
} }
} }
......
...@@ -122,6 +122,9 @@ class Dwarf { ...@@ -122,6 +122,9 @@ class Dwarf {
* Best effort: * Best effort:
* - fills @inlineFrames if mode == FULL_WITH_INLINE, * - fills @inlineFrames if mode == FULL_WITH_INLINE,
* - calls @eachParameterName on the function parameters. * - calls @eachParameterName on the function parameters.
*
* if @checkAddress is true, we verify that the address is mapped to
* a range in this CU before running the line number VM
*/ */
bool findLocation( bool findLocation(
uintptr_t address, uintptr_t address,
...@@ -129,7 +132,8 @@ class Dwarf { ...@@ -129,7 +132,8 @@ class Dwarf {
detail::CompilationUnit& cu, detail::CompilationUnit& cu,
LocationInfo& info, LocationInfo& info,
folly::Range<SymbolizedFrame*> inlineFrames, folly::Range<SymbolizedFrame*> inlineFrames,
folly::FunctionRef<void(folly::StringPiece)> eachParameterName) const; folly::FunctionRef<void(folly::StringPiece)> eachParameterName,
bool checkAddress = true) const;
/** /**
* Finds a subprogram debugging info entry that contains a given address among * Finds a subprogram debugging info entry that contains a given address among
......
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