Systemtap DWARF-less probing (kprobe)

3 minute read

背景

In the absence of debugging information, you can still use the kprobe family of probes to examine the entry and exit points of kernel and module functions. You cannot look up the arguments or local variables of a function using these probes. However, you can access the parameters by following this procedure:

当系统中没有安装内核对应的debuginfo包时, 不能通过kernel.来使用DWARF探针, 也就是前一篇blog中提到的.

http://blog.163.com/digoal@126/blog/static/1638770402013823101827553/

例如

主机A:

[root@db ~]# rpm -qa|grep debuginfo  

没有输出

主机B :

[root@db-172-16-3-39 ~]# rpm -qa|grep debuginfo  
  
  
kernel-debuginfo-common-2.6.18-348.12.1.el5  
kernel-debuginfo-2.6.18-348.12.1.el5  

在主机A上使用kernel.function探针将报错 :

[root@db- ~]#  stap --vp 5 -e 'probe kernel.function("tcp_v4_connect") {exit()}'  
SystemTap translator/driver (version 1.1/0.141 non-git sources)  
Copyright (C) 2005-2010 Red Hat, Inc. and others  
This is free software; see the source for copying conditions.  
Session arch: x86_64 release: 2.6.18-194.el5  
Created temporary directory "/tmp/stapF9BQl7"  
Parsed kernel "/lib/modules/2.6.18-194.el5/build/.config", number of tuples: 1932  
Searched "/usr/share/systemtap/tapset/x86_64/*.stp", found 3  
Searched "/usr/share/systemtap/tapset/*.stp", found 62  
Pass 1: parsed user script and 65 library script(s) using 43936virt/19484res/1768shr kb, in 170usr/0sys/173real ms.  
semantic error: missing x86_64 kernel/module debuginfo under '/lib/modules/2.6.18-194.el5/build' while resolving probe point kernel.function("tcp_v4_connect")  
Pass 2: analysis failed.  Try again with another '--vp 01' option.  

由于缺少debuginfo包, 报错中显示semantic error: missing x86_64 kernel/module debuginfo under ‘/lib/modules/2.6.18-194.el5/build’ while resolving probe point kernel.function(“tcp_v4_connect”)

在主机B上可以正常使用 :

[root@db-172-16-3-39 ~]# stap --vp 5 -e 'probe kernel.function("tcp_v4_connect") {exit()}'  
Parsed kernel "/lib/modules/2.6.18-348.12.1.el5/build/.config", containing 1977 tuples  
Parsed kernel /lib/modules/2.6.18-348.12.1.el5/build/Module.symvers, which contained 3546 vmlinux exports  
Searched: " /usr/share/systemtap/tapset/x86_64/*.stp ", found: 4, processed: 4  
Searched: " /usr/share/systemtap/tapset/*.stp ", found: 81, processed: 81  
Pass 1: parsed user script and 85 library script(s) using 146788virt/23700res/3012shr/21384data kb, in 170usr/10sys/173real ms.  

虽然没有安装debuginfo, 但是依然可以使用kprobe.来加载这些探针, 使用kprobe时有一些局限, 例如只能指定函数的入口部位或者是函数的返回部位(.return), 不能指定函数行号.

使用kprobe时, 无法获得函数的本地变量的值, 但是可以通过其他方法获得函数参数值(非$var).

When you're stopped at the entry to a function, you can refer to the function's arguments by number. For example, when probing the function declared:  

如果使用的是函数返回部位的探针, 那么返回值也不能简单的通过$return来获得, 而是要通过其他函数来获得.

asmlinkage ssize_t sys_read(unsigned int fd, char __user * buf, size_t  
count)  
You can obtain the values of fd, buf, and count, respectively, as uint_arg(1), pointer_arg(2), and ulong_arg(3). In this case, your probe code must first call asmlinkage(), because on some architectures the asmlinkage attribute affects how the function's arguments are passed.  
  
When you're in a return probe, $return isn't supported without DWARF, but you can call returnval() to get the value of the register in which the function value is typically returned, or call returnstr() to get a string version of that value.  

例如以上函数有3个参数, 通过uint_arg(1), pointer_arg(2), and ulong_arg(3)来取这些参数值. 在使用类似函数获得参数值时, 请先调用asmlinkage ()函数.

返回部位探针的返回值则通过returnval()或者returnstr()来获取.

