自动将进入/退出功能日志添加到项目

时间:2010-02-17 15:06:21

标签: c++ c debugging logging compiler-construction

我有第三方源代码,我必须调查。我想知道调用函数的顺序,但我不想浪费时间输入:

printf("Entered into %s", __FUNCTION__)

printf("Exited from %s", __FUNCTION__)

对于每个函数,我也不想触摸任何源文件。

你有什么建议吗?是否有一个编译器标志可以自动为我做这个?

对评论的澄清:

  • 我将交叉编译源代码以在ARM上运行它。
  • 我将用gcc编译它。
  • 我不想分析静态代码。我想跟踪运行时。所以doxygen不会让我的生活更轻松。
  • 我有源代码,我可以编译它。
  • 我不想使用面向方面编程。

编辑: 我发现gdb提示符中的'frame'命令在那个时间点打印当前帧(或者,你可以说是函数名)。也许,每次调用函数时,都可以(使用gdb脚本)调用'frame'命令。你觉得怎么样?

5 个答案:

答案 0 :(得分:28)

除了通常的调试器和面向方面的编程技术之外,您还可以使用gcc的-finstrument-functions命令行选项注入自己的检测功能。您必须实现自己的__cyg_profile_func_enter()__cyg_profile_func_exit()函数(在C ++中将它们声明为extern "C")。

它们提供了一种跟踪从哪里调用函数的方法。但是,接口有点难以使用,因为被调用的函数的地址及其调用站点被传递而不是例如函数名。您可以记录地址,然后使用objdump --symsnm之类的内容从符号表中提取相应的名称,当然假设符号尚未从相关二进制文件中删除。

使用gdb可能更容易。因人而异。 :)

答案 1 :(得分:11)

你说“我也不想触摸任何源文件”......如果你让一个脚本为你做这个公平游戏?

在所有.cpp文件上运行

sed 's/^{/{ENTRY/'

因此它将它们转换为:

void foo()
{ENTRY
  // code here
}

将它放在每个单位都可以#include的标题中:

#define ENTRY EntryRaiiObject obj ## __LINE__ (__FUNCTION__);

struct EntryRaiiObject {
  EntryRaiiObject(const char *f) : f_(f) { printf("Entered into %s", f_); }
  ~EntryRaiiObject() { printf("Exited from %s", f_); }
  const char *f_;
};

您可能必须使用sed脚本获得更高级别的功能。您还可以将ENTRY宏放在您想要探测的任何其他位置,例如函数的一些深度嵌套的内部范围。

答案 2 :(得分:4)

使用/Gh (Enable _penter Hook Function)/GH (Enable _pexit Hook Function)编译器开关(如果可以编译资源)

注意:您将无法使用这些宏。 See here(“您需要获取函数地址(在EIP寄存器中)并将其与映射文件中可由链接器生成的地址进行比较(假设没有发生变基)。它会非常慢虽然。“)

答案 3 :(得分:2)

同意William,使用gdb查看运行时间流程 有一些静态代码分析器可以告诉哪些函数调用哪个,并且可以给你一些调用流程图。一个工具是“理解C ++”(支持C / C ++),但我认为这不是免费的。但你可以找到类似的工具。

答案 4 :(得分:1)

如果你正在使用gcc,魔术编译器标志是-g。使用调试符号编译,在gdb下运行程序,并生成堆栈跟踪。你也可以使用ptrace,但使用gdb可能要容易得多。