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);
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;
}
// 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_);
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;
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:
} // namespace
void SymbolizedFrame::set(const std::shared_ptr<ElfFile>& file,
- uintptr_t address) {
+ uintptr_t address,
+ Dwarf::LocationInfoMode mode) {
clear();
found = true;
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,
auto const adjusted = addr - base;
if (elfFile->getSectionContainingAddress(adjusted)) {
- frame.set(elfFile, adjusted);
+ frame.set(elfFile, adjusted, mode_);
--remaining;
}
}
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;
fbstring demangledName() const {
return name ? demangle(name) : fbstring();
}
+
private:
std::shared_ptr<ElfFile> file_;
};
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.
}
private:
- ElfCacheBase* const cache_ = nullptr;
+ ElfCacheBase* const cache_;
+ const Dwarf::LocationInfoMode mode_;
};
/**
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");
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]);