perf工具如何利用eh_frame实现无帧指针下的调用栈回溯?
无帧指针程序中基于perf的栈回溯实现疑问
背景与尝试
我正在学习如何在无帧指针的程序中打印调用栈,目前已经能借助ELF文件里的DWARF eh_frame 段实现栈回溯,也完成了ELF文件的分析测试。现在想了解如何通过perf_event_open进行采样并实现栈回溯。
我尝试编写了如下代码:
attr.type=PERF_TYPE_SOFTWARE; attr.config=PERF_COUNT_SW_CPU_CLOCK; attr.sample_period=100000; attr.sample_type=PERF_SAMPLE_CALLCHAIN; int fd=perf_event_open(&attr,0,-1,-1,0); ...
但遇到了问题:由于perf是异步写入采样数据,我们异步读取时,无帧指针情况下Linux内核仅返回一个栈帧(有帧指针时会返回多个),这时候再想用eh_frame回溯栈已经太晚,程序可能已经退出。
perf工具的有效测试
于是我用perf的--call-graph dwarf选项做了测试:
perf record --call-graph dwarf -p PID perf report --call-graph --stdio -G
它能正确显示我用-fomit-frame-pointer编译的测试程序的调用栈。
核心疑问与跟踪结果
我的疑问是:它是如何实现的?我通过strace跟踪perf的调用:
# strace perf record --call-graph dwarf -p PID perf_event_open({type=PERF_TYPE_SOFTWARE, size=0x88 /* PERF_ATTR_SIZE_??? */, config=PERF_COUNT_SW_DUMMY, sample_period=0, sample_type=0, read_format=0, watermark=1, precise_ip=0 /* arbitrary skid */, sample_id_all=1, bpf_event=1,...}, 1, 63, -1, PERF_FLAG_FD_CLOEXEC) = 132
发现它并没有设置sample_type为PERF_SAMPLE_CALLCHAIN,那它是如何获取栈信息的?我知道perf使用libunwind进行回溯,但不清楚触发机制——比如前文提到的,内核仅返回一个PC(程序计数器)时,perf是如何完成栈回溯的?
内容的提问来源于stack exchange,提问作者Nail Jay
相关产品推荐
相关产品推荐

