From: Philip Pronin Date: Sat, 15 Oct 2016 04:44:00 +0000 (-0700) Subject: fall back to .debug_info scan in fatal signal handler X-Git-Tag: v2016.10.17.00^0 X-Git-Url: http://plrg.eecs.uci.edu/git/?p=folly.git;a=commitdiff_plain;h=cb3a7e4572affb970e7491a94c9503b6a2745d1e fall back to .debug_info scan in fatal signal handler Summary: We've found clang might be generating incomplete `.debug_aranges`, while falling back to linear `.debug_info` scan is too expensive and shouldn't be used by default, we can afford doing that in fatal signal handler. Also optimize `exception_tracer::printExceptionInfo()` to avoid `LocationInfo` resolution if `NO_FILE_AND_LINE` is used. Reviewed By: luciang, ot Differential Revision: D4020989 fbshipit-source-id: 84172208736b224c19206da48bcb3b5c0b2c67d0 --- diff --git a/folly/experimental/exception_tracer/ExceptionTracer.cpp b/folly/experimental/exception_tracer/ExceptionTracer.cpp index 1e3159a5..d2ec8f64 100644 --- a/folly/experimental/exception_tracer/ExceptionTracer.cpp +++ b/folly/experimental/exception_tracer/ExceptionTracer.cpp @@ -73,7 +73,10 @@ void printExceptionInfo( std::vector frames; frames.resize(frameCount); - Symbolizer symbolizer; + Symbolizer symbolizer( + (options & SymbolizePrinter::NO_FILE_AND_LINE) + ? Dwarf::LocationInfoMode::DISABLED + : Symbolizer::kDefaultLocationInfoMode); symbolizer.symbolize(addresses, frames.data(), frameCount); OStreamSymbolizePrinter osp(out, options); diff --git a/folly/experimental/symbolizer/Dwarf.cpp b/folly/experimental/symbolizer/Dwarf.cpp index 7709dc0b..4474895f 100644 --- a/folly/experimental/symbolizer/Dwarf.cpp +++ b/folly/experimental/symbolizer/Dwarf.cpp @@ -566,10 +566,16 @@ bool Dwarf::findLocation(uintptr_t address, return locationInfo.hasFileAndLine; } -bool Dwarf::findAddress(uintptr_t address, LocationInfo& locationInfo) const { +bool Dwarf::findAddress(uintptr_t address, + LocationInfo& locationInfo, + LocationInfoMode mode) const { locationInfo = LocationInfo(); - if (!elf_) { // no file + if (mode == LocationInfoMode::DISABLED) { + return false; + } + + if (!elf_) { // No file. return false; } @@ -577,20 +583,25 @@ bool Dwarf::findAddress(uintptr_t address, LocationInfo& locationInfo) const { // Fast path: find the right .debug_info entry by looking up the // address in .debug_aranges. uint64_t offset = 0; - if (!findDebugInfoOffset(address, aranges_, offset)) { - // NOTE: clang doesn't generate entries in .debug_aranges for - // some functions, but always generates .debug_info entries. - // We could read them from .debug_info but that's too slow. - // If .debug_aranges is present fast address lookup is assumed. + if (findDebugInfoOffset(address, aranges_, offset)) { + // Read compilation unit header from .debug_info + folly::StringPiece infoEntry(info_); + infoEntry.advance(offset); + findLocation(address, infoEntry, locationInfo); + return locationInfo.hasFileAndLine; + } else if (mode == LocationInfoMode::FAST) { + // NOTE: Clang (when using -gdwarf-aranges) doesn't generate entries + // in .debug_aranges for some functions, but always generates + // .debug_info entries. Scanning .debug_info is slow, so fall back to + // it only if such behavior is requested via LocationInfoMode. return false; + } else { + DCHECK(mode == LocationInfoMode::FULL); + // Fall back to the linear scan. } - // Read compilation unit header from .debug_info - folly::StringPiece infoEntry(info_); - infoEntry.advance(offset); - findLocation(address, infoEntry, locationInfo); - return true; } + // Slow path (linear scan): Iterate over all .debug_info entries // and look for the address in each compilation unit. folly::StringPiece infoEntry(info_); diff --git a/folly/experimental/symbolizer/Dwarf.h b/folly/experimental/symbolizer/Dwarf.h index ed7d1ae8..192d0c03 100644 --- a/folly/experimental/symbolizer/Dwarf.h +++ b/folly/experimental/symbolizer/Dwarf.h @@ -100,25 +100,37 @@ class Dwarf { folly::StringPiece file_; }; - struct LocationInfo { - LocationInfo() : hasMainFile(false), hasFileAndLine(false), line(0) { } + enum class LocationInfoMode { + // Don't resolve location info. + DISABLED, + // Perform CU lookup using .debug_aranges (might be incomplete). + FAST, + // Scan all CU in .debug_info (slow!) on .debug_aranges lookup failure. + FULL, + }; - bool hasMainFile; + struct LocationInfo { + bool hasMainFile = false; Path mainFile; - bool hasFileAndLine; + bool hasFileAndLine = false; Path file; - uint64_t line; + uint64_t line = 0; }; - /** Find the file and line number information corresponding to address */ - bool findAddress(uintptr_t address, LocationInfo& info) const; + /** + * Find the file and line number information corresponding to address. + */ + bool findAddress(uintptr_t address, + LocationInfo& info, + LocationInfoMode mode) const; private: - void init(); static bool findDebugInfoOffset(uintptr_t address, StringPiece aranges, uint64_t& offset); + + void init(); bool findLocation(uintptr_t address, StringPiece& infoEntry, LocationInfo& info) const; diff --git a/folly/experimental/symbolizer/SignalHandler.cpp b/folly/experimental/symbolizer/SignalHandler.cpp index b5dd4c14..06173c08 100644 --- a/folly/experimental/symbolizer/SignalHandler.cpp +++ b/folly/experimental/symbolizer/SignalHandler.cpp @@ -396,7 +396,9 @@ void dumpStackTrace(bool symbolize) { if (!getStackTraceSafe(addresses)) { print("(error retrieving stack trace)\n"); } else if (symbolize) { - Symbolizer symbolizer(gSignalSafeElfCache); + // Do our best to populate location info, process is going to terminate, + // so performance isn't critical. + Symbolizer symbolizer(gSignalSafeElfCache, Dwarf::LocationInfoMode::FULL); symbolizer.symbolize(addresses); // Skip the top 2 frames: diff --git a/folly/experimental/symbolizer/Symbolizer.cpp b/folly/experimental/symbolizer/Symbolizer.cpp index 365aff41..13fe68fa 100644 --- a/folly/experimental/symbolizer/Symbolizer.cpp +++ b/folly/experimental/symbolizer/Symbolizer.cpp @@ -60,7 +60,8 @@ ElfCache* defaultElfCache() { } // namespace void SymbolizedFrame::set(const std::shared_ptr& file, - uintptr_t address) { + uintptr_t address, + Dwarf::LocationInfoMode mode) { clear(); found = true; @@ -73,12 +74,11 @@ void SymbolizedFrame::set(const std::shared_ptr& file, file_ = file; name = file->getSymbolName(sym); - Dwarf(file.get()).findAddress(address, location); + Dwarf(file.get()).findAddress(address, location, mode); } - -Symbolizer::Symbolizer(ElfCacheBase* cache) - : cache_(cache ?: defaultElfCache()) { +Symbolizer::Symbolizer(ElfCacheBase* cache, Dwarf::LocationInfoMode mode) + : cache_(cache ?: defaultElfCache()), mode_(mode) { } void Symbolizer::symbolize(const uintptr_t* addresses, @@ -143,7 +143,7 @@ void Symbolizer::symbolize(const uintptr_t* addresses, auto const adjusted = addr - base; if (elfFile->getSectionContainingAddress(adjusted)) { - frame.set(elfFile, adjusted); + frame.set(elfFile, adjusted, mode_); --remaining; } } diff --git a/folly/experimental/symbolizer/Symbolizer.h b/folly/experimental/symbolizer/Symbolizer.h index bbbb1e75..bd93c121 100644 --- a/folly/experimental/symbolizer/Symbolizer.h +++ b/folly/experimental/symbolizer/Symbolizer.h @@ -41,7 +41,10 @@ class Symbolizer; struct SymbolizedFrame { SymbolizedFrame() { } - void set(const std::shared_ptr& file, uintptr_t address); + void set(const std::shared_ptr& file, + uintptr_t address, + Dwarf::LocationInfoMode mode); + void clear() { *this = SymbolizedFrame(); } bool found = false; @@ -54,6 +57,7 @@ struct SymbolizedFrame { fbstring demangledName() const { return name ? demangle(name) : fbstring(); } + private: std::shared_ptr file_; }; @@ -107,7 +111,14 @@ inline bool getStackTraceSafe(FrameArray& fa) { class Symbolizer { public: - explicit Symbolizer(ElfCacheBase* cache = nullptr); + static constexpr Dwarf::LocationInfoMode kDefaultLocationInfoMode = + Dwarf::LocationInfoMode::FAST; + + explicit Symbolizer(Dwarf::LocationInfoMode mode = kDefaultLocationInfoMode) + : Symbolizer(nullptr, mode) {} + + explicit Symbolizer(ElfCacheBase* cache, + Dwarf::LocationInfoMode mode = kDefaultLocationInfoMode); /** * Symbolize given addresses. @@ -130,7 +141,8 @@ class Symbolizer { } private: - ElfCacheBase* const cache_ = nullptr; + ElfCacheBase* const cache_; + const Dwarf::LocationInfoMode mode_; }; /** diff --git a/folly/experimental/symbolizer/test/DwarfBenchmark.cpp b/folly/experimental/symbolizer/test/DwarfBenchmark.cpp index 877b5811..50f63c80 100644 --- a/folly/experimental/symbolizer/test/DwarfBenchmark.cpp +++ b/folly/experimental/symbolizer/test/DwarfBenchmark.cpp @@ -20,9 +20,12 @@ void dummy() {} -BENCHMARK(DwarfFindAddress, n) { +namespace { + +using namespace folly::symbolizer; + +void run(Dwarf::LocationInfoMode mode, size_t n) { folly::BenchmarkSuspender suspender; - using namespace folly::symbolizer; // NOTE: Using '/proc/self/exe' only works if the code for @dummy is // statically linked into the binary. ElfFile elf("/proc/self/exe"); @@ -30,10 +33,20 @@ BENCHMARK(DwarfFindAddress, n) { suspender.dismiss(); for (size_t i = 0; i < n; i++) { Dwarf::LocationInfo info; - dwarf.findAddress(uintptr_t(&dummy), info); + dwarf.findAddress(uintptr_t(&dummy), info, mode); } } +} // namespace + +BENCHMARK(DwarfFindAddressFast, n) { + run(folly::symbolizer::Dwarf::LocationInfoMode::FAST, n); +} + +BENCHMARK(DwarfFindAddressFull, n) { + run(folly::symbolizer::Dwarf::LocationInfoMode::FULL, n); +} + int main(int argc, char* argv[]) { gflags::ParseCommandLineFlags(&argc, &argv, true); google::InitGoogleLogging(argv[0]);