五天时间,把6.828的Lec 1和2的课程材料、源码读完,然后把Lab1做完了。
前七道题不用细说,都是概念和操作性的。中间碰到一个很囧的问题,在ssh下,make qemu会失败,改成make qemu-nox就OK了(实际上是给了qemu一个-nographic参数)。折腾了大半个钟头,其实manual里已经写清楚了——以后先把manual看完,再动手。
第8题完成cprintf的%o方式,完全仿照%d部分的代码就OK了,其中有个base被传入printnum(),是进制的基数,改一下就好。
11和12题完成backtrace指令,这个是重头戏。函数调用栈回溯的主要思路是:
假设所有函数调用都是
call func # 等价于push %eip; jmp func
push %ebp
movl %esp, %ebp
那么逆一下这个过程,从%ebp获得%esp,通过%esp获得上一个调用栈的%ebp以及返回地址%eip,如此循环即可。
这里犯了一个错误是去修改栈指针,这样函数返回后系统没法正常运行下去。于是先把%ebp、%esp备份,函数完成后修复,还是报错,发现是栈结构破坏了。所以整个过程最好是完全读内存,而不要操作真正的栈指针、栈数据。(代码附后)
打印调用函数信息部分,实际上绝大部分代码已经写好了,需要补充查询源码行数的代码,通过对stabs做二分查找实现。stabs类型在stab.h中,很显然应该用N_SLINE,注释显示其含义为text segment line number。调用方法上参考search source file那一部分,难点在于,返回结果中什么是我们要的行数?
一开始我以为就是lline,跑出来以后发现出错。在stab.h中有一个URL,进去查到这里:
http://sourceware.org/gdb/onlinedocs/stabs.html#Line-Numbers
注意这句话:The desc field contains the line number and the value contains the code address for the start of that source line.所以真正应该返回的是stabs[lline].n_desc。
此外,打印栈信息时的几个细节问题:
1、eip_fn_name不是以\0结尾的指针,应该用%.*s配合eip_fn_namelen来正确打印;
2、返回地址偏移不是eip本身,而是eip-info.eip_fn_addr。
最后,主体代码如下:
运行结果如下:
通过make grade可以查看自己的成绩,但是评判标准很不严格,比如backtrace的输出细节(源码行数、偏移地址)都没有被检查。
6.828的材料真的非常丰富,真正做到了自包含。做题过程中发现老师做了非常周到的准备工作,完全可以自己学习。总之,感觉很舒服,也学到了很多。
你好!我也在作JOS,是2012版本的,差别应该不大,我的lab1做的比较顺利,我像请问下您的lab2有做么?可以分享下关于lab2的经验么?谢谢!