lab1 练习5 实现函数调用堆栈跟踪函数 (补全代码)

练习5:实现函数调用堆栈跟踪函数 (需要编程)

我们需要在lab1中完成kdebug.c中函数print_stackframe的实现,可以通过函数print_stackframe来跟踪函数调用堆栈中记录的返回地址。在如果能够正确实现此函数,可在lab1中执行 “make qemu”后,在qemu模拟器中得到类似如下的输出:

……
ebp:0x00007b28 eip:0x00100992 args:0x00010094 0x00010094 0x00007b58 0x00100096
    kern/debug/kdebug.c:305: print_stackframe+22
ebp:0x00007b38 eip:0x00100c79 args:0x00000000 0x00000000 0x00000000 0x00007ba8
    kern/debug/kmonitor.c:125: mon_backtrace+10
ebp:0x00007b58 eip:0x00100096 args:0x00000000 0x00007b80 0xffff0000 0x00007b84
    kern/init/init.c:48: grade_backtrace2+33
ebp:0x00007b78 eip:0x001000bf args:0x00000000 0xffff0000 0x00007ba4 0x00000029
    kern/init/init.c:53: grade_backtrace1+38
ebp:0x00007b98 eip:0x001000dd args:0x00000000 0x00100000 0xffff0000 0x0000001d
    kern/init/init.c:58: grade_backtrace0+23
ebp:0x00007bb8 eip:0x00100102 args:0x0010353c 0x00103520 0x00001308 0x00000000
    kern/init/init.c:63: grade_backtrace+34
ebp:0x00007be8 eip:0x00100059 args:0x00000000 0x00000000 0x00000000 0x00007c53
    kern/init/init.c:28: kern_init+88
ebp:0x00007bf8 eip:0x00007d73 args:0xc031fcfa 0xc08ed88e 0x64e4d08e 0xfa7502a8
<unknow>: -- 0x00007d72 –
……

请完成实验,看看输出是否与上述显示大致一致,并解释最后一行各个数值的含义。

提示:可阅读小节“函数堆栈”,了解编译器如何建立函数调用关系的。在完成lab1编译后,查看lab1/obj/bootblock.asm,了解bootloader源码与机器码的语句和地址等的对应关系;查看lab1/obj/kernel.asm,了解 ucore OS源码与机器码的语句和地址等的对应关系。

要求完成函数kern/debug/kdebug.c::print_stackframe的实现,提交改进后源代码包(可以编译执行),并在实验报告中简要说明实现过程,并写出对上述问题的回答。

补充材料:

由于显示完整的栈结构需要解析内核文件中的调试符号,较为复杂和繁琐。代码中有一些辅助函数可以使用。例如可以通过调用print_debuginfo函数完成查找对应函数名并打印至屏幕的功能。具体可以参见kdebug.c代码中的注释。

实验报告:练习5

ebp esp的位置指向堆栈的站地和栈顶。此为函数堆栈,用于保存返回地址和局部变量等数据

每次进入新的函数时,就会用系统栈记录ebp的位置方便返回,每次进入新的函数都会默认执行下列两句汇编:

pushl   %ebp
movl   %esp , %ebp

先将caller的栈底指针ebp压栈方便返回,再将esp栈顶指针的值赋给ebp,因为esp是caller的栈顶,当进入新的函数时,esp便是新的栈底,所以把esp给ebp后,ebp此时指向的就是called函数的栈底。于是,栈底指针就这样从calling栈帧切换到了called栈帧。

+|  栈底方向        | 高位地址
 |    ...        |
 |    ...        |
 |  参数3        |
 |  参数2        |
 |  参数1        |
 |  返回地址        |
 |  上一层[ebp]    | <-------- [ebp]
 |  局部变量        |  低位地址

EIP指向下一条指令

ebp为栈底指针

esp为栈顶指针

kdebug.c 要求补全代码在最下面的 print_stackframe函数里:

         void
         print_stackframe(void) {
           /* LAB1 YOUR CODE : STEP 1 */
           /* (1) call read_ebp() to get the value of ebp. the type is (uint32_t);
 
            * (2) call read_eip() to get the value of eip. the type is (uint32_t);
            * (3) from 0 .. STACKFRAME_DEPTH
            * (3.1) printf value of ebp, eip
            * (3.2) (uint32_t)calling arguments [0..4] = the contents in address (unit32_t)ebp +2 [0..4]
            * (3.3) cprintf("\n");
            * (3.4) call print_debuginfo(eip-1) to print the C calling function name and line number, etc.
            * (3.5) popup a calling stackframe
            * NOTICE: the calling funciton's return addr eip  = ss:[ebp+4]
            * the calling funciton's ebp = ss:[ebp]
              */
              uint32_t ebp = read_ebp(), eip = read_eip();
 
          int i, j;
             //从栈底开始
          for (i = 0; ebp != 0 && i < STACKFRAME_DEPTH; i ++) {
              //以16进制输出ebp eip,占8位,不足的左侧补0填补。ebp,eip为32位寄存器
              cprintf("ebp:0x%08x eip:0x%08x args:", ebp, eip);
              //args为参数1的初始地址
              uint32_t *args = (uint32_t *)ebp + 2;
              //输出参数地址
              for (j = 0; j < 4; j ++) {
                  cprintf("0x%08x ", args[j]);
              }
              cprintf("\n");
              print_debuginfo(eip - 1);
              eip = ((uint32_t *)ebp)[1];
              ebp = ((uint32_t *)ebp)[0];
          }
         }

分析输出:

根据图表,可以得知:

ss:ebp指向的堆栈位置储存着caller的ebp。
ss:ebp+4指向caller调用时的eip,也就是返回地址, 调用被调用函数的那一条指令地址。

ss:ebp+8等是(可能的)参数。

输出中,堆栈最深一层为

其对应的是第一个使用堆栈的函数,bootmain.c中的bootmain。
bootloader设置的堆栈从0x7c00开始,使用"call bootmain"转入bootmain函数。
call指令压栈,所以bootmain中ebp为0x7bf8。

	ebp:0x00007bf8 eip:0x00007d68 \
		args:0x00000000 0x00000000 0x00000000 0x00007c4f
	    <unknow>: -- 0x00007d67 --

其对应的是第一个使用堆栈的函数,bootmain.c中的bootmain。
bootloader设置的堆栈从0x7c00开始,使用"call bootmain"转入bootmain函数。
call指令压栈,所以bootmain中ebp为0x7bf8。

posted @ 2021-01-04 16:00  lsxkugou  阅读(172)  评论(0编辑  收藏  举报