6.828: Operating System Engineering (20)
kern/kdebug.c の諸々確認ってことにて。とりあえず例示されてるのが以下。
// For example, given these N_SO stabs: // Index Type Address // 0 SO f0100000 // 13 SO f0100040 // 117 SO f0100176 // 118 SO f0100178 // 555 SO f0100652 // 556 SO f0100654 // 657 SO f0100849 // this code: // left = 0, right = 657; // stab_binsearch(stabs, &left, &right, N_SO, 0xf0100184); // will exit setting left = 118, right = 554.
ふむ。ある意味これが stab_binsearch の仕様なのかな。これを踏まえてコードを見れば良さげ。てか、left と right が戻りなのか。
動かしてみる
昨日の勉強会でも、「まず動かしてみるのがナニ」という話が出てたのもありますが、あまりにもイメージできないので、諸々確認の上、mon_backtrace 手続きに debuginfo_eip 手続きの呼び出しを盛り込んで gdb で確認してみます。
とりあえず、Eipdebuginfo 構造体について今更確認。
// Debug information about a particular instruction pointer struct Eipdebuginfo { const char *eip_file; // Source code filename for EIP int eip_line; // Source code linenumber for EIP const char *eip_fn_name; // Name of function containing EIP // - Note: not null terminated! int eip_fn_namelen; // Length of function name uintptr_t eip_fn_addr; // Address of start of function int eip_fn_narg; // Number of function arguments };
ここで盛り込まなきゃいかんのは eip_line の値の決定と構造体属性への代入か。とりあえず monitor.c の mon_backtrace 手続きのケツのあたりを以下にしてデバッガで確認。
struct Eipdebuginfo info; debuginfo_eip(ebp_ptr, &info);
失敗
ケツに盛り込んだら ebp_ptr は 0x0 です。
(gdb) n => 0xf0100b03 <debuginfo_eip+21>: movl $0xf0101f1c,(%ebx) 112 info->eip_file = "<unknown>"; (gdb) n => 0xf0100b09 <debuginfo_eip+27>: movl $0x0,0x4(%ebx) 113 info->eip_line = 0; (gdb) n => 0xf0100b10 <debuginfo_eip+34>: movl $0xf0101f1c,0x8(%ebx) 114 info->eip_fn_name = "<unknown>"; (gdb) n => 0xf0100b17 <debuginfo_eip+41>: movl $0x9,0xc(%ebx) 115 info->eip_fn_namelen = 9; (gdb) n => 0xf0100b1e <debuginfo_eip+48>: mov %esi,0x10(%ebx) 116 info->eip_fn_addr = addr; (gdb) n => 0xf0100b21 <debuginfo_eip+51>: movl $0x0,0x14(%ebx) 117 info->eip_fn_narg = 0; (gdb) n => 0xf0100b28 <debuginfo_eip+58>: cmp $0xef7fffff,%esi 120 if (addr >= ULIM) { (gdb) p/x addr $1 = 0x0 (gdb)
先頭に盛り込んでリトライ。
int mon_backtrace(int argc, char **argv, struct Trapframe *tf) { // Your code here. int i; unsigned int ebp_ptr = read_ebp(); struct Eipdebuginfo info; debuginfo_eip(ebp_ptr, &info);
で再度 make qemu-gdb して云々。とりあえず確認。
(gdb) n => 0xf01008f4 <mon_backtrace+11>: lea -0x30(%ebp),%eax 67 debuginfo_eip(ebp_ptr, &info); (gdb) p/x ebp_ptr $1 = 0xf010ff18 (gdb)
ここから si すれば良いのかな。
ダウト
というか天然爆発。eip を渡さなければならないのでした。戻り番地で良いので、ってことで以下に修正。
int mon_backtrace(int argc, char **argv, struct Trapframe *tf) { // Your code here. int i; unsigned int ebp_ptr = read_ebp(); unsigned int eip_ptr = read_eip(); struct Eipdebuginfo info; debuginfo_eip(eip_ptr, &info); while(ebp_ptr) {
とりあえず n でスルーして info 構造体のソレを見てみます。
(gdb) p info $5 = {eip_file = 0xf010696c "kern/monitor.c", eip_line = 0, eip_fn_name = 0xf0106b8e "mon_backtrace:F(0,1)", eip_fn_namelen = 13, eip_fn_addr = 4027582697, eip_fn_narg = 3} (gdb) x/13c 0xf0106b8e 0xf0106b8e <__STABSTR_BEGIN__+4209>: 109 'm' 111 'o' 110 'n' 95 '_' 98 'b' 97 'a' 99 'c' 107 'k' 0xf0106b96 <__STABSTR_BEGIN__+4217>: 116 't' 114 'r' 97 'a' 99 'c' 101 'e' (gdb)
ええと、eip は 0xf01008f9 として info->eip_fn_addr が 0xf01008e9 とのこと。とは言え、gdb で色々確認してるんですが、動作が微妙。なんとなく lline と rline 使えば良さげなカンジなので無理矢理盛り込んでみます。
// Your code here. stab_binsearch(stabs, &lline, &rline, N_SLINE, addr);
戻ってきた値を確認してみます。というか中に入って gdgd 確認したら、どうやら
531 SLINE 0 70 0000001f 0
が hit している模様。ちょっと stab_binsearch 手続きをちゃんと理解できとらんのが敗因な模様だなぁ。
根拠としては以下なソレです。
(gdb) p l $11 = 532 (gdb) p r $12 = 531 (gdb) p m No symbol "m" in current context. (gdb) p stabs $13 = (struct Stab *) 0xf0102194 (gdb) p stabs[532] $14 = {n_strx = 0, n_type = 68 'D', n_other = 0 '\000', n_desc = 70, n_value = 31} (gdb)
たしかに monitor.c の 70 行目は
debuginfo_eip(eip_ptr, &info); while(ebp_ptr) {
上記 while な命令の行なので大丈夫なのか。なので以下で OK なのかな。
// Your code here. stab_binsearch(stabs, &lline, &rline, N_SLINE, addr); info->eip_line = stabs[lline].n_value;
これで gdb で戻り値な info を確認してみます。
(gdb) b mon_backtrace Breakpoint 1 at 0xf01008e9: file kern/monitor.c, line 61. (gdb) c Continuing. The target architecture is assumed to be i386 => 0xf01008e9 <mon_backtrace>: push %ebp Breakpoint 1, mon_backtrace (argc=0, argv=0x0, tf=0x0) at kern/monitor.c:61 61 { (gdb) n => 0xf01008f2 <mon_backtrace+9>: mov %ebp,%esi 240 __asm __volatile("movl %%ebp,%0" : "=r" (ebp)); (gdb) n => 0xf01008f4 <mon_backtrace+11>: call 0xf01006a0 <read_eip> 65 unsigned int eip_ptr = read_eip(); (gdb) n => 0xf01008f9 <mon_backtrace+16>: lea -0x30(%ebp),%edx 68 debuginfo_eip(eip_ptr, &info); (gdb) n => 0xf0100908 <mon_backtrace+31>: test %esi,%esi 70 while(ebp_ptr) { (gdb) p info $1 = {eip_file = 0xf0106a00 "kern/monitor.c", eip_line = 16, eip_fn_name = 0xf0106c22 "mon_backtrace:F(0,1)", eip_fn_namelen = 13, eip_fn_addr = 4027582697, eip_fn_narg = 3} (gdb)
あら? 何故かしらんが
(gdb) p lline $4 = 531 (gdb) p rline $5 = 531 (gdb)
とほほ
n_value ではなくて n_desc だったよorz
修正して確認。
(gdb) p info $4 = {eip_file = 0xf0106a00 "kern/monitor.c", eip_line = 68, eip_fn_name = 0xf0106c22 "mon_backtrace:F(0,1)", eip_fn_namelen = 13, eip_fn_addr = 4027582697, eip_fn_narg = 3} (gdb)
とりあえず、binsearch 云々なあたりをちゃんと読んで理解しないとマズい。