llvm-symbolizer - 将地址转换为源代码位置¶
概要¶
llvm-symbolizer [选项] [地址…]
描述¶
llvm-symbolizer 从命令行读取输入名称和地址,并将相应的源代码位置打印到标准输出。它还可以通过 --filter-markup
符号化包含 符号化标记 的日志。地址可以指定为数字或符号名称。
如果命令行上未指定地址,则从标准输入读取地址。如果命令行上未指定输入名称,但指定了地址,则第一个地址值将被视为输入名称。如果未识别输入值,则报告未找到源信息。
输入名称可以与地址一起指定在标准输入或命令行的位置参数中。默认情况下,输入名称被解释为目标文件路径。但是,在名称前加上 BUILDID:
表示它是一个十六进制构建 ID 而不是路径。这将查找相应的调试二进制文件。为了保持一致性,在名称前加上 FILE:
明确表示它是一个目标文件路径(默认值)。
位置参数或标准输入值可以以“DATA”或“CODE”开头,以指示地址应分别作为数据或可执行代码进行符号化。如果两者都没有指定,则假定为“CODE”。DATA 被符号化为地址和符号大小,而不是行号。
llvm-symbolizer 在解析命令行选项后,从环境变量 LLVM_SYMBOLIZER_OPTS
解析选项。 LLVM_SYMBOLIZER_OPTS
主要用于在其他程序或运行时调用 llvm-symbolizer 时补充命令行选项。
示例¶
以下所有示例都使用以下两个源文件作为输入。它们混合使用 C 样式和 C++ 样式的链接来说明这些名称是如何以不同方式打印的(参见 --demangle
)。
// test.h
extern "C" inline int foz() {
return 1234;
}
// test.cpp
#include "test.h"
int bar=42;
int foo() {
return bar;
}
int baz() {
volatile int k = 42;
return foz() + k;
}
int main() {
return foo() + baz();
}
这些文件构建如下
$ clang -g test.cpp -o test.elf
$ clang -g -O2 test.cpp -o inlined.elf
示例 1 - 命令行上的地址和对象
$ llvm-symbolizer --obj=test.elf 0x4004d0 0x400490
foz
/tmp/test.h:1:0
baz()
/tmp/test.cpp:11:0
示例 2 - 标准输入上的地址
$ cat addr.txt
0x4004a0
0x400490
0x4004d0
$ llvm-symbolizer --obj=test.elf < addr.txt
main
/tmp/test.cpp:15:0
baz()
/tmp/test.cpp:11:0
foz
/tmp/./test.h:1:0
示例 3 - 使用地址指定的对象
$ llvm-symbolizer "test.elf 0x400490" "FILE:inlined.elf 0x400480"
baz()
/tmp/test.cpp:11:0
foo()
/tmp/test.cpp:8:10
$ cat addr2.txt
FILE:test.elf 0x4004a0
inlined.elf 0x400480
$ llvm-symbolizer < addr2.txt
main
/tmp/test.cpp:15:0
foo()
/tmp/test.cpp:8:10
示例 4 - BUILDID 和 FILE 前缀
$ llvm-symbolizer "FILE:test.elf 0x400490" "DATA BUILDID:123456789abcdef 0x601028"
baz()
/tmp/test.cpp:11:0
bar
6295592 4
$ cat addr3.txt
FILE:test.elf 0x400490
DATA BUILDID:123456789abcdef 0x601028
$ llvm-symbolizer < addr3.txt
baz()
/tmp/test.cpp:11:0
bar
6295592 4
示例 5 - CODE 和 DATA 前缀
$ llvm-symbolizer --obj=test.elf "CODE 0x400490" "DATA 0x601028"
baz()
/tmp/test.cpp:11:0
bar
6295592 4
$ cat addr4.txt
CODE test.elf 0x4004a0
DATA inlined.elf 0x601028
$ llvm-symbolizer < addr4.txt
main
/tmp/test.cpp:15:0
bar
6295592 4
示例 6 - 路径样式选项
此示例使用与上面相同的源文件,但源文件的完整路径为 /tmp/foo/test.cpp,并且编译如下。第一种情况显示默认的绝对路径,第二种情况显示 –basenames,第三种情况显示 –relativenames。
$ pwd
/tmp
$ clang -g foo/test.cpp -o test.elf
$ llvm-symbolizer --obj=test.elf 0x4004a0
main
/tmp/foo/test.cpp:15:0
$ llvm-symbolizer --obj=test.elf 0x4004a0 --basenames
main
test.cpp:15:0
$ llvm-symbolizer --obj=test.elf 0x4004a0 --relativenames
main
foo/test.cpp:15:0
示例 7 - 地址作为符号名称
$ llvm-symbolizer --obj=test.elf main
main
/tmp/test.cpp:14:0
$ llvm-symbolizer --obj=test.elf "CODE foz"
foz
/tmp/test.h:1:0
示例 8 - 没有行对应关系的地址(与行零关联的地址)的 --skip-line-zero
输出
// test.c
int foo = 0;
int x = 1234;
int main() {
if (x)
return foo;
else
return x;
}
这些文件构建如下
$ clang -g -O2 -S test.c -o test.s
$ llvm-mc -filetype=obj -triple=x86_64-unknown-linux test.s -o test.o
$ llvm-symbolizer --obj=test.o --skip-line-zero 0xa
main
/tmp/test.c:5:7 (approximate)
选项¶
- --adjust-vma <偏移量>¶
在执行查找时,将指定的偏移量添加到目标文件地址。这可以用来执行查找,就好像目标文件已通过偏移量重新定位一样。
- --skip-line-zero¶
如果地址没有关联的行号,则使用行表中当前序列中的最后一行号。此类行在输出中标记为“近似”,因为它们可能具有误导性。
- --basenames, -s¶
打印文件的名称,不带任何目录,而不是绝对路径。
- --color [=<always|auto|never>]¶
指定是否在
--filter-markup
模式下使用颜色。默认为auto
,它检测标准输出是否支持颜色。仅指定--color
等效于--color=always
。
- --debug-file-directory <路径>¶
提供一个路径到包含 .build-id 子目录的目录,以搜索剥离二进制文件的调试信息。按给定顺序搜索此参数的多个实例。
- --debuginfod, --no-debuginfod¶
是否尝试对调试二进制文件进行 debuginfod 查找。除非指定,否则仅当编译了 libcurl(
LLVM_ENABLE_CURL
)并且环境变量DEBUGINFOD_URLS
提供了至少一个服务器 URL 时,才会启用 debuginfod。
- --demangle, -C¶
打印反混淆的函数名称,如果名称被混淆(例如,混淆的名称 _Z3bazv 变成 baz(),而未混淆的名称 foz 按原样打印)。默认为 true。
- --dwp <路径>¶
对任何具有拆分 DWARF 调试数据的 CU 使用
<path>
中指定 DWP 文件。
- --fallback-debug-path <路径>¶
当单独的文件包含调试数据,并且由 GNU 调试链接部分引用时,如果无法相对于对象找到调试数据,则使用指定的路径作为查找调试数据的基础。
- --filter-markup¶
从标准输入读取,将包含的 符号化标记 转换为人类可读的形式,并将结果打印到标准输出。以下标记元素尚不受支持
{{{hexdict}}}
{{{dumpfile}}}
{{{bt}}}
回溯元素使用以下语法报告帧#<number>[.<inline>] <address> <function> <file>:<line>:<col> (<module>+<relative address>)
<inline>
为内联到调用者(对应于<number>
)中的调用的帧提供帧号。内联调用号从 1 开始,从被调用者到调用者递增。<address>
是调用指令内部的地址,指向该函数。该地址可能不是指令的开头。<relative address>
是加载到该地址的<module>
中相应的虚拟偏移量。
- --functions [=<none|short|linkage>], -f¶
指定打印函数名称的方式(省略函数名称、打印简短函数名称或打印完整链接名称)。默认为
linkage
。
- --help, -h¶
显示此命令的帮助和用法。
- --inlining, --inlines, -i¶
如果源代码位置位于内联函数中,则打印所有内联帧。这是默认设置。
- --no-inlines¶
不打印内联帧。
- --no-demangle¶
不要打印解符号后的函数名称。
- --obj <path>, --exe, -e¶
要符号化的目标文件路径。如果指定了
-
,则直接从标准输入流读取对象。与--build-id
互斥。
- --output-style <LLVM|GNU|JSON>¶
指定首选的输出样式。默认为
LLVM
。当输出样式设置为GNU
时,该工具遵循GNU的addr2line的样式。与LLVM
样式的不同之处在于不打印源代码位置的列。
在地址报告后不添加空行。
当未显示内联帧时,不将内联函数的名称替换为最顶层调用者的名称。
当地址的调试数据鉴别器非零时打印它。一种生成鉴别器的方法是使用clang的-fdebug-info-for-profiling进行编译。
JSON
样式提供机器可读的JSON输出。如果地址是通过stdin提供的,则输出JSON将是一系列单独的对象。否则,所有结果都将包含在一个数组中。
$ llvm-symbolizer --obj=inlined.elf 0x4004be 0x400486 -p baz() at /tmp/test.cpp:11:18 (inlined by) main at /tmp/test.cpp:15:0 foo() at /tmp/test.cpp:6:3 $ llvm-symbolizer --output-style=LLVM --obj=inlined.elf 0x4004be 0x400486 -p --no-inlines main at /tmp/test.cpp:11:18 foo() at /tmp/test.cpp:6:3 $ llvm-symbolizer --output-style=GNU --obj=inlined.elf 0x4004be 0x400486 -p --no-inlines baz() at /tmp/test.cpp:11 foo() at /tmp/test.cpp:6 $ clang -g -fdebug-info-for-profiling test.cpp -o profiling.elf $ llvm-symbolizer --output-style=GNU --obj=profiling.elf 0x401167 -p --no-inlines main at /tmp/test.cpp:15 (discriminator 2) $ llvm-symbolizer --output-style=JSON --obj=inlined.elf 0x4004be 0x400486 -p [ { "Address": "0x4004be", "ModuleName": "inlined.elf", "Symbol": [ { "Column": 18, "Discriminator": 0, "FileName": "/tmp/test.cpp", "FunctionName": "baz()", "Line": 11, "StartAddress": "0x4004be", "StartFileName": "/tmp/test.cpp", "StartLine": 9 }, { "Column": 0, "Discriminator": 0, "FileName": "/tmp/test.cpp", "FunctionName": "main", "Line": 15, "StartAddress": "0x4004be", "StartFileName": "/tmp/test.cpp", "StartLine": 14 } ] }, { "Address": "0x400486", "ModuleName": "inlined.elf", "Symbol": [ { "Column": 3, "Discriminator": 0, "FileName": "/tmp/test.cpp", "FunctionName": "foo()", "Line": 6, "StartAddress": "0x400486", "StartFileName": "/tmp/test.cpp", "StartLine": 5 } ] } ]
- --pretty-print, -p¶
打印人类可读的输出。如果指定了
--inlining
,则封闭作用域以(inlined by)为前缀。对于JSON输出,该选项将导致JSON缩进并在新行中拆分。否则,JSON输出将以紧凑形式打印。$ llvm-symbolizer --obj=inlined.elf 0x4004be --inlining --pretty-print baz() at /tmp/test.cpp:11:18 (inlined by) main at /tmp/test.cpp:15:0
- --print-address, --addresses, -a¶
在源代码位置之前打印地址。默认为false。
$ llvm-symbolizer --obj=inlined.elf --print-address 0x4004be 0x4004be baz() /tmp/test.cpp:11:18 main /tmp/test.cpp:15:0 $ llvm-symbolizer --obj=inlined.elf 0x4004be --pretty-print --print-address 0x4004be: baz() at /tmp/test.cpp:11:18 (inlined by) main at /tmp/test.cpp:15:0
- --print-source-context-lines <N>¶
为每个符号化的地址打印
N
行源代码上下文。$ llvm-symbolizer --obj=test.elf 0x400490 --print-source-context-lines=3 baz() /tmp/test.cpp:11:0 10 : volatile int k = 42; 11 >: return foz() + k; 12 : }
- --relativenames¶
打印相对于编译目录的文件路径,而不是绝对路径。如果编译器的命令行包含完整路径,则这将与默认值相同。
- --verbose¶
打印详细的地址、行和列信息。
$ llvm-symbolizer --obj=inlined.elf --verbose 0x4004be baz() Filename: /tmp/test.cpp Function start filename: /tmp/test.cpp Function start line: 9 Function start address: 0x4004b6 Line: 11 Column: 18 main Filename: /tmp/test.cpp Function start filename: /tmp/test.cpp Function start line: 14 Function start address: 0x4004b0 Line: 15 Column: 18
- --version, -v¶
打印工具的版本信息。
- @<FILE>¶
从响应文件<FILE>读取命令行选项。
WINDOWS/PDB 特定选项¶
- --dia¶
使用Windows DIA SDK进行符号化。如果找不到DIA SDK,llvm-symbolizer将回退到原生实现。
MACH-O 特定选项¶
- --default-arch <arch>¶
如果二进制文件包含多个架构的目标文件(例如,它是Mach-O通用二进制文件),则为给定架构符号化目标文件。您也可以通过在输入中写入
binary_name:arch_name
来指定架构(请参见下面的示例)。如果未以任何方式指定架构,则不会符号化地址。默认为空字符串。$ cat addr.txt /tmp/mach_universal_binary:i386 0x1f84 /tmp/mach_universal_binary:x86_64 0x100000f24 $ llvm-symbolizer < addr.txt _main /tmp/source_i386.cc:8 _main /tmp/source_x86_64.cc:8
- --dsym-hint <path/to/file.dSYM>¶
如果二进制文件的调试信息不在默认位置,请在通过此选项提供的.dSYM路径中查找调试信息。此标志可以多次使用。
退出状态¶
llvm-symbolizer 返回 0。其他退出代码表示内部程序错误。