Lab1_challenge1 打印用户程序调用栈
在main函数中调用了多层函数。需要打印栈的情况。
相关知识:
代理内核的启动过程
重点在于理解lab1中进程的定义。
1 | 19 typedef struct process { |
包含栈指针和指向trapframe的指针。trapframe中包含寄存器regs,里面存了我们所需要的fp。
elf_fpread函数需要一个ctx变量。ctx是什么?elf.h文件里有定义
1 | typedef struct elf_ctx_t { |
在elf_init函数里面对ctx进行了初始化。由此可以得到elf_header
然后就是根据手册里面的指导读取所有的section table。得到symtab和strtab
打印的symtab.value和其name在strtab偏移量中的字符串取值如下
1 | st_value 00000000 |
此外,可以通过对current->trapframe->regs.s0循环查询函数调用栈。从中可以找到不同栈的fp和ra。
1 | regs.s0:810fff60 |
可以发现ra和value存在对应关系。
有一个问题,81000000对应的有一个空字符串…所以需要特判st_info字段是否为18(FUNC宏定义)。为18时代表这个字段是有意义的。至于为什么是18….百度..一下。很多信息藏在elf(5) - Linux manual page (man7.org)里面。
Lab1_challenge2 打印异常代码行
目标:内核能够输出触发异常的用户程序的源文件名和对应代码行
elf.c中给出了debug_line段的解析函数make_addr_line。
1 | make_addr_line(elf_ctx *ctx, char *debug_line, uint64 length) |
elf文件中名为.debug_line的段保存到缓冲区中,然后将缓冲区指针传入这个参数;length为.debug_line段数据的长度。
函数调用结束后,process结构体的dir、file、line三个指针会各指向一个数组。
dir数组存储
所有代码文件的文件夹路径字符串指针
file数组存储所有代码文件的文件名字符串指针以及其文件夹路径在dir数组中的索引
file数组存储所有代码文件的文件名字符串指针以及其文件夹路径在dir数组中的索引
为完成该挑战,需要利用用户程序编译时产生的调试信息,目前最广泛使用的调试信息格式是DWARF
在lab1_challenge1中我们还可以得到elf文件中各个段的名字。可以发现.debug_line段就在其中。
1 | section名字 |
所以我们先参照前面的方法读取出debuf_line段的地址,再调用解析函数make_addr_line。
得到的三个数组按道理是存在process结构体里面,但是我查找process.h文件没有发现有这些东西。实际上该函数里面的做法如下:
1 | void make_addr_line(elf_ctx *ctx, char *debug_line, uint64 length) { |
所以我们仿照这个做法试试。
注意,还是要把两个函数声明在elf.h头文件中供其他调用。
1 | uint64 elf_fpread(elf_ctx *ctx, void *dest, uint64 nb, uint64 offset); |
问题:make_addr_line的第二个参数是 char *指针类型,而我们定义的指向.debug_line段数据的指针是Elf64_Shdr类型的…所以强转看看。(错误理解)
不是强转,而是缓冲区,开一个char数组即可。
还有elf_info这个结构体也没有定义。定义在elf.c中。把它移到.h中。
1 | typedef struct elf_info_t { |
不能直接移。需要链接到spike.h。。。。md
发现一个问题。如果直接运行,结果是illegal instruction,这是正常的。
换成访问process里面的东西的时候就变成了Load access fault!
原来process_t里面的结构被改了,变成下面的样子
1 | // the extremely simple definition of process, used for begining labs of PKE |
其中code_file以及addr_line的定义又如下:
1 | // code file struct, including directory index and file name char pointer |
在读到缓冲区的时候出现misaligned load的错误…要定义在.h文件里面…
…数组要开8000+ “那么这个数组必须足够大”
打开文件的时候不能用fopen,而应该用spike_file里面的spike_file_open。相应的,FILE文件应该用spike_file_t*
1 | typedef struct file { |
没有strcat函数…
…麻
lab2_challenge2 堆空间管理
这是碰都不能碰的滑梯.jpg
申请100和50个字节的一个物理页的内存,然后使用better_free释放掉100个字节,向50个字节中复制一串字符串,进行输出。原本的pke中malloc的实现是非常简化的(一次直接分配一个页面),你的挑战任务是修改内核(包括machine文件夹下)的代码,使得应用程序的malloc能够在一个物理页中分配,并对各申请块进行合理的管理。
首先要做的当然是在顺着系统调用的次序逐步跟随malloc和free找到userlib和syscall中对应的代码,然后将前者改为better_malloc和better_free。改完之后自然是实现。原来的实现是直接调用user_vm_map和user_vm_unmap进行映射,所以我们找到vmm.h,在其中加入user_better_free和user_better_malloc函数。
执行过程中要用到current,所以还要include process.h
lab3_challenge2 实现信号量
简单来说就是在user_lib和syscall里面实现sem_new, sem_P, sem_V操作。
sem_new(n):找到一个未被占用的信号量,初值设置为n
sem_P(n):对编号为n的信号量执行P操作。还需要进行进程调度。维护一个等待队列。
sem_V(n):同理。
需要添加的工作是:
在process中添加init_sem_pool(参考线程池),并声明信号灯数组。注意,信号池和线程池的初始化需要在process.c里面一起实现。
然后参照系统调用的步骤在userlib、kernel和syscall里面加上三个函数的调用实现。
若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏
扫描二维码,分享此文章