xv6---Lab4 traps

参考:

Lab: Traps

  • 关于寄存器s0和堆栈

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

RISC-V assembly

Q: 哪些寄存器包含函数的参数?例如,哪个寄存器在main对printf的调用中保存了传参13 ?

A: a2保存13(通过gdb调试可看出寄存器a2的值)

Q:在main的程序集代码中,函数f的调用在哪里?调用g在哪里?(提示:编译器可能内联函数。)

A:查看asm文件,发现没有对f,g的调用,g被内联f函数,f函数被内联到main函数

Q:printf函数的地址在哪里?

A:34:   600080e7            jalr    1536(ra)

    # 630 <printf>可知0x630是printf函数入口

Q:main中,jalr跳转到printf之后,ra的值是多少?

A:ra的值是0x38, 对应的0x34的下一条指令

  当printf执行完成后,会让pc=寄存器ra的值,然后程序会执行main函数中的0x38这行的代码


 

Q: xv6是小端的,如果要实现一样的输出:HE110 World,大端模式下该如何实现?

小端:低地址在前

    0x00000064用字符串打出来,发现解释的方向是64 00 00 00 即r\0\0\0 而不是 \0\0\0r这就是小端

1. 所以如果大端需要输出r ,int c = 0x64000000; 即可输出r.

2. 而对于int的数据,则无论大小端用%d输出的值都一样

Q: printf("x=%d y=%d", 3); 输出结果是什么?

y输出的是寄存器a2的值

Backtrace 

首先

static inline uint64
r_fp()
{
  uint64 x;
  asm volatile("mv %0, s0" : "=r" (x) );
  return x;
} // 返回的是寄存器s0的值

寄存器s0的值代表Frame pointer

  • 栈指针fp:代表当前函数的入口地址
  • fp - 8: 代表返回地址,代表当前栈帧执行结束后,下一行该执行的代码地址
  • fp - 16代表调用当前栈帧的栈帧(比如函数A调用函数B,那么B的fp -16就代表A),所以可通过prev.Frame的地址打印,即可得到调用当前函数的Frame pointer, 在通过addr2line工具即可得到代码执行的情况。
  • stack frame: 函数的调用栈

  • xv6为每一个stack分配4K的页,于是可通fp = r_fp(); 得到当前栈帧,PGROUNDDOWN(fp) and PGROUNDUP(fp) 来得到当前stack的函数调用界限。
  • 根据fp得到Return Address , 即fp - 8 ;

  •  比如调用顺序是:
  1. bttest函数的sleep(1);系统调用
  2. trap.c的usertrap()函数
  3. syscall.c的syscall()函数
  4. sysproc.c的sys_sleep()函数
  5. 调用backtrace()函数: 可通过fp--->得到return adrees,即可向上递归,得到调用栈
void
backtrace(void)
{
  printf("backtrace:\n");
  uint64 fp = r_fp();
  uint64 *frame = (uint64*) fp;

  uint64  up = PGROUNDUP(fp);
  uint64  down = PGROUNDDOWN(fp);
// xv6为每个堆栈分配一个页。大小为4K,
// 通过PGROUNDUP和PGROUNDDOWN可计算出这个页的边界
  while (fp < up && fp > down)
  {
    printf("%p\n", frame[-1]);  // 返回地址
    fp = frame[-2]; // 上一个fp
    frame = (uint64* )fp;
  }
  
}

结果如下:

a123@ubuntu:~/Public/repo/xv6-labs-2020$ make qemu
qemu-system-riscv64 -machine virt -bios none -kernel kernel/kernel -m 128M -smp 3 -nographic -drive file=fs.img,if=none,format=raw,id=x0 -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0

xv6 kernel is booting

hart 2 starting
hart 1 starting
init: starting sh
$ bttest
backtrace:
0x0000000080002d56
0x0000000080002bb8
0x00000000800028a2
$ QEMU: Terminated
a123@ubuntu:~/Public/repo/xv6-labs-2020$ addr2line -e kernel/kernel
0x0000000080002d56
/home/a123/Public/repo/xv6-labs-2020/kernel/sysproc.c:76
0x0000000080002bb8
/home/a123/Public/repo/xv6-labs-2020/kernel/syscall.c:140
0x00000000800028a2
/home/a123/Public/repo/xv6-labs-2020/kernel/trap.c:76
^C
a123@ubuntu:~/Public/repo/xv6-labs-2020$ 

test0: invoke handler

实现参考:Mit6.S081-实验4-Traps_解析Ta的博客-CSDN博客

目标:调用signalarm(n, f)函数,实现间隔n秒,执行一次f函数

  • 首先实现sigalarm和sigalreturn的系统调用,便于alarmtest.c执行系统调用
  • 在sigalarm函数:
  1. 得到当前进程
  2. 在struct proc中添加函数指针handler, 间隔时间,消耗时间。
  3. 在当前进程的表示struct proc中去记下回调函数handler和alarm间隔时间
  • 在中断产生:会进入usertrap()函数,而其中which_dev == 2表示是滴答中断,于是在此中断检查是否时间到了,到了就执行定时回调函数

test1/test2(): resume interrupted code

MIT 6.S081 Lab4: traps_rocketeerLi的博客-CSDN博客_mit 6.s081 traps

目标:在执行signal_alarm函数前后,希望可以保持trapframe不变。

  • 在调用signal_alarm(n,f);设定的f函数前,先保存trapframe
  • 在usertraps中调用完成设定的函数之后,将trapframe设置为保存的trapframe
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值