Using gdb
gdb使用:
xv6 gdb调试方法
问题1:
- Looking at the backtrace output, which function called syscall?
按照提示开启gdb后键入:
b syscall
c
layout src
backtrace
输出结果:
(gdb) backtrace
#0 syscall () at kernel/syscall.
#1 0x0000000080001d70 in usertra
#2 0x0505050505050505 in ?? ()
(gdb)
usertra调用了syscall
问题2:
- What is the value of p->trapframe->a7 and what does that value represent?
- (线索: look user/initcode.S, the first user program xv6 starts.)
- proc结构体源码:
// Per-process state
struct proc {
struct spinlock lock;
// p->lock must be held when using these:
enum procstate state; // Process state
void *chan; // If non-zero, sleeping on chan
int killed; // If non-zero, have been killed
int xstate; // Exit status to be returned to parent's wait
int pid; // Process ID
// wait_lock must be held when using this:
struct proc *parent; // Parent process
// these are private to the process, so p->lock need not be held.
uint64 kstack; // Virtual address of kernel stack
uint64 sz; // Size of process memory (bytes)
pagetable_t pagetable; // User page table
struct trapframe *trapframe; // data page for trampoline.S
struct context context; // swtch() here to run process
struct file *ofile[NOFILE]; // Open files
struct inode *cwd; // Current directory
char name[16]; // Process name (debugging)
};
- trapframe结构体:
// the entire kernel call stack.
struct trapframe {
/* 0 */ uint64 kernel_satp; // kernel page table
/* 8 */ uint64 kernel_sp; // top of process's kernel stack
/* 16 */ uint64 kernel_trap; // usertrap()
/* 24 */ uint64 epc; // saved user program counter
/* 32 */ uint64 kernel_hartid; // saved kernel tp
/* 40 */ uint64 ra;
/* 48 */ uint64 sp;
/* 56 */ uint64 gp;
/* 64 */ uint64 tp;
/* 72 */ uint64 t0;
/* 80 */ uint64 t1;
/* 88 */ uint64 t2;
/* 96 */ uint64 s0;
/* 104 */ uint64 s1;
/* 112 */ uint64 a0;
/* 120 */ uint64 a1;
/* 128 */ uint64 a2;
/* 136 */ uint64 a3;
/* 144 */ uint64 a4;
/* 152 */ uint64 a5;
/* 160 */ uint64 a6;
/* 168 */ uint64 a7;
/* 176 */ uint64 s2;
/* 184 */ uint64 s3;
/* 192 */ uint64 s4;
/* 200 */ uint64 s5;
/* 208 */ uint64 s6;
/* 216 */ uint64 s7;
/* 224 */ uint64 s8;
/* 232 */ uint64 s9;
/* 240 */ uint64 s10;
/* 248 */ uint64 s11;
/* 256 */ uint64 t3;
/* 264 */ uint64 t4;
/* 272 */ uint64 t5;
/* 280 */ uint64 t6;
};
- initcode.S源码:
# Initial process that execs /init.
# This code runs in user space.
#include "syscall.h"
# exec(init, argv)
.globl start
start:
la a0, init
la a1, argv
li a7, SYS_exec
ecall
# for(;;) exit();
exit:
li a7, SYS_exit
ecall
jal exit
# char init[] = "/init\0";
init:
.string "/init\0"
# char *argv[] = { init, 0 };
.p2align 2
argv:
.long init
.long 0
键入n
数次使gdb越过struct proc *p = myproc();
,此后键入p /x *p
,此命令打印了进程的proc struct
打印输出:
$1 = {lock = {locked = 0x0, name = 0x800081b8, cpu = 0x0},
state = 0x4, chan = 0x0, killed = 0x0, xstate = 0x0, pid = 0x1,
parent = 0x0, kstack = 0x3fffffd000, sz = 0x1000,
pagetable = 0x87f73000, trapframe = 0x87f74000, context = {
ra = 0x800014c2, sp = 0x3fffffde80, s0 = 0x3fffffdeb0,
s1 = 0x80008d50, s2 = 0x80008920, s3 = 0x1, s4 = 0x0,
s5 = 0x3, s6 = 0x800199f0, s7 = 0x8, s8 = 0x80019b18,
s9 = 0x4, s10 = 0x1, s11 = 0x0}, ofile = {
0x0 <repeats 16 times>}, cwd = 0x80016e60, name = {0x69, 0x6e,
0x69, 0x74, 0x63, 0x6f, 0x64, 0x65, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0}}
(gdb)
p->trapframe->a7
为proc结构体中trapframe指针指向的结构体中a7的值
(gdb) p /x p->trapframe->a7
$8 = 0x7
(gdb)
所以a7中存放值为0x07,此值代表exec系统调用的编号,后续用于调用 ecall 重新进入内核。
问题3:
- What was the previous mode that the CPU was in?
(gdb) p /x $sstatus
$9 = 0x22
(gdb)
十进制为100010
,查询RISC-V privileged instructions可知:
此时第八位为0,代表CPU之前处于用户态
问题4:(错误测试)
- Write down the assembly instruction the kernel is panicing at. Which register corresponds to the variable num?