6.828 Xv6实验工具指导

6.828实验工具指南

       熟悉您的环境对于高效开发和调试至关重要。 本页简要介绍了JOS环境以及有用的GDB和QEMU命令。 阅读GDB和QEMU手册,这些是让你知道如何使用的强大工具。
调试提示:内核用户环境

参考:JOS makefile JOS obj / GDB QEMU

调试提示

内核

      GDB是你的朋友。使用qemu-gdb(或其qemu-gdb-nox变体)使QEMU等待GDB连接。有关在调试内核时有用的命令,请参阅下面的GDB参考资料。
      如果遇到意外的中断,异常或三重故障,可以要求QEMU使用-d参数生成中断的详细日志。
      要调试虚拟内存问题,请尝试使用QEMU监视器命令info mem(用于高级概述)或info pg(用于大量的细节)。请注意,这些命令仅显示当前页面表。
    (Lab 4+)要调试多个CPU,请使用GDB的线程相关命令,如线程和信息线程。

用户环境(实验3+)

      GDB还允许您调试用户环境,但有几件事情需要注意,因为GDB不知道多用户环境之间或用户与内核之间存在区别。
你可以使用make run-name在特定的用户环境下启动JOS(或者你可以直接编辑kern / init.c)。要使QEMU等待GDB连接,请使用run-name-gdb变体。
      您可以像使用内核代码一样,象征性地调试用户代码,但必须告诉GDB使用symbol-file命令使用哪个符号表,因为它一次只能使用一个符号表。提供的.gdbinit加载内核符号表obj / kern / kernel。用户环境的符号表位于其ELF二进制文件中,因此您可以使用symbol-file obj / user / name加载它。不要加载任何.o文件中的符号,因为那些链接器没有重定位(库被静态链接到JOS用户二进制文件中,所以这些符号已经包含在每个用户二进制文件中)。确保你得到正确的用户二进制文件;库函数将在不同的二进制文件中的不同EIP中链接,并且GDB不会了解更多!

      (Lab 4+)由于GDB作为一个整体连接到虚拟机,它将时钟中断视为另一个控制转移。这使得单步执行用户代码基本上是不可能的,因为在虚拟机再次运行时,时钟中断几乎是必然发生的。 stepi命令可以工作,因为它禁止中断,但它只能执行一条汇编指令。断点通常是有效的,但要注意,因为你可以在不同的环境中实现相同的EIP(实际上,完全不同的二进制!)。

参考

JOS makefile

     JOS GNUmakefile包含许多用于以各种方式运行JOS的假目标。所有这些目标都将QEMU配置为侦听GDB连接(* -gdb目标也等待此连接)。要启动QEMU运行,只需从您的实验目录运行gdb。我们提供了一个.gdbinit文件,可以在QEMU中自动指向GDB,加载内核符号文件,并在16位和32位模式之间切换。退出GDB将关闭QEMU。
make qemu
    build everything,并在新窗口中启动带VGA控制台的QEMU,并在终端中启动串口控制台。要退出,请关闭VGA窗口或在终端中按Ctrl-c或Ctrl-a x。

make qemu-nox
      就像make qemu一样,只用串口控制台运行。要退出,请按Ctrl-a x。这对于通过SSH连接到Athena拨号特别有用,因为VGA窗口占用大量带宽。
make qemu-gdb
    就像make qemu一样,但不是随时被动地接受GDB连接,而是在第一条机器指令处暂停并等待GDB连接。make qemu-nox-gdb
qemu-nox和qemu-gdb目标的组合。

make run-name
(Lab 3+)运行用户程序名称。例如,make run-hello运行user / hello.c。
make run-name-nox,run-name-gdb,run-name-gdb-nox,
(Lab 3+)与qemu目标的变体相对应的运行名称的变体。

makefile也接受一些实用的变量:
make V = 1 ...
详细模式。打印出正在执行的每个命令,包括参数。
make V = 1 grade
在任何失败的等级测试结束后停止,并将QEMU输出留在jos.out中进行检查。
make QEMUEXTRA ='args'...
指定传递给QEMU的其他参数。

JOS obj /

在构建JOS时,makefile还会生成一些额外的输出文件,这些文件在调试时可能很有用:
obj / boot / boot.asm,obj / kern / kernel.asm,obj / user / hello.asm等
引导加载程序,内核和用户程序的汇编代码清单。
obj / kern / kernel.sym,obj / user / hello.sym等
内核和用户程序的符号表。
obj / boot / boot.out,obj / kern / kernel,obj / user / hello等
内核和用户程序的链接ELF映像。这些包含GDB可以使用的符号信息。

GDB

