Commit cb3a7e45 authored by Philip Pronin's avatar Philip Pronin Committed by Facebook Github Bot

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
parent fc838f2b
...@@ -73,7 +73,10 @@ void printExceptionInfo( ...@@ -73,7 +73,10 @@ void printExceptionInfo(
std::vector<SymbolizedFrame> frames; std::vector<SymbolizedFrame> frames;
frames.resize(frameCount); frames.resize(frameCount);
Symbolizer symbolizer; Symbolizer symbolizer(
(options & SymbolizePrinter::NO_FILE_AND_LINE)
? Dwarf::LocationInfoMode::DISABLED
: Symbolizer::kDefaultLocationInfoMode);
symbolizer.symbolize(addresses, frames.data(), frameCount); symbolizer.symbolize(addresses, frames.data(), frameCount);
OStreamSymbolizePrinter osp(out, options); OStreamSymbolizePrinter osp(out, options);
......
...@@ -566,10 +566,16 @@ bool Dwarf::findLocation(uintptr_t address, ...@@ -566,10 +566,16 @@ bool Dwarf::findLocation(uintptr_t address,
return locationInfo.hasFileAndLine; 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(); locationInfo = LocationInfo();
if (!elf_) { // no file if (mode == LocationInfoMode::DISABLED) {
return false;
}
if (!elf_) { // No file.
return false; return false;
} }
...@@ -577,20 +583,25 @@ bool Dwarf::findAddress(uintptr_t address, LocationInfo& locationInfo) const { ...@@ -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 // Fast path: find the right .debug_info entry by looking up the
// address in .debug_aranges. // address in .debug_aranges.
uint64_t offset = 0; uint64_t offset = 0;
if (!findDebugInfoOffset(address, aranges_, offset)) { if (findDebugInfoOffset(address, aranges_, offset)) {
// NOTE: clang doesn't generate entries in .debug_aranges for // Read compilation unit header from .debug_info
// some functions, but always generates .debug_info entries. folly::StringPiece infoEntry(info_);
// We could read them from .debug_info but that's too slow. infoEntry.advance(offset);
// If .debug_aranges is present fast address lookup is assumed. 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; 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 // Slow path (linear scan): Iterate over all .debug_info entries
// and look for the address in each compilation unit. // and look for the address in each compilation unit.
folly::StringPiece infoEntry(info_); folly::StringPiece infoEntry(info_);
......
...@@ -100,25 +100,37 @@ class Dwarf { ...@@ -100,25 +100,37 @@ class Dwarf {
folly::StringPiece file_; folly::StringPiece file_;
}; };
struct LocationInfo { enum class LocationInfoMode {
LocationInfo() : hasMainFile(false), hasFileAndLine(false), line(0) { } // 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; Path mainFile;
bool hasFileAndLine; bool hasFileAndLine = false;
Path file; 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: private:
void init();
static bool findDebugInfoOffset(uintptr_t address, static bool findDebugInfoOffset(uintptr_t address,
StringPiece aranges, StringPiece aranges,
uint64_t& offset); uint64_t& offset);
void init();
bool findLocation(uintptr_t address, bool findLocation(uintptr_t address,
StringPiece& infoEntry, StringPiece& infoEntry,
LocationInfo& info) const; LocationInfo& info) const;
......
...@@ -396,7 +396,9 @@ void dumpStackTrace(bool symbolize) { ...@@ -396,7 +396,9 @@ void dumpStackTrace(bool symbolize) {
if (!getStackTraceSafe(addresses)) { if (!getStackTraceSafe(addresses)) {
print("(error retrieving stack trace)\n"); print("(error retrieving stack trace)\n");
} else if (symbolize) { } 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); symbolizer.symbolize(addresses);
// Skip the top 2 frames: // Skip the top 2 frames:
......
...@@ -60,7 +60,8 @@ ElfCache* defaultElfCache() { ...@@ -60,7 +60,8 @@ ElfCache* defaultElfCache() {
} // namespace } // namespace
void SymbolizedFrame::set(const std::shared_ptr<ElfFile>& file, void SymbolizedFrame::set(const std::shared_ptr<ElfFile>& file,
uintptr_t address) { uintptr_t address,
Dwarf::LocationInfoMode mode) {
clear(); clear();
found = true; found = true;
...@@ -73,12 +74,11 @@ void SymbolizedFrame::set(const std::shared_ptr<ElfFile>& file, ...@@ -73,12 +74,11 @@ void SymbolizedFrame::set(const std::shared_ptr<ElfFile>& file,
file_ = file; file_ = file;
name = file->getSymbolName(sym); name = file->getSymbolName(sym);
Dwarf(file.get()).findAddress(address, location); Dwarf(file.get()).findAddress(address, location, mode);
} }
Symbolizer::Symbolizer(ElfCacheBase* cache, Dwarf::LocationInfoMode mode)
Symbolizer::Symbolizer(ElfCacheBase* cache) : cache_(cache ?: defaultElfCache()), mode_(mode) {
: cache_(cache ?: defaultElfCache()) {
} }
void Symbolizer::symbolize(const uintptr_t* addresses, void Symbolizer::symbolize(const uintptr_t* addresses,
...@@ -143,7 +143,7 @@ void Symbolizer::symbolize(const uintptr_t* addresses, ...@@ -143,7 +143,7 @@ void Symbolizer::symbolize(const uintptr_t* addresses,
auto const adjusted = addr - base; auto const adjusted = addr - base;
if (elfFile->getSectionContainingAddress(adjusted)) { if (elfFile->getSectionContainingAddress(adjusted)) {
frame.set(elfFile, adjusted); frame.set(elfFile, adjusted, mode_);
--remaining; --remaining;
} }
} }
......
...@@ -41,7 +41,10 @@ class Symbolizer; ...@@ -41,7 +41,10 @@ class Symbolizer;
struct SymbolizedFrame { struct SymbolizedFrame {
SymbolizedFrame() { } SymbolizedFrame() { }
void set(const std::shared_ptr<ElfFile>& file, uintptr_t address); void set(const std::shared_ptr<ElfFile>& file,
uintptr_t address,
Dwarf::LocationInfoMode mode);
void clear() { *this = SymbolizedFrame(); } void clear() { *this = SymbolizedFrame(); }
bool found = false; bool found = false;
...@@ -54,6 +57,7 @@ struct SymbolizedFrame { ...@@ -54,6 +57,7 @@ struct SymbolizedFrame {
fbstring demangledName() const { fbstring demangledName() const {
return name ? demangle(name) : fbstring(); return name ? demangle(name) : fbstring();
} }
private: private:
std::shared_ptr<ElfFile> file_; std::shared_ptr<ElfFile> file_;
}; };
...@@ -107,7 +111,14 @@ inline bool getStackTraceSafe(FrameArray<N>& fa) { ...@@ -107,7 +111,14 @@ inline bool getStackTraceSafe(FrameArray<N>& fa) {
class Symbolizer { class Symbolizer {
public: 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. * Symbolize given addresses.
...@@ -130,7 +141,8 @@ class Symbolizer { ...@@ -130,7 +141,8 @@ class Symbolizer {
} }
private: private:
ElfCacheBase* const cache_ = nullptr; ElfCacheBase* const cache_;
const Dwarf::LocationInfoMode mode_;
}; };
/** /**
......
...@@ -20,9 +20,12 @@ ...@@ -20,9 +20,12 @@
void dummy() {} void dummy() {}
BENCHMARK(DwarfFindAddress, n) { namespace {
using namespace folly::symbolizer;
void run(Dwarf::LocationInfoMode mode, size_t n) {
folly::BenchmarkSuspender suspender; folly::BenchmarkSuspender suspender;
using namespace folly::symbolizer;
// NOTE: Using '/proc/self/exe' only works if the code for @dummy is // NOTE: Using '/proc/self/exe' only works if the code for @dummy is
// statically linked into the binary. // statically linked into the binary.
ElfFile elf("/proc/self/exe"); ElfFile elf("/proc/self/exe");
...@@ -30,10 +33,20 @@ BENCHMARK(DwarfFindAddress, n) { ...@@ -30,10 +33,20 @@ BENCHMARK(DwarfFindAddress, n) {
suspender.dismiss(); suspender.dismiss();
for (size_t i = 0; i < n; i++) { for (size_t i = 0; i < n; i++) {
Dwarf::LocationInfo info; 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[]) { int main(int argc, char* argv[]) {
gflags::ParseCommandLineFlags(&argc, &argv, true); gflags::ParseCommandLineFlags(&argc, &argv, true);
google::InitGoogleLogging(argv[0]); google::InitGoogleLogging(argv[0]);
......
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