首页 > 其他分享 >【XV6】 system calls

【XV6】 system calls

时间:2024-02-14 19:13:10浏览次数:39  
标签:SYS calls trace kernel system XV6 sys gdb num

代码:https://github.com/JasenChao/xv6-labs.git

使用GDB调试

安装risc-v的GDB

先安装依赖:

sudo apt-get install libncurses5-dev python2 python2-dev texinfo libreadline-dev

再下载源码,可以从清华镜像源下载:

wget https://mirrors.tuna.tsinghua.edu.cn/gnu/gdb/gdb-13.2.tar.xz

解压缩并编译安装:

tar xvf gdb-13.2.tar.xz
cd gdb-13.2/
mkdir build
cd build
../configure --prefix=/usr/local --target=riscv64-unknown-elf --enable-tui=yes
make -j$(nproc)
sudo make install

使用GDB

先用qemu运行xv6,在xv6目录下执行:

make qemu-gdb

此时应该打印一个端口号,例如tcp::26000,记住这个端口号,另起一个终端,运行gdb:

riscv64-unknown-elf-gdb

在GDB中连接这个端口,由于本次实验想在每次syscall中断时断点,所以file kernel/kernel

target remote localhost:26000
file kernel/kernel
b syscall

c让程序从断点处继续执行,输出如下:

(gdb) b syscall
Breakpoint 1 at 0x80002142: file kernel/syscall.c, line 243.
(gdb) c
Continuing.
[Switching to Thread 1.2]

Thread 2 hit Breakpoint 1, syscall () at kernel/syscall.c:243
243     {
(gdb) layout src
(gdb) backtrace

layout 命令将窗口一分为二,显示src,也可以layout asm等。

GDB有一些常用指令:

1.break/b (*地址)/函数名 #设置断点,指令地址可以查看asm文件
#除此之外通常可以使用b *$stvec,在trampoline处设置断点

2.continue/c #运行到断点处然后停下

3.stepi/si #运行单个汇编指令,进入函数

4.n #运行一行c语言代码,不进入函数

5.step/s #运行一行C语言代码,进入函数

6.info/i reg/r #查看32个同一寄存器和PC寄存器的值

7.info/i break/b #查看断点信息

8.info/i frame #打印当前栈帧

9.print/p (/x) 变量/$寄存器 #打印C语言变量值或寄存器的值,/x是将值为打印16进制的值

10.examining/x 地址 #检测内存单元并打印
                #可以使用/x十六进制 /i指令 /c字符格式化打印值
                #而且可以使用/4c打印4个字节单元并输出为字符
11.list 地址  #打印函数的源代码在指定的位置。

12.layout asm/src/split #分别打开汇编代码窗口、源码窗口、split打开汇编和源码窗口
                        #ctrl x + a 可以关闭layout窗口

添加系统调用-trace

题目要求基于已经给出的trace.c实现系统调用跟踪。根据提示按步骤进行。

  • $U/_trace\添加到MakefileUPROGS
  • user/user.h中添加系统调用int trace(int)
  • user/usys.pl中添加stub entry("trace")
  • kernel/syscall.h中添加系统调用编号#define SYS_trace 22
  • kernel/sysproc.c中添加函数sys_trace(),代码如下:
    uint64
    sys_trace(void)
    {
        int n;
        argint(0, &n);
        myproc()->trace_mask = n;
        return 0;
    }
    
  • kernel/syscall.c中添加命令名称数组,便于显示系统调用名,修改syscall函数,代码如下:
    static char syscall_name[23][16] = {"fork", "exit", "wait", "pipe", "read", "kill", "exec", "fstat", "chdir", "dup", "getpid", "sbrk", "sleep", "uptime", "open", "write", "mknod", "unlink", "link", "mkdir", "close", "trace", "sysinfo"};
    
    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 > 0 && (p->trace_mask & (1 << num)))
        {
        printf("%d: syscall %s -> %d\n", p->pid, syscall_name[num - 1], p->trapframe->a0);
        }
    } else {
        printf("%d %s: unknown sys call %d\n",
                p->pid, p->name, num);
        p->trapframe->a0 = -1;
    }
    }
    
  • kernel/syscall.c中还需要增加系统调用的函数指针:
    extern uint64 sys_trace(void);
    
    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,
    };
    
  • 修改kernel/proc.h中的struct proc结构体,增加int trace_mask
  • 修改kernel/proc.c中的fork函数,使得子进程可以继承父进程的trace_mask,增加的代码如下:
    acquire(&np->lock);
    np->trace_mask = p->trace_mask;
    release(&np->lock);
    

