一尘不染

跟踪Linux中本地函数调用的工具

linux

我正在寻找可以跟踪可执行文件中本地定义的函数的ltracestrace之类的工具。ltrace仅跟踪动态库调用,而strace仅跟踪系统调用。例如,给定以下C程序:

#include <stdio.h>

int triple ( int x )
{
  return 3 * x;
}

int main (void)
{
  printf("%d\n", triple(10));
  return 0;
}

使用来运行程序ltrace将显示对的调用,printf因为这是标准库函数(在我的系统上是动态库),并且strace将显示启动代码,用于实现printf的系统调用以及关闭代码的所有系统调用。
,但是我想要让我知道该函数triple已被调用的东西。假设优化编译器未内联局部函数,并且二进制文件未剥离(删除符号),是否有工具可以做到这一点?

编辑

一些澄清:

  • 如果该工具还提供非本地功能的跟踪信息,也可以。
  • 我不想在支持特定工具的情况下重新编译程序,可执行文件中的符号信息就足够了。
  • 如果可以像使用ltrace / strace一样使用该工具附加到现有进程,我将非常好。

阅读 235

收藏
2020-06-02

共1个答案

一尘不染

假设只希望收到有关特定功能的通知,可以这样进行:

使用调试信息进行编译(由于您已经具有符号信息,因此您可能还具有足够的调试功能)

给定

#include <iostream>

int fac(int n) {
    if(n == 0)
        return 1;
    return n * fac(n-1);
}

int main()
{
    for(int i=0;i<4;i++)
        std::cout << fac(i) << std::endl;
}

使用gdb跟踪:

[js@HOST2 cpp]$ g++ -g3 test.cpp
[js@HOST2 cpp]$ gdb ./a.out
(gdb) b fac
Breakpoint 1 at 0x804866a: file test.cpp, line 4.
(gdb) commands 1
Type commands for when breakpoint 1 is hit, one per line.
End with a line saying just "end".
>silent
>bt 1
>c
>end
(gdb) run
Starting program: /home/js/cpp/a.out
#0  fac (n=0) at test.cpp:4
1
#0  fac (n=1) at test.cpp:4
#0  fac (n=0) at test.cpp:4
1
#0  fac (n=2) at test.cpp:4
#0  fac (n=1) at test.cpp:4
#0  fac (n=0) at test.cpp:4
2
#0  fac (n=3) at test.cpp:4
#0  fac (n=2) at test.cpp:4
#0  fac (n=1) at test.cpp:4
#0  fac (n=0) at test.cpp:4
6

Program exited normally.
(gdb)

这是我收集所有函数地址的方法:

tmp=$(mktemp)
readelf -s ./a.out | gawk '
{ 
  if($4 == "FUNC" && $2 != 0) { 
    print "# code for " $NF; 
    print "b *0x" $2; 
    print "commands"; 
    print "silent"; 
    print "bt 1"; 
    print "c"; 
    print "end"; 
    print ""; 
  } 
}' > $tmp; 
gdb --command=$tmp ./a.out; 
rm -f $tmp

请注意,除了打印当前frame(bt 1)之外,您还可以执行任何操作,打印某些全局值,执行一些shell命令,或者在命中该fatal_bomb_exploded函数时发送邮件:)不幸的是,gcc输出了一些“当前语言已更改”消息之间。但这很容易被窃听。没什么大不了的。

2020-06-02