Systemtap examples, Network - 2 Tracing Functions Called in Network Socket Code
背景
这个例子来自socket-trace.stp 脚本, 跟踪内核中函数在net/socket.c代码中的调用和返回, 帮助用户从内核层面了解进程和网络的交互情况.
脚本内容以及注解
[root@db-172-16-3-150 network]# cd /usr/share/systemtap/testsuite/systemtap.examples/network
[root@db-172-16-3-150 network]# cat socket-trace.stp
#!/usr/bin/stap
probe kernel.function("*@net/socket.c").call {
printf ("%s -> %s\n", thread_indent(1), probefunc())
}
// kernel.function("*@net/socket.c").call探针, 用了*通配符, net/socket.c所有函数的调用都会触发这个探针.
// thread_indent(1), 同一个线程, 每次执行thread_indent时加1个空格.
probe kernel.function("*@net/socket.c").return {
printf ("%s <- %s\n", thread_indent(-1), probefunc())
}
// thread_indent(-1), 与函数调用相反, 函数返回时, 这里同一个线程, 每次执行thread_indent时减1个空格.
// 这样的话更容易看清除调用和返回的层次.
// probefunc()函数用于输出当前地址对应的函数名. 从内核符号表中根据地址取出函数名.
参考
http://blog.163.com/digoal@126/blog/static/1638770402013101381844107/
https://sourceware.org/systemtap/tapsets/API-probefunc.html
执行输出举例
[root@db-172-16-3-150 network]# stap ./socket-trace.stp
0 init(1): -> sock_poll
15 init(1): <- do_select
0 init(1): -> sock_poll
4 init(1): <- do_select
0 portreserve(1545): -> sock_poll
9 portreserve(1545): <- do_select
0 udevd(1168): -> sock_poll
0 rpc.statd(1726): -> sock_poll
8 rpc.statd(1726): <- do_select
0 rpc.statd(1726): -> sock_poll
3 rpc.statd(1726): <- do_select
0 rpc.statd(1726): -> sock_poll
4 rpc.statd(1726): <- do_select
0 rpc.statd(1726): -> sock_poll
3 rpc.statd(1726): <- do_select
0 rpcbind(1595): -> sock_poll
9 rpcbind(1595): <- do_sys_poll
0 rpcbind(1595): -> sock_poll
4 rpcbind(1595): <- do_sys_poll
0 init(1): -> sock_poll
4 init(1): <- do_select
0 init(1): -> sock_poll
0 rpcbind(1595): -> sock_poll
4 rpcbind(1595): <- do_sys_poll
0 rpcbind(1595): -> sock_poll
14 init(1): <- do_select
95 udevd(1168): <- do_sys_poll
0 rpc.statd(1726): -> sock_poll
14 rpcbind(1595): <- do_sys_poll
0 rpcbind(1595): -> sock_poll
0 hald-addon-inpu(1874): -> sock_poll
14 rpcbind(1595): <- do_sys_poll
25 rpc.statd(1726): <- do_select
probefunc()函数使用symname(addr) 或者 usymname(uaddr) 函数从内核表中取出对应的函数名:
[root@db-172-16-3-150 network]# cat /boot/System.map-2.6.32-358.el6.x86_64 |grep sock_poll
ffffffff81431450 t sock_poll
例如把socket-trace.stp 改一下, 同时输出当前探针的地址信息, 则更可以看出probefunc()是通过符号表把地址转换成函数名的.
如下 :
[root@db-172-16-3-150 network]# vi socket-trace.stp
#!/usr/bin/stap
probe kernel.function("*@net/socket.c").call {
printf ("%s -> %p, %s\n", thread_indent(1), addr(), probefunc())
}
probe kernel.function("*@net/socket.c").return {
printf ("%s <- %p, %s\n", thread_indent(-1), addr(), probefunc())
}
[root@db-172-16-3-150 network]# stap ./socket-trace.stp
0 init(1): -> 0xffffffff81431450, sock_poll
17 init(1): <- 0xffffffff81197f42, do_select
0 init(1): -> 0xffffffff81431450, sock_poll
4 init(1): <- 0xffffffff81197f42, do_select
0 NetworkManager(1694): -> 0xffffffff81431450, sock_poll
15 NetworkManager(1694): <- 0xffffffff8119764b, do_sys_poll
0 NetworkManager(1694): -> 0xffffffff81431450, sock_poll
5 NetworkManager(1694): <- 0xffffffff8119764b, do_sys_poll
0 NetworkManager(1694): -> 0xffffffff81431450, sock_poll
5 NetworkManager(1694): <- 0xffffffff8119764b, do_sys_poll
0 NetworkManager(1694): -> 0xffffffff81431450, sock_poll
4 NetworkManager(1694): <- 0xffffffff8119764b, do_sys_poll
参考
1. /usr/share/systemtap/testsuite/systemtap.examples
2. https://sourceware.org/systemtap/SystemTap_Beginners_Guide/useful-systemtap-scripts.html
3. systemtap-testsuite
4. https://sourceware.org/systemtap/examples/
5. /usr/share/systemtap/testsuite/systemtap.examples/index.txt
6. /usr/share/systemtap/testsuite/systemtap.examples/keyword-index.txt
7. /usr/share/systemtap/tapset
8. /usr/src/debug/kernel-2.6.32-358.el6/linux-2.6.32-358.el6.x86_64/net/socket.c
9. http://blog.163.com/digoal@126/blog/static/16387704020131071118496/
10. https://sourceware.org/systemtap/tapsets/API-probefunc.html
11. http://blog.163.com/digoal@126/blog/static/1638770402013101381844107/