2ちゃんねる スマホ用 ■掲示板に戻る■ 全部 1- 最新50    

SGI KDBを使ったカーネルデバッグスレ

1 :名無しさん@お腹いっぱい。:2001/05/13(日) 19:02.net
カーネルデバッグの話はここで存分にどうぞ

2 :名無しさん@お腹いっぱい。:2001/05/13(日) 20:06.net
age


3 :1:2001/05/14(月) 14:34.net
1.http://oss.sgi.com/projects/kdb/ より、使用しているカーネルにあった
 パッチをダウンロードし、カーネルソースにパッチを当てる。
2.make xconfigなりのカーネルコンフィグアプリを起動。
 Kernel Hackingの項目が追加されているので、
 "Build-in Kernel Debugger support"をyにする。ついでに
 "compile the kernel with frame pointers"もyにしたほうがスタック
 トレースがとりやすくなる。
3.カーネル再構築。
4.lilo.confに以下のように"kdb=on"のカーネルブートオプションをつける。
>image=/boot/vmlinuz-2.4.4-test
> label=test
> read-only
> root=/dev/hda2
> append="kdb=on"
5.liloを実行し、ブート情報を書き込み、ブートオプションをつけたカーネルから
 ブート。
6.Pauseキーを押すとカーネルデバッガに入る。"g"コマンドで再開。


4 :別のスレの1:2001/05/14(月) 14:34.net
リモートの場合。
1.同じくクロスシリアルケーブルを用意しターゲットとターミナルを繋ぐ。
2.ターミナルマシン上で適当なターミナルプログラムを起動する。
3.liloのappendコマンドを以下のように変更。
 append="kdb=on console=ttyS0,38400"
 これで、シリアルコンソールにデバッガの出力が表示される。
 停止はターゲットでPauseキーか、ターミナルでCTRL-A。
4.ただこれだと、ブートメッセージがターミナルにしか表示されなく
 なるので、以下のようにしたほうがいいかも。
 append="kdb=on console=ttyS0,38400 console=tty0"
 これで、ブートメッセージは両方に出力される。そのかわりCTRL-Aでの
 Breakinはできなくなる。
 Initは最後に指定されたコンソールに出力するらしく、
 append="kdb=on console=tty0 console=ttyS0,38400"
 のようにしてしまうとInitの出力がターミナルだけになってしまうため
 不便。


5 :別のスレの1:2001/05/14(月) 14:35.net
とりあえず、Linuxカーネルのなかで実際に止めてみて、どんな感じになるか見てみよう。
えっと、とりあえずSGI KDBは動いてるとします。で、なんかユーザーが特定の
操作をやったらとまる場所を探そう。俺が今回使うのはipv4のicmpのコード。
ユーザーがping叩けばそこ必ずとおるからね。普段はあまり通らないから変に
たくさん止まることもないと。
ソースをみていい止める関数を探してもいいが、今回俺はsystem.mapを使った。
system.mapをエディタで開いてみるとこんな感じでicmpがらみの関数がある。
c0206a60 t icmp_reply
c0206be0 T icmp_send
c0206f60 t icmp_unreach
c0207220 t icmp_redirect
c02072d0 t icmp_echo
c0207320 t icmp_timestamp
c0207410 t icmp_address
c0207420 t icmp_address_reply
c0207570 t icmp_discard
c0207580 T icmp_rcv
icmp_unreachなんかがいいかね。多分icmpが届かなかった場合にくるファンクション
だろう。はい、ターゲットマシンでPauseキーを押してbreakinしましょう。
[1]kdb> とかいうプロンプトがでるな。最初の数字はプロセッサナンバーだ。
シングルプロセッサで動かしてるなら常に0になる。
で、icmp_unreachにbreakpoint張るわけだが、system.mapを見て
[1]kdb> bp c0206f60 とじかにアドレス指定してもいいんだが、もっと簡単に
[1]kdb> bp icmp_unreach とシンボルを指定してもできる。
うまくbreakpoint張れたら
Instruction(i) BP #0 at 0xc0206f60 (icmp_unreach)
is enabled globally adjust 1
とか出るはず。あと、とりあえず、breakpoint張る前に実際のそのアドレスが
ファンクションの先頭であるか確認したほうがいいな。
ディスアセンブルはidコマンドだ。
[1]kdb> id icmp_unreach
0xc0206f60 icmp_unreachpush %ebp
0xc0206f61 icmp_unreach+0x1mov %esp,%ebp
0xc0206f63 icmp_unreach+0x3mov $0x14,%eax
0xc0206f68 icmp_unreach+0x8push %edi
0xc0206f69 icmp_unreach+0x9push %esi
0xc0206f6a icmp_unreach+0xapush %ebx
こんな風に先頭2インストラクションが push %ebpとpush %esp,%ebp ならそれは
まず間違いなく関数の先頭だ。これはC言語のStackFramを作るコードだ。


