GDB
如何启动gdb
- 启动 make CPUs=1 qemu-gdb
- 在另一个终端启动 gdb-multiarch kernel/kernel
- 进入gdb后输入 target remote localhost:26000
GDB 的一些命令
- shell clear # 清屏
- layout src # 显示源码
- layout regs # 显示寄存器
- layout split # 同时显示源码和寄存器
- backtrace # 显示函数调用栈
在XV6 如何添加系统调用
- 在
user/user.h
中添加系统调用函数的定义. 比如:
struct stat;
int fork(void);
int exit(int) __attribute__((noreturn));
int wait(int*);
int pipe(int*);
int write(int, const void*, int);
int read(int, void*, int);
int close(int);
- 在
user/usys.pl
中添加入口, 这个文件会在 make
后生成 user/usys.S
文件, 在该汇编文件中,每个函数就只有三行,将系统调用号通过 li(load imm)
存入 a7 寄存器,之后使用 ecall
进入内核态,最后返回。
sub entry {
my $name = shift;
print ".global $name\n";
print "${name}:\n";
print " li a7, SYS_${name}\n";
print " ecall\n";
print " ret\n";
}
entry("fork");
entry("exit");
- 在
kernel/syscall.h
中定义系统调用号
#define SYS_mkdir 20
#define SYS_close 21
#define SYS_trace 22
- 在
kernel/syscall.c
的 syscalls
函数指针数值中添加对应的函数。
static uint64 (*syscalls[])(void) = {
[SYS_fork] sys_fork,
[SYS_exit] sys_exit,
[SYS_wait] sys_wait,
[SYS_pipe] sys_pipe,
[SYS_read] sys_read,
[SYS_kill] sys_kill,
[SYS_exec] sys_exec,
[SYS_fstat] sys_fstat,
[SYS_chdir] sys_chdir,
[SYS_dup] sys_dup,
[SYS_getpid] sys_getpid,
[SYS_sbrk] sys_sbrk,
[SYS_sleep] sys_sleep,
[SYS_uptime] sys_uptime,
[SYS_open] sys_open,
[SYS_write] sys_write,
[SYS_mknod] sys_mknod,
[SYS_unlink] sys_unlink,
[SYS_link] sys_link,
[SYS_mkdir] sys_mkdir,
[SYS_close] sys_close,
[SYS_trace] sys_trace,
};
- 在
syscall
函数中,先读取 trapframe->a7
获取系统调用号之后,根据系统调用号查找syscalls
数组中的对应的处理函数并调用。
- 获取传入的参数。