最近在调试nvme的驱动,顺便分享一下分析内核代码的方法,我自己感觉异常高效,整体逻辑分分钟可以掌握的明明白白。
对于给定的一个函数,例如nvme_probe()函数,如果想分析系统怎样调到这个函数,也就是想知道函数之前的调用栈,可以在函数中添加WARN_ON(1)打印堆栈,但是这样要重新编译源码,内核提供了ftrace 技术,可以使用ftrace function + 和enable func_stace_trace达到同样的效果。
cd /sys/kernel/debug/tracing/echo nvme_probe > set_ftrace_filterecho 1 > ./options/func_stack_trace
如果nvme_probe()函数中包含trace_event的内嵌函数,那就更加方便了,可以使用:
cd /sys/kernel/debug/tracing/echo 1 > ./events/nvme/nvme_probe/enableecho 1 > ./options/stacktrace 或者 echo 'stacktrace' > ./events/nvme/nvme_probe/trigger
也可以设置内核启动参数:
trace_options=func_stack_trace,userstacktrace,sym-addr ftrace=function ftrace_filter="nvme_probe"
效果图:
![569189ff97a06bdbf6e7ef8c6b9e25c1.png](https://img-blog.csdnimg.cn/img_convert/569189ff97a06bdbf6e7ef8c6b9e25c1.png)
如果想知道nvme_probe()函数之后的调用逻辑,可以使用ftrace + func_graph的方式
debugfs=/sys/kernel/debug echo nop > $debugfs/tracing/current_tracer echo 0 > $debugfs/tracing/tracing_on echo 10 > $debugfs/tracing/max_graph_depth #echo $$ > $debugfs/tracing/set_ftrace_pid echo function_graph > $debugfs/tracing/current_tracer echo nvme_probe > $debugfs/tracing/set_graph_function echo 1 > $debugfs/tracing/tracing_on exec "$@"
同样也可以设置内核启动参数:
ftrace=function_graph ftrace_graph_filter="nvme_probe"
效果图:
![856233a1e7054c1ec44b69aa7aaee4e7.png](https://img-blog.csdnimg.cn/img_convert/856233a1e7054c1ec44b69aa7aaee4e7.png)
(图中白色背景的函数还可以再展开详细查看)
呈现上图的效果可以借助折叠脚本:function-graph-fold.vim
脚本来源:https://lore.kernel.org/patchwork/patch/166422/
使用方法:
vim ./ftrace-nvme/func-graph-nvme-probe.log -S ./function-graph-fold.vim
更详细的说明可以参考我的github:
https://github.com/x-lugoo/Anytime-Note/tree/master/trace