如何获取调用函数的名称?

我正在使用gnu工具链。 我怎样才能在运行时找到函数的调用者? 即例如函数B()被许多函数使用函数指针调用。 现在,每当B被调用时,我想打印调用者名称。 我需要这个来调试某个问题。

如果您使用的是GNU,则可以使用回溯function。 在该手册页上有一个使用示例。

调用函数的代码位置__builtin_return_address()内在函数中的gcc保存。 要检索该名称 ,您必须解析程序的符号表; 虽然这是可以做到的,通过dladdr() ,这是有限制的:

  1. 在所有上下文中调用backtrace() / dladdr() (例如,从信号处理程序,或在multithreading程序中同时执行,或从不能调用malloc()上下文中调用可能并不安全。)。
  2. 操作不是即时的,但可能需要将调用线程置于睡眠状态; 如果在通话时保持任何锁定,这是一件坏事。
  3. 返回地址在名称中“可解析”的程度有限; 例如,如果有内联函数调用你的函数,那么你的调用者的调用者就会出现( backtrace()联机帮助页也会出现这种情况,就像“BUGS”部分中的dladdr() )一样。
  4. 在C ++中,还有通过con / destructors / initializers进行调用的额外挑战,其中函数的“调用者”可能最终成为编译器生成的元代码,而您感兴趣的实际位置可能在其他地方(调用者的调用者) ,甚至更深入的调用堆栈)。

这通常是解耦跟踪和函数名称解析的更好方法; 即只输出返回地址(作为hex/二进制),然后根据程序运行时检索到的符号表对结果日志进行后处理。

Vasil Dimov在回答类似问题时指出的另一种方法是用报告或传递调用函数名称的包装宏替换函数调用。 这将适用于内联函数,其中backtrace不会。 另一方面,如果您通过引用调用函数或以其他方式获取其地址,它将无法工作。

例如:

 int B(int x){ ... } 

可能成为:

 int _B(int x, char *caller){ printf("caller is %s\n", caller); ... } #define B(x) _B((x), __func__) 

每次调用B()都会打印出来的姓名。 Vasil Dimov以不同方式构造它,直接在宏中打印名称并保持函数不变。