xv6:labs2 syscall
lab2
1、lab2的内容总结:关于系统调用整个跟踪过程:
使用系统调用时,用户态会通过软中断(trap,陷阱)进入内核中,由trap识别中断来自系统调用,然后调用syscall函数,
跟踪过程:
打开gdb:

跟踪用户态trace执行过程:

首先执行以下两条指令,为trace的main函数打上断点
file user/_trace
b main
三次c之后成功进入trace的main函数

接下来单步运行到exec语句,这里有点问题,s跳入函数时只能跳入atoi,而trace没有反应。所以trace(atoi(argv[1]))中的trace作用是什么?

s跳入exec函数,会进入usys.S文件:

si单步执行,然后打印出a7的值,其实就是exec的系统调用索引(该索引在syscall.h和syscall.c中规定),所以系统调用号被存储在了a7中,后面进入内核态syscall.c会读出a7的内容并调用系统调用函数:

再次执行si,ecall之后发现是进不去的,根据文档描述,ecall之后会进入内核态,首先跳转到trampoline.S文件的usevec函数:
.globl uservec
uservec:
#
# trap.c sets stvec to point here, so
# traps from user space start here,
# in supervisor mode, but with a
# user page table.
#
# sscratch points to where the process's p->trapframe is
# mapped into user space, at TRAPFRAME.
#
# swap a0 and sscratch
# so that a0 is TRAPFRAME
csrrw a0, sscratch, a0
# save the user registers in TRAPFRAME
sd ra, 40(a0)
sd sp, 48(a0)
sd gp, 56(a0)
sd tp, 64(a0)
sd t0, 72(a0)
sd t1, 80(a0)
sd t2, 88(a0)
sd s0, 96(a0)
sd s1, 104(a0)
sd a1, 120(a0)
sd a2, 128(a0)
sd a3, 136(a0)
sd a4, 144(a0)
sd a5, 152(a0)
sd a6, 160(a0)
sd a7, 168(a0)
sd s2, 176(a0)
sd s3, 184(a0)
sd s4, 192(a0)
sd s5, 200(a0)
sd s6, 208(a0)
sd s7, 216(a0)
sd s8, 224(a0)
sd s9, 232(a0)
sd s10, 240(a0)
sd s11, 248(a0)
sd t3, 256(a0)
sd t4, 264(a0)
sd t5, 272(a0)
sd t6, 280(a0)
# save the user a0 in p->trapframe->a0
csrr t0, sscratch
sd t0, 112(a0)
# restore kernel stack pointer from p->trapframe->kernel_sp
ld sp, 8(a0)
# make tp hold the current hartid, from p->trapframe->kernel_hartid
ld tp, 32(a0)
# load the address of usertrap(), p->trapframe->kernel_trap
ld t0, 16(a0)
# restore kernel page table from p->trapframe->kernel_satp
ld t1, 0(a0)
csrw satp, t1
sfence.vma zero, zero
# a0 is no longer valid, since the kernel page
# table does not specially map p->tf.
# jump to usertrap(), which does not return
jr t0
userevec函数保存了用户寄存器,执行一些列操作(加载内核栈顶指针巴拉巴拉,不是很懂)。然后jump到usertrap()函数中,通过trap进入内核态。因为ecall之后不知道为什么进不去内核,所以接下来跟踪内核态重开gdb。
3、跟踪内核态sys_trace:
进入内核态后首先会进入usertrap函数,所以先在usertrap函数达断点
b kernel/trap.c:usertrap
之后一直按c执行,内核加载完毕,输入指令trace 32 echo,执行后会进入usertrap函数
单步n执行到syscall(),usertrap会进入系统调用,不过刚开始的系统调用是shell产生的系统调用,然后才是trace

可以在syscall的166行处打个断点,每次产生系统调用的时候打印num(p num),查看系统调用编号,trace的编号为22 。

在syscall函数中其实可以发现,系统调用编号num存在 p->trapfram->a7,通过函数指针数组(syscalls)以及传入的数组索引(num),操作系统会执行对应的系统调用,系统调用的返回值存入 p->trapfram->a0。
接下来可以在b sysproc.c:sys_trace ,在sys_trace处打一个断点后按c进入,也可以直接单步执行到168行,按s步入sys_trace函数。

执行完syscall函数后,会回到usertrap函数中,执行usertrapret()函数,该函数的作用在于返回用户态:

