Makefile中的执行过程
make --dry-run 只打印不执行make执行命令的过程
make V=1 打印详细执行信息
make --debug
make --debug运行示意图
shell脚本的执行过程
#!/bin/sh -x 执行过程详细信息
sh -x script_name.sh 同上
set -x;function;set +x 通上,只打开区域间执行详细信息
sh -n scripte_name.sh 只做语法检查,而不执行脚本。
Gcc编译trace
gcc --save-temps hotplug.c -o hotplug
$ls hotplug*
hotplug hotplug.c hotplug.i hotplug.i.orig hotplug.o hotplug.s
可以使用astyle格式化.i文件
astyle -A8 hotplug.i
Kbuild系统下编译trace选项
为某些对象增加编译选项
CFLAGS_foo.o = -O0 -g -save-temps
去除某些对象的编译选项
CFLAGS_REMOVE_foo.o = = -Os
内核ftrace
使用ftrace function
root@linux:/sys/kernel/debug/tracing# cat available_filter_functions |grep file_permission
security_file_permission
selinux_file_permission
apparmor_file_permission
root@linux:/sys/kernel/debug/tracing# echo security_file_permission > set_ftrace_filter
root@linux:/sys/kernel/debug/tracing# echo function > current_tracer
可选项,如果想要打印堆栈,可以echo 1 > options/func_stack_trace
root@linux:/sys/kernel/debug/tracing# sh -c 'echo 1 > tracing_on;echo $$ >set_ftrace_pid;exec cat enabled_functions;echo 0>tracing_on'
root@linux:/sys/kernel/debug/tracing# cat trace
# tracer: function
#
# entries-in-buffer/entries-written: 13/13 #P:8
#
# _-----=> irqs-off
# / _----=> need-resched
# | / _---=> hardirq/softirq
# || / _--=> preempt-depth
# ||| / delay
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
# | | | |||| | |
cat-6430 [007] .... 2198.209159: security_file_permission <-vfs_write
cat-6430 [007] .... 2198.213087: security_file_permission <-vfs_write
cat-6430 [007] .... 2198.213174: security_file_permission <-vfs_read
cat-6430 [007] .... 2198.213299: security_file_permission <-vfs_write
cat-6430 [000] .... 2198.213656: security_file_permission <-vfs_read
在退出的时候记得将function ftrace关闭,不然其他的tracer不会生效
echo nop > current_tracer
echo > set_ftrace_filter
限制:没有打印参数的功能,也不会打印返回值
funciton graph
和function的区别:function graph中设置追踪的函数之后会显示函数调用的所有函数及其时间间隔,而function显示调用到本函数的堆栈,是向上追溯的。
function graph主要用来看调用哪些函数,也可以用来查看时间消耗。
root@linux:/sys/kernel/debug/tracing# echo do_sys_open > set_graph_function
root@linux:/sys/kernel/debug/tracing# echo 1 > tracing_on;echo $$ >set_ftrace_pid ;exec cat set_ftrace_pid;echo 0>tracing_on
root@linux:/t/tracing# cat trace
# tracer: function_graph
#
# CPU DURATION FUNCTION CALLS
# | | | | | | |
7) | do_sys_open() {
7) | getname() {
7) | getname_flags() {
7) | kmem_cache_alloc() {
7) 0.132 us | _cond_resched();
7) 0.108 us | _cond_resched();
7) 0.122 us | memcg_kmem_put_cache();
7) 3.438 us | }
7) | __check_object_size() {
7) 0.108 us | is_vmalloc_or_module_addr();
7) 0.125 us | __virt_addr_valid();
7) 0.102 us | __check_heap_object();
7) 0.132 us | check_stack_object();
7) 3.474 us | }
7) 8.708 us | }
7) 9.699 us | }
使用完毕后清理设置:
root@linux:/t/tracing# echo nop > current_tracer
root@linux:/t/tracing# echo > set_graph_function
root@linux:/t/tracing# echo > set_ftrace_pid
原始的接口比较复杂,不太熟悉的话建议使用trace-cmd/kernelshark
,其中kernelshark底层依赖于trace-cmd,但是它提供图形化操作,相对来说比较友好。
kprobe event
kprobe可以在任意的位置添加hook点,通常需要额外编写module来完成工作,而ftrace集成了kprobe功能,当我们只需要一些打印的时候可以使用这个kprobe_events接口,但是操作会比trace event要复杂一些,主要是创建kprobe event的过程比较复杂.
内核中的示例文档Documentation/trace/kprobetrace.txt
介绍了基本的用法,就直接搬运过来了
p[:[GRP/]EVENT] [MOD:]SYM[+offs]|MEMADDR [FETCHARGS] : Set a probe
r[:[GRP/]EVENT] [MOD:]SYM[+0] [FETCHARGS] : Set a return probe
-:[GRP/]EVENT : Clear a probe
创建kprobe_event:
echo 'p:myprobe do_sys_open'> kprobe_events 销毁现有的并创建新的event,在调用的时候就触发,可以打印传入参数
echo 'r:myprobe do_fork' >> kprobe_events 追加return event,在返回的时候会触发,可以打印返回值
除了基本的使用之外,我们通常想要查看传入的参数,如何控制格式化打印输出呢
FETCHARGS : Arguments. Each probe can have up to 128 args.
%REG : Fetch register REG
@ADDR : Fetch memory at ADDR (ADDR should be in kernel) //可以查看全局的静态变量,它的地址固定
@SYM[+|-offs] : Fetch memory at SYM +|- offs (SYM should be a data symbol) //可以查看全局的静态变量,它的地址固定
$retval : Fetch return value.(*) //创建retprobe event的时候用到
+|-offs(FETCHARG) : Fetch memory at FETCHARG +|- offs address.(**)
NAME=FETCHARG : Set NAME as the argument name of FETCHARG. 打印更加直观
FETCHARG:TYPE : Set TYPE as the type of FETCHARG. Currently, basic types 格式化输出
(u8/u16/u32/u64/s8/s16/s32/s64), "string" and bitfield are supported.
以do_sys_open为例,类型为long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
,查看4个参数的具体值,能够更加直观地输出它的值:
1.函数传参通常都是通过寄存器,以x86_64为例,参考asmlinkage中的介绍,4个参数都会放到寄存器里:rdi rsi rdx rcx
,但是这些寄存器名称是x86_64自己定义的,在内核中可能就不叫这个名称了,查找arch/x86/include/asm/ptrace.h
,我们可以对应上:rdi->di,rsi->si,rdx->dx,rcx->cx,rax->ax
arch/x86/include/asm/calling.h
x86 function call convention, 64-bit:
-------------------------------------
arguments | callee-saved | extra caller-saved | return |
[callee-clobbered] [callee-clobbered]
---------------------------------------------------------------------------
rdi rsi rdx rcx r8-9 | rbx rbp [*] r12-15 | r10-11 | rax, rdx [**]
arch/x86/include/asm/ptrace.h
struct pt_regs {
...
unsigned long ax;
unsigned long cx;
unsigned long dx;
unsigned long si;
unsigned long di;
unsigned long orig_ax;
...
};
但是第三个参数filename是一个指针,我们拿到的寄存器地址只是指向字符串的指针,对我们来说没有意义,我们需要将字符串读取出来:+|-offs(FETCHARG)
->+0($si):string
,最终我们可以通过echo 'p:myprobe do_sys_open dfd=%di filename=+0(%si):string flags=%dx ' > kprobe_events
创建一个event,并且结构化输出:
teamviewerd-2352 [001] .... 55981.990255: myprobe: (do_sys_open+0x0/0x290) dfd=0xffffff9c filename="/sys/devices/virtual/tty/tty0/active" flags=0x8000
有人写了一个更加复杂的例子:打印报文假,设函数第一个参数是skb,并且skb->data指向ip头(协议栈中大部分时候都是这种情况),我们就可以打印出一些有用的信息,如下
skb=%di head=+0x18(%di) data=+0x20(%di) mac=+0x38(%di):u32 dev=+0(+16(%di)):string sip=+12(+0x20(%di)):u32 sport=+20(+0x20(%di)):u16 dip=+16(+0x20(%di)):u32 dport=+22(+0x20(%di)):u16
其中“head=+0x18(%di)”的0x18这个偏移需要根据当前内核中sk_buff结构体来确定,其他的几个偏移也一样。
开启kprobe_event:
之后就能在events/kprobes/myprobe/
下看到创建的event,之后的所有操作就和静态的trace event一样了,可以通过echo 1 > enable
使能一组event,也可以控制单独的event.(记得设置current_trace为nop,这时候event才生效).
关闭kprobe_event:
echo 0 > enable 可以控制一个组,单独的event,所有的kprobe event
销毁kprobe_event:
echo '-:do_sys_open' > kprobe_events 销毁单独的event
echo '-:myprobe' > kprobe_events 销毁myprobe组下所有的event
参考
https://events.linuxfoundation.org/wp-content/uploads/2017/12/oss-eu-2018-fun-with-dynamic-trace-events_steven-rostedt.pdf
https://blog.csdn.net/cll__/article/details/51417291