您的位置:首页 > 运维架构 > Linux

如何在Linux中添加一个简单自定义系统调用

2020-04-19 22:33 781 查看

一、思路以及具体任务

思路 完全不知道该干什么==,但是基于在之前简单的练习(也许是复制粘贴)已经大体知道task_struct结构体是Linux内核的进程描述符,用以管理进程,于是决定可以先去task_struct里面寻找一下思路。
先进入浏览下Linux源码的网站(这里不能嫌麻烦,后面迟早是要正式看的): https://elixir.bootlin.com/linux/latest/source.

先选个较低的版本,版本高了函数会更复杂,本来看源码就是个头疼的事,更何况暂时不用细看,只需要知道task_struct中的成员项有什么。

搜索task_struct,进入Defined中的sched.h:

然后就可以开始大致看下其中的成员项有些什么,笔者在浏览过程中最后选定了以下几个成员:

之后去查找这几个成员到底是负责干什么的:
start_time :记录某个文件的创建时间;
stime :记录了某个进程执行时在用户态上耗费的时间;
utime :记录了某个进程执行时在系统态上耗费的时间。
那么现在有东西搞了,可以拿这三个成员项干什么呢?于是最终决定了:
具体任务 用户传入两个参数(pid和flag)用以获取用户想知道的某个进程的创建时间以及在某个态上的执行时间。
参数作用:(pid:想要获取的进程的pid;flag:具体执行的任务选项:此处设置为输入1传出start_time,设置2传出stime,设置3传出utime)。

二、系统调用的构成(知道的可以跳过)

添加一个系统调用必要的几个步骤:
(注:以下步骤均需要取得root权限,即shell窗口中输入“sudo su”,并且需要自己已安装了Linux内核)
*1、*添加一个系统调用号
*2、*声明系统调用服务例程
*3、*具体完善系统调用服务例程
*4、*外部C语言完善并且执行

三、代码解析

以下的文件’linux-5.5.6’是根据自身的版本而选,在这以5.5.6版本为例。
1、添加一个系统调用号 进入路径usr/src/linux-5.5.6/arch/x86/entry/syscalls
,执行sudo vim syscall_64.tbl,在里面合适的地方添加一个系统调用号,注意系统调用号是唯一的,所以不能与已有的重复,格式大概照抄上一个调用号的格式:

在这里选择了337号(337 64 myunixtime __x64_sys_myunixtime),然后esc加**:wq**
2、声明系统调用服务例程进入路径usr/src/linux-5.5.6/arch/x86/include/asm,执行sudo vim syscalls.h,

合适的地方依旧是,添加(asmlinkage long __x64_sys_myunixtime(pid_t pid,int flag);
),然后依然esc加**:wq**
3、具体完善系统调用服务例程进入usr/src/linux-5.5.6/kernel,执行sudo vim sys.c,在最末尾开始编写代码:

其中:
SYSCALL_DEFINE2指的是后面有两个参数,以此类推有n个参数则是SYSCALL_DEFINEn ( 所以输出一个hello,world中的是SYSCALL_DEFINE0,因为没有传参的过程 ;并且SYSCALL_DEFINE类型的函数参数声明中类型和参数名要用逗号分开,至于为什么想了解的可以参考:Linux系统调用之SYSCALL_DEFINE
**②struct task_struct *p;**定义了一个task_struct类型的结构体
③p=pid_task(find_vpid(pid),PIDTYPE_PID);,其中pid_task是结构体类型,用于根据pid和其类型找到对应的task_struct,返回值为pid所对应的结构体类型。其原型是:pid_task(struct pid *pid, enum pid_type type),
而enum pid_type的定义:
enum pid_type
{
PIDTYPE_PID,
PIDTYPE_PGID,
PIDTYPE_SID,
PIDTYPE_MAX
};
并且 p=pid_task(find_vpid(pid),PIDTYPE_PID) 作用和以下代码的作用是相同的:

最后仍然是 esc:wq
最后进入“linux-5.5.6” 文件所在位置开始重新编译内核即:
make -j16(这里的-j16是16核16线程编译,速度快的一) —>sudo make modules_install —>sudo make install

四、运行结果

添加外部C语言:
在桌面打开shell, vim myunixtime.c

#include<unistd.h>
#include<sys/syscall.h>
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>

#define mysyscall 337
int main(){
int pid,flag;
time_t temp;//进一步翻阅源码知道,start_time、utime等的类型是time_t,而time_t又需要进一步翻阅
char str_time[10];
printf("\t\tplease input a pid:\n");
scanf("%d",&pid);
printf("\t\tplease input a number:\n\t\t1.show crate"
"time;\n\t\t2.show time spent in user mode;\n\t\t3.show time"
" spent in system mod\n");
scanf("%d",&flag);
temp=syscall(mysyscall,pid,flag);
printf("%ld",temp);//long int型,用%ld输出
return 0;
}

保存关闭
然后shell输入:

gcc myunixtime.c

此处没有命名,则自动生成一个"a.out"的文件。
紧接着输入
./a.out
开始查询,输入pid值和flag值(注:pid值要有对应的文件,否则会报错)
最后结果:

为何会显示这个奇怪的数字?原因是因为在unix中,时间是以时间戳的形式存储,想要知道代表什么,将数字复制下来,进入:
Unix时间戳转换工具

这就是该进程创建的时间。

五、完善(不通过在线转换直接获得时间)

这就需要先了解这个时间戳是怎么来的了:Unix时间戳是一种时间表示方式,定义为从1970年01月01日00时00分00秒起至现在的总秒数
也就是说我们只要再写个函数,可以将这个数字加上1970年01月01日00时00分00秒,就可以得到现在的时间。
注意 :localtime返回的年为什么要加上1900,月为什么要加1???---->因为tm_year 从1900年计算,所以要加1900,月tm_mon,从0计算,所以要加1。
完整的C语言代码

#include<unistd.h>
#include<sys/syscall.h>
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>

#define mysyscall 337

//传入时间戳,打印出对应的时间
char *Time2String(const time_t timep){
struct tm* tm;
time_t tempTime = timep;
char *bars = (char *)"-",*colon = (char *)":",
*space = (char *)" ";
tm = localtime(&tempTime);
tm->tm_year += 1900;
tm->tm_mon += 1;
printf("%04d%s%02d%s%02d%s%02d%s%02d%s%02d\n", tm->tm_year,
bars, tm->tm_mon, bars, tm->tm_mday, space, tm->tm_hour,
colon, tm->tm_min, colon, tm->tm_sec);
return 0;
}

int main(){
int pid,flag;
time_t temp;
char str_time[10];
printf("\t\tplease input a pid:\n");
scanf("%d",&pid);
printf("\t\tplease input a number:\n\t\t1.show crate time;\n\t\t2.show time spent in user mode;\n\t\t3.show time spent in system mod\n");
scanf("%d",&flag);
temp=syscall(mysyscall,pid,flag);
Time2String(temp);
return 0;
}

退出保存,继续上面的测试步骤:

成功了!

  • 点赞
  • 收藏
  • 分享
  • 文章举报
新手工作人员 发布了20 篇原创文章 · 获赞 1 · 访问量 692 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: