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(
std::vector<SymbolizedFrame> 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);
......
......@@ -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_);
......
......@@ -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;
......
......@@ -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:
......
......@@ -60,7 +60,8 @@ ElfCache* defaultElfCache() {
} // namespace
void SymbolizedFrame::set(const std::shared_ptr<ElfFile>& file,
uintptr_t address) {
uintptr_t address,
Dwarf::LocationInfoMode mode) {
clear();
found = true;
......@@ -73,12 +74,11 @@ void SymbolizedFrame::set(const std::shared_ptr<ElfFile>& 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;
}
}
......
......@@ -41,7 +41,10 @@ class Symbolizer;
struct 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(); }
bool found = false;
......@@ -54,6 +57,7 @@ struct SymbolizedFrame {
fbstring demangledName() const {
return name ? demangle(name) : fbstring();
}
private:
std::shared_ptr<ElfFile> file_;
};
......@@ -107,7 +111,14 @@ inline bool getStackTraceSafe(FrameArray<N>& 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_;
};
/**
......
......@@ -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]);
......
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