实验相关链接

哔哩哔哩网课链接

实验要求翻译链接

课程翻译文字版本

课程阅读材料

课表安排

其他人的总结链接

  1. David-Dong
  2. 解析Ta
  3. 林夕丶
  4. 星见遥
  5. Doraemonzzz

课程个人理解

本课程使用RISC-V架构的XV6操作系统,该操作系统是类Unix类型,虽然简单,但是包含了Unix的重要概念,完成所有lab后对操作系统会拥有更加深入的了解。

实验的每一个lab都有专门的代码可供打分,便于直观判断自己的代码实际效果。

并且每个lab之间互不干扰,lab3的代码不会影响lab4,这种相互隔离做法让实验的进行更加方便。

环境

  1. 使用ubuntu-20.04版本
  2. 环境配置链接

Tmux(screen类似应用)

相关教程

Tmux可以在一个窗口中使用多个终端,Linux类的操作系统在关闭终端后,正在终端中运行的程序便会终止,Tmux可以在退出窗口时保存窗口内容,后续可以通过指令快速恢复环境。*(如图:一个窗口分出来了三个终端)*

Tmux常用操作

会话管理

1.新建会话 tmux new -s <**session-name**>

2.分离会话 tmux detach 或者 Ctrl+b d 上面命令执行后,就会退出当前 Tmux 窗口,但是会话和里面的进程仍然在后台运行。

3.查看当前所有的 Tmux 会话 tmux lstmux list-session

4.接入会话

1
2
3
4
5
# 使用会话编号
$ tmux attach -t 0

# 使用会话名称
$ tmux attach -t <session-name>

5.杀死会话

1
2
3
4
# 使用会话编号
$ tmux kill-session -t 0
# 使用会话名称
$ tmux kill-session -t <session-name>

6.切换会话

1
2
3
4
5
# 使用会话编号
$ tmux switch -t 0

# 使用会话名称
$ tmux switch -t <session-name>

7.重命名会话 tmux rename-session -t 0 <new-name>

窗格操作

​ -Ctrl+b %:划分左右两个窗格。

  • Ctrl+b ":划分上下两个窗格。
  • Ctrl+b <arrow key>:光标切换到其他窗格。<arrow key>是指向要切换到的窗格的方向键,比如切换到下方窗格,就按方向键
  • Ctrl+b ;:光标切换到上一个窗格。
  • Ctrl+b o:光标切换到下一个窗格。
  • Ctrl+b {:当前窗格与上一个窗格交换位置。
  • Ctrl+b }:当前窗格与下一个窗格交换位置。
  • Ctrl+b Ctrl+o:所有窗格向前移动一个位置,第一个窗格变成最后一个窗格。
  • Ctrl+b Alt+o:所有窗格向后移动一个位置,最后一个窗格变成第一个窗格。
  • Ctrl+b x:关闭当前窗格。
  • Ctrl+b !:将当前窗格拆分为一个独立窗口。
  • Ctrl+b z:当前窗格全屏显示,再使用一次会变回原来大小。
  • Ctrl+b Ctrl+<arrow key>:按箭头方向调整窗格大小。
  • Ctrl+b q:显示窗格编号。

代码调试

使用 gdb-multiarch 进行调试*(xv6不是x86架构,不能使用普通的gdb直接进行调试)*

一般的调试流程

  1. tmux在窗口中建立两个终端

  2. 终端1在代码目录下输入make clean清除实验缓存

  3. 终端1在代码目录下输入make qemu-gdb打开调试模式*(make CPUS=1 qemu-gdb 为单核调试模式)*,出现

  4. 终端2在代码目录下输入gdb-multiarch ,出现0x0000000000001000 in ?? ()代表成功

  5. 1
    2
    3
    4
    file kernel/kernel //加载kernel  或者 file user/_ls

    b main //设置断点
    c //运行程序

调试指令

1
step 一次运行一行代码。当有函数调用时,它将步进到被调用的对象函数。
1
next 也是一次运行一行代码。但当有函数调用时,它不会进入该函数。
1
2
3
stepi 
nexti
对于汇编指令是单步调试。

所有命令都可以采用一个数字参数来指定重复执行的次数。按回车键将重复上一个命令。
layout src 产看原代码
layout asm:查看汇编
layout reg:查看寄存器
info reg:查看寄存器
info frame 看到有关当前Stack Frame许多有用的信息
b *0x1234:在指定地址设定断点

1
i args  : 查看当前函数的入参
1
i locals   : 查看局部变量

continue继续运行程序直到断点
info b 查看断点
delete 删除所有断点
d 1 删除断点1
bt backtrace 回溯程序运行顺序
watch i 监视变量i当其发生变化时停下
p *args 输出指针的值
p *args@2 输出数组前两个值
b sum if i==5 设置条件断点

实际遇到的问题

在实际情况下,使用gdb调试涉及内核的代码并不是很方便,在用户态下使用stepi 调试程序,内核态的发生过程对于用户态是透明的。

我们需要在进入内核态前使用file kernel/kernel加载内核,再使用stepi进入内核

进入内核后,系统会 调用 进程替换、中断函数、usertrap函数等保证系统的正常运行但是与我们的用户态程序直接关系不大的代码,使用stepi太繁琐,使用断点需要我们提前知道内核哪里发生了崩溃,使用gdb调试效率不高

解决方案

进行实验时,我们需要在自己修改的代码后,增加足够多的printf函数,这样我们可以跟踪系统的执行情况。

在修改内核时,对自己的修改应拥有充分的理解,发生错误时,回滚至正常的版本,一步一步根据自己的代码进行修改,直到错误的出现,定位问题。