Skip to content

Commit e144ae5

Browse files
committed
[symbolizer] Support symbol lookup
Recent versions of GNU binutils starting from 2.39 support symbol+offset lookup in addition to the usual numeric address lookup. This change adds symbol lookup to llvm-symbolize and llvm-addr2line. Now llvm-symbolize behaves closer to GNU addr2line, - if the value specified as address in command line or input stream is not a number, it is treated as a symbol name. For example: llvm-symbolize --obj=abc.so func_22 llvm-symbolize --obj=abc.so "CODE func_22" This lookup is now supported only for functions. Specification with offset is not supported yet. This is a recommit of 2b27948, reverted in 39fec54 because the test llvm/test/Support/interrupts.test started failing on Windows. The test was changed in 18f036d and is also updated in this commit. Differential Revision: https://reviews.llvm.org/D149759
1 parent fd8be1e commit e144ae5

24 files changed

+333
-42
lines changed

llvm/docs/CommandGuide/llvm-symbolizer.rst

+12-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ DESCRIPTION
1414
:program:`llvm-symbolizer` reads input names and addresses from the command-line
1515
and prints corresponding source code locations to standard output. It can also
1616
symbolize logs containing :doc:`Symbolizer Markup </SymbolizerMarkupFormat>` via
17-
:option:`--filter-markup`.
17+
:option:`--filter-markup`. Addresses may be specified as numbers or symbol names.
1818

1919
If no address is specified on the command-line, it reads the addresses from
2020
standard input. If no input name is specified on the command-line, but addresses
@@ -196,6 +196,17 @@ shows --relativenames.
196196
main
197197
foo/test.cpp:15:0
198198
199+
Example 7 - Addresses as symbol names:
200+
201+
.. code-block:: console
202+
203+
$ llvm-symbolizer --obj=test.elf main
204+
main
205+
/tmp/test.cpp:14:0
206+
$ llvm-symbolizer --obj=test.elf "CODE foz"
207+
foz
208+
/tmp/test.h:1:0
209+
199210
OPTIONS
200211
-------
201212

llvm/docs/ReleaseNotes.rst

+2
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,8 @@ Changes to the LLVM tools
201201
* ``llvm-nm`` now supports the ``--line-numbers`` (``-l``) option to use
202202
debugging information to print symbols' filenames and line numbers.
203203

204+
* llvm-symbolizer and llvm-addr2line now support addresses specified as symbol names.
205+
204206
Changes to LLDB
205207
---------------------------------
206208

llvm/include/llvm/DebugInfo/Symbolize/DIPrinter.h

+7
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class SourceCode;
3434
struct Request {
3535
StringRef ModuleName;
3636
std::optional<uint64_t> Address;
37+
StringRef Symbol;
3738
};
3839

