Linux 命令之 addr2line

本文介绍了一个简单的C++程序,该程序尝试执行除法操作但因除数为零而引发错误。通过使用g++编译器和addr2line工具,详细展示了如何定位导致程序崩溃的具体代码行。

先上程序


#include <stdio.h>
int divide(int a, int b) {
    return a/b;
}

int main() {
    fprintf(stdout, "input value\n");
    int a = 3, b = 0;
    int div = divide(a, b);
    fprintf(stdout, "div value: %d\n", div);
    return 0;
}

首先执行:

ubuntu:~/CPPWorkSpace/BasicCPP$ g++ -g main.cpp -o main

输出中包含一个文件  main, 如下图所示:

然后过滤一下:

ubuntu:~/CPPWorkSpace/BasicCPP$ dmesg | grep main

得到结果:

[    0.246864] PCI: MMCONFIG for domain 0000 [bus 00-7f] at [mem 0xf0000000-0xf7ffffff] (base 0xf0000000)
[    0.332945] PCI: MMCONFIG for domain 0000 [bus 00-7f] at [mem 0xf0000000-0xf7ffffff] (base 0xf0000000)
[    0.357689] ACPI: PCI Root Bridge [PCI0] (domain 0000 [bus 00-7e])
[    0.387227] iommu: Default domain type: Translated 
[    0.429714] NetLabel:  domain hash size = 128
[    1.182184] platform eisa.0: EISA: Cannot allocate resource for mainboard
[    2.655487] intel_rapl_common: Found RAPL domain package
[    2.655489] intel_rapl_common: Found RAPL domain core
[    2.655489] intel_rapl_common: Found RAPL domain uncore
[    2.655491] intel_rapl_common: Found RAPL domain dram
[ 7860.005797] traps: main[4727] trap divide error ip:55d8fcb1a6d8 sp:7ffd1c2168a0 error:0 in main[55d8fcb1a000+1000]

注意IP 字段符号,代表的是出错的位置地址

当前的执行环境是Ubuntu18.04 ,其实地址有偏移 ,所以要做作差

IP 地址减去后面的方框中地址,得到最终位置地址

55d8fcb1a6d8  —  55d8fcb1a000 =  6d8  (注意是十六进制)

所以写法为:0x6d8 

ubuntu:~/CPPWorkSpace/BasicCPP$ addr2line -e main 0x6d8 -f -a -p -C

最终定位到如下的行数

0x00000000000006d8: divide(int, int) at /home/mi/CPPWorkSpace/BasicCPP/main.cpp:4

定位到函数和对应的行数

addr2line 是一个强大的工具,用于将程序地址(如函数地址、指令指针地址)转换为源代码文件名和行号。其基本用法是 `addr2line -e <executable> <address>` [^1]。 addr2line 还有一些高级用法和技巧,能帮助更高效地调试和分析程序,其完整命令格式如下: `addr2line [-a| --addresses ] [-b bfdname | --target=bfdname] [-C | --demangle[=style]] [-e filename | --exe=filename] [-f | --function] [-s | --basename] [-i | --inlines] [-p | --pretty-print] [-j | --section=name] [-H | --help] [-V | --version] [addr addr ...]` [^3] 各选项的含义如下: - `-a| --addresses`:显示地址。 - `-b bfdname | --target=bfdname`:指定目标文件格式。 - `-C | --demangle[=style]`:将低级别的符号名解码成用户级别的名字。 - `-e filename | --exe=filename`:指定可执行文件。 - `-f | --function`:显示函数名。 - `-s | --basename`:只显示文件名的基名。 - `-i | --inlines`:显示内联函数。 - `-p | --pretty-print`:以更美观的格式输出。 - `-j | --section=name`:指定要从中读取地址的节。 - `-H | --help`:显示帮助信息。 - `-V | --version`:显示版本信息。 在实际应用中,addr2line 可用于定位导致程序崩溃的源码位置。在 Linux 开发中,程序崩溃时通常只能获取到十六进制内存地址,通过 addr2line 工具可以将这些地址转换为源代码位置,其核心流程为:在代码中植入 backtrace 逻辑捕获崩溃点堆栈,提取崩溃地址(如 ip:4005f5),使用 addr2line 解析地址对应的源码位置 [^4]。 ### 代码示例 ```c #include <execinfo.h> #include <stdio.h> #include <stdlib.h> #define MAX_STACK_FRAMES 100 void print_backtrace() { void *array[MAX_STACK_FRAMES]; size_t size; char **strings; size_t i; size = backtrace(array, MAX_STACK_FRAMES); strings = backtrace_symbols(array, size); if (strings != NULL) { for (i = 0; i < size; i++) { printf("%s\n", strings[i]); } free(strings); } } void func() { // 模拟崩溃 int *ptr = NULL; *ptr = 1; } int main() { print_backtrace(); func(); return 0; } ``` 编译上述代码时需要加上 `-g` 选项以保留调试信息,如 `gcc -g -o test test.c`。程序崩溃后,获取到崩溃地址,然后使用 `addr2line -e test <address>` 命令解析地址对应的源码位置。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值