MIT6.S081 Preparation: GDB, Calling conventions

调试,调用规则,栈

MIT6.S081调试总结

debug开启

在一个窗口运行make qemu-gdb
在另一窗口运行gdb-multiarch,如果要导入其他debubg的可执行文件,如调试find程序,执行file user/_find,然后正常调试(需要将项目目录下的.gdbinit文件add-auto-load-safe-path~/.gdbinit中:add-auto-load-safe-path ~/Project/xv6-labs-2021/.gdbinit)。

一些有用的调试技巧:

分屏

Change the layout of windows.
Usage: layout prev | next | LAYOUT-NAME

List of layout subcommands:

layout asm -- Apply the "asm" layout.
layout next -- Apply the next TUI layout.
layout prev -- Apply the previous TUI layout.
layout regs -- Apply the TUI register layout.
layout split -- Apply the "split" layout.
layout src -- Apply the "src" layout.

分屏后窗口聚焦

focus reg -- 聚焦在reg窗口
focus asm -- 聚焦在asm窗口

显示技巧

set print address on -- 查看地址
set print array on -- 数组显示
set print pretty on -- 结构体内容显示
p *argv -- 显示字符串
p *argv@2 -- 显示一定长度的字符串数组
p *argv@argc -- 显示所有参数数组

info显示信息

info breakpoints(info b) -- Status of specified breakpoints (all user-settable breakpoints if no argument).
info registers(info r) -- List of integer registers and their contents, for selected stack frame.
info frame, info f -- All about the selected stack frame.
i f frame-level -- 查看特定的栈

栈的显示

backtrace -- 显示调用栈
frame number -- Select and print a stack frame.
up n -- Move n frames up the stack; n defaults to 1. For positive numbers n, this advances toward the outermost frame, to higher frame numbers, to frames that have existed longer.
down n -- Move n frames down the stack; n defaults to 1. For positive numbers n, this advances toward the innermost frame, to lower frame numbers, to frames that were created more recently. You may abbreviate down as do.

delete

delete breakpoints -- Delete all or some breakpoints or auto-display expressions.

GDB的内置手册

apropos -- Search for commands matching a REGEXP.

calling convention

RISC-V的calling约定一般是在寄存器间传参,最多有8个整数寄存器(a0-a7)和8个浮点寄存器(fa0-fa7)。

当在整数寄存器中传参时,参数保存在对齐的even-odd寄存器对中,even寄存器存储最低有效位。RV32中,如函数void foo(int, long long)第一个参数传给寄存器a0,第二个参数传给寄存器a2和a3,没有参数传给a1。超过指针字大小两倍的参数通过引用传递。

struct中没有通过参数寄存器传递的部分在栈上传递,栈指针sp指向第一个没有在参数寄存器中传递的参数。

返回值存储在寄存器a0和a1中或者寄存器fa0和fa1中。只有当浮点值是单独的浮点值或者只有一两个浮点数组成的struct结构才可以通过浮点寄存器返回。其他两个指针字大小的返回值用a0和a1返回。

更大的返回值在内存中传递,由调用者分配内存空间,将第一个参数的指针传给被调用者。

栈使函数保持正常运行,正常返回。

 --->Return Address
 |   To Prev.Frame(fp)
 |   Saved Registers
 |   Local Variables
 |   ...
 |   Return Address
 ----To Prev.Frame(fp)
     Saved Registers
     Local Variables
     ...

Return Address,To Prev.Frame(fp),Saved Registers,Local Variables,...为一个stack frame,都是由函数调用生成的。
栈是向下扩展的(高地址到低地址),栈指针的运算通常是减法处理。

函数栈桢包含寄存器,局部变量。如果参数寄存器用完了,额外的参数就会出现在栈上。栈桢大小不同(不同函数局部变量数量不同,使用的寄存器数量不同)。但是返回地址和前一个fp会出现在可以预测的位置,ra寄存器指向返回地址,fp寄存器指向当前栈的顶部,sp寄存器指向当前栈的底部。

原文地址:https://www.cnblogs.com/seaupnice/p/15810694.html