最近我在重装了我的笔记本,OS用的是Ubuntu12.04.3,内核版本是:
-
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,但是发现按照老的方法不行了。执行:
-
stap -e '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掉了。
-
if (!strcmp(m->name, "kernel")) {
-
/* notes_addr = m->build_id_offset; REPLACE THIS LINE BY THE NEXT ONE */
-
notes_addr = _stp_module_relocate("kernel", "_stext", m->build_id_offset);
-
base_addr = _stp_module_relocate("kernel", "_stext", 0);
-
} else {
我们看下当前的源代码:
-
/* notes end address */
-
if (!strcmp(m->name, "kernel")) {
-
notes_addr = _stp_kmodule_relocate("kernel",
-
"_stext", m->build_id_offset);
-
base_addr = _stp_kmodule_relocate("kernel",
-
"_stext", 0);
接下来搜到了这篇文章:SystemTap初体验,这片文章把打印出Build-id dismatch那部分的检查代码给修改了,跳过了检查build-id。
代码还是在runtime/sym.c下,把theory!= practice这个条件注释掉。
-
if (rc /*|| (theory != practice*)*/) {
-
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
-
_stp_error ("Build-id mismatch [man error::buildid]: \"%s\" byte %d (0x%02x vs 0x%02x) address %#lx rc %d\n",
-
m->path, j, theory, practice, notes_addr, rc);
-
return 1
表面上看,结果是对的,但是执行真正的内核探察,就会发现会报错。因为systemtap报错是有原因的。他表明了内核符号表和运行的内核不匹配,你跳过检查,不过是掩耳盗铃的勾当。
一线曙光
我痛苦我彷徨我纠结的时候,我看到了这个帖子:,下面有个回复提供了,这个脚本执行的结果我指明了方向。为了不让这个给了我巨大帮助的脚本湮没在历史的长河之中,为了表示我对作者的无限感激,我把它全文copy下来:
-
#!/bin/bash
-
-
distro="$(lsb_release --id --short)"
-
if [ "$distro" != "Debian" -a "$distro" != "Ubuntu" ]; then
-
echo Unsupported distro $distro
-
exit 1
-
fi
-
-
# 2.6.32-5-amd64
-
# 2.6.32-37-generic
-
abiname="$(cut -d " " -f 3 /proc/version)"
-
-
# 2.6.32
-
baseversion="$(echo "$abiname" | cut -d "-" -f 1)"
-
-
case "$distro" in
-
Debian) # 2.6.32-39
-
if uname -v | grep -q Debian; then
-
version=$(uname -v | cut -d " " -f 4)
-
else
-
version="$(cut -d " " -f 5 /proc/version | cut -d ")" -f 1)"
-
fi
-
;;
-
Ubuntu)
-
# 2.6.32-37.81
-
version="$(cut -d " " -f 2 /proc/version_signature | cut -d "-" -f 1-2)"
-
;;
-
esac
-
-
-
(
-
echo make >= 0
-
echo linux-image-$abiname = $version
-
echo linux-headers-$abiname = $version
-
echo linux-kbuild-$baseversion >= $version
-
case "$distro" in
-
Debian) echo linux-image-$abiname-dbg = $version
-
;;
-
Ubuntu) echo linux-image-$abiname-dbgsym = $version
-
;;
-
esac
-
) | while read package relation requiredversion; do
-
installedversion="$(dpkg-query -W "$package" 2> /dev/null | cut -f 2)"
-
if [ "$installedversion" = "" ]; then
-
availableversion="$(apt-cache show $package 2> /dev/null | grep ^Version: | cut -d " " -f 2)"
-
if [ "$availableversion" = "" ]; then
-
echo "You need package $package but it does not seem to be available"
-
if [ "$distro" = "Ubuntu" -a "$(echo $package | grep dbgsym$)" ]; then
-
echo " Ubuntu -dbgsym packages are typically in a separate repository"
-
echo " Follow to add this repository"
-
elif [ "$distro" = "Debian" -a "$(echo $package | grep dbg$)" ]; then
-
echo " Debian does not have -dbg packages for all kernels. Consider switching to a kernel that has one."
-
fi
-
else
-
echo "Please install $package"
-
fi
-
elif ! dpkg --compare-versions $installedversion $relation $requiredversion; then
-
echo "Package $package version $installedversion does not match version of currently running kernel: $requiredversion"
-
echo " Consider apt-get upgrade && reboot"
-
fi
-
done
-
-
user="$(id --user --name)"
-
if [ "$user" != "root" ]; then
-
groups="$(id --groups --name)"
-
for i in stapusr stapdev; do
-
if [ "$(echo $groups | grep $i)" = "" ]; then
-
echo "Be root or adduser $user $i"
-
fi
-
done
-
fi
执行结果如下:
-
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
记忆力好的筒子可能会记得,我前面提到,我的内核版本是:
-
root@manu-hacks:~/software/systemtap# uname -r
-
3.8.0-29-generic
尼玛,我的内核版本明明是3.8.0-29.42~precise1,可是uname -r告诉我的是3.8.0-29-generic,而我上篇博客提到的get-dbg,错误的下载了debuginfo。
正确的方法
1 寻找到正确的内核版本,执行这个,看到我们的版本信息是
-
root@manu-hacks:~/software/systemtap# cat /proc/version_signature
-
Ubuntu 3.8.0-29.42~precise1-generic 3.8.13.5
2去路径下找到你的debug info。下载之
-
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 安装之
-
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?
-
$ cd $HOME
-
$ sudo apt-get install dpkg-dev debhelper gawk
-
$ mkdir tmp
-
$ cd tmp
-
$ sudo apt-get build-dep --no-install-recommends linux-image-$(uname -r)
-
$ apt-get source linux-image-$(uname -r)
-
$ cd linux-2.6.31 (this is currently the kernel version of 9.10)
-
$ fakeroot debian/rules clean
-
$ AUTOBUILD=1 fakeroot debian/rules binary-generic skipdbg=false
-
$ sudo dpkg -i ../linux-image-debug-2.6.31-19-generic_2.6.31-19.56_amd64.ddeb
最后,我不是文艺青年,我只是一个想顺顺利利装上systemtap的苦逼青年。泪流满面啊。
阅读(1479) | 评论(0) | 转发(0) |