使用ftrace过滤选择性跟踪父函数
背景
以memory cgroup子系统里的代码为例, __memory_events_show
函数有2处调用, 分别是memory_events_show
和memory_events_local_show
.
代码如下:
1 | static int memory_events_show(struct seq_file *m, void *v) |
如果要利用ftrace
实现以下需求:
- 将
memory_events_show
中的__memory_events_show
替换成自己实现的同时 - 让
memory_events_local_show
中的__memory_events_show
保持原始的调用 - 可以借助内核代码段自增的特点加以实现
思路简介
使用/proc/kallsyms
可以看到内核函数的开始地址并初步判断其区间, 如下:
1 | # cat /proc/kallsyms | grep memory_events_show -C 1 |
可以看到memory_events_local_show
的代码段范围是[0xffffffff811d89b0,0xfffffff811d89e0]
,
而memory_events_show
的代码段范围是[0xffffffff811d89e0,0xffffffff811d8a10]
,
因此可以通过判断ftrace
跟踪函数__memory_events_show
的调用点地址, 即在x86_64体系结构里的IP寄存器的范围,
确定当前__memory_events_show
的调用点是处于memory_events_local_show
还是memory_events_show
的代码段范围内
恰好ftrace_func_t
这个ftrace
注册在handler上的回调函数指针类型提供了parent_ip
这个参数可以方便的判断IP的范围
实现
该实现参考了内核kernel/livepatch/patch.c
这个kpatch模块的源码, 进行了一定的简化.
编译和加载内核模块前确保内核Kconfig开启以下特性
- CONFIG_FUNCTION_TRACER
- MEMCG
代码如下:
1 |
|
运行结果
1 | # cat /sys/fs/cgroup/task/memory.events |