6.828: Operating System Engineering (18)
ええと、inc/x86.h とか kern/monitor.c とか書いてあります。mon_backtrace という手続きを実装せぇとか何とか。
Exercise 11
Implement the backtrace function as specified above. Use the same format as in the example, since otherwise the grading script will be confused. When you think you have it working right, run make grade to see if its output conforms to what our grading script expects, and fix it if it doesn't. After you have handed in your Lab 1 code, you are welcome to change the output format of the backtrace function any way you like.
引数と思われるソレを 5 つ出力すれば良いのか。あとは read_ebp で取得できる base pointer をどう操作するかがカギ。
void * で受けて足し算したら大丈夫かなぁ。実装として以下が提示されてるんですが、
int mon_backtrace(int argc, char **argv, struct Trapframe *tf) { // Your code here. return 0; }
呼び出し元は以下な形なので、
// Test the stack backtrace function (lab 1 only) void test_backtrace(int x) { cprintf("entering test_backtrace %d\n", x); if (x > 0) test_backtrace(x-1); else mon_backtrace(0, 0, 0); cprintf("leaving test_backtrace %d\n", x); }
引数は現時点では気にしないことにします。
あと、昨晩エントリによればいっちゃん最初のフレームの base pointer は 0x0 だったので、これを条件にループすれば良いはず。
で、実装を盛り込みつつ試験してみたのですが
- void * にしてコンパイルエラー
- ポインタ演算色々ナチュラル
- 戻り番地の位置とか引数の位置とか
ええと、試験の最初から控えを。
(gdb) b i386_init Breakpoint 1 at 0xf010013a: file kern/init.c, line 24. (gdb) c Continuing. The target architecture is assumed to be i386 => 0xf010013a <i386_init>: push %ebp Breakpoint 1, i386_init () at kern/init.c:24 24 { (gdb) n => 0xf0100140 <i386_init+6>: mov $0xf0110980,%eax i386_init () at kern/init.c:30 30 memset(edata, 0, end - edata); (gdb) n => 0xf0100162 <i386_init+40>: call 0xf01004aa <cons_init> 34 cons_init(); (gdb) n => 0xf0100167 <i386_init+45>: movl $0x1aac,0x4(%esp) 36 cprintf("6828 decimal is %o octal!\n", 6828); (gdb) n => 0xf010017b <i386_init+65>: movl $0x5,(%esp) 45 test_backtrace(5); (gdb)
戻り番地はこの次、になるはず。
(gdb) si => 0xf0100182 <i386_init+72>: call 0xf01000dd <test_backtrace> 0xf0100182 45 test_backtrace(5); (gdb) si => 0xf01000dd <test_backtrace>: push %ebp test_backtrace (x=5) at kern/init.c:13 13 { (gdb)
あら 0xf0100182 の次かな?
レジスタの値を確認してみます。
(gdb) info registers eax 0x0 0 ecx 0x3d5 981 edx 0x3d5 981 ebx 0x10094 65684 esp 0xf010ffdc 0xf010ffdc ebp 0xf010fff8 0xf010fff8 esi 0x10094 65684 edi 0x0 0 eip 0xf01000dd 0xf01000dd <test_backtrace> eflags 0x82 [ SF ] cs 0x8 8 ss 0x10 16 ds 0x10 16 es 0x10 16 fs 0x10 16 gs 0x10 16 (gdb)
ええとまだ ebp push した直後だったりするのでもう少し進めます。
(gdb) si => 0xf01000de <test_backtrace+1>: mov %esp,%ebp 0xf01000de 13 { (gdb) si => 0xf01000e0 <test_backtrace+3>: push %ebx 0xf01000e0 13 { (gdb) si => 0xf01000e1 <test_backtrace+4>: sub $0x14,%esp 0xf01000e1 13 { (gdb) si => 0xf01000e4 <test_backtrace+7>: mov 0x8(%ebp),%ebx 0xf01000e4 13 { (gdb) si => 0xf01000e7 <test_backtrace+10>: mov %ebx,0x4(%esp) 14 cprintf("entering test_backtrace %d\n", x); (gdb)
ここで確認か。
(gdb) info registers eax 0x0 0 ecx 0x3d5 981 edx 0x3d5 981 ebx 0x5 5 esp 0xf010ffc0 0xf010ffc0 ebp 0xf010ffd8 0xf010ffd8 esi 0x10094 65684 edi 0x0 0 eip 0xf01000e7 0xf01000e7 <test_backtrace+10> eflags 0x86 [ PF SF ] cs 0x8 8 ss 0x10 16 ds 0x10 16 es 0x10 16 fs 0x10 16 gs 0x10 16 (gdb)
で、戻り番地確認。
(gdb) x/x 0xf010ffdc 0xf010ffdc <bootstack+32732>: 0xf0100187 (gdb)
0xf0100182 の次だろうと思われます。で、間違えて n タタいてしまったので流れてしまいました。コンソール出力が以下です。
entering test_backtrace 5 entering test_backtrace 4 entering test_backtrace 3 entering test_backtrace 2 entering test_backtrace 1 entering test_backtrace 0 ebp f010ff18 eip f0100124 args 0 0 0 0 f01009a5 ebp f010ff38 eip f0100106 args 0 1 f010ff78 0 f01009a5 ebp f010ff58 eip f0100106 args 1 2 f010ff98 0 f01009a5 ebp f010ff78 eip f0100106 args 2 3 f010ffb8 0 f01009a5 ebp f010ff98 eip f0100106 args 3 4 0 0 0 ebp f010ffb8 eip f0100106 args 4 5 0 10094 10094 ebp f010ffd8 eip f0100187 args 5 1aac 660 0 0 ebp f010fff8 eip f010003d args 0 0 ffff 10cf9a00 ffff leaving test_backtrace 0 leaving test_backtrace 1 leaving test_backtrace 2 leaving test_backtrace 3 leaving test_backtrace 4 leaving test_backtrace 5
これ、一体どーゆー意味だ?
あ、そーか。いっちゃん下が i386_init の stack frame で、上から二番目までが test_backtrace の stack frame になるのか。いっちゃん上が mon_backtrace ということであればなんとなく話は合ってますね。
make grade
以下。
Printf: WRONG (1.3s) Backtrace: Count WRONG (1.4s) Args WRONG, (0 0 1 2 3 4 5 0) (1.4s) Symbols WRONG, () (1.4s) Score: 0/50
ローボコン、れいてん、という気分ですorz
grade-function.sh
見てみたのですが、引数の出力の編集がアレだったり空白文字が一つ多かったりしてる模様です。ただ、シンボル出力せい、ってのは直接の記述は無かったんですが、これがアメリカ式の課題の出しかたですかそうですか。
それが次の Exercise 12 になるのかなぁ。というかどう考えても空白文字が 2 文字なんだけどなぁ。
実装以下です。
int mon_backtrace(int argc, char **argv, struct Trapframe *tf) { // Your code here. int i; unsigned int ebp_ptr = read_ebp(); while(ebp_ptr) { /* ebp f0109ed8 eip f01000d6 args 00000000 00000000 f0100058 f0109f28 00000061 */ cprintf("ebp %x eip %x args ", ebp_ptr, *((int *)ebp_ptr + 1)); for(i = 0; i < 5; i++) { cprintf("%x ", *((int *)ebp_ptr + i + 2)); } cprintf("\n"); ebp_ptr = *(int *)ebp_ptr; } return 0; }
ちょっと色々な意味で微妙に気にいらないし、0 点だし。あと、採点スクリプト微妙。