# [6.S081: Operating System Engineering](https://pdos.csail.mit.edu/6.828/2020/xv6.html) ### 安装编译环境 步骤:根据教程[Labs Tools](https://pdos.csail.mit.edu/6.828/2020/tools.html)在ubuntu上安装qume 结果:在xv6目录下执行`make qume`可正常执行并且进入xv6系统(退出qemu: `Ctrl-a x`) ### Lab Guidance #### 1. C与指针 教程建议先熟悉C和指针,阅读下面一段程序给出答案看是否了解指针: 提示:查看Linux机器的Byte Order使用命令:`lscpu` ```c= #include <stdio.h> #include <stdlib.h> void f(void) { int a[4]; int *b = malloc(16); int *c; int i; printf("1: a = %p, b = %p, c = %p\n", a, b, c); c = a; for (i = 0; i < 4; i++) a[i] = 100 + i; c[0] = 200; printf("2: a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d\n", a[0], a[1], a[2], a[3]); c[1] = 300; *(c + 2) = 301; 3[c] = 302; printf("3: a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d\n", a[0], a[1], a[2], a[3]); c = c + 1; *c = 400; printf("4: a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d\n", a[0], a[1], a[2], a[3]); c = (int *) ((char *) c + 1); *c = 500; printf("5: a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d\n", a[0], a[1], a[2], a[3]); b = (int *) a + 1; c = (int *) ((char *) a + 1); printf("6: a = %p, b = %p, c = %p\n", a, b, c); } int main(int ac, char **av) { f(); return 0; } ``` 在小端机器上运行结果: ```shell 1: a = 0x7ffdf4e2cca0, b = 0x55653369c2a0, c = 0x7ffdf4e2ccc7 2: a[0] = 200, a[1] = 101, a[2] = 102, a[3] = 103 3: a[0] = 200, a[1] = 300, a[2] = 301, a[3] = 302 4: a[0] = 200, a[1] = 400, a[2] = 301, a[3] = 302 5: a[0] = 200, a[1] = 128144, a[2] = 256, a[3] = 302 6: a = 0x7ffdf4e2cca0, b = 0x7ffdf4e2cca4, c = 0x7ffdf4e2cca1 ``` 通常时候我们看到的栈是形象的栈,适合分析PUSH和POP操作。如下图: ![栈 分析PUSH与POP操作](https://i.imgur.com/Ds1NThN.png) 涉及到字节序问题或其他情况,使用一维线性地址描述可能会更直观。如下图: ![栈 分析字节序](https://i.imgur.com/u4cPgzC.png) #### 2. script命令 > You may find that your print statements may produce much output that you would like to search through; one way to do that is to run `make qemu` inside of `script` (run man script on your machine), which logs all console output to a file, which you can then search. Don't forget to exit script. 当调试的时候可能有大量的调试信息被输出,如果想从中查找信息,一种办法是在`script`命令之中执行`make qemu`。 - 退出`script`使用`exit`或`Ctrl-D` - `script`命令相当于启动录制,回放使用`scriptreplay` #### 3. 使用gdb调试 > To use gdb with xv6, run make make qemu-gdb in one window, run gdb (or riscv64-linux-gnu-gdb) in another window, set a break point, followed by followed by 'c' (continue), and xv6 will run until it hits the breakpoint. (See Using the [GNU Debugger](https://pdos.csail.mit.edu/6.828/2019/lec/gdb_slides.pdf) for helpful GDB tips.) 1. 执行`make qemu-gdb` 2. 在另一个窗口执行`gdb` 3. 设置断点 GDB指令简介内容来自[GNU Debugger](https://pdos.csail.mit.edu/6.828/2019/lec/gdb_slides.pdf): | 指令 | 含义 | | ---------------------------------------- | ----------------------------------------------------------------------------------------------- | | `help <conmand-name>` | 帮助 | | `step` | 执行一条指令,当遇到函数的时候进入(into)函数 | | `next` | 执行一条指令,当遇到函数的时候跳过(over)函数 | | `stepi` | 调试汇编 | | `nexti` | 调试汇编 | | `continue` | 直到执行到断点或`Ctrl-C` | | `finish` | 直到当前函数返回 | | `advance <location>` | 执行到指定的位置 | | `break <location>` | 在指定位置设置断点 | | <b style="color: red;">`<location>` </b> | <b style="color: red;">addresses (“*0x7c00”) or<br> names (“mon_backtrace”, “monitor.c:71”)</b> | | `delete`<br>`enable`<br>`disable` | 改变断点 | | `break <location> if <condition>` | 当条件满足时候断点 | | `cond <number> <condition>` | 给已经存在的断点加条件 | | `watch <expression>` | 当表达式的值改变时候停止执行 | | `watch -l \<address>` | 指定地址处的内容改变则停止 | | `rwatch [-l] <expression>` | 当表达式的值被读取的时候则停止执行 | | `x ` | 打印内存内容 x/x十六进制 x/i汇编 | | `print ` | 打印C表达式的结果<br>p *((struct elfhdr *) 0x10000) | | `info register` | 显示所有寄存器的值 | | `info frame` | 打印当前栈帧 | | `list <location>` | 列出指定位置处函数的源码 | | `layout <name>` | | | `set ` | 改变变量的值 | | `symbol-file obj/user/` | 从指定文件解析符号 | #### 4. 查看汇编文件(*.asm 由Makefile产生) #### 5. panics处理办法 1. 从kernel.asm中查看停在那个函数中 `addr2line -e kernel/kernel _pc-value_` 2. 打印backtrace #### 6. 处理hangs 1. Ctrl-C 2. bt #### 7. qemu monitor > qemu has a "monitor" that lets you query the state of the emulated machine. You can get at it by typing `control-a c` (the "c" is for console). A particularly useful monitor command is <b style="color: red;">`info mem`</b> to print the page table. You may need to use the cpu command to select which core info mem looks at, or you could start qemu with <b style="color: red;">`make CPUS=1 qemu`</b> to cause there to be just one core.