【问题标题】:Automatically adding Enter/Exit Function Logs to a Project自动将进入/退出功能日志添加到项目中
【发布时间】:2011-01-17 21:54:37
【问题描述】:

我有一个必须调查的第 3 方源代码。我想看看函数的调用顺序,但我不想浪费时间打字:

printf("Entered into %s", __FUNCTION__)

printf("Exited from %s", __FUNCTION__)

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

你有什么建议吗?是否有一个编译器标志可以自动为我执行此操作?

对cmets的澄清:

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

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

【问题讨论】:

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


【解决方案1】:

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

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

使用gdb 可能更容易。 YMMV。 :)

【讨论】:

  • 正是我想要的:)
  • 虽然...我认为这种事情会带来很大的开销,即使自定义的 before/after 函数是轻量级的。
【解决方案2】:

你说“我也不想碰任何源文件”……如果你让脚本为你做这件事,公平游戏吗?

在所有 .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 宏放在您想要探测的任何其他位置,例如某个函数的深层嵌套内部范围。

【讨论】:

  • 行首可以有很多以{ 开头的东西:结构等。如何定位可靠的函数?
【解决方案3】:

使用/Gh (Enable _penter Hook Function)/GH (Enable _pexit Hook Function) 编译器开关(如果你当然可以编译源代码)

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

【讨论】:

  • 感谢 PoweRoy。你知道gcc对应的编译器标志吗?或者这种技术的名称是什么,以便我可以谷歌它?
  • 不知道 gcc,William 的“-g”看起来一样。我在 google 上搜索了“c++ enter/exit function hook”:gcc.gnu.org/onlinedocs/gccint/Function-Entry.html
【解决方案4】:

如果您使用 gcc,那么神奇的编译器标志是 -g。使用调试符号进行编译,在 gdb 下运行程序,并生成堆栈跟踪。您也可以使用 ptrace,但只使用 gdb 可能要容易得多。

【讨论】:

  • 据我所知,堆栈跟踪是函数调用堆栈在特定时刻的状态。我可以使用gdb中的堆栈跟踪选项将被调用函数的函数名依次输出到文件中吗?
【解决方案5】:

同意 William,使用 gdb 查看运行时流程。
有一些静态代码分析器可以判断哪些函数调用了哪些函数,并可以为您提供一些调用流图。一种工具是“了解 C++”(支持 C/C++),但我猜这不是免费的。但是你可以找到类似的工具。

【讨论】:

  • sparse,“语义解析器”,具有绘图实用程序。它生成一个可以转换为图形的graphviz文件。 sparse.wiki.kernel.org/index.php/Main_Page
  • gdb 的确切选项标志是什么,它将使它能够打印当时正在调用的每个函数?
猜你喜欢
  • 2021-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-07-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多