前言
在阅读内核代码的时候,经常需要查看函数调用栈,来帮助理解代码的调用流程。ftrace就提供了这样一种强大的功能,它可以把调用的每个函数都显示出来,同时也统计了每个函数花费的时间。但是有时候我们并不需要这么详细的信息,我们只关注某个函数的基本函数调用栈就可以了,此时可以采用stack trace进行查看。
编译配置
开启如下的编译配置项
CONFIG_TRACING=y
CONFIG_TRACING_SUPPORT=y
CONFIG_FTRACE=y
CONFIG_GENERIC_TRACER=yCONFIG_FUNCTION_TRACER=y
CONFIG_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=yCONFIG_CONTEXT_SWITCH_TRACER=y
这里需要注意的是ftrace依赖于debugfs,因此需要开启内核的如下配置项:
CONFIG_DEBUG_FS=yes
同时也需要挂载debugfs:
mount -t debugfs none /sys/kernel/debug
使用方法
可以定义如下的脚本stack_trace.sh:
#!/bin/sh
debugfs=/sys/kernel/debug
echo 0 > $debugfs/tracing/tracing_on
echo nop > $debugfs/tracing/current_tracer
echo function > $debugfs/tracing/current_tracer
echo $$ > $debugfs/tracing/set_ftrace_pid
echo 1 > $debugfs/tracing/options/func_stack_trace
echo submit_bio > $debugfs/tracing/set_ftrace_filter
echo 1 > $debugfs/tracing/tracing_on
exec "$@"
使用举例
以submit_bio这个函数为例,来查看sync系统调用操作时submit_bio函数调用栈:
./stack_trace.sh sync
cat /sys/kernel/debug/tracing/trace 显示结果如下:
=> submit_bio
=> submit_bh_wbc
=> __block_write_full_page
=> block_write_full_page
=> blkdev_writepage
=> __writepage
=> write_cache_pages
=> generic_writepages
=> blkdev_writepages
=> do_writepages
=> __filemap_fdatawrite_range
=> filemap_fdatawrite
=> fdatawrite_one_bdev
=> iterate_bdevs
=> ksys_sync
=> __arm64_sys_sync
=> el0_svc_common
=> el0_svc_handler
=> el0_svc
参考文档
- https://www.kernel.org/doc/html/v4.17/trace/ftrace.html
- https://github.com/x-lugoo/Anytime-Note/tree/master/trace