# [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操作。如下图:

涉及到字节序问题或其他情况,使用一维线性地址描述可能会更直观。如下图:

#### 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.