Project0:小游戏

2.1 找到故障指令

FAIL
Test output failed to match any acceptable form.

Acceptable output:
  do-nothing: exit(162)
Differences in `diff -u' format:
- do-nothing: exit(162)
+ Page fault at 0xc0000008: rights violation error reading page in user context.
+ do-nothing: dying due to interrupt 0x0e (#PF Page-Fault Exception).
+ Interrupt 0x0e (#PF Page-Fault Exception) at eip=0x80488ee
+  cr2=c0000008 error=00000005
+  eax=00000000 ebx=00000000 ecx=00000000 edx=00000000
+  esi=00000000 edi=00000000 esp=bfffffe4 ebp=bffffffc
+  cs=001b ds=0023 es=0023 ss=0023
  1. 程序试图从用户空间访问哪个虚拟地址导致它崩溃?
    0xc0000008
  2. 导致崩溃的指令的虚拟地址是什么?
    0x80488ee
  3. 要进行调查,请使用 objdump 反汇编 do-nothing 二进制文件。程序崩溃时所在的函数的名称是什么?,并确定程序崩溃的指令。
080488e8 <_start>:
 80488e8:       55                      push   %ebp
 80488e9:       89 e5                   mov    %esp,%ebp
 80488eb:       83 ec 18                sub    $0x18,%esp
 80488ee:       8b 45 0c                mov    0xc(%ebp),%eax    ;argv
 80488f1:       89 44 24 04             mov    %eax,0x4(%esp)
 80488f5:       8b 45 08                mov    0x8(%ebp),%eax    ;argc
 80488f8:       89 04 24                mov    %eax,(%esp)
 80488fb:       e8 94 f7 ff ff          call   8048094 <main>
 8048900:       89 04 24                mov    %eax,(%esp)
 8048903:       e8 d3 21 00 00          call   804aadb <exit>
  1. 找到您在上面确定的函数的 C 代码(提示:它是在用户空间中执行的,因此它位于 do-nothing.c 或 proj-pregame/src/lib 或 proj-pregame/src/lib/user 中的文件之一)。对于 #3 中反汇编函数中的每条指令,用几句话解释为什么它是必要的和/或它试图做什么。提示:参见 80x86 调用约定。
    向 main 函数传递参数。80x86 的函数参数都是通过栈传送,而80x86_64 的前 6 个参数通过寄存器传送。
//proj-pregame/src/lib/user/entry.c
#include <syscall.h>

int main(int, char* []);
void _start(int argc, char* argv[]);

void _start(int argc, char* argv[]) { exit(main(argc, argv)); }
  1. 为什么您在 #3 中确定的指令尝试访问您在 #1 中确定的虚拟地址处的内存?不要用寄存器的值来解释这个;我们正在寻找更高层次的解释。
    此时指令想要将参数 argv 作为调用 main 函数的参数,而 ebp 指向它的旧值,ebp + 4 指向返回地址,ebp + 8 指向 argc,ebp + 12 指向 argv,因此该指令试图访问该虚拟地址。

2.2 单步调试崩溃

  1. 进入进程执行功能。运行此函数的线程的名称和地址是什么?目前 Pintos 中还有哪些其他线程?复制他们的线程结构。
    名称为 main,地址为 0xc000e000
pintos-debug: dumplist #0: 0xc000e000 {tid = 1, status = THREAD_RUNNING, name = "main", '\000' <repeats 11 times>, stack = 0xc000e
dbc "\001", priority = 31, allelem = {prev = 0xc0039cf8 <all_list>, next = 0xc0104020}, elem = {prev = 0xc0039ce8 <fifo_ready_list
>, next = 0xc0039cf0 <fifo_ready_list+8>}, pcb = 0xc010500c, magic = 3446325067}
pintos-debug: dumplist #1: 0xc0104000 {tid = 2, status = THREAD_BLOCKED, name = "idle", '\000' <repeats 11 times>, stack = 0xc0104
f14 "", priority = 0, allelem = {prev = 0xc000e020, next = 0xc0039d00 <all_list+8>}, elem = {prev = 0xc0039ce8 <fifo_ready_list>,
next = 0xc0039cf0 <fifo_ready_list+8>}, pcb = 0x0, magic = 3446325067}
  1. 当前线程的回溯是什么?从 GDB 复制回溯作为您的答案,并复制对应于每个函数调用的 C 代码行。
#0  process_execute (file_name=0xc0007d50 "do-nothing") at ../../userprog/process.c:55
#1  0xc0020a19 in run_task (argv=0xc0039bec <argv+12>) at ../../threads/init.c:317
#2  0xc0020b8f in run_actions (argv=0xc0039bec <argv+12>) at ../../threads/init.c:390
#3  0xc00203d9 in main () at ../../threads/init.c:138
process_wait(process_execute(task));
a->function(argv);
run_actions(argv);
  1. 在 start_process 处设置断点并继续运行到该点。运行此函数的线程的名称和地址是什么?目前 Pintos 中还有哪些其他线程?复制他们的结构线程。
    do-nothing,0xc010b000。
pintos-debug: dumplist #0: 0xc000e000 {tid = 1, status = THREAD_BLOCKED, name = "main", '\000' <repeats 11 times>, stack = 0xc000e
e7c "", priority = 31, allelem = {prev = 0xc0039cf8 <all_list>, next = 0xc0104020}, elem = {prev = 0xc003b718 <temporary+4>, next
= 0xc003b720 <temporary+12>}, pcb = 0xc010500c, magic = 3446325067}
pintos-debug: dumplist #1: 0xc0104000 {tid = 2, status = THREAD_BLOCKED, name = "idle", '\000' <repeats 11 times>, stack = 0xc0104
f14 "", priority = 0, allelem = {prev = 0xc000e020, next = 0xc010b020}, elem = {prev = 0xc0039ce8 <fifo_ready_list>, next = 0xc003
9cf0 <fifo_ready_list+8>}, pcb = 0x0, magic = 3446325067}
pintos-debug: dumplist #2: 0xc010b000 {tid = 3, status = THREAD_RUNNING, name = "do-nothing\000\000\000\000\000", stack = 0xc010bf
d4 "", priority = 31, allelem = {prev = 0xc0104020, next = 0xc0039d00 <all_list+8>}, elem = {prev = 0xc0039ce8 <fifo_ready_list>,
next = 0xc0039cf0 <fifo_ready_list+8>}, pcb = 0x0, magic = 3446325067}
  1. 单步执行 start_process 函数,直到您跨过对 load 的调用。注意 load 设置 if_ 结构中的 eip 和 esp 字段。打印出 if_ 结构的值,以十六进制显示值(提示: p/x if )。
{edi = 0x0, esi = 0x0, ebp = 0x0, esp_dummy = 0x0, ebx = 0x0, edx = 0x0, ecx = 0x0, eax = 0x0, gs = 0x23, fs = 0x23, es = 0x2
3, ds = 0x23, vec_no = 0x0, error_code = 0x0, frame_pointer = 0x0, eip = 0x80488e8, cs = 0x1b, eflags = 0x202, esp = 0xc0000000, s
s = 0x23}
  1. asm volatile 语句中的第一条指令将堆栈指针设置为 if_ 结构的底部。第二条指令跳转到 intr_exit。代码中的注释解释了这里发生了什么。单步执行 asm volatile 语句,然后单步执行指令。当您逐步执行 iret 指令时,观察到函数“返回”到用户空间。为什么在执行此函数时处理器会切换模式?请随时根据 iret 时内存和/或寄存器中的值来解释这一点执行,以及 iret 指令的功能。
intr_exit:
 52/* Restore caller's registers. */
 53│         popal
 54│         popl %gs
 55│         popl %fs
 56│         popl %es
 57│         popl %ds
 5859/* Discard `struct intr_frame' vec_no, error_code,
 60│            frame_pointer members. */
 61│         addl $12, %esp
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值