例如 :

上一篇blog中举例用到的tcp_v4_connect函数, 有3个参数.

int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)  

kprobe使用如下, 记得先调用asmlinkage().

[root@db- ~]# stap -e 'probe kprobe.function("tcp_v4_connect") {asmlinkage(); printf("%s, %d, %d, 0x%x, 0x%x, %d\n", pp(), pid(), cpu(), pointer_arg(1), pointer_arg(2), uint_arg(3));}'  
kprobe.function("tcp_v4_connect"), 32372, 11, 0xffff81024ce51380, 0xffff81038aa2fec8, 16  
[root@db- ~]# stap -e 'probe kprobe.function("tcp_v4_connect").return {asmlinkage(); printf("%d\n", returnval());}'  
0  

更多的类型对应的获取它们的值的函数请参考

https://sourceware.org/systemtap/tapsets/

如: int_arg, long_arg, longlong_arg, pointer_arg, s32_arg, s64_arg, u32_arg, u64_arg, uint_arg, ulong_arg, ulonglong_arg.

And at any code probepoint, you can call register("regname") to get the value of the specified CPU register when the probe point was hit. u_register("regname") is like register("regname"), but interprets the value as an unsigned integer.  

CPU寄存器的值可以通过register(“regname”)或者u_register获得.

参考

https://sourceware.org/systemtap/tapsets/API-print-regs.html

https://sourceware.org/systemtap/tapsets/API-register.html

例如 :

[root@db- ~]# stap -e 'probe kprobe.function("tcp_v4_connect") {asmlinkage(); printf("%d, %d, %d\n", pid(), cpu(), print_regs()); exit()}'  
RIP: ffffffff8025b538  
RSP: ffff81061a62be50  EFLAGS: 00000246  
RAX: ffffffff8035bda0 RBX: ffff8105fa1e1300 RCX: 0000000000000802  
RDX: 0000000000000010 RSI: ffff81061a62bec8 RDI: ffff8105fa1e1300  
RBP: 00000000ffffffea R08: ffffffff802a4f80 R09: ffff8105fa1e1300  
R10: 0000000000000000 R11: ffff81045fc1a350 R12: ffff81061a62bec8  
R13: ffff81045fc1a300 R14: 0000000000000010 R15: 0000000000000802  
FS:  00002b12ea2a0a60(0000) GS:ffff81033a97e940(0000) knlGS:0000000000000000  
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033  
CR2: 0000003aca8e0090 CR3: 000000062b47f000 CR4: 00000000000006e0  
3666, 10, 0  

单独打印 :

[root@db-192-168-101-35 ~]# stap -e 'probe kprobe.function("tcp_v4_connect") {asmlinkage(); printf("%d, %d, %x\n", pid(), cpu(), register("rip")); exit()}'  
4859, 10, ffffffff8025b538  
kprobe支持的格式 :   
SystemTap supports the following constructs:  
kprobe.function(FUNCTION)  
kprobe.function(FUNCTION).return  
kprobe.module(NAME).function(FUNCTION)  
kprobe.module(NAME).function(FUNCTION).return  
kprobe.statement(ADDRESS).absolute  
Use .function probes for kernel functions and .module probes for probing functions of a specified module.   
If you do not know the absolute address of a kernel or module function, use .statement probes.   
Do not use wildcards in FUNCTION and MODULE names. Wildcards cause the probe to not register.   
Also, statement probes are available only in guru mode.  

这里几点需要注意,

1. 在函数和模块名部位, 不要使用通配符.

2. kprobe.statement探针仅仅支持guru模式运行, 也就是stap -g

       -g     Guru mode.  Enable parsing of unsafe expert-level constructs like embedded C.  

参考

1. https://sourceware.org/systemtap/langref/Probe_points.html

2. https://sourceware.org/systemtap/tapsets/API-asmlinkage.html

3. https://sourceware.org/systemtap/tapsets/

4. https://sourceware.org/systemtap/tapsets/API-returnval.html

5. https://sourceware.org/systemtap/tapsets/API-returnval.html

6. https://sourceware.org/systemtap/tapsets/API-returnstr.html

7. https://sourceware.org/systemtap/tapsets/API-register.html

8. https://sourceware.org/systemtap/tapsets/API-print-regs.html

Flag Counter

digoal’s 大量PostgreSQL文章入口