systemtap targets

Target变量

  • 默认变量 变量一般是在一个probe内的local变量
  • 全局变量 如果需要在probe之间共享变量,则需要在声明时加上global
  • target变量 target变量是用来获取被探测事件代码内部结构的变量,可以使用-L选项来查看某个探测点可以使用的target变量:stap -L 'kernel.function("vfs_read")'
    kernel.function("vfs_read@fs/read_write.c:294") $file:struct file* $buf:char* $count:size_t $pos:loff_t* 再看下fs/read_write.cvfs_read函数,这些target变量其实就是vfs_read函数的传参ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
  • 举例说明target变量的用法

比如监控进程读取文件时,打印出被读取文件的inode 从上面stap -L 'kernel.function("vfs_read")'知道vfs_readstruct file*类型的filetarget变量

查看内核源码结构体struct file*(定义在include/linux/fs.h

再查看结构体struct path(定义在include/linux/path.h

再查看结构体struct dentry(定义在include/linux/dcache.h

终于找到了inode(定义在include/linux/fs.h

最后,我们得到了这样一个变量:$file->f_path->dentry->d_inode->i_ino

编写systemtap脚本如下:

probe kernel.function("vfs_read").return  
{
     if(execname() != "stapio")
         printf("%s[%ld], %ld\n", execname(), pid(), $file->f_path->dentry->d_inode->i_ino)
}
vmstat[5117], 4026532032  

使用find / -inum 4026532032可以看到4026532032这个inode对应的是/proc/meminfo文件

如何打印出文件名呢,再看下第4步中的dentry结构体,其中有struct qstr d_name;,再查看struct qstr(定义在include/linux/dcache.h

文件名就是这个name变量了:$file->f_path->dentry->d_name->name

但是有个问题,从struct qstr的定义上我们可以得知,$file->f_path->dentry->d_name->name变量是个指针,也就是个地址(长整型),如何可以获取该指针指向的内容,也就是我们需要的文件名呢?

systemtap内置带有获取内核空间数据的函数,这一系列函数的作用就是读取内核内存中address所指向的不同类型的数据:

  1. kernel_char(address)
  2. kernel_short(address)
  3. kernel_int(address)
  4. kernel_long(address)
  5. kernel_string(address)
  6. kernel_string_n(address, n)

由此我们可以用kernel_string($file->f_path->dentry->d_name->name)来获取文件名,将脚本改写如下:

probe kernel.function("vfs_read").return  
{
        if(execname() != "stapio")
            printf("%s[%ld], %ld, %s\n", execname(), pid(), $file->f_path->dentry->d_inode->i_ino, kernel_string($file->f_path->dentry->d_name->name))
}
probe timer.s(2)  
{
        exit()
}
vmstat[16556], 4026532032, meminfo