(gdb) file kernel/kernel (gdb) file user/_ls
Xv6 Window
GDB Window
$ ssh@cpsc.umw.edu $ cd xv6-labs $ gdb-multiarch (gdb) target remote localhost:<PORT_NUMBER> The PORT_NUMBER is from item 5 in the first window steps above. file user/_ptr (gdb) file user/_ptr A program is being debugged already. Are you sure you want to change the file? (y or n) y Reading symbols from user/_ptr... b ptr.c:8 (gdb) b ptr.c:9 Breakpoint 1 at 0xa: file user/ptr.c, line 9. (gdb) info breakpoints Num Type Disp Enb Address What 1 breakpoint keep y 0x000000000000000a in main at user/ptr.c:9 (gdb) c Continuing. Breakpoint 1, main (ac=1, av=0x3fe0) at user/ptr.c:9 9 int l = 5; // local variables don't have a default value (gdb) c Continuing. Breakpoint 1, main (ac=8224, av=0x64 ) at user/ptr.c:9 9 int l = 5; // local variables don't have a default value (gdb) c Continuing.
Breakpoint 1, main (ac=1, av=0x3fe0) at user/ptr.c:9 9 int l = 5; // local variables don't have a default value (gdb) layout src // to show source code (gdb) n
(gdb) p l $1 = 5 (gdb) n (gdb) p q $2 = (int *) 0x3fac (gdb) p *q $3 = 5 (gdb) b 29 Breakpoint 2 at 0x54: file user/ptr.c, line 29. (gdb) c Continuing. Breakpint 2, main (ac=The following shows the GDB window after Breakpoint 2 has been hit., av= ) at user/ptr.c:29
(gdb) p ptr->a s4 = 10 (gdb) p s.a // ptr->a and s.a are equivalent $5 = 10 (gdb) p s.b $6 =// We did not assign s.b a value (gdb) p ptr->b $7 = // ptr->b and s.b are equivalent (gdb) b 40 Breakpoint 3 at 0x9a: file user/ptr.c, line 40. (gdb) c Continuing. Breakpint 3, main (ac= , av= ) at user/ptr.c:40 (gdb) p pp $8 = (int **)0x3fa0 (gdb) p *pp $9 = (int *)0x1000 (gdb) p **pp $10 = 11 (gdb) p *p $11 = 11 (gdb) c Continuing. Breakpint 2, main (ac=8224, av=0x64 ) at user/ptr.c:9 (gdb) c Continuing.
Xv6 Window
$ make CPUS=1 qemu-gdb *** Now run 'gdb' in another window. qemu-system-riscv64 -machine virt -bios none -kernel kernel/kernel -m 128M -smp 1 -nographic -global virtio-mmio.force-legacy=false -drive file=fs.img,if=none,format=raw,id=x0 -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0 -S -gdb tcp::26003 xv6 kernel is booting init: starting sh $ ptr p 0x0000000000001000 q 0x0000000000003FAC g 11 l 13 10 10 pp 0x0000000000003FA0 0x0000000000001000 11 main: 0x0000000000000000
Out helpful webpages have been crafted for our class, and they are an abbreviated version of the MIT GDB Webpages, with an index at MIT GDB Webpages.
GDB is a source-level debugger created by Richard M. Stallman. Many have contributed to the development of GDB: Contributors to GDB
To perform symbolic debugging, you must tell gdb where to find symbol definitions. When a program is loaded into memory, the code and variables are loaded into specific addresses. The symbol information is created by the compiler/linker and defines the relationships between symbols (functions and variables) and memory. The gdb file filename
command tells gdb where the symbol information is located. The following is a sample.
(gdb) file kernel/kernel
The gdb p exp
command is used to print the value of expressions. Just like in programming languages, the expression contains operands (i.e., variables, constants) and operators. When a variable is used in an expression, the value of the variable is printed. The following show simple uses of the gdb p
command where the expressions are addition of constants, a variable, and multiplication of a variable and a constant.
(gdb) p 5 + 6 $7 = 11 (gdb) p num $8 = 7 (gdb) p num * 4 $9 = 28
You can also use the p
command to print the values of pointers and the struture that that pointer points to. Suppose you had a variable struct proc *p
that points to a struct proc
. The definition of struct proc
is in kernel/proc.h, which is repeated here.
// 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) };
When a pointer is used in an expression, the value of a pointer is an address. When you use the p
command to print the variable p
, you see the value of the pointer p
, which is just a hex number. What you are really interested in is the structure that p
points to.
(gdb) p p $1 (struct proc *)0x80008eb0
When a pointer is dereferenced (e.g., *p
) in an expression, the value of the dereferenced pointer is the entire structure that it points to. The value of *p
is the entire contents of the struct proc
. To see the contents of the struct proc
that p points to, and the value of the struct proc's
member trapframe
, you enter the following commands. The /x
option of p /x
instructs gdb to display the values as hexadecimal numbers.
(gdb) p /x *p $2 = {lock = {locked = 0x0, name = 0x80008178, cpu = 0x0}, state = 0x4, chan = 0x0, killed = 0x0, xstate = 0x0, pid = 0x1, mask = 0x0, parent = 0x0, kstack = 0x3fffffd000, sz = 0x1000, pagetable = 0x87f73000, trapframe = 0x87f74000, context = {ra = 0x800014ba, sp = 0x3fffffde70, s0 = 0x3fffffdea0, s1 = 0x80008eb0, s2 = 0x80008a80, s3 = 0x1, s4 = 0x3fffffded0, s5 = 0x8000ed38, s6 = 0x3, s7 = 0x80019b50, s8 = 0x1, s9 = 0x80019c78, s10 = 0x4, s11 = 0x0}, ofile = {0x0}, cwd = 0x80016fc0, name = {0x69, 0x6e, 0x69, 0x74, 0x63, 0x6f, 0x64, 0x65, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}} (gdb) p /x *(p->trapframe) $3 = {kernel_satp = 0x8000000000087fff, kernel_sp = 0x3fffffe000, kernel_trap = 0x80001d0c, epc = 0x18, kernel_hartid = 0x1, ra = 0x505050505050505, sp = 0x1000, gp = 0x505050505050505, tp = 0x505050505050505, t0 = 0x505050505050505, t1 = 0x505050505050505, t2 = 0x505050505050505, s0 = 0x505050505050505, s1 = 0x505050505050505, a0 = 0x24, a1 = 0x2b, a2 = 0x505050505050505, a3 = 0x505050505050505, a4 = 0x505050505050505, a5 = 0x505050505050505, a6 = 0x505050505050505, a7 = 0x7, s2 = 0x505050505050505, s3 = 0x505050505050505, s4 = 0x505050505050505, s5 = 0x505050505050505, s6 = 0x505050505050505, s7 = 0x505050505050505, s8 = 0x505050505050505, s9 = 0x505050505050505, s10 = 0x505050505050505, s11 = 0x505050505050505, t3 = 0x505050505050505, t4 = 0x505050505050505, t5 = 0x505050505050505, t6 = 0x505050505050505}