不落辰

知不可乎骤得,托遗响于悲风

0%

操作系统-xv6-debug方法

xv6 debug基本方法

Debug

调试kernel代码

Console

  • .gdbinit
    1
    2
    3
    4
    5
    6
    1 set confirm off
    2 set architecture riscv:rv64
    3 target remote 127.0.0.1:26000
    4 symbol-file kernel/kernel
    5 set disassemble-next-line auto
    6 set riscv use-compressed-breakpoints yes
  • make qemu-gdb : 开启gdb server
  • gdb-multiarch : 连接gdb server

VsCode

  • .gdbinit
    1
    2
    3
    4
    5
    6
    7
    1 set confirm off
    2 set architecture riscv:rv64
    3 # target remote 127.0.0.1:26000
    4 symbol-file kernel/kernel
    5 # symbol-file user/_ls
    6 set disassemble-next-line auto
    7 set riscv use-compressed-breakpoints yes
  • terminal : make qemu-gdb CPUs=1
  • debug console : attach to gdbServer

调试user代码

Console

  • .gdbinit
    1
    2
    3
    4
    5
    6
    7
    1 set confirm off
    2 set architecture riscv:rv64
    3 target remote 127.0.0.1:26000
    4 # symbol-file kernel/kernel
    5 symbol-file user/_ls
    6 set disassemble-next-line auto
    7 set riscv use-compressed-breakpoints yes

VsCode

  • Step1: terminal : make qemu-gdb。
  • Step2: 点击左侧按钮运行与调试,并点击左上角绿色三角(Attach to gdb)
  • Step3 : debug console : interrupt
  • Step5 : debug console : b *0x27a,即将断点置于ls程序入口
  • Step6 : debug console : file user/_ls。加载ls的调试符号 ; then continue
  • Step7 : terminal : (运行应用程序)ls
  • debug console
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    Reading symbols from /home/shc/OSLab/xv6-labs-2020/kernel/kernel...
    The target architecture is assumed to be riscv:rv64
    0x0000000000001000 in ?? ()
    => 0x0000000000001000: 97 02 00 00 auipc t0,0x0
    **interrupt**
    Thread 1 received signal SIGINT, Interrupt. scheduler () at kernel/proc.c:465 \n 465 intr_on();
    **b *0x27a**
    Breakpoint 1 at 0x27a
    **file user/_ls**
    Reading symbols from user/_ls...
    **c**
    Continuing.
    Thread 2 hit Breakpoint 1, main (argc=0, argv=0x6c <fmtname+108>) at user/ls.c:75
    75 {

    通过readelf确认应用程序入口点

调试系统调用 kernel -> user -> kernel

  • step1 : gdb client 连接 gdb server,一开始是kenrel。

  • step2 : 加载user文件,打断点

    • file user/_ls ; break [line at user program使用的system call]
  • step3 : break point at (你想要调试的系统调用)(这里时fstat syscall); and then breakpoint at ecall

    • bug : 按理来说这时候page table应该是user的page table,不知道为什么这里时kernel的page table ?
    • b 38 ; b [at ecall] (ecall的语义类似于x86-64的syscall)


  • step4 : 进入trampoline (进入kenrel前的最后阶段)

    • break at start of trampoline


    • break at end of trampoline

      • 如何知道trampoline最后jr t0的addr是0x3ffffff08e?
        • x/40i $pc显示当前PC后面的40条汇编
    • si从trampoline中出来。进入kernel的usertrap

      • 记得file kernel/kernel 因为现在要调试kernel

  • step5: 成功进入kernel,接下来就是正常的调试 kernel的C code