addr2line 回复“问号”问题的解决和一些发现

我在尝试使用LTTng的prebuilt user space tracing helper来自动插入trace point来监控函数的进出。

这一套东西的原理是利用gcc 的-finstrument-functions参数,在函数的进出口插入hook,动态链接到liblttng-ust-cyg-profile.so来提供被hook的代码用来发射event。

在记录的trace log 的field里。是以地址的形式记录进出口位置。
例如:

[17:58:51.390638416] (+0.000000542) PC lttng_ust_cyg_profile:func_exit: { cpu_id = 9 }, { addr = 0x5609DC20A642, call_site = 0x5609DC20ACA6 }
[17:58:51.390639034] (+0.000000618) PC lttng_ust_cyg_profile:func_entry: { cpu_id = 9 }, { addr = 0x5609DC20A1A4, call_site = 0x5609DC20ACB6 }
[17:58:51.390639560] (+0.000000526) PC lttng_ust_cyg_profile:func_exit: { cpu_id = 9 }, { addr = 0x5609DC20A1A4, call_site = 0x5609DC20ACB6 }

如果需要知道调用的是哪个函数,需要将地址翻译成符号名。用到addr2line

下面出现了惊喜一幕:

>>addr2line 0x5609DC20A1A4  -e tp_test -f -s -C
回复:
>>??
>>??:0

经过一番研究,发现需要添加几个编译链接参数,可解决问题:

  • -g
    编译时加-g,可以在文件中保留调试信息。

*-rdynamic
链接时 添加 - rdynamic 用来通知链接器将所有符号添加到动态符号表中。

*-no-pie

What version of addr2line do you use? – 
ssbssa
 Dec 9, 2021 at 11:24
@ssbssa I'm using addr2line 2.34. – 
ChrisZZ
 Dec 9, 2021 at 11:36
Now I see the problem, the newer executable has ASLR enabled, that's why the addresses are so high (0x55baa10213f1). So the debug information in the executable uses a different base address than the actual running executable. – 
ssbssa
 Dec 9, 2021 at 12:04
@ssbssa I'm now even more confused.. How can I disable ASLR temporarily for gcc? I tried gcc -fno-stack-protector -z execstack but not working. – 
ChrisZZ
 Dec 9, 2021 at 12:45
Try compiling with -no-pie. – 
ssbssa
 Dec 9, 2021 at 13:43
@ssbssa Thank you! Actually before asking this question I tried with adding -fno-pie but didn't work. Now with full command ` gcc -g -rdynamic -no-pie x.c` it works! – 
ChrisZZ
 Dec 10, 2021 at 0:59

高版本的GCC 默认使用了ASLR,ASLR(Address space layout randomization)是一种针对缓冲区溢出的安全保护技术,通过对堆、栈、共享库映射等线性区布局的随机化,通过增加攻击者预测目的地址的难度,防止攻击者直接定位攻击代码位置,达到阻止溢出攻击的目的。

这个也许是问题的根源。

在链接中加入-no-pie来关闭PIE,来解决问题。我这里在编译和链接都加上了-no-pie。因为只在编译处加上似乎没有解决问题。

结果:

[17:58:51.390636664] (+0.000000529) PC lttng_ust_cyg_profile:func_exit: { cpu_id = 9 }, { addr = 0x5609DC20B191, call_site = 0x5609DC20AB02 }
[17:58:51.390637270] (+0.000000606) PC lttng_ust_cyg_profile:func_exit: { cpu_id = 9 }, { addr = 0x5609DC20AAD2, call_site = 0x5609DC20AC96 }
[17:58:51.390637874] (+0.000000604) PC lttng_ust_cyg_profile:func_entry: { cpu_id = 9 }, { addr = 0x5609DC20A642, call_site = 0x5609DC20ACA6 }
[17:58:51.390638416] (+0.000000542) PC lttng_ust_cyg_profile:func_exit: { cpu_id = 9 }, { addr = 0x5609DC20A642, call_site = 0x5609DC20ACA6 }
[17:58:51.390639034] (+0.000000618) PC lttng_ust_cyg_profile:func_entry: { cpu_id = 9 }, { addr = 0x5609DC20A1A4, call_site = 0x5609DC20ACB6 }
[17:58:51.390639560] (+0.000000526) PC lttng_ust_cyg_profile:func_exit: { cpu_id = 9 }, { addr = 0x5609DC20A1A4, call_site = 0x5609DC20ACB6 }
[17:58:51.390653259] (+0.000013699) PC lttng_ust_cyg_profile:func_entry: { cpu_id = 0 }, { addr = 0x404BF8, call_site = 0x403E48 }
[17:58:51.390654040] (+0.000000781) PC lttng_ust_cyg_profile:func_entry: { cpu_id = 0 }, { addr = 0x40480B, call_site = 0x404C30 }
[17:58:51.390654617] (+0.000000577) PC lttng_ust_cyg_profile:func_entry: { cpu_id = 0 }, { addr = 0x404341, call_site = 0x40483F }
[17:58:51.390655219] (+0.000000602) PC lttng_ust_cyg_profile:func_exit: { cpu_id = 0 }, { addr = 0x404341, call_site = 0x40483F }

因为我的程序链接了so库,所以可能库里的地址仍为随机地址,但是本程序中已经变为了可以使用的地址。

再尝试一次:

$ addr2line 0x404190  -e tp_test -f -s -C
std::chrono::duration<long, std::ratio<1l, 1000000000l> >::count() const
chrono:346

最后说一下lttng相关的:

Compile your application with compiler option -finstrument-functions.

Launch your application by preloading liblttng-ust-cyg-profile-fast.so for fast function tracing:

$ LD_PRELOAD=liblttng-ust-cyg-profile-fast.so my-app
Launch your application by preloading liblttng-ust-cyg-profile.so for slower, more verbose function tracing:

$ LD_PRELOAD=liblttng-ust-cyg-profile.so my-app

你可能感兴趣的:(linux)