由于发行版的内核默认无内核调试信息,所以需要一个调试内核镜像,在http://ddebs.ubuntu.com/pool/main/l/linux-lts-wily/。找到内核版本相对应的内核调试镜像(版本号包括后面的发布次数、硬件体系等都必须一致),如针对我上面的内核版本,就可以用如下命令下载安装内核调试镜像:

dpkg -i linux-image-4.2.0-42-generic-dbgsym_4.2.0-42.49-14.04.1_amd64.ddeb

一般这种方法下,你只需要使用apt在线安装systemtap即可:

$sudo apt-get install systemtap

寻找到正确的内核版本,执行这个,看到版本信息是

cat /proc/version_signature

uname -r


stap -e 'probe kernel.function("sys_open") {log("hello world"exit()}'


对应的systemtap简单脚本test.tsp如下:
probe udp.sendmsg {
  if ( dport == 1234 ) {
        printf("send to the port 1234 is PID %d ,process name is %s",pid(),execname())
  }
}


http://blog.chinaunix.net/uid-24774106-id-3949772.html


最近我在重装了我的笔记本,OS用的是Ubuntu12.04.3,内核版本是:

  1. root@manu-hacks:~/software/systemtap# uname -r
    3.8.0-29-generic
    熟悉我博客的人知道,去年写过一博客,就叫systemtap在Ubuntu的安装,当时我用的是Ubuntu 12.04,内核还是3.2.0-29的内核。为啥我又冒出来一篇博客。
   我安装的最新版本是3.8.0.29,但是发现按照老的方法不行了。执行:
  1. stap -'probe kernel.function("sys_open") {log("hello world") exit()}'
    结果报错,报错信息是 ERROR:Build-id mismatch 云云。
   不愿意听我罗嗦的,直接跳转到正确的方法

   错误的尝试
   我最初以为是因为systemtap版本太低,然后源代码装了systemtap 2.0/2.1/2.3的版本,结果还是不行。后来我怀疑是不是因为我kernel升过级,重新安装还是不行。在后来,我看到了Brenden's blog中有一文章叫Using SystemTap提到了这个问题,给出了Solution,无奈他的方法是老黄历了,不能解决问题,这个bug,SystemTap早就修过了.
   他的解决方法是:在runtime/sym.c中将注释行替换成下面的一行,事实上,这个bug ,systemtap早就已经fix掉了。 
  1. if (!strcmp(m->name, "kernel")) {
  2. /* notes_addr = m->build_id_offset; REPLACE THIS LINE BY THE NEXT ONE */
  3.    notes_addr = _stp_module_relocate("kernel", "_stext", m->build_id_offset);
  4.    base_addr = _stp_module_relocate("kernel", "_stext", 0);
  5. else {
    我们看下当前的源代码:
  1.           /* notes end address */
  2.           if (!strcmp(m->name, "kernel")) {
  3.               notes_addr = _stp_kmodule_relocate("kernel",
  4.                   "_stext", m->build_id_offset);
  5.               base_addr = _stp_kmodule_relocate("kernel",
  6.                   "_stext", 0);
     接下来搜到了这篇文章: SystemTap初体验,这片文章把打印出Build-id dismatch那部分的检查代码给修改了,跳过了检查build-id。
     代码还是在runtime/sym.c下,把theory!= practice这个条件注释掉。
  1. if (rc /*|| (theory != practice*)*/) {
  2. #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
  3.       _stp_error ("Build-id mismatch [man error::buildid]: \"%s\" byte %d (0x%02x vs 0x%02x) address %#lx rc %d\n",
  4.          m->path, j, theory, practice, notes_addr, rc);
  5.       return 1
    表面上看,结果是对的,但是执行真正的内核探察,就会发现会报错。因为systemtap报错是有原因的。他表明了内核符号表和运行的内核不匹配,你跳过检查,不过是掩耳盗铃的勾当。

    一线曙光
   
我痛苦我彷徨我纠结的时候,我看到了这个帖子: systemtap reports error 'Build-id mismatch',下面有个回复提供了 脚本,这个脚本执行的结果我指明了方向。为了不让这个给了我巨大帮助的脚本湮没在历史的长河之中,为了表示我对作者的无限感激,我把它全文copy下来: 
  1. #!/bin/bash

  2. distro="$(lsb_release --id --short)"
  3. if [ "$distro" != "Debian" -"$distro" != "Ubuntu" ]; then
  4.     echo Unsupported distro $distro
  5.     exit 1
  6. fi

  7. # 2.6.32-5-amd64
  8. # 2.6.32-37-generic
  9. abiname="$(cut -d " " -f 3 /proc/version)"

  10. # 2.6.32
  11. baseversion="$(echo "$abiname" | cut -d "-" -f 1)"

  12. case "$distro" in 
  13. Debian) # 2.6.32-39
  14.     if uname -| grep -q Debian; then
  15.      version=$(uname -| cut -" " -f 4)
  16.     else
  17.      version="$(cut -d " " -f 5 /proc/version | cut -d ")" -f 1)"
  18.     fi
  19.     ;;
  20. Ubuntu)
  21.     # 2.6.32-37.81
  22.     version="$(cut -d " " -f 2 /proc/version_signature | cut -d "-" -f 1-2)"
  23.     ;;
  24. esac


  25. (
  26. echo make >= 0
  27. echo linux-image-$abiname = $version
  28. echo linux-headers-$abiname = $version
  29. echo linux-kbuild-$baseversion >= $version
  30. case "$distro" in
  31. Debian) echo linux-image-$abiname-dbg = $version
  32.     ;;
  33. Ubuntu) echo linux-image-$abiname-dbgsym = $version
  34.     ;;
  35. esac
  36. ) | while read package relation requiredversion; do
  37.     installedversion="$(dpkg-query -W "$package" 2> /dev/null | cut -f 2)"
  38.     if [ "$installedversion" = "" ]; then
  39.     availableversion="$(apt-cache show $package 2> /dev/null | grep ^Version: | cut -d " " -f 2)"
  40.     if [ "$availableversion" = "" ]; then
  41.      echo "You need package $package but it does not seem to be available"
  42.      if [ "$distro" = "Ubuntu" -"$(echo $package | grep dbgsym$)" ]; then
  43.         echo " Ubuntu -dbgsym packages are typically in a separate repository"
  44.         echo " Follow https://wiki.edubuntu.org/DebuggingProgramCrash to add this repository"
  45.      elif [ "$distro" = "Debian" -"$(echo $package | grep dbg$)" ]; then
  46.         echo " Debian does not have -dbg packages for all kernels. Consider switching to a kernel that has one."
  47.      fi
  48.     else
  49.      echo "Please install $package"
  50.     fi
  51.     elif ! dpkg --compare-versions $installedversion $relation $requiredversion; then
  52.     echo "Package $package version $installedversion does not match version of currently running kernel: $requiredversion"
  53.     echo " Consider apt-get upgrade && reboot"
  54.     fi
  55. done

  56. user="$(id --user --name)"
  57. if [ "$user" != "root" ]; then
  58.     groups="$(id --groups --name)"
  59.     for i in stapusr stapdev; do
  60.     if [ "$(echo $groups | grep $i)" = "" ]; then
  61.      echo "Be root or adduser $user $i"
  62.     fi
  63.     done
  64. fi
    执行结果如下:
  1. Package linux-image-3.8.0-29-generic-dbgsym version 3.8.0-29.42 does not match version of currently running kernel: 3.8.0-29.42~precise1
    记忆力好的筒子可能会记得,我前面提到,我的内核版本是:
  1. root@manu-hacks:~/software/systemtap# uname -r
  2. 3.8.0-29-generic
    尼玛,我的内核版本明明是 3 . 8 . 0 - 29 . 42~precise1,可是uname -r告诉我的是 3 . 8 . 0 - 29 - generic,而我上篇博客提到的get-dbg,错误的下载了debuginfo。

 

   正确的方法 
    1 寻找到正确的内核版本,执行这个,看到我们的版本信息是
  1. root@manu-hacks:~/software/systemtap# cat /proc/version_signature 
  2. Ubuntu 3.8.0-29.42~precise1-generic 3.8.13.5
    2 http://ddebs.ubuntu.com/pool/main/l/linux-lts-raring/ 路径下找到你的debug info。下载之
  1. wget http://ddebs.ubuntu.com/pool/main/l/linux-lts-raring/linux-image-3.8.0-29-generic-dbgsym_3.8.0-29.42~precise1_i386.ddeb
   3 安装之    
  1. dpkg -i linux-image-3.8.0-29-generic-dbgsym_3.8.0-29.42~precise1_i386.ddeb
    如果你和我一样苦逼,装错了,请先执行dpkg -r 错误的版本。 如果你记不清楚错误的名字,请执行dpkg --list |grep linux-image.

   如果你不是普通青年,你是文艺青年,你也可以自己下载source code,自己编出内核符号表。参考下面的步骤,来源在: Linux系统分析工具续-SystemTap和火焰图(Flame Graph),或者自行搜索  How do I build a debuginfo kernel if one isn't available?
  1.     $ cd $HOME
  2.     $ sudo apt-get install dpkg-dev debhelper gawk
  3.     $ mkdir tmp
  4.     $ cd tmp
  5.     $ sudo apt-get build-dep --no-install-recommends linux-image-$(uname -r)
  6.     $ apt-get source linux-image-$(uname -r)
  7.     $ cd linux-2.6.31 (this is currently the kernel version of 9.10)
  8.     $ fakeroot debian/rules clean
  9.     $ AUTOBUILD=1 fakeroot debian/rules binary-generic skipdbg=false
  10.     $ sudo dpkg -../linux-image-debug-2.6.31-19-generic_2.6.31-19.56_amd64.ddeb
    最后,我不是文艺青年,我只是一个想顺顺利利装上systemtap的苦逼青年。泪流满面啊。


Logo

更多推荐