trace系统调用到此结束,接下来trace会根据传入的参数32 echo执行exec(echo)系统调用。
2、trace
syscall.c
void syscall(void)
{
int num;
struct proc *p = myproc();
num = p->trapframe->a7;
if (num > 0 && num < NELEM(syscalls) && syscalls[num])
{
p->trapframe->a0 = syscalls[num](); // 调用syscalls[num], 返回值存入a0
// printf("num :%d , syscall mask :%d syscall&num :%d\n", num, p->syscall_mask, p->syscall_mask & num);
if (p->syscall_mask > 0 && (p->syscall_mask & (1 << num))) // trace here
{
printf("%d: syscall %s -> %d\n", p->pid, syscall_name[num], p->trapframe->a0);
}
}
else
{
printf("%d %s: unknown sys call %d\n", p->pid, p->name, num);
p->trapframe->a0 = -1;
}
}
sysproc.c
// sys_trace implement here.
uint64
sys_trace(void)
{
// acquire(&tickslock);
argint(0, &myproc()->syscall_mask); // for trace, get syscall_mask
// printf("%d\n",myproc()->syscall_mask);
// release(&tickslock);
return 0;
}
3、sysinfo
kalloc.c
uint64 FreeMem = 0; //labs 2 sysinfo
uint64
getFreeMem() //labs2 sysinfo
{
return FreeMem * 4096;
}
void kfree(void *pa)
{
struct run *r;
if (((uint64)pa % PGSIZE) != 0 || (char *)pa < end || (uint64)pa >= PHYSTOP)
panic("kfree");
// Fill with junk to catch dangling refs.
memset(pa, 1, PGSIZE);
r = (struct run *)pa;
acquire(&kmem.lock);
r->next = kmem.freelist;
kmem.freelist = r;
FreeMem++; // lab2 here
release(&kmem.lock);
}
void *
kalloc(void)
{
struct run *r;
acquire(&kmem.lock);
r = kmem.freelist;
if (r)
{
kmem.freelist = r->next;
FreeMem--; // lab2 here
}
release(&kmem.lock);
if (r)
memset((char *)r, 5, PGSIZE); // fill with junk
return (void *)r;
}
proc.c
uint64 procs = 0; // lab2 sysinfo
// labs 2 sysinfo
uint64
getProcs()
{
return procs;
}
//这个函数是本来就有的,但是需要对allocproc时,进行procs++;
static struct proc *
allocproc(void)
{
struct proc *p;
for (p = proc; p < &proc[NPROC]; p++)
{
acquire(&p->lock);
if (p->state == UNUSED)
{
goto found;
}
else
{
release(&p->lock);
}
}
return 0;
found:
p->pid = allocpid();
// Allocate a trapframe page.
if ((p->trapframe = (struct trapframe *)kalloc()) == 0)
{
release(&p->lock);
return 0;
}
procs++; // labs2 here
// printf("procs :%d\n", getProcs());
// An empty user page table.
p->pagetable = proc_pagetable(p);
if (p->pagetable == 0)
{
freeproc(p);
release(&p->lock);
return 0;
}
//freeproc时,对procs--;
static void
freeproc(struct proc *p)
{
if (p->trapframe)
kfree((void *)p->trapframe);
p->trapframe = 0;
if (p->pagetable)
proc_freepagetable(p->pagetable, p->sz);
p->pagetable = 0;
p->sz = 0;
p->pid = 0;
p->parent = 0;
p->name[0] = 0;
p->chan = 0;
p->killed = 0;
p->xstate = 0;
p->state = UNUSED;
procs--; // labs2 here
// printf("procs :%d\n", getProcs());
}
sysproc.c
extern uint64 getProcs();
extern uint64 getFreeMem();
//`sysinfo`需要将一个`struct sysinfo`复制回用户空间
uint64
sys_sysinfo(void)
{
struct sysinfo
{
uint64 freemem;
uint64 procs;
} sysinfo;
sysinfo.freemem = getFreeMem();
sysinfo.procs = getProcs();
uint64 addr;
if (argaddr(0, &addr) < 0){ //获取参数(一个虚地址,也就是用户空间的sysinfo的地址)
return -1;
}
// copyout:将sysinfo指向的sizeof(sysinfo)大小的内存存到addr所指内存中
if(copyout(myproc()->pagetable, addr, (char *)&sysinfo, sizeof(sysinfo))<0){
return -1;
};
// printf("procs :%d\n", getProcs());
// printf("freemem :%d\n", getFreeMem());
return 0;
}
xv6:labs2 syscall的更多相关文章
- Linux中应用程序如何使用系统调用syscall
最近在做Android,其中一个任务是写一个能在Linux命令行运行的测试AP,运行这个AP就能关闭设备电源,即Power Off. 在 Linux内核中已经找到了关闭电源的函数kernel_powe ...
- gdb 调试 ncurses 全过程:
转载地址: http://blog.jobbole.com/107759/ gdb 调试 ncurses 全过程: 发现网上的“gdb 示例”只有命令而没有对应的输出,我有点不满意.gdb 是 GNU ...
- perl学习之:函数总结
一.进程处理函数 1.进程启动函数 函数名 eval 调用语法 eval(string) 解说 将string看作Perl语句执行.正确执行后,系统变量$@为空串,如果有错误,$@中为错误信息. 例子 ...
- Golang源码学习:调度逻辑(四)系统调用
Linux系统调用 概念:系统调用为用户态进程提供了硬件的抽象接口.并且是用户空间访问内核的唯一手段,除异常和陷入外,它们是内核唯一的合法入口.保证系统的安全和稳定. 调用号:在Linux中,每个系统 ...
- 攻防世界pwn题:Recho
0x00:查看文件信息 一个64位二进制文件,canary和PIE保护机制没开. 0x01:用IDA进行静态分析 分析:主程序部分是一个while循环,判断条件是read返回值大于0则循环.函数ato ...
- 编译可在Android上运行的qemu user mode
前言 本文在Ubuntu 64位系统上对qemu项目进行交叉编译,并且只编译与qemu user mode有关的代码. 下文中的”NDK”若无特殊说明均指”Android NDK”. 下文中”$NDK ...
- 调试多线程 & 查死锁的bug & gcore命令 & gdb对多线程的调试 & gcore & pstack & 调试常用命令
gdb thread apply all bt 如果你发现有那么几个栈停在 pthread_wait 或者类似调用上,大致就可以得出结论:就是它们几个儿女情长,耽误了整个进程. 注意gdb的版本要高于 ...
- 关于Linux系统调用,内核函数【转】
转自:http://blog.csdn.net/ubuntulover/article/details/5988220 早上听人说到某个程序的一部分是内核态,另一部分是用户态,需要怎么怎么.当时突然想 ...
- Arm Linux系统调用流程详细解析
Linux系统通过向内核发出系统调用(system call)实现了用户态进程和硬件设备之间的大部分接口. 系统调用是操作系统提供的服务,用户程序通过各种系统调用,来引用内核提供的各种服务,系统调用的 ...
- perl5 附录一 函数集(未定稿)
附录一 函数集(未定稿) by flamephoenix 一.进程处理函数 1.进程启动函数 2.进程终止函数 3.进程控制函数 4.其它控制函数二.数学函数三.字符串处理函数四.标量转换函数 ...
随机推荐
- 手工搭建并配置apache,php,mysql环境服务器
1,安装apache2.4: 从apache官网中下载windows版本的apache二进制文件,解压 打开apache目录中的bin目录,在其中打开cmd窗口,使用命令: httpd -k inst ...
- UI自动化执行过程中,隐藏浏览器页面
在执行UI自动化的过程中,浏览器总是会弹出,如果自动化环境是在个人办公笔记本,在工作过程中会影响正常办公.故需要将UI自动化执行时的浏览器隐藏. 代码实现如下: from selenium impor ...
- Gin中间件开发
Gin是一个用Go语言编写的Web框架,它提供了一种简单的方式来创建HTTP路由和处理HTTP请求.中间件是Gin框架中的一个重要概念,它可以用来处理HTTP请求和响应,或者在处理请求之前和之后执行一 ...
- 《CTFshow-Web入门》01. Web 1~10
@ 目录 web1 题解 web2 题解 web3 题解 web4 题解 web5 题解 原理 web6 题解 原理 web7 题解 web8 题解 web9 题解 原理 web10 题解 ctf - ...
- 面霸的自我修养:volatile专题
王有志,一个分享硬核Java技术的互金摸鱼侠 加入Java人的提桶跑路群:共同富裕的Java人 今天是<面霸的自我修养>第4篇文章,我们一起来看看面试中会问到哪些关于volatile的问题 ...
- iframe子窗口调用父窗口方法
//一个iframe页面调用另一个iframe页面的方法self.parent.frames["sort_bottom"].mapp($("#id").val( ...
- 使用HTML一键打包APK工具打包KRPANO全景项目
"HMTL一键打包APK工具"可以把本地HTML项目或者网站打包为一个安卓应用APK文件,无需编写任何代码,支持在安卓设备上安装运行. 打包工具群:429338543 下载地址: ...
- 【解惑】孜孜不倦,用足球赛程详解c#中的yield return用法
在一个知名企业赞助的足球联赛中,有256支球队参赛.为了确保比赛的顺利进行,企业指派了小悦负责熬夜加班制定每一个球队的赛程.尽管她对足球的了解并不多,但是她对待工作的认真态度却让人钦佩. 在小悦的努力 ...
- antd/fusion表格增加圈选复制功能
背景介绍 我们存在着大量在PC页面通过表格看数据业务场景,表格又分为两种,一种是 antd / fusion 这种基于 dom 元素的表格,另一种是通过 canvas 绘制的类似 excel 的表格. ...
- 深入理解 Skywalking Agent
概述 Agent 功能介绍 + 整体结构 + 设计 插件机制详解 Trace Segment Span 详解 异步 Trace 详解 如何正确地编写插件并防止内存泄漏 扩展:如何基于 Skywalki ...