我想知道我们是否可以在任何 C 或 C++ 应用程序中启用跟踪。
例如,使用 gcc 选项或小工具,我将启用跟踪,并将跟踪打印在控制台上或转储到文件中。
由于有很多文件和函数/类,我不想开始手动添加跟踪打印。
如果此类工具不可用,下一个选择是使用脚本并尝试在跟踪打印时添加。
strace
没有多大用处,因为它主要提供系统调用。
-finstrument-functions
重新编译代码,以便每次调用函数时,都会调用 __cyg_profile_func_enter()
函数,并在函数返回时调用 __cyg_profile_func_exit()
。
您可以实现这些函数来跟踪被调用函数的地址,它们使用 nm 将地址转换为函数名称。
编辑:etrace完成了这一切:它提供了
__cyg_profile_func_enter()
和__cyg_profile_func_exit()
的源代码以及将地址写入命名管道的函数以及用于读取地址并执行以下操作的Perl和Python脚本使用函数名称和缩进进行实际跟踪。
对于 GCC,您可以使用 profiling 支持进行构建,然后运行程序。这将创建
gmon.out
文件,该文件又将包含程序执行的函数的(某种)跟踪。
但这甚至无法接近手写跟踪 printf() 的实用性或易用性。
既然你问的是 gcc。它具有选项
-finstrument-functions
,允许您在调用函数之前和之后执行任意代码。
我知道您不想为每个函数添加一些东西,但如果就像将 { 更改为 {_ 一样简单,这会赢得您的青睐吗?一些脚本可以自动完成此操作 - 如果您需要,请联系我。如果这确实有效,那么看看我放在一起的这个小实用程序 - 只需包含一个头文件,然后您就可以得到很好的便携式跟踪
https://github.com/goblinhack/callstack
例如:
void my_function (void)
{_
// rest of code
}
随时调用 CALLSTACK_DUMP() 转储当前调用堆栈。
就做吧
make
./callstack
Stack dump:
(stack) 1 main.cpp void foo3(int, int), line 7
(stack) 2 main.cpp void foo2(int), line 12
(stack) 3 main.cpp void foo1(), line 17
(stack) 4 main.cpp int main(int32_t, char **), line 22
如果您不想修改所有
printf()
调用,我建议您在头文件中执行一些操作,并将其包含在所有 C 代码文件中:
#ifndef DEBUG /* if not in debug mode, disable printf */
#ifdef printf
#undef printf
#define printf(format, ...)
#endif
#endif
最酷的是,您还可以用自己的日志记录功能替换 printf:
#define printf(format, ...) my_log_function( format, ##__VA_ARGS__ )
请注意,我在这里使用了一个很好的宏技巧:可变宏。