ucore-lab1-ex5

实现函数调用堆栈跟踪函数

我们需要在 lab1 中完成 kdebug.c 中函数 print_stackframe 的实现,可以通过函数 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 (uint32_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();
    uint32_t ra = read_eip();
    int i;
    for(i = 0 ; i < STACKFRAME_DEPTH && ebp != 0 ; i++)
    {
        cprintf("ebp: 0x%08x eip: 0x%08x ", ebp, ra);
        uint32_t *args = (uint32_t*)(ebp) + 2;
        cprintf("args: 0x%08x 0x%08x 0x%08x 0x%08x\n", args[0], args[1], args[2], args[3]);
        print_debuginfo(ra-1);
        ra = *((uint32_t*)(ebp) + 1);
        ebp = *(uint32_t*)(ebp);
    }
}

基本的思路在注释里写得很清楚了,关键就是要理解函数调用栈的递归调用关系,以及ebp和esp的运动过程。这部分建议直接看视频和课上的图,陈渝老师讲的很清楚。

这里并没有深入分析kdebug.c中的其他函数。

make qemu结果如下:

接下来分别解释输出的含义:

  1. ebp表示ebp寄存器的值,这个值是上一层函数内ebp寄存器的值;
  2. eip表示当前函数的返回地址;
  3. args表示传给当前函数的参数;
  4. kern/debug/kdebug.c:306: print_stackframe 这种东西表示在kdebug.c的306行,print_stackframe函数内发生函数调用,而且上面这些都是print_stackframe函数的调用栈信息;
  5. +22之类的表示当前函数入口距离调用函数入口的字节数。

需要注意的是最后一行:<unknow>: -- 0x00007d71 --。从整个函数调用栈的输出来看,不难推测应该是最“外层”的函数,即要进入 OS kernel 开始执行的那个函数,而我们之前分析过,bootmain函数的最后一行完成了这个操作,所以最后一行输出的是 bootmain 的栈帧信息。

// in obj/bootblock.asm function <bootmain>
    // call the entry point from the ELF header
    // note: does not return
    ((void (*)(void))(ELFHDR->e_entry & 0xFFFFFF))();
    7d66:	a1 18 00 01 00       	mov    0x10018,%eax
    7d6b:	25 ff ff ff 00       	and    $0xffffff,%eax
    7d70:	ff d0                	call   *%eax

可以看到这个0x7d71是进入 OS kernel 的 call 指令的最后一个字节。因为 stabs 中没有这个符号(好像),所以返回 unknow。

本节的分析其实比较粗略,因为并没有涉及到 kernel 整体的分析。

posted @ 2020-08-29 21:43  xinze  阅读(169)  评论(0编辑  收藏  举报