在linux内核中用到了大量的函数回调,但是对于内核的调试过程,在遇到这样的回调操作,有时是很难找到回调函数对应的真实函数定义的位置。下面介绍怎样通过回调函数的指针来定位实际被调用的函数。
方法1:通过printk输出函数指针对应的函数名。
printk("func: %pS at address: %px\n", func, func);
%pS会输出函数名,%px会输出函数指针(尝试过通过%p和%pF无法正确输出函数指针和函数名)。
下面例子摘录内核源码。
int drm_atomic_commit(struct drm_atomic_state *state)
{
struct drm_mode_config *config = &state->dev->mode_config;
int ret;
ret = drm_atomic_check_only(state);
if (ret)
return ret;
DRM_DEBUG_ATOMIC("committing %p\n", state);
printk("Name:%pS Point:%px \n",config->funcs->atomic_commit,config->funcs->atomic_commit); //这个是添加的log
return config->funcs->atomic_commit(state->dev, state, false);
}
EXPORT_SYMBOL(drm_atomic_commit);
输出结果:
[ 5.141936] Name:drm_atomic_helper_commit+0x0/0x188 Point:ffffffc01096a508
方法2:
如上printk可以通过%px将函数的地址打印出来,在内核编译完后会在内核的顶层目录中生成一个System.map文件,System.map文件记录了所有符号的运行地址,这里的符号可以是函数名和变量。但是System.map文件不是一层不变的,每次编译内核都会重新生成System.map文件。所以在这个文件中查找函数名和对应地址时需要确定内核镜像和System.map是同一次编译所得的产物。
例:方法一中获取的地址就可以通过下面的命令查找到对应的函数名。
cat System.map | grep "ffffffc01096a508"
结果如下:
ffffffc01096a508 T drm_atomic_helper_commit