From d8bd6d2e5713aac40d49345dd4a793acd4d1ea77 Mon Sep 17 00:00:00 2001 From: Tudor Bosman Date: Wed, 16 Jun 2021 00:54:38 +0000 Subject: [PATCH] Speed up findLocation in the absence of .debug_aranges --- folly/experimental/symbolizer/Dwarf.cpp | 87 +++++++++++++++++++++---- folly/experimental/symbolizer/Dwarf.h | 6 +- 2 files changed, 80 insertions(+), 13 deletions(-) diff --git a/folly/experimental/symbolizer/Dwarf.cpp b/folly/experimental/symbolizer/Dwarf.cpp index f15574bd7ec..b55aa5145e4 100644 --- a/folly/experimental/symbolizer/Dwarf.cpp +++ b/folly/experimental/symbolizer/Dwarf.cpp @@ -458,6 +458,9 @@ bool Dwarf::findDebugInfoOffset( * Best effort: * - fills @inlineFrames if mode == FULL_WITH_INLINE, * - 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( uintptr_t address, @@ -465,7 +468,8 @@ bool Dwarf::findLocation( detail::CompilationUnit& cu, LocationInfo& locationInfo, folly::Range inlineFrames, - folly::FunctionRef eachParameterName) const { + folly::FunctionRef eachParameterName, + bool checkAddress) const { detail::Die die = getDieAtOffset(cu, cu.firstDie); // Partial compilation unit (DW_TAG_partial_unit) is not supported. FOLLY_SAFE_CHECK( @@ -477,41 +481,98 @@ bool Dwarf::findLocation( folly::StringPiece compilationDirectory; folly::Optional mainFileName; folly::Optional baseAddrCU; + folly::Optional 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) { switch (attr.spec.name) { case DW_AT_stmt_list: + expectedAttributes &= ~kStmtList; // Offset in .debug_line for the line number VM program for this // compilation unit lineOffset = boost::get(attr.attrValue); break; case DW_AT_comp_dir: + expectedAttributes &= ~kCompDir; // Compilation directory compilationDirectory = boost::get(attr.attrValue); break; case DW_AT_name: + expectedAttributes &= ~kName; // File name of main file being compiled mainFileName = boost::get(attr.attrValue); break; case DW_AT_low_pc: - case DW_AT_entry_pc: - // 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. + expectedAttributes &= ~kLowPC; baseAddrCU = boost::get(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; + case DW_AT_high_pc: + expectedAttributes &= ~kHighPCOrRanges; + if (!foundAddress) { + if (address >= boost::get(attr.attrValue)) { + return false; + } + 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(attr.attrValue); + if (seenLowPC) { + if (!isAddrInRangeList(address, baseAddrCU, *rangesOffset, + cu.addrSize)) { + return false; + } + foundAddress = true; + } + } break; } - return true; // continue forEachAttribute + return (expectedAttributes != 0); // continue forEachAttribute }); + if (!foundAddress || !lineOffset) { + return false; + } + if (mainFileName) { locationInfo.hasMainFile = true; locationInfo.mainFile = Path(compilationDirectory, "", *mainFileName); } - if (!lineOffset) { - return false; - } - folly::StringPiece lineSection(debugLine_); lineSection.advance(*lineOffset); LineNumberVM lineVM(lineSection, compilationDirectory); @@ -660,7 +721,8 @@ bool Dwarf::findAddress( // Read compilation unit header from .debug_info auto unit = getCompilationUnit(debugInfo_, offset); return findLocation( - address, mode, unit, locationInfo, inlineFrames, eachParameterName); + address, mode, unit, locationInfo, inlineFrames, eachParameterName, + false /*checkAddress*/); } else if (mode == LocationInfoMode::FAST) { // NOTE: Clang (when using -gdwarf-aranges) doesn't generate entries // in .debug_aranges for some functions, but always generates @@ -688,7 +750,8 @@ bool Dwarf::findAddress( unit, locationInfo, inlineFrames, - eachParameterName)) { + eachParameterName, + true /*checkAddress*/)) { return true; } } diff --git a/folly/experimental/symbolizer/Dwarf.h b/folly/experimental/symbolizer/Dwarf.h index 564e419df1d..479b1f1e660 100644 --- a/folly/experimental/symbolizer/Dwarf.h +++ b/folly/experimental/symbolizer/Dwarf.h @@ -122,6 +122,9 @@ class Dwarf { * Best effort: * - fills @inlineFrames if mode == FULL_WITH_INLINE, * - 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( uintptr_t address, @@ -129,7 +132,8 @@ class Dwarf { detail::CompilationUnit& cu, LocationInfo& info, folly::Range inlineFrames, - folly::FunctionRef eachParameterName) const; + folly::FunctionRef eachParameterName, + bool checkAddress = true) const; /** * Finds a subprogram debugging info entry that contains a given address among