我正在寻找一个像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.假设局部函数没有被优化编译器内联,并且二进制文件没有被剥离(删除符号),有没有工具可以做到这一点?

Edit

有几点需要澄清:

  • 如果该工具还提供非本地函数的跟踪信息,那也没关系.
  • 我不想在支持特定工具的情况下重新编译程序,可执行文件中的符号信息应该足够了.
  • 如果我能像使用ltrace/strace一样,使用该工具连接到现有流程,我会非常高兴.

推荐答案

假设您只想收到特定功能的通知,您可以这样做:

使用调试信息编译(因为您已经有了符号信息,所以在中可能也有足够的调试)

鉴于

#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

请注意,不只是打印当前帧(bt 1),您可以做任何您想做的事情,打印一些全局的值,执行一些shell命令,或者在点击fatal_bomb_exploded函数时发送一些内容:)遗憾的是,gcc会在这两者之间输出一些"当前语言已更改"的消息.但这很容易被抹掉.没什么大不了的.

Linux相关问答推荐

无法下载Centos 7上的存储库的元数据

Docker 守护进程安装在 ubuntu jenkins docker 容器代理权限被拒绝

使用 ansible 验证 firewalld 配置

重新运行时避免 Linux bash 脚本中的文件重命名重复

有必要注意非错误提示吗?好像没有找到包裹‘***’?

$RANDOM 变量在输出通过管道后似乎没有改变

使用具有特定值的字段对文件进行排序

Azure Nvidia 中的 apt-update 给出公钥错误

在 Linux 中 Select 多个同名的可执行文件

获取变量中的当前路径并使用它

需要解释 Linux bash 内置 exec 命令行为

如何更改某些文件模式/扩展名的权限?

从 Linux shell 将多个文件从一个目录复制到另一个目录

通过 VM 的 Centos - 镜像列表中没有 URL

如何告诉 valgrind 对Forking 进程进行 memcheck?

从Linux中的行尾删除空格

Anaconda:禁用提示更改

如何自动化 HTML 到 PDF 的转换?

后缀 - status=bounced(未知用户myuser)

构建窗口管理器