`
字符串
  • 浏览: 36284 次
文章分类
社区版块
存档分类
最新评论

Syscall系统调用Linux内核跟踪

 
阅读更多
在Linux的用户空间,我们经常会调用系统调用,下面我们跟踪一下read系统调用,使用的Linux内核版本为Linux2.6.37。不同的Linux版本其中的实现略有不同。
在一些应用中我们可以看到下面的一些定义:
#define real_read(fd, buf, count ) (syscall(SYS_read, (fd), (buf), (count)))
其实真正调用的还是系统函数syscall(SYS_read),也就是sys_read()函数中,在Linux2.6.37中的利用几个宏定义实现。
Linux 系统调用(SCI,system call interface)的实现机制实际上是一个多路汇聚以及分解的过程,该汇聚点就是 0x80 中断这个入口点(X86 系统结构)。也就是说,所有系统调用都从用户空间中汇聚到 0x80 中断点,同时保存具体的系统调用号。当 0x80 中断处理程序运行时,将根据系统调用号对不同的系统调用分别处理(调用不同的内核函数处理)。
引起系统调用的两种途径
(1)int $0×80 , 老式linux内核版本中引起系统调用的唯一方式
(2)sysenter汇编指令
在Linux内核中使用下面的宏进行系统调用
SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
{
    struct file *file;
    ssize_t ret = -EBADF;
    int fput_needed;

    file = fget_light(fd, &fput_needed);
    if (file) {
        loff_t pos = file_pos_read(file);
        ret = vfs_read(file, buf, count, &pos);
        file_pos_write(file, pos);
        fput_light(file, fput_needed);
    }

    return ret;
}
其中SYSCALL_DEFINE3的宏定义如下:
#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)
##的意思就是宏中的字符直接替换,
如果name = read,那么在宏中__NR_##name就替换成了__NR_read了。 __NR_##name是系统调用号,##指的是两次宏展开.即用实际的系统调用名字代替"name",然后再把__NR_...展开.如name == ioctl,则为__NR_ioctl。

#ifdef CONFIG_FTRACE_SYSCALLS
#define SYSCALL_DEFINEx(x, sname, ...)                \
    static const char *types_##sname[] = {            \
        __SC_STR_TDECL##x(__VA_ARGS__)            \
    };                            \
    static const char *args_##sname[] = {            \
        __SC_STR_ADECL##x(__VA_ARGS__)            \
    };                            \
    SYSCALL_METADATA(sname, x);                \
    __SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
#else
#define SYSCALL_DEFINEx(x, sname, ...)                \
    __SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
#endif
不管是否定义CONFIG_FTRACE_SYSCALLS宏,最终都会执行 下面的这个宏定义:
__SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS

#define SYSCALL_DEFINE(name) static inline long SYSC_##name

#define __SYSCALL_DEFINEx(x, name, ...)                    \
    asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__));        \
    static inline long SYSC##name(__SC_DECL##x(__VA_ARGS__));    \
    asmlinkage long SyS##name(__SC_LONG##x(__VA_ARGS__))        \
    {                                \
        __SC_TEST##x(__VA_ARGS__);                \
        return (long) SYSC##name(__SC_CAST##x(__VA_ARGS__));    \
    }                                \
    SYSCALL_ALIAS(sys##name, SyS##name);                \
    static inline long SYSC##name(__SC_DECL##x(__VA_ARGS__))

#else /* CONFIG_HAVE_SYSCALL_WRAPPERS */

#define SYSCALL_DEFINE(name) asmlinkage long sys_##name
#define __SYSCALL_DEFINEx(x, name, ...)                    \
    asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__))

#endif /* CONFIG_HAVE_SYSCALL_WRAPPERS */
最终会调用下面类型的宏定义:
asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__))
也就是我们前面提到的sys_read()系统函数。
asmlinkage通知编译器仅从栈中提取该函数的参数。所有的系统调用都需要这个限定词!这和我们上一篇文章quagga中提到的宏定义,有异曲同工之妙。
也就是宏定义中的下面代码:
struct file *file;
    ssize_t ret = -EBADF;
    int fput_needed;

    file = fget_light(fd, &fput_needed);
    if (file) {
        loff_t pos = file_pos_read(file);
        ret = vfs_read(file, buf, count, &pos);
        file_pos_write(file, pos);
        fput_light(file, fput_needed);
    }

    return ret;
代码解析:
fget_light() :根据 fd 指定的索引,从当前进程描述符中取出相应的 file 对象(见图3)。
如果没找到指定的 file 对象,则返回错误
如果找到了指定的 file 对象:
调用 file_pos_read() 函数取出此次读写文件的当前位置。
调用 vfs_read() 执行文件读取操作,而这个函数最终调用 file->f_op.read() 指向的函数,代码如下:
if (file->f_op->read)
ret = file->f_op->read(file, buf, count, pos);
调用 file_pos_write() 更新文件的当前读写位置。
调用 fput_light() 更新文件的引用计数。
最后返回读取数据的字节数。
到此,虚拟文件系统层所做的处理就完成了,控制权交给了 ext2 文件系统层。
分享到:
评论

相关推荐

    Linux 内核中listen系统调用

    这段代码是 Linux 内核中负责...接下来,使用 SYSCALL_DEFINE2(listen, int, fd, int, backlog) 宏定义 syscall 接口 listen,这个接口让用户空间的程序可以调用内核中定义的 __sys_listen 函数进行 socket 监听设置。

    ARM32 架构增加一个系统调用.pdf

    系统调用在内核中都是必不可少的一部分,ARM 结构对系统调用的支持相比其他 架构有很多改进,其化繁为简,为开发者提供了一个便捷的方法添加一个新的系统 调用。这里涉及 ARM 架构的系统调用表 syscall.tbl, 以及 ...

    基于Linux内核的键盘模拟实现

    由于Linux内核作为系统最深层次的核心,因此外部的开发人员并不能直接对内核进行操作。然而在一些应用程序的开发过程中,又不得不使用内核的某些功能,因此就提供了一些外部接口供开发人员直接与底层内核打交道。 ...

    Linux内核压栈操作对比(v4.1.15 vs v3.10).jpg

    Linux内核压栈操作对比(v4.1.15 vs v3.10):对比Linux两个版本的内核压栈操作的差异,早期3.10由于AMD syscall和Intel sysenter指令的差异导致内核压栈操作要屏蔽掉两个公司系统调用指令的差异

    vltrace:使用eBPF linux内核功能以快速方式跟踪系统调用的工具

    vltrace是一个系统调用跟踪工具,它利用eBPF(Linux内核的有效跟踪功能)。执照请参阅文件以获取有关此工具如何获得的信息。依赖vltrace取决于库。 libbcc的安装指南可以在找到。系统要求内核v4.7或更高版本 安装的...

    深入理解LINUX内核(中文第三版)第十章 系统调用

    俺花了N个大洋买来的,现在免费提供给大家

    SyscallAdder:Linux内核模块,可用于以更加用户友好的方式添加自定义系统调用

    Linux内核模块,可用于以更加用户友好的方式添加自定义系统调用。 该模块将添加2个系统调用: syscall_adder((void *)custom_syscall_addr,char * syscall_name,int num_parameters) :将检查syscall表上...

    linux内核 0.11版本源码 带中文注释

    static inline _syscall0 (int, sync) // int sync()系统调用:更新文件系统。 #include <linux/tty.h> // tty 头文件,定义了有关tty_io,串行通信方面的参数、常数。 #include <linux/sched.h> // 调度程序...

    嵌入式系统/ARM技术中的ARM linux系统调用的实现原理

    作者:刘洪涛,华清远见嵌入式培训中心讲师。... at91rm9200处理器对应的linux2.4.19内核系统调用对应的软中断定义如下:  #if defined(__thumb__) //thumb模式  #define __syscall(name) \  "push {r7}\n\t

    linux操作系统课程设计完善代码

    大学操作系统课程设计linux代码完善,(30%,125行)实现文件系统的系统调用(creat,open,read,write,close和unlink,在syscall.h文件中列出)。你可以在UserProcess.java中看到处理halt系统调用的代码;最好把...

    strace:linux syscall跟踪器-开源

    strace是Linux的诊断,调试和说明性用户空间跟踪程序。 它用于监视和篡改用户空间进程与Linux内核之间的交互,其中包括系统调用,信号传递和进程状态更改。 内核功能ptrace使strace的操作成为可能。

    kernel-module-syscall:拦截系统调用

    系统调用拦截 在Linux上使用可加载的内核模块拦截系统调用的概念证明。 测试于:Linux debian 4.19.0-14-amd64#1 SMP Debian 4.19.171-2(2021-01-30)x86_64 GNU / Linux

    Android系统调用记录器:Android系统调用记录器

    测试环境操作系统:Kali Linux(我个人建议您像我一样使用Kali Linux,因为它看起来比Ubuntu还不错) Android Linux内核版本:3.18.70-g1292056优势与仿真器(独角兽)相比,在呼吸设备上捕获您喜欢的系统调用,降低...

    1_syscall.tar.gz

    linux内核与用户通信示例之系统调用。此内容为博客http://blog.csdn.net/shallnet 文章对应源码下载

    syscall-table:从 Linux 源生成 JSON 系统调用信息

    从 Linux 源生成 JSON 系统调用表。 托管在 。 生成 JSON $ brew install ctags $ easy_install python-ctags simplejson $ tar -zxvf linux-2.6.35.4.tar.gz $ cd linux-2.6.35.4 $ ctags --fields=afmikKlnsStz ...

    Linux系统守护进程详解

    红帽企业Linux 4 Update 2改进了对审核子系统的内核和用户支持。审核子系统可以被系统管理员用来监测系统调用和那些符合CAPP或其它审核要求的文件系统访问。系统管理员还可以使用auditctl工具程序来修改 auditd守护...

    syscalls-table:用于在不同体系结构上生成Linux系统调用HTML表的简单工具

    Linux内核具有为用户空间提供的一组系统调用(简称为syscalls)。 每种体系结构都可以支持它们,但是用于标识它们的数字在不同的拱门之间可以有所不同。 这些数字对于某些项目可能很重要(例如Valgrind)。如何帮助...

    Android系统调用记录器-C/C++开发

    内核模块通过重写syscall表来挂接到Android设备上的某些系统调用。 Android-Syscall-Logger一个内核模块,通过重写syscall表来挂钩您的Android设备上的某些系统调用。 前提条件支持的设备:Pixel(Tested),Pixel 2...

    linux 应用程序中的open 操作与硬件驱动之间的联系浅析

    对于linux 下所有的系统调用函数,均可找到与其对应的内核函数sys_xxx().比如此处的open函数,对应内核函数就是sys_open。只不过,在此内核版本中,它的定义是如下这种形式 SYSCALL_DEFINE3(open, const char __user...

    krf:内核空间系统调用拦截器和随机故障器

    因为它拦截原始系统调用而不是它们的 libc 包装器,所以它可以将错误注入到由syscall(3)或内联汇编发出的syscall(3) 。 与使用dlsym相比,它可能更快且更不容易出错。 也有几个缺点: 您可能需要自己构建它。 ...

Global site tag (gtag.js) - Google Analytics