systemtap使用调试记录(一)

systemtap使用调试记录(一)

一、调试环境介绍

Linux 3.10.0-514.16.1.el7.x86_64 
kernel-devel-3.10.0-514.16.1.el7.x86_64.rpm 同版本的开发头文件
kernel-debuginfo-common-x86_64-3.10.0-514.16.1.el7.x86_64.rpm
kernel-debuginfo-3.10.0-514.16.1.el7.x86_64.rpm 同版本调试数据包
linux-3.10.0-514.16.1.el7.tar.xz 同版本的源码

kernel开发头文件下载地址
kernel调试包下载地址
kernel调试common包下载地址
根据当前虚拟机获取内核代码的方法

二、centos7安装方法

yum install *.rpm  安装上述3个(debugifo,devel,debuginfo-common)rpm包
yum install systemtap
stap -ve 'probe begin { log("hello world") exit() }'

测试正常结果如下:

[root@localhost qinlong]# stap -ve ‘probe begin { log(“hello world”) exit() }’
Pass 1: parsed user script and 120 library scripts using 227352virt/40488res/3260shr/37400data kb, in 260usr/30sys/338real ms.
Pass 2: analyzed script: 1 probe, 2 functions, 0 embeds, 0 globals using 228540virt/41804res/3420shr/38588data kb, in 10usr/0sys/6real ms.
Pass 3: translated to C into “/tmp/stap5CqHmN/stap_f7a5084b8a638f5ce64a31271684ef1f_1133_src.c” using 228672virt/42408res/3996shr/38720data kb, in 0usr/0sys/0real ms.
Pass 4: compiled C into “stap_f7a5084b8a638f5ce64a31271684ef1f_1133.ko” in 1000usr/330sys/1247real ms.
Pass 5: starting run.
hello world
Pass 5: run completed in 10usr/40sys/362real ms.

三、通用案例

1.函数调用栈打印

1
2
3
4
5
6
7
8
9
[root@localhost stp]# cat bt.stp
probe kernel.function(@1){
print("----------------START-------------------------\n")
printf("In process [%s]\n", execname())
print_regs()
print_backtrace()
print("----------------END-------------------------\n")
exit()
}

打印内核函数的调用栈

[root@localhost stp]# stap bt.stp tcp_sendmsg
—————-START————————-
In process [sshd]
RIP: ffffffff815c1ee0
RSP: ffff88003d217d28 EFLAGS: 00000202
RAX: ffffffff81aa20a0 RBX: ffff88003d217e38 RCX: 0000000000000024
RDX: ffff88003d217da8 RSI: ffff88003b3b87c0 RDI: ffff88003d217e38
RBP: ffff88003d217d50 R08: 0000000000000000 R09: 0000000000000000
R10: ffff88003d217da8 R11: 0000000000000000 R12: ffff88003d217e38
R13: 0000000000000001 R14: ffff88003d217e28 R15: ffff8800274d3480
FS: 00007f03e5514840(0000) GS:ffff88003fd00000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007f19c6dc8000 CR3: 0000000035a5c000 CR4: 00000000000406e0
0xffffffff815c1ee0 : tcp_sendmsg+0x0/0xc40 [kernel]
0xffffffff815ed254 : inet_sendmsg+0x64/0xb0 [kernel]
0xffffffff81554e07 : sock_aio_write+0x157/0x180 [kernel]
0xffffffff811fdf3d : do_sync_write+0x8d/0xd0 [kernel]
0xffffffff811fe8a5 : vfs_write+0x1b5/0x1e0 [kernel]
0xffffffff811ff2cf : sys_write+0x7f/0xe0 [kernel]
0xffffffff81697189 : system_call_fastpath+0x16/0x1b [kernel]
—————-END————————-

2.函数的调用过程

1
2
3
4
5
6
7
[root@localhost stp]# cat socket-trace.stp
probe kernel.function("*@net/socket.c").call{
printf("%s -> %s\n",thread_indent(1),ppfunc())
}
probe kernel.function("*@net/socket.c").return{
printf("%s<-%s\n",thread_indent(-1),ppfunc())
}

thread_indent(1) 打印程序名称(线程id)
ppfunc() 打印出执行函数符号

kernel.function(“@net/socket.c”).call
调用net/socket.c 文件中函数时候会触发函数体执行打印动作
kernel.function(“
@net/socket.c”).return
调用net/socket.c文件中函数执行完成返回后会触发函数体打印动作

[root@localhost stp]# stap socket-trace.stp
0 dndX11(3295): -> SyS_recvmsg
0 dndX11(3295): -> sys_recvmsg
0 dndX11(3295): -> sockfd_lookup_light
0 dndX11(3295):<-sockfd_lookup_light
1 dndX11(3295): -> _
sys_recvmsg
3 dndX11(3295): -> sock_recvmsg
7 dndX11(3295):<-sock_recvmsg
8 dndX11(3295):<-_sys_recvmsg
9 dndX11(3295):<-
sys_recvmsg
10 dndX11(3295):<-SyS_recvmsg
25274 dndX11(3295): -> SyS_recvmsg
25279 dndX11(3295): -> sys_recvmsg
25281 dndX11(3295): -> sockfd_lookup_light
25284 dndX11(3295):<-sockfd_lookup_light
25285 dndX11(3295): -> _
sys_recvmsg
25288 dndX11(3295): -> sock_recvmsg
25291 dndX11(3295):<-sock_recvmsgx

3.打印协议栈函数中某一行数据

/home/qinlong/rpmbuild/SOURCES/linux-3.10.0-514.16.1.el7/net/ipv4/tcp.c
局部源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
1065 int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
1066 size_t size)
1067 {
1068 struct iovec *iov;
1069 struct tcp_sock *tp = tcp_sk(sk);
1070 struct sk_buff *skb;
1071 int iovlen, flags, err, copied = 0;
1072 int mss_now = 0, size_goal, copied_syn = 0, offset = 0;
1073 bool sg;
1074 long timeo;
1075
1076 lock_sock(sk);
1077
1078 flags = msg->msg_flags;

1
2
[root@localhost ~]# stap -L 'kernel.statement("*@net/ipv4/tcp.c:1078")'
kernel.statement("tcp_sendmsg@net/ipv4/tcp.c:1078") $iocb:struct kiocb* $sk:struct sock* $msg:struct msghdr* $size:size_t $copied:int $mss_now:int $size_goal:int $copied_syn:int $offset:int $timeo:long int

执行上述函数,可确代码具体的函数局部变量

1
2
3
4
5
6
7
8
9
10
$iocb:struct kiocb* 
$sk:struct sock*
$msg:struct msghdr*
$size:size_t
$copied:int
$mss_now:int
$size_goal:int
$copied_syn:int
$offset:int
$timeo:long int

根据以上变量打印出size值

1
2
3
[root@localhost ~]# stap -e 'probe kernel.statement("*@net/ipv4/tcp.c:1078") {printf("size %d \n",$size)}'
size 36
size 44