【发布时间】:2011-09-09 06:08:42
【问题描述】:
我正在使用 gnu 工具链。如何在运行时找到函数的调用者?即例如函数 B() 被许多函数使用函数指针调用。现在,每当 B 被呼叫时,我想打印呼叫者的姓名。我需要这个来调试某个问题。
【问题讨论】:
标签: c gcc function-pointers
我正在使用 gnu 工具链。如何在运行时找到函数的调用者?即例如函数 B() 被许多函数使用函数指针调用。现在,每当 B 被呼叫时,我想打印呼叫者的姓名。我需要这个来调试某个问题。
【问题讨论】:
标签: c gcc function-pointers
Vasil Dimov 在回答类似问题时指出的另一种方法是将函数调用替换为报告或传入调用函数名称的包装宏。这将适用于内联函数,而回溯则不会。另一方面,如果您通过引用调用该函数,或者以其他方式获取其地址,则它将不起作用。
例如:
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 以不同的方式构造它,直接在宏中打印名称并保持函数不变。
【讨论】:
__func__,这违反了这个问题的整个想法。
调用函数的代码位置由 gcc 保存在 __builtin_return_address() 内在函数中。要为此检索 name,您必须解析程序的符号表;虽然可以通过dladdr() 做到这一点,但这是有限制的:
backtrace()/dladdr() 可能并不安全(例如,从信号处理程序,或同时在多线程程序中,或从不能调用malloc() 的上下文中。)。
backtrace() 手册页也说明了这一点,dladdr() 在“BUGS”部分的说明也是如此) .这通常是解耦跟踪和函数名称解析的更好方法;即只输出返回地址(作为十六进制/二进制),然后根据程序运行时检索到的符号表对生成的日志进行后处理。
【讨论】:
如果您使用的是 GNU,则可以使用 backtrace 函数。该手册页上有一个使用示例。
【讨论】: