【MIT 6.S081】2021, 实验记录(4),Lab: Traps

在学完 Traps 一节课后,了解了在 OS 中,用户态是如何转换到内核态,再转回用户态的。

Task: Backtrace

这个任务目标是实现 backtrace() 函数,它用来打印当前堆栈中的所有函数调用信息。

为了完成这个任务,我们需要遍历函数调用栈中的每个栈帧(frame),并打印每个 frame 中的 Return Address 信息。因此,我们需要看一下函数调用堆栈的结构:

stack 示例

上图展示了一个堆栈结构,堆栈从上向下生长,其中每个 stack frame 中有两个关键字段:

  • Return Address:这个函数的返回地址,也是在 backtrace() 函数中需要打印的信息;
  • To Prev Frame:指向上一个 frame 的一个指针

为了遍历所有 frames,我们需要认识两个关键的寄存器:

  • SP 寄存器:指向当前函数栈的底部并代表了当前栈帧的位置
  • FP 寄存器:它指向当前函数栈帧的顶部

在这里,我们可以借助 FP 的值来遍历所有栈帧,而且我们所需要的两个关键字段都相对于栈帧顶部具有固定的 offset。

根据实验提示,我们现在 kernel/riscv.h 文件中添加一个用于获取 FP 寄存器值的函数:

static inline uint64
r_fp()
{
   
  uint64 x;
  asm volatile("mv %0, s0" : "=r" (x) );
  return x;
}

在 kernel/printf.c 中添加 backtrace() 函数的实现:

void
backtrace()
{
   
  printf("backtrace:\n");
  uint64 fp = r_fp();   // FP 寄存器值
  uint64 base = PGROUNDUP(fp);  // 栈底地址
  while (fp < base) {
     // 向前遍历 frame,直到达到 base
    printf("%p\n", *((uint64*)(fp - 8)));  // 打印 Return Address 字段值
    fp = *((uint64*)(fp - 16));  // prev frame
  }
}

在 kernel/defs.h 添加 backtrace 函数的声明:

void            backtrace(void);

在 sysproc.c 中的 sys_sleep 函数中添加对 backtrace 函数的调用:

uint64
sys_sleep(void)
{
   
  int n;
  uint ticks0;

  if(argint(0, &n) < 0)
    return -1;
  backtrace();
  acquire(&tickslock);
  ticks0 = ticks;
  while(ticks - ticks0 < n){
   
    if(myproc()->killed){
   
      release(&tickslock);
      return -1;
    }
    sleep(&ticks, &tickslock);
  }
  release(&tickslock);
  return 0;
}

这样,就可以在 make qemu 后执行 bttest 来测试:

bttest
按照官网的提示测试后,如果 backtrace() 函数没问题,就可以在 kernel/printf.c 的 panic() 中加入对 backtrace 的函数调用了,这样当程序 panic 时会打印当前的堆栈信息:

void
panic(char *s)
{
   
  pr.locking = 0;
  printf("panic: ");
  printf(s);
  printf("\n");
  backtrace();
  panicked = 1; // freeze uart output from other CPUs
  for(;;)
    ;
}

相关推荐

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-02-01 18:10:01       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-02-01 18:10:01       101 阅读
  3. 在Django里面运行非项目文件

    2024-02-01 18:10:01       82 阅读
  4. Python语言-面向对象

    2024-02-01 18:10:01       91 阅读

热门阅读

  1. 通过 React 来构建界面

    2024-02-01 18:10:01       51 阅读
  2. 白虎汤原方

    2024-02-01 18:10:01       58 阅读
  3. QTimer 指针类型和引用类型使用的区别

    2024-02-01 18:10:01       57 阅读
  4. 2024 高级前端面试题之 Node 「精选篇」

    2024-02-01 18:10:01       63 阅读
  5. c++if else 解释

    2024-02-01 18:10:01       50 阅读
  6. 基于低代码的管理系统模板库的设计与实现

    2024-02-01 18:10:01       55 阅读
  7. Python 构造方法

    2024-02-01 18:10:01       46 阅读