How to use addr2line

addr2line 是 GNU Binutils 提供的一个调试工具,用于将程序地址转换为源代码文件 + 行号。
其底层依赖 ELF 文件中的 DWARF 调试信息。

典型使用场景:

  • core dump 分析
  • 崩溃栈回溯解析
  • 日志中只有地址信息
  • 线上二进制与调试符号分离

示例分析

例如某崩溃日志中看到:

1
2
.../your_binary(_ZN19MyTableC1EPS_+0x10d)[0x1f792fd]
......

含义:

  • ZN19MyTableC1EPS → C++ mangled 名字
  • +0x10d → 相对于函数起始地址的偏移
  • [0x1f792fd] → 实际程序地址
  1. 如果符号信息在可执行文件上

    1
    addr2line -e your_binary -f -C 0x1f792fd
  2. use eu-addr2line 加载symbol

    1
    eu-addr2line -e ./your_binary --debuginfo-path=./your_binary.debug 0x1f792fd

    output:
    mytable/MyTable.cpp:1070

  3. 只有函数名 + 偏移
    例如日志只有: MyTable::insert+0x52
    需要手动计算地址。

    • 查函数起始地址
      1
      nm -C your_binary | grep my_func

      如果 binary 已 strip,需要对 debug 文件执行 nm:

      1
      objdump -t your_binary | grep MyTable::insert
      假设得到:
      1
      0000000000401230 T MyTable::insert
    • 加上偏移
      1
      0x401230 + 0x52 = 0x401282
    • 再 addr2line
      1
      addr2line -e your_binary -f -C 0x401282

PIE / ASLR 注意事项

如果二进制是 PIE(Position Independent Executable):

1
readelf -h your_binary | grep Type

如果看到:

1
Type: DYN (Position-Independent Executable file)

说明是 PIE。

这时:

  • 崩溃日志中的地址 = load_base + offset

  • 必须减去加载基地址

在 core dump 中:

1
info proc mappings

或者

1
cat /proc/<pid>/maps

找到加载基址,例如:

1
2
7f3c2d400000-...
真实地址 = 崩溃地址 - 基址

再传给 addr2line。

否则会解析失败或定位错误。

常用排错检查

  1. 是否包含调试信息

    1
    readelf --sections your_binary | grep debug
  2. 是否被 strip

    1
    file your_binary