Makefile调用perl脚本user/usys.pl,该脚本生成user/usys.S,这是实际的系统调用,它使用RISC-V ecall指令转换到内核。

使用make GRADEFLAGS=trace grade测试代码是否通过。

添加系统调用-sysinfo

题目要求基于已经给出的sysinfotest.c实现系统调用跟踪。根据提示按步骤进行。

  • $U/_sysinfotest\添加到MakefileUPROGS
  • user/user.h中添加系统调用:
    struct sysinfo;
    int sysinfo(struct sysinfo*);
    
  • user/usys.pl中添加stub entry("sysinfo");
  • kernel/syscall.h中添加系统调用编号#define SYS_sysinfo 23
  • kernel/sysproc.c中添加函数sys_sysinfo(),代码如下,free_memory()proc_num()函数待实现:
    #include "sysinfo.h"
    
    uint64
    sys_sysinfo(void)
    {
        struct sysinfo info;
        uint64 addr;
    
        argaddr(0, &addr);
        struct proc* p = myproc();
        info.freemem = free_memory();
        info.nproc = proc_num();
        // 将内核态中的info复制到用户态
        if (copyout(p->pagetable, addr, (char*)&info, sizeof(info)) < 0)
            return -1;
        return 0;
    }
    
  • kernel/syscall.c中增加系统调用的函数指针:
    extern uint64 sys_sysinfo(void);
    
    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,
    [SYS_sysinfo] sys_sysinfo,
    };
    
  • kernel/proc.c中增加proc_num()函数,统计进程数,代码如下:
    int
    proc_num(void)
    {
        int i;
        int n = 0;
        for (i = 0; i < NPROC; i++)
        {
            if (proc[i].state != UNUSED) n++;
        }
        return n;
    }
    
  • kernel/kalloc.c中增加free_memory()函数,统计可用内存,代码如下:
    uint64 
    free_memory(void)
    {
        struct run* p = kmem.freelist;
        uint64 num = 0;
        while (p)
        {
            num ++;
            p = p->next;
        }
        return num * PGSIZE;
    }
    
  • kernel/defs.h中对应的区域增加函数声明,代码如下:
    uint64          free_memory(void);
    int             proc_num(void);
    

使用make GRADEFLAGS=sysinfo grade测试代码是否通过。

题目提示copyout()函数的使用可以参考filestat()函数,这个函数的功能是从内核复制到用户,传入参数依次为当前进程的页表、地址、需要复制内容的起始地址、需要复制的长度。

测试结果

使用make grade测试,结果如下:

== Test trace 32 grep ==
$ make qemu-gdb
trace 32 grep: OK (1.5s)
== Test trace all grep ==
$ make qemu-gdb
trace all grep: OK (1.0s)
== Test trace nothing ==
$ make qemu-gdb
trace nothing: OK (0.9s)
== Test trace children ==
$ make qemu-gdb
trace children: OK (8.3s)
== Test sysinfotest ==
$ make qemu-gdb
sysinfotest: OK (1.1s)

标签:SYS,calls,trace,kernel,system,XV6,sys,gdb,num
From: https://www.cnblogs.com/JasenChao/p/18015446

