zoukankan      html  css  js  c++  java
  • 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("
    ");
          *    (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
    ", 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 整体的分析。

  • 相关阅读:
    利用calc()宽度计算做响应式布局
    设置背景图片后,使用backgroup-size出现的问题
    三、算法与控制结构
    C++数值计算
    python认识及环境变量
    Unity查找Editor下Project视图中特定的资源
    UGUI ScrollRect滑动居中CenterOnChild实现
    unity与android交互总结
    UGUI笔记
    UGUI性能优化
  • 原文地址:https://www.cnblogs.com/LuoboLiam/p/13583485.html
Copyright © 2011-2022 走看看