在 Linux/C++ 开发中,程序崩溃后经常只能拿到一个地址,例如:

0x55b3d2d1a5fe

这时候如果没有源码行号,排查问题会非常困难。

addr2line 是 GNU Binutils 提供的一个非常实用的工具,可以把“地址”转换成:

  • 源文件

  • 函数名

  • 代码行号

非常适合:

  • core dump 分析

  • crash 日志定位

  • ASan/TSan/SIGSEGV 排查

  • 线上问题快速定位


一、addr2line 基本作用

核心功能:

addr2line -e 可执行文件 地址

例如:

addr2line -e app 0x4011c3

输出:

/home/test/main.cpp:25

说明:

  • 地址 0x4011c3

  • 对应 main.cpp

  • 第 25 行


二、准备一个示例程序

创建:

#include <iostream>

void crash()
{
    int *p = nullptr;
    *p = 100;
}

void test()
{
    crash();
}

int main()
{
    test();
    return 0;
}

文件名:

main.cpp

三、编译时必须带调试符号

这是很多人最容易遗漏的地方。

正确编译:

g++ -g -O0 main.cpp -o app

参数说明:

参数作用
-g生成调试符号
-O0关闭优化,避免行号混乱

如果没有 -g:

addr2line

将无法找到源码行号。


四、运行程序制造崩溃

执行:

./app

输出:

Segmentation fault (core dumped)

五、通过 gdb 获取崩溃地址

进入 gdb:

gdb ./app core

查看 backtrace:

(gdb) bt

示例输出:

#0  0x0000555555555169 in crash() at main.cpp:6
#1  0x0000555555555180 in test() at main.cpp:11
#2  0x0000555555555191 in main() at main.cpp:16

如果线上日志只有地址:

0x0000555555555169

就可以用 addr2line 分析。


六、使用 addr2line 定位源码

执行:

addr2line -e app 0x0000555555555169

输出:

/home/test/main.cpp:6

成功定位:

*p = 100;

七、显示函数名

增加:

-f

例如:

addr2line -f -e app 0x0000555555555169

输出:

crash
/home/test/main.cpp:6

含义:

  • 第一行:函数名

  • 第二行:源码位置


八、实际线上场景

很多线上日志类似:

signal 11 received
RIP: 0x7f12ab34cd91

或者:

backtrace:
0x55aa12345678
0x55aa12345789
0x55aa12345890

可以批量解析:

addr2line -f -C -e app \
0x55aa12345678 \
0x55aa12345789 \
0x55aa12345890

参数说明:

参数作用
-f显示函数名
-C反解 C++ 符号
-e指定 ELF 文件

九、C++ 符号反解

没有 -C:

_Z5crashv

加上:

-C

输出:

crash()

建议线上分析固定使用:

addr2line -f -C -e app 地址

十、配合 nm 使用

有时只有函数名,没有地址。

先查符号:

nm app | grep crash

输出:

0000000000001169 T _Z5crashv

然后:

addr2line -f -C -e app 0x1169

十一、为什么有时定位不准确

1. 编译时开启优化

例如:

-O2

会导致:

  • 内联

  • 指令重排

  • 行号错乱

建议问题排查阶段:

-g -O0

2. strip 删除符号

如果执行:

strip app

调试符号会被删除。

此时:

??
:0

解决方法:

保留独立 debug 文件:

objcopy --only-keep-debug app app.debug

3. 地址来自共享库

如果崩溃来自:

libxxx.so

必须指定对应 so:

addr2line -e libxxx.so 地址

十二、线上推荐命令

推荐直接封装:

addr2line -f -C -p -e app 地址

参数:

参数作用
-f函数名
-Cdemangle
-p单行输出

示例:

addr2line -f -C -p -e app 0x555555555169

输出:

crash at /home/test/main.cpp:6

十三、批量解析脚本

实际工作中很常用。

#!/bin/bash

APP=./app

for addr in "$@"
do
    addr2line -f -C -p -e $APP $addr
done

使用:

./decode.sh \
0x555555555169 \
0x555555555180

十四、与 ASan 配合使用

ASan 日志中常见:

#0 0x55d8e0b2d1c3 in crash()

有时 ASan 已经给出行号。

但如果没有:

addr2line -f -C -e app 地址

依然可以快速定位。


十五、总结

addr2line 是 Linux/C++ 崩溃分析中的基础工具。

核心流程:

崩溃地址
    ↓
addr2line
    ↓
源码文件 + 行号

推荐牢记:

addr2line -f -C -p -e app 地址

这是线上排查问题最常用的组合。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