6 :別のスレの1:2001/05/14(月) 14:35.net
breakpointが張れたらgコマンドで再開。icmp_unreach関数を呼ぶために
適当な存在しないipアドレスへpingを送ってみよう。
breakpointにHitしたら
Instruction(i) breakpoint #0 at 0xc0206f60 (adjusted)
0xc0206f60 icmp_unreachint3
Entering kdb (current=0xc1228000, pid 0) on processor 1 due to Breakpoint @ 0xc0206f60
のようなメッセージが出てコマンド待ちになる。
なにはともかく。止まったらスタックバックトレースを取ろう。コマンドはbtだ。
[1]kdb> bt
EBP EIP Function(args)
0xc1229e5c 0xc0206f60 icmp_unreach (0xc01051b0, 0xffffe000, 0xc1228000, 0xc1228000, 0xc1228000)
kernel .text 0xc0100000 0xc0206f60 0xc0207220
0xc0106fac ret_from_intr
kernel .text 0xc0100000 0xc0106fac 0xc0106fcc
Interrupt registers:
eax = 0x00000000 ebx = 0xc01051b0 ecx = 0xffffe000 edx = 0xc1228000
esi = 0xc1228000 edi = 0xc1228000 esp = 0xc1229fac eip = 0xc01051df
ebp = 0xc1229fac xss = 0x00000018 xcs = 0x00000010 eflags = 0x00000246
xds = 0xc1220018 xes = 0xc1220018 origeax = 0xffffff00 ®s = 0xc1229f78
0xc01051df default_idle+0x2f
kernel .text 0xc0100000 0xc01051b0 0xc01051f0
0xc1229fc0 0xc0105272 cpu_idle+0x52
kernel .text 0xc0100000 0xc0105220 0xc0105290
うーん、なんかうまく取れてないね。StackFrameがちゃんと作られてないと
完全には取れないんだね。でも関数の頭を見る限り全部StackFrameは
作られてるんだけどね。謎だ。KDBのソースを見て調べてみるしかないね。



7 :別のスレの1:2001/05/14(月) 14:36.net
うまくスタックトレースが取れないから、ssコマンドを使ってトレースを
しながら、breakpointをうまく張って上位の関数に戻っていくと、
ip_rcv->icmp_unreachと来ていることがわかる。さらにトレースすると、以下の
トレースが取れるようになる。
#[1]kdb> bt
# EBP EIP Function(args)
#0xc1229e74 0xc01e92bf ip_run_ipprot+0x3f (0xc191fb60, 0xc76cdc70, 0xc030e108, 0x1, 0x1)
# kernel .text 0xc0100000 0xc01e9280 0xc01e92e0
#0xc1229eac 0xc01e93f6 ip_local_deliver+0x116 (0xc01051b0, 0xffffe000, 0xc1228000, 0xc1228000, 0xc1228000)
# kernel .text 0xc0100000 0xc01e92e0 0xc01e9460
# 0xc0106fac ret_from_intr
# kernel .text 0xc0100000 0xc0106fac 0xc0106fcc
#Interrupt registers:
#eax = 0x00000000 ebx = 0xc01051b0 ecx = 0xffffe000 edx = 0xc1228000
#esi = 0xc1228000 edi = 0xc1228000 esp = 0xc1229fac eip = 0xc01051df
#ebp = 0xc1229fac xss = 0x00000018 xcs = 0x00000010 eflags = 0x00000246
#xds = 0xc1220018 xes = 0xc1220018 origeax = 0xffffff00 ®s = 0xc1229f78
# 0xc01051df default_idle+0x2f
# kernel .text 0xc0100000 0xc01051b0 0xc01051f0
#0xc1229fc0 0xc0105272 cpu_idle+0x52
# kernel .text 0xc0100000 0xc0105220 0xc0105290
これで、大体のコードの流れがわかる。


8 :別のスレの1:2001/05/14(月) 14:36.net
ちょっとレジスタをいじって、不正処理を起こしてみよう。
とりあえず、bc * コマンドで設定した全てのbreakpointを消して、再実行。
で、pingコマンドを終了。しばらくまってicmpの処理が終わったのを待って、
icmp_unreachに再度breakpointを設定。ping実行。ssコマンドを使って
icmp_unreach+0x18までステップトレース。次の命令はこの命令のはず。
0xc0206f78 icmp_unreach+0x18mov 0x5c(%edx),%ebx
これで、edxに0を入れれば当然不正処理が起きる。rm edx 0 でedxに0が入る。
確認はrdコマンドで出来る。edxに0が入ったことが分かったらgコマンドで再実行。
[0]kdb> g
Unable to handle kernel NULL pointer dereference at virtual address 0000005c
printing eip:
c0206f78
*pde = 00000000

Entering kdb (current=0xc0312000, pid 0) on processor 0 Oops: Oops
due to oops @ 0xc0206f78
eax = 0x00000014 ebx = 0xc226d0a0 ecx = 0x00000008 edx = 0x00000000
esi = 0xc1aeaea4 edi = 0xc7536c00 esp = 0xc0313e30 eip = 0xc0206f78
ebp = 0xc0313e58 xss = 0x00000018 xcs = 0x00000010 eflags = 0x00010286
xds = 0x00000018 xes = 0x00000018 origeax = 0xffffffff ®s = 0xc0313dfc
のようなメッセージを出して止まるはず。メッセージより、0xc0206f78のコードが
0x5c番地をアクセスして不正処理で止まったことがわかる。[0]kdb> id %eip とすれば
0xc0206f78 icmp_unreach+0x18mov 0x5c(%edx),%ebx
とでるから、edx=0が原因となったことがわかる。

9 :別のスレの1:2001/05/14(月) 14:38.net
あとは俺は基本的にsage進行。オリジナルスレは適当にうっちゃってsage out
させてくれ。

10 :名無しさん@お腹いっぱい。:2001/05/14(月) 14:55.net
○岡さん?>>別スレ1

131 KB
新着レスの表示

掲示板に戻る 全部 前100 次100 最新50
名前: E-mail (省略可) :

read.cgi ver 2014.07.20.01.SC 2014/07/20 D ★