首先设置版本0内核为分析对象,并启动gdb调试
一.在do_execve函数处设置断点,并跳到断点处
(gdb)b do_execve
(gdb)c
可以看到到页故障由2号进程引发,filename即为发生页故障前执行的最后一个可执行文件:/bin/sh
二.然后quit退出gdb,用./run启动bochs虚拟机查看sh的第二块头16个字节
[/usr/root]hexdump /bin/sh | less
可知sh的第二块头16个字节为:
8b 44 24 08 a3 00 f0 02 00 e8 26 01 00 00 6a 00
三.关闭虚拟机,重新启用gdb调试
在函数do_no_page处设置断点,并跳到断点处,address即为引发页故障的线性地址,进程的代码段起始地址可以查看进程控制块的start_code成员
(gdb)b do_no_page
(gdb)c
(gdb)p/x address
(gdb)p/x current->start_code
四.线性地址0x8000000的高10位化为10进制是32,因此需要查看页目录项(一级页表)的第32项
(gdb)x/33wx 0
可以看到,第32项的地址为0x80,值为0x00000000
五.然后在do_no_page函数内部的分配空闲页帧(381行),读入数据(387行),修改页表项(394行)三处分别设置断点,以跟踪页故障的处理过程
(gdb)b 381
(gdb)b 387
(gdb)b 394
先执行分配空闲页帧的语句(381行),即可查看分配到的空闲页帧的起始地址,再查看该页帧的头16字节内容
(gdb)c
(gdb)n
(gdb)p/x page
(gdb)x/4wx 0xffa000
可以看到此时页帧的头16字节全为00
六.执行读入数据的语句(387行),再查看页帧的头16字节内容
(gdb)c
(gdb)n
(gdb)x/4wx 0xffa000
可以看到页帧的头16字节变为:
8b 44 24 08 a3 00 f0 02 00 e8 26 01 00 00 6a 00
七.再执行修改页表项的语句(394行),重新查看页表目录项(一级页表)的第32项
(gdb)c
(gdb)n
(gdb)x/33wx 0
可以看到其值变为0x00ff7007
去掉偏移量007得到0x00ff7000,即为页表项(二级页表)的首地址。而线性地址0x8000000的中间10位化为10进制为0,因此对应页表项(二级页表)的第0项,只需要查看一项,即为线性地址对应的页表项的值
(gdb)x/wx 0xff7000
最后quit退出gdb调试
补充:如果题目问对应的物理地址是多少,还应用0x00ffa007加上线性地址0x8000000低12位的偏移量。对于本题来说,偏移量为0,页表项的值即为物理地址