最近做LVS的性能测试,自然会用的各种工具检视系统状态,用了很多工具,都 不甚满意,于是想尝试下Systemtap,系统环境是SUSE Enterprise SP2,已经3.0的 kernel,可以search到的suse上安装systemtap的内容不多,碰到问题并解决了 的更是少,自然我又要成为苦逼的问题解决者了。

##正常安装的步骤是##

  • 添加suse enterprise的包含debuginfo的iso,有几个G啊
  • zypper in kernel-default-debuginfo
  • zypper in systemtap

当我做完了以上这些,运行一个简单的脚本时:

systemtap hello_world 
sudo stap -ve 'probe begin { log("hello world") exit() }'

这个简单的例子是ok的,因为它不会涉及到systemtap的pass5,与kernel module交互。跑下面这个的时候,就不行了:

systemtap hello_world 
stap -v -e 'probe vfs.read {printf("has VFS read()\n"); exit()}' 

会报出类似ERROR: Build-id mismatch: "kernel" vs. "vmlinux" byte 0 (0xf9 vs 0xa2)的问题,关于build-id mismatch这个问题,还是可以 搜索到不少资料的,不过告诉如何解决的也不多。先说明下这个问题, kernel-default-debuginfo里面是附赠了一个kernel elf文件的,在SUSE里, 安装后放在/usr/lib/debug/boot/vmlinux-3.0.13-0.27-default.debug,这 是debug版本的kernel vmlinux文件,是elf原始文件,未经压缩。stap运行时会去检查它的。 执行eu-readelf -n /usr/lib/debug/boot/vmlinux-3.0.13-0.27-default.debug,可以拿到的 build-id,执行结果的第一个字节是f9,那另外一个a2是从哪里得出来的,猜想应该和当 前运行的kernel有关,于是拿到当前运行的vmlinux的压缩文件,解压后检查 build-id:

check build-id 
   gunzip /boot/vmlinux-3.0.13-0.27-default.gz 
   eu-readelf -n /boot/vmlinux-3.0.13-0.27-default 

执行结果也是f9,是对得上的啊。

但是注意,这份.gz文件是SUSE附赠的,跟当前跑的vmlinz文件没有关系,于是 开始打vmlinuz文件的主意,得先想办法把vmlinuz->vmlinux,及bzImage到elf, 才能去取它的build-id, https://www.globalways.net/blog/archives/76-Extracting-bzImage-from-vmlinuz.html有可行的方法。 eu-readelf -n vmlinux-unpacked的结果果然是a2,我只能是怀疑SUSE给的 默认vmlinuz有问题了,不能和SUSE提供的用于debuginfo的vmlinux匹配。

只能另外想办法,其实systemtap做kernel mismatch判断的关键代码,就在:

systemtap/runtime/sym.c
static int _stp_build_id_check (struct _stp_module *m,
            unsigned long notes_addr,
            struct task_struct *tsk)
{
...
/* just hack it */
if (rc || (theory != practice)) {
      const char *basename;
      basename = strrchr(m->path, '/');
      if (basename)
|   basename++;
      else
|   basename = m->path;

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
      _stp_error ("Build-id mismatch: \"%s\" vs. \"%s\" byte %d (0x%02x vs 0x%02x) address %#lx rc %d\n",
|   |     m->name, basename, j, theory, practice, notes_addr, rc);
      return 1;
#else
      /* This branch is a surrogate for kernels affected by Fedora bug
       * #465873. */
      _stp_warn (KERN_WARNING
|   |    "Build-id mismatch: \"%s\" vs. \"%s\" byte %d (0x%02x vs 0x%02x) rc %d\n",
|   |    m->name, basename, j, theory, practice, rc);
#endif
      break;
    } /* end mismatch */

关键就在于if (rc || (theory != practice)),小小修改的一下,写成: if (0 && (rc || (theory != practice)))就OK了,绕过了检查。然后重新编 译systemtap,直接用的SUSE提供的老版本的源码,新的会有问题,注意还要用 到SUSE提供的libdwfl的source code,才能完成编译,编译时在 /usr/src/packages/SOURCES/elfutils-0.152/libdwfl/linux-kernel-modules.c 文件上遇到了问题,稍作修改就可过关。尝试下新编译出来的stap,完全OK,它是不知 道’build-id mismatch`为何物的,敢这样改也就是因为都是offical的东西,本 应该match得上,应该不会出什么大问题,实践中检验吧。

Have fun.