如何用ftrace打印部分函数追踪?ftrace是否有类trace_printk的调用栈打印功能?
一、ftrace 打印当前函数调用栈的实现
ftrace 本身没有专门对应 trace_printk() 的栈打印函数,但可以通过内核提供的 trace_dump_stack() 实现类似效果——它能将当前调用栈信息输出到 ftrace 缓冲区,和 trace_printk() 的日志整合在一起,用法也和 trace_printk() 一致:
trace_dump_stack();
编译进内核后,执行到该代码点时,栈信息会被写入 ftrace 缓冲区,你可以通过 cat /sys/kernel/tracing/trace 查看输出。
如果不需要修改代码,也可以利用 ftrace 的 stack tracer 功能,但它是全局生效的,会记录所有函数调用的栈信息,适合全局排查而非特定点的栈打印。
二、仅在特定位置启用 function 追踪器的方案
完全可以实现“局部启用 function 追踪,其余位置仅保留 trace_printk() 输出”的需求,核心是利用 ftrace 的事件触发器和动态追踪器切换功能,步骤如下:
1. 初始配置(全局保持 nop 追踪器)
先将全局追踪器设为 nop,确保平时只有 trace_printk() 的日志输出:
echo nop > /sys/kernel/tracing/current_tracer echo 1 > /sys/kernel/tracing/tracing_on # 确保 trace_printk 能正常输出
2. 为目标位置创建探测事件
假设你关注的代码位置是函数 target_func() 的入口,我们用 kprobe 创建一个探测事件:
# 创建入口探测点 echo 'p:my_target_probe target_func' > /sys/kernel/tracing/kprobe_events # 启用该事件 echo 1 > /sys/kernel/tracing/events/kprobes/my_target_probe/enable # 创建退出探测点(用于后续切回 nop 追踪器) echo 'r:my_target_retprobe target_func' > /sys/kernel/tracing/kprobe_events echo 1 > /sys/kernel/tracing/events/kprobes/my_target_retprobe/enable
3. 添加触发器实现追踪器动态切换
当进入目标函数时,切换到 function 追踪器开始记录调用栈;当函数退出时,切回 nop 追踪器:
# 触发入口探测时,切换到 function 追踪器 echo 'wakeup write current_tracer function' > /sys/kernel/tracing/events/kprobes/my_target_probe/trigger # 触发退出探测时,切回 nop 追踪器 echo 'wakeup write current_tracer nop' > /sys/kernel/tracing/events/kprobes/my_target_retprobe/trigger
替代方案:基于 trace_printk 事件触发
如果你的目标位置已经有 trace_printk() 调用,也可以直接利用它生成的 ftrace/print 事件来触发追踪器切换,无需额外创建 kprobe:
# 启用 ftrace/print 事件 echo 'set_event ftrace/print' > /sys/kernel/tracing/set_event # 添加触发器:当 trace_printk 触发时切换到 function 追踪器 echo 'wakeup write current_tracer function' > /sys/kernel/tracing/events/ftrace/print/trigger # 可选:添加延迟切回 nop 的触发器(比如 5 秒后切回) echo 'wakeup delay 5000 write current_tracer nop' > /sys/kernel/tracing/events/ftrace/print/trigger
这样就能实现:只有当目标位置的代码执行时,才会启用 function 追踪器记录调用过程,其余时间全局保持 nop 追踪器,仅输出 trace_printk() 的单行日志。
内容的提问来源于stack exchange,提问作者tristone

