---
# System prepended metadata

title: '[6.S081: Operating System Engineering](https://pdos.csail.mit.edu/6.828/2020/xv6.html)'

---

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