mit6.828 lab1 exercise11

lab1-exercise11

在这个exercise中,我们需要完成一个mon_backtrace()函数(在kern/monitor.c中),

这个函数的功能就是把当前栈里面的所有栈帧按照规定的格式输出出来,格式如下:

在这里插入图片描述

经过前面exercise的洗礼,我们对于栈中的栈帧应该有了足够的了解,为了直观的展示栈帧的结构,上图:

在这里插入图片描述

从图上可以直观的看出:

  • esp和ebp共同划分了一个栈帧的上下边界,其中,ebp指针指向的地址中存着的是父函数的ebp指针,因此我们只要知道栈顶的栈帧的ebp就能逐层推导出所有函数的edp地址了
  • 在当前栈帧的ebp的上面,也就是(ebp+4)的地址处保存的是父函数的返回地址,也就是eip寄存器的值,再往上的五个格子就是父函数需要传递给子函数的参数,但是这五个参数不一定都有用,需要被子函数使用的参数依次放在参数1,参数2,参数3…的地址处

all right,我们已经分析完了我们需要做的事情,但是目前还存在几个问题

  1. 如何获取当前函数的ebp的值,讲义里面提到,我们可以使用icn/x86.h中的read_ebp()函数,这个函数可以直接返回当前栈顶函数的ebp值。
  2. 我们通过不断向上回溯获取每个函数栈帧的ebp,但是万事万物都是有尽头的,我们到什么时候终止回溯呢?讲义让我们钻研kern/entry.S,注意到,在kern/entry.S中有这样一段:

在这里插入图片描述

​ 可以看到,这段代码在栈区建立之前,把ebp初始化为0x0,“Salvation lies within”。这 就是我们需要的答案!

万事俱备,我们可以开始code了

先写下第一行关键性的代码uint32_t ebp = read_ebp();

int backtrace(){
    
    uint32_t  ebp = read_ebp();

    return 0;
}

但是问题又来了,read_ebp()函数返回的是一个16进制的地址值,类似于0xf01000fd,我们如何通过这一个地址来对内存中的数据进行访问呢?

是的,可以定义一个同类型的指针变量,将该地址赋值给该指针变量,这样,我们就可以通过这个指针变量进行非常方便的寻址操作了。

写下第二行关键性代码uint32_t * temp = (uint32_t *) ebp;,注意先进行类型的转换再赋值

int backtrace(){
    
    uint32_t  ebp = read_ebp();
	uint32_t * temp = (uint32_t *) ebp;
    return 0;
}

接下来就是按照前述的逻辑编写代码了,写下第三行关键性代码—终止条件while(* temp !=0)

int backtrace(){
    
    uint32_t  ebp = read_ebp();
	uint32_t * temp = (uint32_t *) ebp;
    cprintf("Stack backtrace:\n");
    while(* temp !=0){}
    return 0;
}

继续完成代码的编写,注意%08x可以输出8个字节的十六进制数

int backtrace(){
    
    uint32_t  ebp = read_ebp();
    uint32_t * temp = (uint32_t *) ebp;
    cprintf("Stack backtrace:\n");
    while(* temp !=0){
        cprintf("  ebp %08x  eip %08x  args %08x %08x %08x %08x %08x\n",temp,*(temp+1),*(temp+2),*(temp+3),*(temp+4),*(temp+5),*(temp+6));
        temp = (uint32_t *)(*temp);
    }

    return 0;
}

好了,为了测验一下自己的代码是否按照预期的方式输出数据,可以运行内核程序,查看输出,输出如下:

在这里插入图片描述

看上去很完美了,可以开始make grade了,“让我试试刀吧”!

在这里插入图片描述

????为什么只有30分?

backtrace symbolsbacktrace lines是exercise12的内容,不予关注,所以我们应该是backtrace count出错了,图中显示需要8个栈帧,而我们只有7个,少了一个,少了哪个呢?

我们回到之前输出的内容中:

在这里插入图片描述

由上往下,依次是函数一个mon_backtrace(),六个test_backtrace(),哦吼,居然少了最开始的init()函数,这个函数是最早被压入栈的,为什么没有被输出呢?可以想到是终止条件出了问题,回顾一下代码,哦!由于疏忽大意,导致while()函数被提前一轮终止了:

在这里插入图片描述

太马虎了,反思一会。

ok,把代码更正之后如下:

int backtrace(){
    
    uint32_t  ebp = read_ebp();
    uint32_t * temp = (uint32_t *) ebp;
    cprintf("Stack backtrace:\n");
    while( temp != 0 ){
        cprintf("  ebp %08x  eip %08x  args %08x %08x %08x %08x %08x\n",temp,*(temp+1),*(temp+2),*(temp+3),*(temp+4),*(temp+5),*(temp+6));
        temp = (uint32_t *)(*temp);
    }

    return 0;
}

make grade

40分,顺利通关!

在这里插入图片描述

现在只剩exercise12没做了,胜利就在前方,冲啊!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值