3940
class DIPrinter {
@@ -46,6 +47,8 @@ class DIPrinter {
4647
virtual void print(const Request &Request, const DIGlobal &Global) = 0;
4748
virtual void print(const Request &Request,
4849
const std::vector<DILocal> &Locals) = 0;
50+
virtual void print(const Request &Request,
51+
const std::vector<DILineInfo> &Locations) = 0;
4952

5053
virtual bool printError(const Request &Request,
5154
const ErrorInfoBase &ErrorInfo) = 0;
@@ -91,6 +94,8 @@ class PlainPrinterBase : public DIPrinter {
9194
void print(const Request &Request, const DIGlobal &Global) override;
9295
void print(const Request &Request,
9396
const std::vector<DILocal> &Locals) override;
97+
void print(const Request &Request,
98+
const std::vector<DILineInfo> &Locations) override;
9499

95100
bool printError(const Request &Request,
96101
const ErrorInfoBase &ErrorInfo) override;
@@ -141,6 +146,8 @@ class JSONPrinter : public DIPrinter {
141146
void print(const Request &Request, const DIGlobal &Global) override;
142147
void print(const Request &Request,
143148
const std::vector<DILocal> &Locals) override;
149+
void print(const Request &Request,
150+
const std::vector<DILineInfo> &Locations) override;
144151

145152
bool printError(const Request &Request,
146153
const ErrorInfoBase &ErrorInfo) override;

llvm/include/llvm/DebugInfo/Symbolize/SymbolizableModule.h

+3
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ class SymbolizableModule {
3636
virtual std::vector<DILocal>
3737
symbolizeFrame(object::SectionedAddress ModuleOffset) const = 0;
3838

39+
virtual std::vector<object::SectionedAddress>
40+
findSymbol(StringRef Symbol) const = 0;
41+
3942
// Return true if this is a 32-bit x86 PE COFF module.
4043
virtual bool isWin32Module() const = 0;
4144

llvm/include/llvm/DebugInfo/Symbolize/SymbolizableObjectFile.h

+2
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ class SymbolizableObjectFile : public SymbolizableModule {
4343
DIGlobal symbolizeData(object::SectionedAddress ModuleOffset) const override;
4444
std::vector<DILocal>
4545
symbolizeFrame(object::SectionedAddress ModuleOffset) const override;
46+
std::vector<object::SectionedAddress>
47+
findSymbol(StringRef Symbol) const override;
4648

4749
// Return true if this is a 32-bit x86 PE COFF module.
4850
bool isWin32Module() const override;

llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h

+11
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,14 @@ class LLVMSymbolizer {
104104
Expected<std::vector<DILocal>>
105105
symbolizeFrame(ArrayRef<uint8_t> BuildID,
106106
object::SectionedAddress ModuleOffset);
107+
108+
Expected<std::vector<DILineInfo>> findSymbol(const ObjectFile &Obj,
109+
StringRef Symbol);
110+
Expected<std::vector<DILineInfo>> findSymbol(StringRef ModuleName,
111+
StringRef Symbol);
112+
Expected<std::vector<DILineInfo>> findSymbol(ArrayRef<uint8_t> BuildID,
113+
StringRef Symbol);
114+
107115
void flush();
108116

109117
// Evict entries from the binary cache until it is under the maximum size
@@ -146,6 +154,9 @@ class LLVMSymbolizer {
146154
Expected<std::vector<DILocal>>
147155
symbolizeFrameCommon(const T &ModuleSpecifier,
148156
object::SectionedAddress ModuleOffset);
157+
template <typename T>
158+
Expected<std::vector<DILineInfo>> findSymbolCommon(const T &ModuleSpecifier,
159+
StringRef Symbol);
149160

150161
Expected<SymbolizableModule *> getOrCreateModuleInfo(const ObjectFile &Obj);
151162

llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp

+26
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,17 @@ void PlainPrinterBase::print(const Request &Request,
260260
printFooter();
261261
}
262262

263+
void PlainPrinterBase::print(const Request &Request,
264+
const std::vector<DILineInfo> &Locations) {
265+
if (Locations.empty()) {
266+
print(Request, DILineInfo());
267+
} else {
268+
for (const DILineInfo &L : Locations)
269+
print(L, false);
270+
printFooter();
271+
}
272+
}
273+
263274
bool PlainPrinterBase::printError(const Request &Request,
264275
const ErrorInfoBase &ErrorInfo) {
265276
ErrHandler(ErrorInfo, Request.ModuleName);
@@ -273,6 +284,8 @@ static std::string toHex(uint64_t V) {
273284

274285
static json::Object toJSON(const Request &Request, StringRef ErrorMsg = "") {
275286
json::Object Json({{"ModuleName", Request.ModuleName.str()}});
287+
if (!Request.Symbol.empty())
288+
Json["SymName"] = Request.Symbol.str();
276289
if (Request.Address)
277290
Json["Address"] = toHex(*Request.Address);
278291
if (!ErrorMsg.empty())
@@ -362,6 +375,19 @@ void JSONPrinter::print(const Request &Request,
362375
printJSON(std::move(Json));
363376
}
364377

378+
void JSONPrinter::print(const Request &Request,
379+
const std::vector<DILineInfo> &Locations) {
380+
json::Array Definitions;
381+
for (const DILineInfo &L : Locations)
382+
Definitions.push_back(toJSON(L));
383+
json::Object Json = toJSON(Request);
384+
Json["Loc"] = std::move(Definitions);
385+
if (ObjectList)
386+
ObjectList->push_back(std::move(Json));
387+
else
388+
printJSON(std::move(Json));
389+
}
390+
365391
bool JSONPrinter::printError(const Request &Request,
366392
const ErrorInfoBase &ErrorInfo) {
367393
json::Object Json = toJSON(Request, ErrorInfo.message());

llvm/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp

+13
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,19 @@ std::vector<DILocal> SymbolizableObjectFile::symbolizeFrame(
351351
return DebugInfoContext->getLocalsForAddress(ModuleOffset);
352352
}
353353

354+
std::vector<object::SectionedAddress>
355+
SymbolizableObjectFile::findSymbol(StringRef Symbol) const {
356+
std::vector<object::SectionedAddress> Result;
357+
for (const SymbolDesc &Sym : Symbols) {
358+
if (Sym.Name.equals(Symbol)) {
359+
object::SectionedAddress A{Sym.Addr,
360+
getModuleSectionIndexForAddress(Sym.Addr)};
361+
Result.push_back(A);
362+
}
363+
}
364+
return Result;
365+
}
366+
354367
/// Search for the first occurence of specified Address in ObjectFile.
355368
uint64_t SymbolizableObjectFile::getModuleSectionIndexForAddress(
356369
uint64_t Address) const {

llvm/lib/DebugInfo/Symbolize/Symbolize.cpp

+44
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,50 @@ LLVMSymbolizer::symbolizeFrame(ArrayRef<uint8_t> BuildID,
231231
return symbolizeFrameCommon(BuildID, ModuleOffset);
232232
}
233233

234+
template <typename T>
235+
Expected<std::vector<DILineInfo>>
236+
LLVMSymbolizer::findSymbolCommon(const T &ModuleSpecifier, StringRef Symbol) {
237+
auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier);
238+
if (!InfoOrErr)
239+
return InfoOrErr.takeError();
240+
241+
SymbolizableModule *Info = *InfoOrErr;
242+
std::vector<DILineInfo> Result;
243+
244+
// A null module means an error has already been reported. Return an empty
245+
// result.
246+
if (!Info)
247+
return Result;
248+
249+
for (object::SectionedAddress A : Info->findSymbol(Symbol)) {
250+
DILineInfo LineInfo = Info->symbolizeCode(
251+
A, DILineInfoSpecifier(Opts.PathStyle, Opts.PrintFunctions),
252+
Opts.UseSymbolTable);
253+
if (LineInfo.FileName != DILineInfo::BadString) {
254+
if (Opts.Demangle)
255+
LineInfo.FunctionName = DemangleName(LineInfo.FunctionName, Info);
256+
Result.push_back(LineInfo);
257+
}
258+
}
259+
260+
return Result;
261+
}
262+
263+
Expected<std::vector<DILineInfo>>
264+
LLVMSymbolizer::findSymbol(const ObjectFile &Obj, StringRef Symbol) {
265+
return findSymbolCommon(Obj, Symbol);
266+
}
267+
268+
Expected<std::vector<DILineInfo>>
269+
LLVMSymbolizer::findSymbol(StringRef ModuleName, StringRef Symbol) {
270+
return findSymbolCommon(ModuleName.str(), Symbol);
271+
}
272+
273+
Expected<std::vector<DILineInfo>>
274+
LLVMSymbolizer::findSymbol(ArrayRef<uint8_t> BuildID, StringRef Symbol) {
275+
return findSymbolCommon(BuildID, Symbol);
276+
}
277+
234278
void LLVMSymbolizer::flush() {
235279
ObjectForUBPathAndArch.clear();
236280
LRUBinaries.clear();

llvm/test/Support/interrupts.test

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
## Show that SIGINT and similar signals don't cause crash messages to be
22
## reported.
33
# RUN: %python %s wrapper llvm-symbolizer 2> %t.err
4-
# RUN: count 0 < %t.err
4+
# RUN: FileCheck --input-file=%t.err %s
5+
6+
# CHECK: {{.*}} error: 'foo': {{[Nn]}}o such file or directory
7+
# CHECK-NOT: {{.+}}
58

69
import os
710
import signal
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
some text
1+
something not a valid address
22
0x40054d
3-
some text2
3+
some text possibly a symbol

llvm/test/tools/llvm-symbolizer/Inputs/discrim.inp

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ some text
55
0x4005b9
66
0x4005ce
77
0x4005d4
8-
some more text
8+
another text
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// This file is a part of sources used to build `symbols.so`, which is used to
2+
// test symbol location search made by llvm-symbolizer.
3+
//
4+
// Build instructions:
5+
// $ mkdir /tmp/dbginfo
6+
// $ cp symbols.h symbols.part1.cpp symbols.part2.cpp symbols.part3.c symbols.part4.c /tmp/dbginfo/
7+
// $ cd /tmp/dbginfo
8+
// $ gcc -osymbols.so -shared -fPIC -g symbols.part1.cpp symbols.part2.cpp symbols.part3.c symbols.part4.c
9+
10+
11+
extern "C" {
12+
extern int global_01;
13+
int func_01();
14+
int func_02(int);
15+
}
16+
17+
template<typename T> T func_03(T x) {
18+
return x + T(1);
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#include "symbols.h"
2+
3+
int global_01 = 22;
4+
5+
int static static_var = 0;
6+
7+
static int static_func_01(int x) {
8+
static_var = x;
9+
return global_01;
10+
}
11+
12+
int func_01() {
13+
int res = 1;
14+
return res + static_func_01(22);
15+
}
16+
17+
int func_04() {
18+
static_var = 0;
19+
return 22;
20+
}
21+
22+
int func_04(int x) {
23+
int res = static_var;
24+
return res + func_03(x);
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#include "symbols.h"
2+
3+
int static static_var = 4;
4+
5+
static int static_func_01(int x) {
6+
static_var--;
7+
return x;
8+
}
9+
10+
int func_02(int x) {
11+
static_var = x;
12+
return static_func_01(x);
13+
}
14+
15+
int func_05(int x) {
16+
int res = static_var;
17+
return res + func_03(x);
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
static int static_func(int);
2+
static int static_var = 0;
3+
4+
int static_func(int x) {
5+
static_var++;
6+
return static_var + x;
7+
}
8+
9+
int func_06(int x) {
10+
return static_func(x);
11+
}
12+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
static int static_func(int);
2+
static int static_var = 5;
3+
4+
int static_func(int x) {
5+
static_var++;
6+
return static_var + x;
7+
}
8+
9+
int func_07(int x) {
10+
static_var++;
11+
return static_func(x);
12+
}
13+
Binary file not shown.

0 commit comments

Comments
 (0)