1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
|
//===------- 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
|