addr2line 是一个用于将程序地址转换为源代码位置(文件名和行号)的命令行工具。它可以帮助你在调试和分析程序崩溃或错误时确定问题出现的位置。
使用 addr2line 命令需要提供可执行文件的路径和要查询的地址。它会解析可执行文件的调试符号表,并根据给定的地址查找对应的源代码位置。
举例
假设我们的程序在运行时发生了崩溃,错误信息包含了地址 "0x12345",我们要通过这个地址找到原始的源代码位置。
1. 我们可以先使用 nm 工具查看可执行文件中的符号表信息,找到与地址 "0x12345" 相关的函数名称
nm -C -A -l myprogram > myprogram_symbols.txt
有时提示
no symbols,意味着so的符号表被剥离了,需要提供带有符号表信息的so文件
nm的所有选项
$ nm -h
Usage: nm [option(s)] [file(s)]
List symbols in [file(s)] (a.out by default).
The options are:
-a, --debug-syms Display debugger-only symbols
-A, --print-file-name Print name of the input file before every symbol
-B Same as --format=bsd
-C, --demangle[=STYLE] Decode mangled/processed symbol names
STYLE can be "none", "auto", "gnu-v3", "java",
"gnat", "dlang", "rust"
--no-demangle Do not demangle low-level symbol names
--recurse-limit Enable a demangling recursion limit. (default)
--no-recurse-limit Disable a demangling recursion limit.
-D, --dynamic Display dynamic symbols instead of normal symbols
-e (ignored)
-f, --format=FORMAT Use the output format FORMAT. FORMAT can be `bsd',
`sysv', `posix' or 'just-symbols'.
The default is `bsd'
-g, --extern-only Display only external symbols
--ifunc-chars=CHARS Characters to use when displaying ifunc symbols
-j, --just-symbols Same as --format=just-symbols
-l, --line-numbers Use debugging information to find a filename and
line number for each symbol # 显示文件:行号
-n, --numeric-sort Sort symbols numerically by address
-o Same as -A
-p, --no-sort Do not sort the symbols
-P, --portability Same as --format=posix
-r, --reverse-sort Reverse the sense of the sort
--plugin NAME Load the specified plugin
-S, --print-size Print size of defined symbols
-s, --print-armap Include index for symbols from archive members
--quiet Suppress "no symbols" diagnostic
--size-sort Sort symbols by size
--special-syms Include special symbols in the output
--synthetic Display synthetic symbols as well
-t, --radix=RADIX Use RADIX for printing symbol values
--target=BFDNAME Specify the target object format as BFDNAME
-u, --undefined-only Display only undefined symbols
-U, --defined-only Display only defined symbols
--unicode={default|show|invalid|hex|escape|highlight}
Specify how to treat UTF-8 encoded unicode characters
-W, --no-weak Ignore weak symbols
--with-symbol-versions Display version strings after symbol names
-X 32_64 (ignored)
@FILE Read options from FILE
-h, --help Display this information
-V, --version Display this program's version number
nm: supported targets: pe-x86-64 pei-x86-64 pe-bigobj-x86-64 elf64-x86-64 pe-i386 pei-i386 elf32-i386 elf32-iamcu pdb elf64-little elf64-big elf32-little elf32-big srec symbolsrec verilog tekhex binary ihex plugin
2. 用 addr2line 命令将该函数名称转换为对应的源代码文件名和行号等信息。
$ addr2line -h
Usage: addr2line [option(s)] [addr(s)]
Convert addresses into line number/file name pairs.
If no addresses are specified on the command line, they will be read from stdin
The options are:
@<file> Read options from <file>
-a --addresses Show addresses
-b --target=<bfdname> Set the binary file format
-e --exe=<executable> Set the input file name (default is a.out) #可执行程序地址
-i --inlines Unwind inlined functions
-j --section=<name> Read section-relative offsets instead of addresses
-p --pretty-print Make the output easier to read for humans # 美化打印结果
-s --basenames Strip directory names
-f --functions Show function names # 函数名
-C --demangle[=style] Demangle function names # 将C++编译器生成的符号名还原成可读的函数名
-R --recurse-limit Enable a limit on recursion whilst demangling. [Default]
-r --no-recurse-limit Disable a limit on recursion whilst demangling
-h --help Display this information
-v --version Display the program's version
addr2line: supported targets: pe-x86-64 pei-x86-64 pe-bigobj-x86-64 elf64-x86-64 pe-i386 pei-i386 elf32-i386 elf32-iamcu pdb elf64-little elf64-big elf32-little elf32-big srec symbolsrec verilog tekhex binary ihex plugin
Report bugs to <https://sourceware.org/bugzilla/>
验证
可以看到的确是和nm的符号表里面的数据对应了
但是发现leaktracer的泄露报告里面的内存地址对不上,
nm -C -A -l libleaktracer.so > libleaktracer.txt
$ addr2line -e libleaktracer.so 0x3c3fe
D:\android\android-projects\NativeMemoryLeakDetector\NativeMemoryLeakDetector\app\.externalNativeBuild\cmake\debug\armeabi-v7a/D:/android/android-projects/NativeMemoryLeakDetector/NativeMemoryLeakDetector/app/src/main/cpp/libleaktracer/src/MemoryTrace.cpp:310
# 这个结果非常长,是因为android对源文件的路径处理造成的
0x3c3fe在libleaktracer.txt没找到,但是addr2line却出现了
nm和objdump
nm和objdump是两个常用的工具,用于对二进制文件进行分析和调试。它们之间有以下区别:
-
功能:
- nm工具主要用于查看二进制文件中的符号表信息,包括函数名、变量名等与地址的关联。
- objdump工具提供了更全面的功能,可以显示二进制文件的汇编代码、符号表、重定位表、段信息等。
-
输出格式:
- nm输出简洁,一般只显示符号名和地址(或其他标记)。适合快速查看符号信息。
- objdump输出详细,可以显示汇编代码、符号表、段信息以及其他附加信息。适合深入分析二进制文件。
-
用途:
- nm主要用于检查符号表,帮助定位函数和变量的地址,方便调试和符号查找。
- objdump提供了更多的信息,可用于查看汇编代码、了解程序的结构、查找特定的代码片段等。
-
命令行参数:
- nm命令通常使用
nm <二进制文件>的格式。可以在命令行中指定不同的选项来改变输出格式或筛选特定类型的符号。 - objdump命令的使用更加复杂,可以通过指定不同的选项来控制输出内容,如
-d用于显示汇编代码,-s用于显示符号表和段信息等。
- nm命令通常使用
总体而言,nm主要用于检查符号表信息,objdump提供了更全面的二进制文件分析功能。根据具体的需求,可以选择使用适合的工具来进行分析和调试。