【问题标题】:Automatic tracing of program execution [closed]程序执行的自动跟踪[关闭]
【发布时间】:2011-08-14 14:07:33
【问题描述】:

我想知道我们是否可以在任何 C 或 C++ 应用程序中启用跟踪。

例如,使用 gcc 选项或小工具,我将启用跟踪,并且跟踪要么打印在控制台上,要么转储到文件中。

由于文件和函数/类很多,我不想开始手动添加跟踪打印。

如果没有此类工具,下一个选择是使用脚本并尝试在跟踪打印时添加。

strace 没有多大用处,因为它主要提供系统调用。

【问题讨论】:

  • 如果这只是用于开发环境,您可以使用 -g 编译所有内容并在 gdb 中运行程序。这将始终为您提供完整的堆栈跟踪。
  • 您可能会检查 C++ 解释器... cint / ch / ...?不确定他们能做什么,但他们比任何编译器更有可能做到这一点。 FWIW,如果您开始查看跟踪的每一行,那么您离使用调试器不远了(除非您的控制较少)。
  • 您要跟踪什么?大约有一百万种不同的答案,编译器无法神奇地推断出您想要跟踪的内容。这使得自动添加跟踪变得更加困难。
  • 投票结束的范围太广,因为不清楚 什么 OP 想要追踪。更精确的请求:源代码行:stackoverflow.com/questions/764382/automate-tracing-in-gdb,函数调用:stackoverflow.com/questions/311948/…,行和数据:stackoverflow.com/questions/763891/…
  • 使用您最喜欢的 CPU 供应商提供的工具。它们是免费的,并且它们利用硬件也可以使您的代码以合理的速度运行。您可能想对此进行调查。英特尔和 AMD 都有我上次检查过的东西:) 跟踪捕获是由 CPU 本身完成的。无需乱码!

标签: c++ c trace


【解决方案1】:

对于 GCC,您可以使用 profiling 支持构建,然后运行该程序。这将创建gmon.out 文件,该文件又将包含程序执行的函数的(某种)跟踪。

不过,这甚至比不上手写跟踪 printf()s 的实用性或易用性。

【讨论】:

    【解决方案2】:

    如果您不想修改所有 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__ )
    

    请注意,我在这里使用了一个不错的宏技巧:variadic macro

    【讨论】:

    • 我在函数中没有任何 printf.. 所以我需要添加它。因此添加是困难的部分。
    【解决方案3】:

    使用Log4cxx

    一旦您在配置文件中指定文件类型、文件名和文件大小,这将记录详细信息。

    按照步骤运行示例程序。

    【讨论】:

    • 谢谢 - 不知道这个包;但是,正如我在logging.apache.org/log4cxx/usage.html 中看到的那样,它只是定义了新的日志记录命令——它不能“自动跟踪”,这就是这个问题的意义所在。
    【解决方案4】:

    既然你问的是 gcc。它具有选项-finstrument-functions,允许您在调用函数之前和之后执行任意代码。

    【讨论】:

      【解决方案5】:

      要跟踪函数进入/退出,您可以使用选项-finstrument-functions 重新编译代码,这样每次调用函数时,都会调用__cyg_profile_func_enter() 函数,并在函数返回时调用__cyg_profile_func_exit()

      您可以实现这些函数来跟踪被调用函数的地址,它们使用nm 将地址转换为函数名。

      编辑etrace 完成了所有这些工作:它提供了__cyg_profile_func_enter()__cyg_profile_func_exit() 的源代码以及将地址写入命名管道、Perl 和 Python 脚本的函数读取地址并使用函数名称和缩进进行实际跟踪。

      【讨论】:

      • 暂时我有我自己的但更快的方法来添加打印/入口点语句。我能够使用 VIM 脚本和 shell 脚本组合来做到这一点。尽管它不是正确的解决方案,但我的工作量减少了 90%。 .首先在 vim 中使用源文件录制宏,以在每个函数的开头添加入口点(使用 '{{' )。使用 shell 为一大堆文件运行这个宏。这会在源文件中产生一些问题,例如结构/类定义等。 C 函数也应该支持在函数中的任何点声明变量。但它比手动好 90%:)
      【解决方案6】:

      我知道你不想为每个函数添加一些东西,但如果它像将 { 更改为 {_ 一样简单,那你会赢吗?一些脚本可以自动执行此操作 - 如果您需要,请联系我。如果这确实有效,那么看看我放在一起的这个小实用程序 - 只需包含一个头文件,然后你就可以得到很好的可移植跟踪

      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
      

      【讨论】:

        猜你喜欢
        • 2020-12-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-09-24
        • 1970-01-01
        • 1970-01-01
        • 2013-05-15
        • 1970-01-01
        相关资源
        最近更新 更多