我有第三方源代码,我必须调查。我想知道调用函数的顺序,但我不想浪费时间输入:
printf("Entered into %s", __FUNCTION__)
和
printf("Exited from %s", __FUNCTION__)
对于每个函数,我也不想触摸任何源文件。
你有什么建议吗?是否有一个编译器标志可以自动为我做这个?
对评论的澄清:
编辑: 我发现gdb提示符中的'frame'命令在那个时间点打印当前帧(或者,你可以说是函数名)。也许,每次调用函数时,都可以(使用gdb脚本)调用'frame'命令。你觉得怎么样?
答案 0 :(得分:28)
除了通常的调试器和面向方面的编程技术之外,您还可以使用gcc的-finstrument-functions
命令行选项注入自己的检测功能。您必须实现自己的__cyg_profile_func_enter()
和__cyg_profile_func_exit()
函数(在C ++中将它们声明为extern "C"
)。
它们提供了一种跟踪从哪里调用函数的方法。但是,接口有点难以使用,因为被调用的函数的地址及其调用站点被传递而不是例如函数名。您可以记录地址,然后使用objdump --syms
或nm
之类的内容从符号表中提取相应的名称,当然假设符号尚未从相关二进制文件中删除。
使用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可能要容易得多。