有关GDB命令的完整指南,请参阅GDB手册。这里有一些6.828特别有用的命令,其中一些通常都在OS开发之内。
Ctrl-C
暂停机器并按当前指令打入GDB。如果QEMU具有多个虚拟CPU,则会暂停所有这些虚拟CPU。
c(or continue)
继续执行,直到下一个断点或Ctrl-c。
si(or stepi)
执行一条机器指令。
b function or b file:line(or breakpoint)
在给定的函数或行处设置断点。
b * addr(or breakpoint)
在EIP地址处设置一个断点。
set print pretty
启用数组和结构来打印。
info registers
打印通用寄存器,eip,eflags和段选择器。有关机器寄存器状态的更彻底转储,请参阅QEMU自己的信息寄存器命令。
x / Nx addr
显示从虚拟地址addr开始的N个字的十六进制转储。如果省略N,则默认为1. addr可以是任何表达式。
x / Ni addr
显示从addr开始的N个汇编指令。使用$ eip作为addr将在当前指令指针处显示指令。
symbol-file file
(Lab 3+)切换到符号文件文件。当GDB连接到QEMU时,虚拟机中没有进程边界的概念,所以我们必须告诉它哪些符号要使用。默认情况下,我们配置GDB使用内核符号文件obj / kern / kernel。如果机器正在运行用户代码(如hello.c),则可以使用symbol-file obj / user / hello切换到hello符号文件。
QEMU将每个虚拟CPU表示为GDB中的一个线程,因此您可以使用所有GDB的线程相关命令来查看或操作QEMU的虚拟CPU。
thread n
GDB一次只关注一个线程(即CPU)。该命令将该焦点切换到线程n,从零开始编号。
info threads
列出所有线程(即CPU),包括它们的状态(活动或暂停)以及它们所处的功能。

QEMU

    QEMU包含一个内置的显示器,可以检查和修改机器状态。要进入监视器,请在运行QEMU的终端中按Ctrl-a c。再次按Ctrl-a c切换回串行控制台。
    有关监视器命令的完整参考,请参阅QEMU手册。这里有一些特别有用的命令:
xp / Nx paddr
显示从物理地址paddr开始的N个字的十六进制转储。如果省略N,则默认为1.这是GDB x命令的物理内存模拟。
info registers
显示机器内部寄存器状态的完整转储。特别是,这包括机器对段选择器和本地,全局和中断描述符表的隐藏段状态以及任务寄存器。这个隐藏状态是虚拟CPU在加载段选择器时从GDT / LDT读取的信息。以下是在实验1中运行JOS内核时的CS以及每个字段的含义:

CS =0008 10000000 ffffffff 10cf9a00 DPL=0 CS32 [-R-]

CS = 0008
代码选择器的可见部分。我们正在使用段0x8。这也告诉我们我们指的是全局描述符表(0x8&4 = 0),而我们的CPL(当前特权级别)是0x8&3 = 0。
100000000
段的基地址。线性地址=逻辑地址+ 0x10000000。
FFFFFFFF
段的最大值。大于0xffffffff的线性地址将导致段违例异常。
10cf9a00
段的原始标志,QEMU在接下来的几个字段中帮助我们解码。
DPL = 0
段的特权级别。只有运行权限级别为0的代码才能加载此段。
CS32
这是一个32位的代码段。其他值包括数据段的DS(不要与DS寄存器混淆)和局部描述符表的LDT。
[-R-]
此分段是只读的。
info mem
(Lab 2+)显示映射的虚拟内存和权限。例如,

ef7c0000-ef800000 00040000 urw
efbf8000-efc00000 00008000 -rw

告诉我们从0xef7c0000到0xef800000的0x00040000字节内存映射为读/写和用户可访问,而从0xefbf8000到0xefc00000的内存映射为读/写,但只能内核访问。
info pg
(Lab 2+)显示当前的页面表结构。输出与info mem相似,但区分页面目录条目和页面表条目,并分别为每个条目赋予权限。重复的PTE和整个页面表被折叠成一行。例如,

VPN range     Entry         Flags        Physical page
[00000-003ff]  PDE[000]     -------UWP
  [00200-00233]  PTE[200-233] -------U-P 00380 0037e 0037d 0037c 0037b 0037a ..
[00800-00bff]  PDE[002]     ----A--UWP
  [00800-00801]  PTE[000-001] ----A--U-P 0034b 00349
  [00802-00802]  PTE[002]     -------U-P 00348

这显示了两个页面目录条目,分别跨越虚拟地址0x00000000到0x003fffff和0x00800000到0x00bfffff。两个PDE都存在,可写和用户,第二个PDE也被访问。这些页表中的第二个映射三个页面,跨越虚拟地址0x00800000到0x00802fff,其中前两个存在,用户和访问,第三个仅存在和用户。这些PTE的第一个映射物理页面0x34b。

QEMU也会使用一些实用命令行参数,这些参数可以使用QEMUEXTRA变量传递给JOS makefile。
make QEMUEXTRA =' - d int'...
将所有中断以及完整寄存器转储记录到qemu.log。您可以忽略前两个日志条目“SMM:enter”和“SMM:RMS之后”,因为它们是在进入引导加载程序之前生成的。在此之后,日志条目看起来像

   4: v=30 e=0000 i=1 cpl=3 IP=001b:00800e2e pc=00800e2e SP=0023:eebfdf28 EAX=00000005
EAX=00000005 EBX=00001002 ECX=00200000 EDX=00000000
ESI=00000805 EDI=00200000 EBP=eebfdf60 ESP=eebfdf28
...

第一行描述中断。 4:只是一个日志记录计数器。 v给出十六进制的向量号。 e给出错误代码。 i = 1表示这是由int指令产生的(与硬件中断相对)。其余的部分应该是不言自明的。有关后面的寄存器转储的说明,请参阅info registers。
注意:如果您运行的是QEMU的0.15以前版本,则日志将写入/ tmp而不是当前目录。

猜你喜欢

转载自blog.csdn.net/qq_36116842/article/details/79863819