相关文章

  • 【XV6】 Multithreading
    代码:https://github.com/JasenChao/xv6-labs.git用户级线程切换题目要求完成用户级线程系统,提示程序要在uthread.c和uthread_switch.S中补充完成。用户级线程调度和进程的机制是类似的,因此uthread_switch.S可以复制swtch.S中的内容: .globlthread_switchthread_switch:......
  • 【XV6】 Copy-on-Write Fork for xv6
    代码:https://github.com/JasenChao/xv6-labs.gitCopy-on-WriteFork系统调用fork()会复制一个父进程的用户空间到子进程,一方面如果进程较大,复制需要很长的时间,另一方面复制的内存的大部分会被丢弃,造成浪费。题目要求实现写时复制COW来延迟fork的物理内存复制,子进程只创建了一个......
  • 【XV6】 traps
    代码:https://github.com/JasenChao/xv6-labs.gitbacktrace题目要求实现backtrace来对堆栈上调用发生错误的地方进行跟踪。寄存器s0包含指向当前堆栈帧的指针,那么返回地址就位于帧指针的固定偏移量-8,前一个fp地址的偏移量为-16。在riscv.h文件中增加提示中的代码:staticinline......
  • 【XV6】 file system
    代码:https://github.com/JasenChao/xv6-labs.git支持大文件XV6目前只支持268个blocks大小的文件,一个block(BSIZE)为1024,文件块inode包含12个一级地址和1个二级地址,二级地址指向另一个block,其中存放了256个一级地址,因此一共是268个。题目要求支持大文件(65803个blocks),提示通过三级......
  • 【XV6】 locks
    代码:https://github.com/JasenChao/xv6-labs.git内存分配器单个空闲内存列表可能引起多个CPU的频繁锁争用,题目要求设计内存分配器,让每个CPU维护一个空闲内存列表,不同CPU的分配和释放可以并行执行,但如果一个CPU可用列表为空,而其他CPU可用列表不为空,则这个CPU必须窃取其他CPU的空......
  • 【XV6】 networking
    代码:https://github.com/JasenChao/xv6-labs.gitE1000网络设备驱动题目已经在kernel/e1000.c中给出了E1000的初始化函数和发送接收函数,要求完善发送和接收的功能。其他相关的代码,上层的网络协议在kernel/net.c和kernel/net.h中。PCI总线上搜索网卡的代码在kernel/pci.c中://t......
  • [MIT 6.S081] Lab: Copy-on-Write Fork for xv6
    Lab:Copy-on-WriteForkforxv6在这个实验中,我们要为xv6实现cowfork。Implementcopy-onwrite根据写时复制的方式,我们在复制页面的时候应该采用的是将父级的物理页面映射到子级的页面,因此我们需要修改kernel/vm.c中的uvmcopy,将页面复制修改为映射的方式,同时应当将......
  • [969] Add a spatial reference (a coordinate reference system, CRS) to a GeoDataF
    Toaddaspatialreference(acoordinatereferencesystem,CRS)toaGeoDataFrameinGeoPandas,youcansetthecrsattributeoftheGeoDataFrametothedesiredCRS.Here'showyoucandoit:importgeopandasasgpdfromshapely.geometryimportPoint......
  • Linux Cgroups blkio Subsystem
    前言本文主要会介绍笔者在学习LinuxCgroupsblkioSubsystem时所总结的知识点,其中会涉及到使用方式以及配置方式等方面的相关内容。笔者也会将自己的理解在文中进行阐述,这也算是在和大家交流心得的一个过程。若文中有错误的理解和概念,请大家及时纠正;吸纳大家的建议,对于我来说也......
  • 读论文-基于会话的推荐系统综述(A survey on session-based recommender systems)
    前言今天读的论文是一篇于2021年发表于"ACMComputingSurveys(CSUR)"的论文,文章写到,推荐系统在信息过载时代和数字化经济中非常重要。基于会话的推荐系统(SBRSs)是新的推荐系统范式,不同于其他模型化长期静态用户偏好的推荐系统,SBRSs专注于捕捉短期动态用户偏好。尽管SBRSs已被深......