Skip to content

Backtrace(moderate)

在kernel/defs.h中添加backtrace的原型

diff --git a/kernel/defs.h b/kernel/defs.h
index 4b9bbc0..137c786 100644
--- a/kernel/defs.h
+++ b/kernel/defs.h
@@ -80,6 +80,7 @@ int             pipewrite(struct pipe*, uint64, int);
 void            printf(char*, ...);
 void            panic(char*) __attribute__((noreturn));
 void            printfinit(void);
void            backtrace(void);
 
 // proc.c
 int             cpuid(void);

那样就能在sys_sleep中引用backtrace

diff --git a/kernel/sysproc.c b/kernel/sysproc.c
index e8bcda9..fd19d2a 100644
--- a/kernel/sysproc.c
+++ b/kernel/sysproc.c
@@ -70,6 +70,7 @@ sys_sleep(void)
     sleep(&ticks, &tickslock);
   }
   release(&tickslock);
  backtrace();
   return 0;
 }

将下面的函数添加到kernel/riscv.h

GCC编译器将当前正在执行的函数的帧指针保存在s0寄存器

diff --git a/kernel/riscv.h b/kernel/riscv.h
index 0aec003..7a443e9 100644
--- a/kernel/riscv.h
+++ b/kernel/riscv.h
@@ -311,6 +311,14 @@ r_ra()
   return x;
 }
 
static inline uint64
r_fp()
{
  uint64 x;
  asm volatile("mv %0, s0" : "=r" (x) );
  return x;
}

 // flush the TLB.
 static inline void
 sfence_vma()

后续在backtrace中调用此函数来读取当前的帧指针。这个函数使用内联汇编来读取s0

打印返回地址和回溯上一个栈帧

pic

https://pdos.csail.mit.edu/6.828/2020/lec/l-riscv-slides.pdf

返回地址位于栈帧帧指针的固定偏移(-8)位置,并且保存的帧指针位于帧指针的固定偏移(-16)位置

一旦backtrace能够运行,就在kernel/printf.c的panic中调用它,就可以在panic发生时看到内核的backtrace

diff --git a/kernel/printf.c b/kernel/printf.c
index e1347de..7d7900c 100644
--- a/kernel/printf.c
+++ b/kernel/printf.c
@@ -121,6 +121,7 @@ panic(char *s)
   printf("panic: ");
   printf(s);
   printf("\n");
  backtrace();
   panicked = 1; // freeze uart output from other CPUs
   for(;;)
     ;
@@ -132,3 +133,16 @@ printfinit(void)
   initlock(&pr.lock, "pr");
   pr.locking = 1;
 }

void
backtrace(void)
{
  uint64 fp = r_fp();
  uint64 top = PGROUNDUP(fp);
  uint64 bottom = PGROUNDDOWN(fp);

  while(fp < top && fp > bottom){
    printf("%p\n", *((uint64 *) (fp - 8)));
    fp = *((uint64 *) (fp - 16));
  }
}
\ No newline at end of file

结果

bash
xv6 kernel is booting

hart 2 starting
hart 1 starting
init: starting sh
$ bttest
0x0000000080002dd6
0x0000000080002c32
0x000000008000291c
$ QEMU: Terminated
eason@eason-VMware-Virtual-Platform:~/work/xv6-labs-2020$ addr2line -e kernel/kernel
0x0000000080002dd6
/home/eason/work/xv6-labs-2020/kernel/sysproc.c:74
0x0000000080002c32
/home/eason/work/xv6-labs-2020/kernel/syscall.c:140 (discriminator 1)
0x000000008000291c
/home/eason/work/xv6-labs-2020/kernel/trap.c:76