進行linux核心和使用者空間開發測試
sailor_forever sailing_9806#163.com
(本原創文章發表于sailor_forever 的個人blog,未經本人許可,不得用于商業用途。任何個人、媒體、其他網站不得私自抄襲;網絡媒體轉載請注明出處,增加原文連結,否則屬于侵權行為。如有任何問題,請留言或者發郵件給sailing_9806#163.com)
【摘要】本文主要介紹在ubuntu平台 + 自定義核心上如何安裝systemtap工具包及解決編譯加載運作過程中的一些問題,如何利用systemtap工具監測分析核心函數,核心子產品及使用者态程式。
【關鍵字】ubuntu, systemtap, utrace, backtrace, dtrace,callstack
systemtap 是學習核心一個必不可少的工具,它不僅可以偵測核心空間的相關資訊,還可以偵測使用者空間的資訊,是研究核心源代碼、優化系統性能及調試診斷系統問題的一個必備工具。相關原理資訊可參見附錄及“linux 下的一個全新的性能測量和調式診斷工具 systemtap, 第 3 部分:
systemtap”
用系統工具自動安裝systemtap時,使用者不用考慮各個軟體包的依賴關系,系統會自動根據目前核心版本下載下傳相應的軟體包。
dd@ubuntu:/mnt/hgfs/systemtap/kvm$ sudoapt-get install systemtap
。。
the following extra packages will beinstalled:
libdw1 systemtap-commonsystemtap-runtime
the following new packages will beinstalled:
libdw1 systemtap systemtap-common systemtap-runtime
。
get:1 http://us.archive.ubuntu.com/ubuntu/quantal-updates/main libdw1 i386 0.153-1ubuntu1.1 [216 kb]
如上可知,系統自動安裝了相關的4個軟體包libdw1 systemtap-common systemtap-runtime
有時候系統自動安裝的不一定能用,這個時候需要更新,此時隻能通過下載下傳源代碼自己編譯
首先要解除安裝系統之前安裝的相關package,避免後續帶來其他副作用。
dd@ubuntu:/mnt/hgfs/systemtap$ sudo apt-getremove systemtap systemtap-common systemtap-runtime
removing systemtap ...
removing systemtap-common ...
removing systemtap-runtime ...
processing triggers for man-db ...
下載下傳相應版本的源碼包。源碼包并不是越新越好,因為他們之間有一定的依賴關系,最簡單的是按照核心源碼包釋出的時間來選擇systemtap。
./configure --with-elfutils=../elfutils-0.156 --prefix=/usr/local
。。。。。
configure: ./configure ‘--with-elfutils=../elfutils-0.156‘‘--prefix=/usr/local‘ --prefix=/home/dd/systemtap-2.0-4155
configure: running systemtap uninstalled, entirely out of the buildtree,
configure: is not supported.
重新開機系統之後再執行,仍然如此,不知是否有其他副作用
dd@ubuntu:/mnt/hgfs/systemtap/systemtap-2.0$sudo make
ln -fs libdw.so libdw.so.1
ln: failed to create symbolic link `libdw.so.1‘: operation notsupported
make[4]: *** [libdw.so] error 1
windows不支援符号連結,是以system包不能放在windows目錄編譯
dd@ubuntu:~/systemtap/systemtap-2.0$ sudomake
。。。
m4 -di386 -ddisassembler../../../elfutils-0.156/libcpu/defs/i386 > i386_defst
/bin/bash: m4: command not found
system調試核心或者application,必須有debuginfo,是以必須安裝核心debug symbol。具體參見附錄。
systemtap安裝完畢後,進行簡單的測試。如果能列印出helloworld則認為基本功能ok。
dd@ubuntu:/usr/src$ sudo stap -ve ‘probebegin { log("hello world") exit() }‘
pass 1: parsed user script and 81 libraryscript(s) using 22640virt/13560res/2192shr kb, in 80usr/10sys/93real ms.
pass 2: analyzed script: 1 probe(s), 2function(s), 0 embed(s), 0 global(s) using 22904virt/14088res/2264shr kb, in0usr/0sys/3real ms.
pass 3: translated to c into"/tmp/stapngferv/stap_202537bef6262d2233e5759ff826c9d3_744_src.c"using 22904virt/14364res/2508shr kb, in 0usr/0sys/0real ms.
pass 4: compiled c into"stap_202537bef6262d2233e5759ff826c9d3_744.ko" in4760usr/900sys/6360real ms.
pass 5: starting run.
hello world
pass 5: run completed in 0usr/20sys/359realms.
dd@ubuntu:/usr/src$ sudo stap -e ‘probekernel.function("sys_open") {log("hello world") exit()}‘
dd@ubuntu:/mnt/hgfs/systemtap/example$ cat./timer.stp
#!/usr/bin/stap
probekernel.function("do_timer").return {
print_backtrace();
printf("\n");
exit();
}
dd@ubuntu:/mnt/hgfs/systemtap/example$ sudostap ./timer.stp
returning from: 0xc1091520 : do_timer+0x0/0x40 [kernel]
returning to : 0xc1097e4a : tick_do_update_jiffies64+0xca/0x130 [kernel]
0xc1098074 : tick_sched_timer+0xc4/0xd0[kernel]
0xc1068f70 : __run_hrtimer+0x70/0x190 [kernel]
0xc1069be7 : hrtimer_interrupt+0xe7/0x2a0 [kernel]
0xc15d0769 :smp_apic_timer_interrupt+0x59/0x8d [kernel]
0xc15c9815 : apic_timer_interrupt+0x31/0x38[kernel]
0xc1036f35 : native_safe_halt+0x5/0x10[kernel]
0xc1017b66 : default_idle+0x46/0x190 [kernel]
0xc1018716 : cpu_idle+0xb6/0xe0 [kernel]
0xc159f715 : rest_init+0x5d/0x68 [kernel]
0xc18ae9be : start_kernel+0x35d/0x363 [kernel]
0xc18ae303 : i386_start_kernel+0xa6/0xad[kernel]
dd@ubuntu:/mnt/hgfs/systemtap/kvm$ sudostap ./vmx_inject_irq.stp
[sudo] password for dd:
semantic error: while resolving probepoint: identifier ‘kernel‘ at ./vmx_inject_irq.stp:1:7
source: probe kernel.function("vmx_inject_irq") {
^
semantic error: no match
pass 2: analysis failed. try again with another ‘--vp 01‘ option.
dd@ubuntu:/mnt/hgfs/systemtap/kvm$ cat/proc/kallsyms | grep vmx_inject_irq
00000000 t vmx_inject_irq [kvm_intel]
kvm_intel以子產品形式加載,其symbol不能以kernel.function形式通路。
ubuntu平台上需要修正動态module的debug info資訊
dd@ubuntu:/mnt/hgfs/systemtap/kvm$ catfix-module.sh
#!/bin/sh
for file in `find /usr/lib/debug -name‘*.ko‘ -print`
do
buildid=`eu-readelf-n $file| grep build.id: | awk ‘{print $3}‘`
dir=`echo$buildid | cut -c1-2`
fn=`echo$buildid | cut -c3-`
mkdir-p /usr/lib/debug/.build-id/$dir
ln-s $file /usr/lib/debug/.build-id/$dir/$fn
ln-s $file /usr/lib/debug/.build-id/$dir/${fn}.debug
done
dd@ubuntu:/mnt/hgfs/systemtap/kvm$ sudostap -l ‘module("*kvm*").function("*")‘ >kvm-module-sysm.log
dd@ubuntu:/mnt/hgfs/systemtap/kvm$ catkvm-module-sysm.log | grep vmx_inject_irq
module("kvm_intel").function("vmx_inject_irq@/build/buildd/linux-3.5.0/arch/x86/kvm/vmx.c:4036")
dd@ubuntu:/mnt/hgfs/systemtap/kvm$ catvmx_inject_irq.stp
probemodule("kvm_intel").function("vmx_inject_irq") {
printf("-------------------------------------\n")
print_backtrace()
很多符号都無法解析啊??????? 根本原因待分析。
-------------------------------------
0xf86e4230 : vmx_inject_irq+0x0/0xe0[kvm_intel]
0xf998e694 [kvm]
0xc10654cd (inexact)
0xf997b25b [kvm] (inexact)
0xf998f11f [kvm] (inexact)
0xf997922b [kvm] (inexact)
0xc1075dee (inexact)
0xc1075ebf (inexact)
0xc1099a12 (inexact)
0xc109be08 (inexact)
0xf9978dd0 [kvm] (inexact)
0xc115e8fa (inexact)
0xc1069c65 (inexact)
0xc109c120 (inexact)
0xc115ee88 (inexact)
0xc15cff5f (inexact)
0xc15c0000 (inexact)
使用者态監控需要utrace支援,但utrace預設隻有redhat系列的kernel支援,如fedora等。其他發行版linux需要patch
systemtap的readme中有關于utrace支援的描述:
- consider applying the utrace kernelpatches, if you wish to probe
user-space applications. http://sourceware.org/systemtap/wiki/utrace
orif your kernel is near 3.5, apply the uprobes and related patches
(see news). or if your kernel is>= 3.5, enjoy the built-in uprobes.
- build the kernel using your normalprocedures. enable
config_debug_info, config_kprobes, config_relay, config_debug_fs,
config_modules, config_module_unload, config_utrace if able
- % make modules_install install headers_install
- boot into the kernel.
ubuntu 要支援utrace有兩種方式:
1. 自己給 ubuntu 自帶的老 kernel 應用 utrace 更新檔,并重新編譯。但好像redhat提供的patch不能通路了
http://people.redhat.com/roland/utrace/
ubuntu 11.10 (oneiric)上編譯帶utrace更新檔的核心
2. 将 kernel 更新到官方最新的 3.5 或以上的版本。最新的kernel 預設包含了 uprobes 機制,不再需要 utrace 更新檔了。
kernel hacking --->
[*] tracers --->
[*] enable uprobes-based dynamic events
新的核心裡已經沒有選項config_utrace,選擇utrace相關的選項即可,包括config_arch_supports_uprobesconfig_uprobes config_uprobe_event config_kprobes config_debug_fs 等
dd@ubuntu:/mnt/hgfs/systemtap/example$ cat/boot/config-3.5.0-17-generic | grep uprobe
config_arch_supports_uprobes=y
config_uprobes=y
config_uprobe_event=y
dd@ubuntu:/mnt/hgfs/systemtap/example$ cat/boot/config-3.5.0-17-generic | grep kprobe
config_kprobes=y
config_have_kprobes=y
# config_kprobes_sanity_test is not set
config_kprobe_event=y
如果不是必須用某一個版本,建議直接更新到3.5以後的核心版本,如ubuntu 12.10
首先寫了一個使用者态的測試函數,可參考如下
utrace調試的程式需要在編譯時加 -g
選項
dd@ubuntu:/mnt/hgfs/systemtap/example$./utrace-test
obtained 8 stack frames.nm
./utrace-test() [0x80485c1]
[0xb77a3400]
./utrace-test() [0x804869f]
./utrace-test() [0x80486ac]
./utrace-test() [0x80486b6]
./utrace-test() [0x80486eb]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0xb75ff4d3]
./utrace-test() [0x80484b1]
有函數調用棧,但是沒有函數名稱,莫非是編譯優化導緻無符号表?經查需要傳遞(-rdynamic),-rdynamic可用來通知連結器将所有符号添加到動态符号表中
dd@ubuntu:/mnt/hgfs/systemtap/example$ gcc-g -rdynamic utrace-test.c -o utrace-test
obtained 7 stack frames.
./utrace-test(print_trace+0x1f) [0x80487ab]
./utrace-test(dummy_function_3+0xb)[0x8048840]
./utrace-test(test2+0xb) [0x804884d]
./utrace-test(test1+0xb) [0x804885a]
./utrace-test(main+0xb) [0x8048867]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0xb75f44d3]
./utrace-test() [0x80486c1]
ok,能夠正确列印出函數調用順序,參考基準已經建立起來了。
如下測試顯示stap可以監測到待調試程式utrace-test的函數清單。
dd@ubuntu:/mnt/hgfs/systemtap/example$ sudostap -l ‘process("./utrace-test").function("*")‘
process("/mnt/hgfs/systemtap/example/utrace-test").function("dummy_function_3@/mnt/hgfs/systemtap/example/utrace-test.c:26")
process("/mnt/hgfs/systemtap/example/utrace-test").function("main@/mnt/hgfs/systemtap/example/utrace-test.c:39")
process("/mnt/hgfs/systemtap/example/utrace-test").function("print_trace@/mnt/hgfs/systemtap/example/utrace-test.c:7")
process("/mnt/hgfs/systemtap/example/utrace-test").function("test1@/mnt/hgfs/systemtap/example/utrace-test.c:34")
process("/mnt/hgfs/systemtap/example/utrace-test").function("test2@/mnt/hgfs/systemtap/example/utrace-test.c:30")
當任意一個函數被調用時,列印其函數名及參數
dd@ubuntu:/mnt/hgfs/systemtap/example$ catutrace.stp
probeprocess("./utrace-test").function("*") {
printf("%s(%s)\n", probefunc(), $$parms);
實際檢測到的函數調用順序與實際比對
dd@ubuntu:/mnt/hgfs/systemtap/example$ sudostap ./utrace.stp
_start()
__libc_csu_init()
__i686.get_pc_thunk.bx()
_init()
frame_dummy()
register_tm_clones()
main()
test1()
test2()
dummy_function_3()
print_trace()
__do_global_dtors_aux()
deregister_tm_clones()
_fini()
利用print_backtrace列印監測點的函數調用棧。
dd@ubuntu:/mnt/hgfs/systemtap/example$ catutrace-stack.stp
probeprocess("./utrace-test").function("dummy_function_3"){
printf("%s(%s)\n", probefunc(),$$parms);
dd@ubuntu:/mnt/hgfs/systemtap/example$ sudostap ./utrace-stack.stp
semantic error: while resolving probepoint: identifier ‘process‘ at ./utrace.stp:3:7
source: probeprocess("./utrace-test").function("dummy_function_3").return{
semantic error: process return probes not available withinode-based uprobes
pass 2: analysis failed. try again with another ‘--vp 01‘ option.
去掉return,再執行
warning: no or bad debug frame hdr
warning: no binary search table for eh frame, doing slow linear searchfor stap_3fb2bcd721ab82a6de577773eff766b_10596
0xf8887e10 [stap_3fb2bcd721ab82a6de577773eff766b_10596+0xbe10/0x0]
0xf8888209[stap_3fb2bcd721ab82a6de577773eff766b_10596+0xc209/0x0]
0xf88868b0[stap_3fb2bcd721ab82a6de577773eff766b_10596+0xa8b0/0x0]
0xc113eb3f
0xc104e51b (inexact)
0xc161ac9d (inexact)
沒有列印出使用者态的調用堆棧,具體原因待分析。
加載動态編譯出來的module時失敗unknown symbol inmodule
dd@ubuntu:/mnt/hgfs/systemtap/kvm$ sudostap -ve ‘probe begin { log("hello world") exit() }‘
pass 4: compiled c into"stap_aeecf973d1b00387ff715fbb9a761ae9_688.ko" in6010usr/1080sys/10345real ms.
error inserting module‘/tmp/stapoo63sx/stap_aeecf973d1b00387ff715fbb9a761ae9_688.ko‘: unknown symbolin module
warning: /usr/bin/staprun exited withstatus: 1
pass 5: run completed in 0usr/0sys/11realms.
pass 5: run failed. try again with another ‘--vp 00001‘ option.
dd@ubuntu:/mnt/hgfs/systemtap/kvm$ sudostap -e ‘probe kernel.function("sys_open") {log("helloworld") exit()}‘
error inserting module‘/tmp/stappq4mh5/stap_b3efd67e86a8df14579c7f419ddcd07f_826.ko‘: unknown symbolin module
pass 5: run failed. try again with another ‘--vp 00001‘ option
檢視核心log,分析unknown symbol inmodule的意義,這種問題通常都是某個symbol無法找到。
dd@ubuntu:~/systemtap/systemtap-2.5$ dmesg| tail
…
[ 76.855961] stap_880c6f2fc0076129ea6feb7db23da703_899:
unknown parameter `_stp_bufsize‘
“-k”參數保留運作過程中生産的檔案,查找線索
dd@ubuntu:~$ sudo stap -k -ve ‘probe begin{ log("hello world") exit() }‘
error inserting module‘/tmp/staplcmn6z/stap_4270.ko‘: unknown symbol in module
pass 5: run completed in 0usr/0sys/3realms.
keeping temporary directory"/tmp/staplcmn6z"
dd@ubuntu:~$ sudo nm/tmp/staplcmn6z/stap_4270.ko | grep _stp_bufsize
00000032 r __mod__stp_bufsize76
00000050 r __mod__stp_bufsizetype75
00000000 r __param__stp_bufsize
00000515 r __param_str__stp_bufsize
00000130 b _stp_bufsize
“--vp00005”啟動systemtap的調試選項獲得更多的log。 具體用法可參考
dd@ubuntu:/mnt/hgfs/systemtap/example$ sudostap --vp 00005 -ve‘probe begin{printf("hello world\n") exit()}‘
running /usr/local/bin/staprun -v -v -v -v -v-r /tmp/stapwlfjon/stap_333448f0b355beeb59e41a501a5421fd_817.ko
staprun:parse_modpath:386
staprun:insert_module:71 inserting module/tmp/stapwlfjon/stap_333448f0b355beeb59e41a501a5421fd_817.ko
staprun:insert_module:97module options: _stp_bufsize=0
staprun:insert_module:105 module pathcanonicalized to ‘/tmp/stapwlfjon/stap_333448f0b355beeb59e41a501a5421fd_817.ko‘
staprun:insert_module:183 modulestap_333448f0b355beeb59e41a501a5421f_6340 inserted from file/tmp/stapwlfjon/stap_333448f0b355beeb59e41a501a5421fd_817.ko
error:couldn‘t insert module ‘/tmp/stapwlfjon/stap_333448f0b355beeb59e41a501a5421fd_817.ko‘:unknown symbol in module
spawn waitpid result (0x100): 1
warning: /usr/local/bin/staprun exited withstatus: 1
pass 5: run completed in 0usr/0sys/2real ms.
pass 5: run failed. [man error::pass5]
running rm -rf /tmp/stapwlfjon
spawn waitpid result (0x0): 0
removed temporary directory"/tmp/stapwlfjon"
dd@ubuntu:~/systemtap/systemtap-2.5$ grep -nr"_stp_bufsize" ./
binary file ./staprun/staprun matches
binary file ./staprun/staprun-staprun.omatches
./staprun/staprun.c:190: /* add the _stp_bufsize option. */
./staprun/staprun.c:192: "_stp_bufsize=%d",buffer_size))
./runtime/transport/transport.c:75:static int_stp_bufsize;
./runtime/transport/transport.c:76:module_param(_stp_bufsize,int, 0);
./runtime/transport/transport.c:77:module_parm_desc(_stp_bufsize,"buffer size");
./runtime/transport/transport.c:408: if (_stp_bufsize) {
./runtime/transport/transport.c:409: unsigned size = _stp_bufsize * 1024 *1024;
./runtime/transport/ring_buffer.c:83: unsigned long buffer_size = _stp_bufsize* 1024 * 1024;
./runtime/transport/transport.h:48:static int_stp_bufsize;
dd@ubuntu:/mnt/hgfs/systemtap/example$ sudomodinfo stapomk4ac/stap_12809.ko [sudo] password for dd:
filename: stapomk4ac/stap_12809.ko
parm: _stp_bufsize:buffer size (int)
從上面的代碼看,子產品參數_stp_bufsize确實存在,且加載的過程沒有問題啊,很奇怪為什麼會fail。難道是版本不比對?嘗試解除安裝2.0版本,安裝2.5版本,依然有問題
于是嘗試分析其内在原理,看是否能真正fix或者workaround這個問題。
./runtime/transport/transport.c接收子產品參數_stp_bufsize,但是從代碼看并沒有特别的用處;另外通過“staprun:insert_module:97module options: _stp_bufsize=0”知道./staprun/staprun.c:192實際傳入的參數值是0,是以可去掉special_options參數試試
static int insert_stap_module(privilege_t*user_credentials)
{
charspecial_options[128] = {0};
#if 0
/* add the _stp_bufsize option. */
if (snprintf_chk(special_options,sizeof (special_options),
"_stp_bufsize=%d", buffer_size))
return -1;
#endif
stap_module_inserted= insert_module(modpath, special_options,
modoptions,
assert_stap_module_permissions,
user_credentials);
if (stap_module_inserted != 0)
err("error insertingmodule ‘%s‘: %s\n", modpath, moderror(errno));
returnstap_module_inserted;
重新編譯加載後,一切正常。
dd@ubuntu:/mnt/hgfs/systemtap/example$ sudostap -ve ‘probe process("./utrace-test").function("*"){printf("-------------------------------------\n") print_backtrace()printf("-------------------------------------\n")}‘
in file included from/tmp/stapri0noh/stap_db3a2cd3f06ff0a78a55d936a32da8b0_1325_src.c:184:0:
/usr/share/systemtap/runtime/uprobes-inode.c:in function ‘stp_inode_uprobes_unreg’:
/usr/share/systemtap/runtime/uprobes-inode.c:94:3:error: implicit declaration of function ‘unregister_uprobe’[-werror=implicit-function-declaration]
/usr/share/systemtap/runtime/uprobes-inode.c:in function ‘stp_inode_uprobes_reg’:
/usr/share/systemtap/runtime/uprobes-inode.c:107:3:error: implicit declaration of function ‘register_uprobe’
[-werror=implicit-function-declaration]
cc1: all warnings being treated as errors
make[1]: ***[/tmp/stapri0noh/stap_db3a2cd3f06ff0a78a55d936a32da8b0_1325_src.o] error 1
make: *** [_module_/tmp/stapri0noh] error 2
warning: make exited with status: 2
pass 4: compiled c into"stap_db3a2cd3f06ff0a78a55d936a32da8b0_1325.ko" in280usr/170sys/681real ms.
pass 4: compilation failed. try again with another ‘--vp 0001‘ option.
stap fails with: "error: implicitdeclaration of function ‘unregister_uprobe’"
dd@ubuntu:/mnt/hgfs/systemtap$ stap -v
systemtap translator/driver (version 1.7/0.153 debian version1.7-1ubuntu1 (quantal))
copyright (c) 2005-2012 red hat, inc. andothers
this is free software; see the source forcopying conditions.
enabled features: avahi libsqlite3 nssboost_shared_ptr tr1_unordered_map nls
核心中沒有systemtap/runtime引用的api register_uprobe。在新版本的systemtap中已經fix了,是以需要下載下傳源代碼手動更新
dd@ubuntu:/mnt/hgfs/systemtap$ sudo grep"\suprobe.*register" /proc/kallsyms
c10fe1d0 t uprobe_register
c10fe430 t uprobe_unregister
更新到2.0版本之後,正常
dd@ubuntu:~/systemtap/systemtap-2.0$ stap-v
systemtap translator/driver (version2.0/0.156, non-git sources)
enabled features: tr1_unordered_map nls
systemtap wiki
a guide on how to install systemtap on anubuntu system
linux 下的一個全新的性能測量和調式診斷工具systemtap, 第 3 部分: systemtap
使用systemtap調試linux核心示例
user-space probing
dynamic tracing with dtrace and systemtap
systemtap : stap processing 5 stepsintroduce