实验说明
实验难度
每个实验都具有相应的难度
Easy:不到一个小时。这些锻炼通常是为后续锻炼做的热身运动。
Moderate:1-2小时。
Hard:超过2个小时。这些练习通常不需要很多代码,但是代码很难正确。
实验往往不需要很多行代码(几十到几百行) ,但是代码在概念上很复杂,而且细节往往很重要。所以,在你写任何代码之前,一定要完成实验室指定的阅读,通读相关文件,查阅文档(RISC-V手册等存放在了参考页面上)。只有当你确定掌握了任务和解决方案,再开始编码。当你开始编写代码的时候,一小步一小步地实现你的解决方案(作业通常会建议如何将问题分解为更小的步骤),并且在继续下一个步骤之前测试每个步骤是否正常工作。
调试技巧
确保你理解了c和指针。Kernighan和Ritchie的《c程序设计语言》一书对C语言进行了简要的描述。这里有一些有用的指针练习。除非你已经完全掌握了C语言,不要跳过或略读上面的指针练习。如果你不能真正理解C语言中的指针,你将在实验室中遭受难以言喻的痛苦,然后最终以一种艰难的方式来理解它们。相信我们,你不会想知道什么是“艰难的路”的。
一些常见的习惯用法特别值得记住:
如果
int *p = (int*)100
,那么(int)p + 1
及(int)(p + 1)
是不同的数字,第一个是101,但第二个是104。当向指针添加一个整数时,如第二种情况,整数被隐式地乘以指针指向的对象的大小。p[i]
被定义为与*(p+i)
相同,指向内存中p指向的第i个对象,当对象大于1字节时,上面所说的加法规则有利于此定义工作
虽然大多数C程序不需要在指针和整数之间进行强制转换,但操作系统经常需要这样做。每当您看到一个包含内存地址的加法时,问问自己它是整数加法还是指针加法,并确保所添加的值是否适当地相乘。
如果你有一个部分工作的练习,请通过提交代码来检查你的进度。如果您稍后破坏了某些东西,那么您可以回滚到您的检查点,然后以较小的步骤继续前进。要了解关于Git的更多信息,请查看Git用户手册,或者您可能会发现这个面向计算机科学家的Git概述非常有用。
如果您没有通过测试,确保您了解为什么您的代码没有通过测试。插入打印(printf)语句,直到您理解正在发生的事情。
您可能会发现您的print语句可能会产生许多您想要搜索的输出;其中一种方法是在
script
内部运行make qemu
(在您的机器上运行man script
),它将所有控制台输出记录到一个文件中,然后您可以搜索该文件。别忘了退出script
。在许多情况下,print语句就足够了,但有时能够单步遍历一些汇编代码或检查堆栈上的变量是有帮助的。要在xv6中使用gdb,请在一个窗口中运行
make qemu-gdb
,在另一个窗口中运行gdb
(或riscv64-linux-gnu-gdb
),设置断点,后跟“c
”(continue),xv6将一直运行,直到到达断点。(有关有用的GDB提示,请参阅使用GNU调试器。)如果要查看编译器为内核生成的程序集是什么,或者要找出特定内核地址的指令是什么,请参阅文件
kernel.asm
,该文件在编译内核时由Makefile生成。(Makefile同时也为所有用户程序生成.asm文件。)如果内核崩溃,它将打印一条错误消息,列出崩溃时程序计数器的值;您可以进行搜索
kernel.asm
找出程序计数器崩溃时在哪个函数中,或者可以运行addr2line -e kernel/kernel pc-value
(有关详细信息,请运行man addr2line
)。如果要获取回溯,请使用gdb重新启动:在一个窗口中运行'make qemu-gdb
',在另一个窗口中运行gdb(或riscv64-linux-gnu-gdb
),在panic
中设置断点(“b panic
”),后跟“c
”(continue)。当内核到达断点时,键入“bt”以获取回溯跟踪。如果您的内核挂起(例如,由于死锁)或无法进一步执行(例如,由于在执行内核指令时出现页面错误),您可以使用gdb查找挂起的位置。在一个窗口中运行“
make qemu-gdb
”,在另一个窗口中运行gdb
(riscv64-linux-gnu-gdb
) ,后跟“c
”(continue)。当内核出现挂起时,在qemu-gdb
窗口中按Ctrl-C
并键入“bt
”以获得回溯跟踪。qemu有一个“监视器”,允许您查询模拟机器的状态。您可以通过键入
<Ctrl>+a c
(c表示控制台)来获得它。一个特别有用的monitor命令是info mem
,用于打印页表。您可能需要使用cpu
命令来选择info mem
查看哪一个核心,或者可以使用make CPUS=1 qemu
启动qemu,以使其只有一个核心。
花时间学习上述工具是非常值得的