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 云々なあたりをちゃんと読んで理解しないとマズい。