blob: 3955469dfc0e6bdf29805884a8f6d476c059b2ac [file] [log] [blame] [edit]
//===------- BacktraceTools.cpp - Backtrace symbolication tools ----------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "llvm/ExecutionEngine/Orc/BacktraceTools.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ExecutionEngine/JITLink/JITLink.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/MemoryBuffer.h"
namespace llvm::orc {
Expected<std::shared_ptr<SymbolTableDumpPlugin>>
SymbolTableDumpPlugin::Create(StringRef Path) {
std::error_code EC;
auto P = std::make_shared<SymbolTableDumpPlugin>(Path, EC);
if (EC)
return createFileError(Path, EC);
return P;
}
SymbolTableDumpPlugin::SymbolTableDumpPlugin(StringRef Path,
std::error_code &EC)
: OutputStream(Path, EC) {}
void SymbolTableDumpPlugin::modifyPassConfig(
MaterializationResponsibility &MR, jitlink::LinkGraph &G,
jitlink::PassConfiguration &Config) {
Config.PostAllocationPasses.push_back([this](jitlink::LinkGraph &G) -> Error {
std::scoped_lock<std::mutex> Lock(DumpMutex);
OutputStream << "\"" << G.getName() << "\"\n";
for (auto &Sec : G.sections()) {
// NoAlloc symbols don't exist in the executing process, so can't
// contribute to symbolication. (Note: We leave Finalize-liftime symbols
// in for now in case of crashes during finalization, but we should
// probably make this optional).
if (Sec.getMemLifetime() == MemLifetime::NoAlloc)
continue;
// Write out named symbols. Anonymous symbols are skipped, since they
// don't add any information for symbolication purposes.
for (auto *Sym : Sec.symbols()) {
if (Sym->hasName())
OutputStream << formatv("{0:x}", Sym->getAddress().getValue()) << " "
<< Sym->getName() << "\n";
}
}
OutputStream.flush();
return Error::success();
});
}
Expected<DumpedSymbolTable> DumpedSymbolTable::Create(StringRef Path) {
auto MB = MemoryBuffer::getFile(Path);
if (!MB)
return createFileError(Path, MB.getError());
return DumpedSymbolTable(std::move(*MB));
}
DumpedSymbolTable::DumpedSymbolTable(std::unique_ptr<MemoryBuffer> SymtabBuffer)
: SymtabBuffer(std::move(SymtabBuffer)) {
parseBuffer();
}
void DumpedSymbolTable::parseBuffer() {
// Read the symbol table file
SmallVector<StringRef, 0> Rows;
SymtabBuffer->getBuffer().split(Rows, '\n');
StringRef CurGraph = "<unidentified>";
for (auto Row : Rows) {
Row = Row.trim();
if (Row.empty())
continue;
// Check for graph name line (enclosed in quotes)
if (Row.starts_with("\"") && Row.ends_with("\"")) {
CurGraph = Row.trim('"');
continue;
}
// Parse "address symbol_name" lines, ignoring malformed lines.
size_t SpacePos = Row.find(' ');
if (SpacePos == StringRef::npos)
continue;
StringRef AddrStr = Row.substr(0, SpacePos);
StringRef SymName = Row.substr(SpacePos + 1);
uint64_t Addr;
if (AddrStr.starts_with("0x"))
AddrStr = AddrStr.drop_front(2);
if (AddrStr.getAsInteger(16, Addr))
continue; // Skip malformed lines
SymbolInfos[Addr] = {SymName, CurGraph};
}
}
std::string DumpedSymbolTable::symbolicate(StringRef Backtrace) {
// Symbolicate the backtrace by replacing rows with empty symbol names
SmallVector<StringRef, 0> BacktraceRows;
Backtrace.split(BacktraceRows, '\n');
std::string Result;
raw_string_ostream Out(Result);
for (auto Row : BacktraceRows) {
// Look for a row ending with a hex number. If there's only one column, or
// if the last column is not a hex number, then just reproduce the input
// row.
auto [RowStart, AddrCol] = Row.rtrim().rsplit(' ');
auto AddrStr = AddrCol.starts_with("0x") ? AddrCol.drop_front(2) : AddrCol;
uint64_t Addr;
if (AddrStr.empty() || AddrStr.getAsInteger(16, Addr)) {
Out << Row << "\n";
continue;
}
// Search for the address
auto I = SymbolInfos.upper_bound(Addr);
// If no JIT symbol entry within 2Gb then skip.
if (I == SymbolInfos.begin() || (Addr - std::prev(I)->first >= 1U << 31)) {
Out << Row << "\n";
continue;
}
// Found a symbol. Output modified line.
auto &[SymAddr, SymInfo] = *std::prev(I);
Out << RowStart << " " << AddrCol << " " << SymInfo.SymName;
if (auto Delta = Addr - SymAddr)
Out << " + " << formatv("{0}", Delta);
Out << " (" << SymInfo.GraphName << ")\n";
}
return Result;
}
} // namespace llvm::orc