syscall
分支学习使用 gdb
调试
SYS_read
struct proc {
// ....
char name[16]; // Process name (debugging)
uint64 trace_mask; // 新增的记录当前进程的 trace 掩码
};
int
fork(void)
{
// ...其他代码
np->sz = p->sz;
np->trace_mask = p->trace_mask; // 子进程创建的时候拷贝父进程的trace mask
}
UPROGS=\
//其他代码
$U/_trace\
struct stat;
// system calls
//其他代码
int trace(int);
//...
#!/usr/bin/perl -w
// 其他代码
entry("trace");
// ...
#define SYS_trace 22
// ...
// sys call name
static
char* syscalls_name[] = {
[SYS_fork] = "syscall fork",
[SYS_exit] = "syscall exit",
[SYS_wait] = "syscall wait",
[SYS_pipe] = "syscall pipe",
[SYS_read] = "syscall read",
[SYS_kill] = "syscall kill",
[SYS_exec] = "syscall exec",
[SYS_fstat] = "syscall fstat",
[SYS_chdir] = "syscall chdir",
[SYS_dup] = "syscall dup",
[SYS_getpid] = "syscall getpid",
[SYS_sbrk] = "syscall sbrk",
[SYS_sleep] = "syscall sleep",
[SYS_uptime] = "syscall uptime",
[SYS_open] = "syscall open",
[SYS_write] = "syscall write",
[SYS_mknod] = "syscall mknod",
[SYS_unlink] = "syscall unlink",
[SYS_link] = "syscall link",
[SYS_mkdir] = "syscall mkdir",
[SYS_close] = "syscall close",
[SYS_trace] = "syscall trace",
};
// ...
// 定义系统调用处理函数
extern uint64 sys_trace(void);
static uint64 (*syscalls[])(void) = {
[SYS_fork] sys_fork,
// ....
// 定义系统调用实际处理函数
[SYS_trace] sys_trace,
};
void
syscall(void)
{
int num;
struct proc *p = myproc();
num = p->trapframe->a7;
if(num > 0 && num < NELEM(syscalls) && syscalls[num]) {
// Use num to lookup the system call function for num, call it,
// and store its return value in p->trapframe->a0
p->trapframe->a0 = syscalls[num]();
// 此处在每个进程的系统调用返回时,判断当前系统调用是否在该进程中被使能
// 如果使能则进行打印
if(p->trace_mask & num){
printf("xxx:%s\n", syscalls_name[num]);
}
} else {
printf("%d %s: unknown sys call %d\n",
p->pid, p->name, num);
p->trapframe->a0 = -1;
}
}
//实际系统调用函数实现,逻辑很简单,设置当前进程的trace mask
uint64
sys_trace(void){
//参考上面的系统调用函数实现,获取参数
int mask;
argint(0, &mask);
myproc()->trace_mask = mask;
return 0;
}
int sysinfo(struct sysinfo *)
函数之前,先预先声明结构体: struct sysinfo;
(struct sysinfo
在kernel/sysinfo.h
中定义)sys_fstat()
(kernel/sysfile.c
) 和 filestat()
(kernel/file.c
) 学习从内核态将 struct sysinfo
拷贝到用户态 (用户态传入一个地址,内核态通过 copyout
函数拷贝到用户态地址)kernel/kalloc.c
中添加一个统计free内存使用量的函数kernel/proc.c
中添加一个统计进程数目的函数sys_sysinfo
接收一个地址参数,然后调用统计内存的函数和统计进程数量的函数,最后使用 copy_out 拷贝到用户态$U/_sysinfotest\
struct stat;
struct sysinfo; //添加sysinfo的预声明
// system calls
// ...
int trace(int);
int uptime(void);
int sysinfo(struct sysinfo *); //声明用户态系统调用API
entry("sysinfo");
#define SYS_sysinfo 23
static
char* syscalls_name[] = {
// ....
[SYS_trace] = "syscall trace",
[SYS_sysinfo] = "syscall sysinfo",
};
// ....
extern uint64 sys_sysinfo(void);
static uint64 (*syscalls[])(void) = {
// ...
[SYS_trace] sys_trace,
[SYS_sysinfo] sys_sysinfo,
};
#include "sysinfo.h"
// ....其他代码
uint64
sys_sysinfo(void){
uint64 addr; // user pointer to struct sysinfo
struct sysinfo sysinfo;
argaddr(0, &addr);
sysinfo.freemem = kfree_mem_get();
sysinfo.nproc = get_proc_num();
if(copyout(myproc()->pagetable, addr, (char *)&sysinfo, sizeof(sysinfo)) < 0){
return -1;
}
return 0;
}
// proc.c
//....proc.c 中其他函数
uint64 get_proc_num(void); //获取进程数目
// kalloc.c
void* kalloc(void);
void kfree(void *);
void kinit(void);
uint64 kfree_mem_get(void); //获取空闲内存
uint64 get_proc_num(void){
uint64 num = 0;
struct proc* p;
for(p = proc; p < &proc[NPROC]; p++) {
if(p->state == UNUSED) {
continue;
} else {
num++;
}
}
return num;
}
uint64 kfree_mem_get(void){
uint64 free = 0;
struct run *r = kmem.freelist;
acquire(&kmem.lock);
while(r){
free += PGSIZE;
r = r->next;
}
release(&kmem.lock);
return free;
}