打印运行时调用的函数的工具?

打印运行时调用的函数的工具?

我正在 Unix/Linux 平台上寻找这样一种工具,它可以实现:

  1. 我有源文件,我自己编译了应用程序(源代码是 C 语言,尽管我认为这并不重要)
  2. 我想在每个函数调用都打印/记录到标准输出/文件时运行此应用程序

例如:

#include <stdio.h>
int square(int x) { return x*x; }
int main(void) {
    square(2);
}

当我运行这个程序时它会打印出来

  • 主要的
  • 正方形

我明白gdb在某种程度上可以做到这一点,或者valgrind但他们都没有完全做到我想要的。我只是想知道是否存在这样的工具?谢谢。

答案1

要让可执行文件在调用时打印函数名称,在 GNU 系统上,您可以使用gcc's-finstrument-functions选项并将dladdr()地址转换为函数名称。

创建一个instrument.c喜欢:

#define _GNU_SOURCE
#include <dlfcn.h>

#include <stdlib.h>
#include <stdio.h>

#define TRACE_FD 3

void __cyg_profile_func_enter (void *, void *)
   __attribute__((no_instrument_function));

void __cyg_profile_func_enter (void *func,  void *caller)
{
  static FILE* trace = NULL;
  Dl_info info;

  if (trace == NULL) {
    trace = fdopen(TRACE_FD, "w");
    if (trace == NULL) abort();
    setbuf(trace, NULL);
  }
  if (dladdr(func, &info))
    fprintf (trace, "%p [%s] %s\n",
             func,
             info.dli_fname ? info.dli_fname : "?",
             info.dli_sname ? info.dli_sname : "?");
}

然后将可执行文件编译为:

$ gcc -O0 -rdynamic -finstrument-functions square.c instrument.c -ldl
$ ./a.out 3>&1
0x400a8f [./a.out] main
0x400a4f [./a.out] square

(这里使用 fd 3 转储函数名称以使其与 stdout 和 stderr 流分开)。

dli_sname如果您只需要函数名称,您可以调整代码以仅打印。

答案2

使用gcov

$ gcc -O0 --coverage square.c
$ ./a.out
$ gcov -i square.c
$ awk -F '[,:]' '$1 == "function" && $3 > 0 {print $3, $4}' square.c.gcov
1 square
1 main

(其中数字是调用函数的次数(我们跳过$3 > 0该部分中从未调用过的函数awk))。

这通常用于代码覆盖率(正在测试多少代码)。您还可以使用gprof代码分析工具(通常用于计算在代码的各个区域花费了多少时间):

$ gcc -O0 -pg square.c
$ ./a.out
$ gprof -b -P
            Call graph


granularity: each sample hit covers 2 byte(s) no time propagated

index % time    self  children    called     name
        0.00    0.00       1/1           main [7]
[1]      0.0    0.00    0.00       1         square [1]
-----------------------------------------------

Index by function name

   [1] square

相关内容