在glibc里找ioctl()系统调用

背景:了解ioctl()从用户空间到内核空间的整个调用链。内核那边已经理清了,glibc这边不太好弄。晚上各种查,捣鼓出了一点结果。

首先从下载的glibc源码里找ioctl(),没发现比较直接的代码实现(主要是没看到陷入内核的相关代码)。后来不得已,干脆调试glibc代码得了,以前没调试过,不妨现在一试。

调试glibc代码,主要参考这两篇:使用gdb调试glibc和用gdb追踪glibc代码执行过程。大致过程是:

(1) 安装glibc符号表:$sudo apt-get install libc6-dbg
(2)下载glibc源码:$sudo apt-get source libc6-dev

a. 命令执行完后,在当前目录下生成eglibc-xxx目录,里面就是glibc源码。我自己生成的目录为~/eglibc-2.15

(3)编译生成带有调试信息的可执行文件:$gcc -g -o xxx xxx.c

(4)调试xxx:gdb xxx

a. 指定源码搜索路径:directory ~/eglibc-2.15

其实~/eglibc-2.15这个目录范围很广,如果知道自己要调试的库函数所在的具体路径,就直接指定这个路径。就鄙人这个情况,我是不知道ioctl()是在哪个路径哪个文件下的,只好指定根目录了。

b. 执行到ioctl()调用处,step进去,报信息如下:

ioctl () at ../sysdeps/unix/syscall-template.S:82
82 ../sysdeps/unix/syscall-template.S: No such file or directory.

指定搜索路径为 ~/eglibc-2.15/sysdeps/unix就好了。得到:

ioctl () at ../sysdeps/unix/syscall-template.S:82
82 T_PSEUDO (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS)

现在到sysdeps/unix/syscall-template.S文件下看这行:T_PSEUDO (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS)。

这是个系统调用生成模板,跟ioctl()没直接关系,不过是在编译的时候把ioctl这个函数名和它的参数个数传进来。关键还得找T_PSEUDO 。

T_PSEUDO 在syscall-template.S里是 #define T_PSEUDO(SYMBOL, NAME, N)
PSEUDO (SYMBOL, NAME, N),所以继续找PSEUDO。

PSEUDO在sysdeps/unix/sysv/Linux/i386/sysdep.h有个定义如下:

#undef    PSEUDO  
#define PSEUDO(name, syscall_name, args)                      \  
  .text;                                      \  
  ENTRY (name)                                    \  
    DO_CALL (syscall_name, args);                         \  
    cmpl $-4095, %eax;                                \  
    jae SYSCALL_ERROR_LABEL;                              \  
  L(pseudo_end):

DO_CALL在同一个文件下是:

#undef    DO_CALL  
#define DO_CALL(syscall_name, args)                           \  
    PUSHARGS_##args                               \  
    DOARGS_##args                                 \  
    movl $SYS_ify (syscall_name), %eax;                       \  
    ENTER_KERNEL                                  \  
    POPARGS_##args

这些宏在同一个文件下基本都有定义,就不在这里一一展示其定义了。

总之,当syscall_name为ioctl,args为3,条件编译的宏I386_USE_SYSENTER和SHARED均定义时,PSEUDO展开得到:

#define   PSEUDO(name, syscall_name, args) \  
  .text;                                    \  
  ENTRY (name)                      \  
    pushl %ebx;                     \  
    cfi_adjust_cfa_offset (4);      \  
    movl 16(%esp), %edx;            \  
    movl 12(%esp), %ecx;            \  
    movl 8(%esp), %ebx;               \  
    movl $SYS_ify (syscall_name), %eax; \  
    call *%gs:SYSINFO_OFFSET            \  
    popl %ebx;                      \  
    cfi_adjust_cfa_offset (-4);     \  
    cfi_restore (ebx);              \  
    cmpl $-4095, %eax;              \  
    jae SYSCALL_ERROR_LABEL;        \  
  L(pseudo_end):  

我们最后再来看对ioctl()反汇编的代码:
在glibc里找ioctl()系统调用_第1张图片
图中,指令cmp $0xfffff001, %eax的0xfffff001,它的十进制值是-4095。

比较ioctl()反汇编代码和sysdep.h中PSEUDO的汇编代码,基本都对应上了。

ps. 没那么多时间,写的好潦草:P

参考

【1】使用gdb调试glibc,http://blog.chinaunix.NET/uid-24774106-id-3642925.html,2016.11.15.

【2】用GDB追踪glibc代码执行过程,http://blog.nlogn.cn/trace-glibc-by-using-gdb/,2016.11.15.

【3】在GLIBC里查找系统调用,http://blog.csdn.Net/caspiansea/article/details/39022377,2016.11.15.

【4】Linux Application-Level System Calls,http://www.cs.fsu.edu/~baker/devices/notes/systemcalls.html,2016.11.15.

你可能感兴趣的:(在glibc里找ioctl()系统调用)