如何从C中的函数指针获取函数的名称?
编辑:真实情况是:我正在编写一个Linux内核模块,我正在调用内核函数.其中一些函数是指针,我想检查内核源代码中该函数的代码.但我不知道它指向哪个功能.我认为可以这样做,因为当系统出现故障(内核崩溃)时,它会在屏幕上打印出具有函数名称的当前callstack.但是,我想我错了......是吗?
我很惊讶为什么每个人都说这是不可能的.在Linux上可以实现非静态功能.
我知道至少有两种方法可以实现这一目标.
有用于回溯打印的GNU函数:backtrace()
和backtrace_symbols()
(参见参考资料man
).在你的情况下,你不需要backtrace()
因为你已经有了函数指针,你只需将其传递给backtrace_symbols()
.
示例(工作代码):
#include#include void foo(void) { printf("foo\n"); } int main(int argc, char *argv[]) { void *funptr = &foo; backtrace_symbols_fd(&funptr, 1, 1); return 0; }
编译 gcc test.c -rdynamic
输出: ./a.out(foo+0x0)[0x8048634]
它为您提供二进制名称,函数名称,函数start和指针值的指针偏移量,以便您可以解析它.
另一种方法是使用dladdr()
(另一个扩展),我想print_backtrace()
使用dladdr()
.dladdr()
返回Dl_info
在dli_sname
字段中具有函数名称的结构.我这里不提供代码示例,但很明显 - 请参阅man dladdr
详细信息.
NB!两种方法都要求功能是非静态的!
好吧,还有一种方法 - 使用调试信息,libdwarf
但它需要未经剥离的二进制文件,并不是很容易做到这一点,我不推荐它.
没有额外的帮助,这是不可能的.
你可以:
在程序映射函数指针中维护一个表到名称
检查可执行文件的符号表(如果有).
然而,后者很难,并且不便携.该方法将取决于操作系统的二进制格式(ELF,a.out,.exe等),以及链接器完成的任何重定位.
编辑:既然你现在已经解释了你的真实用例,答案实际上并不那么难.内核符号表可用/proc/kallsyms
,并且有一个用于访问它的API:
#includeconst char *kallsyms_lookup(unsigned long addr, unsigned long *symbolsize, unsigned long *ofset, char **modname, char *namebuf) void print_symbol(const char *fmt, unsigned long addr)
对于简单的调试目的,后者可能会做你需要的东西-它需要的地址,格式它,并将其发送给printk
,也可以使用printk
与%pF
格式说明.
在Linux内核中,您可以直接使用printk的"%pF"格式!
void *func = &foo; printk("func: %pF at address: %p\n", func, func);
以下是我在Linux上的工作原理:
printf使用函数的地址 %p
然后做一个nm
(没有0x
前缀)
它应该显示函数名称.
它仅在相关函数位于同一程序中时才有效(不在动态链接库中).
如果您可以找到已加载的共享库的加载地址,则可以从打印的数字中减去地址,并使用库上的nm来查找函数名称.