静态查看内核源代码与汇编代码

需求: 在通过静态阅读内核源代码的时候,有大量的宏定义或者是内联汇编代码难以理解,如果能在阅读源代码的时候也能查看到相对应的汇编代码,
那么理解代码就应比较容易。
方法: 使用带有调试符号信息的内核镜像以及相对应的源代码,利用gdb查看信息。带有调试符号的镜像通过静态的方法查看到的代码的运行地址与在内核动态运行时的地址是一致的。
linux 启动的内核镜像vmlinuz文件也是带有符号信息的,存储在/boot下的System.map-xx文件当中。符号信息中的变量名或是函数名被称为符号名,与之对应的则是该变量或是函数在内存中的地址,对System.map更深层次的接受可以参阅维基百科。使用方法,例如查看函数system_call的信息:
[07/09/2016 19:16] root@ubuntu:/boot# cat System.map-3.9.10  | grep system_call
c16133b8 T system_call
现在系统中的内核版本是3.9.10,vmlinux的镜像名为vmlinuz-3.9.10,相对应的符号表存储在System.map-3.9.10当中。
可以看到,c16133b8对应的是system_call的地址。
这种形式的内核镜像文件使用gdb查看信息时会提示没有符号表导入。
[07/09/2016 19:25] root@ubuntu:/boot# gdb vmlinuz-3.9.10
/*中间的语句省略*/
Reading symbols from /boot/vmlinuz-3.9.10…(no debugging symbols found)…done.
(gdb) list sys_open
No symbol table is loaded.  Use the “file” command.
(gdb)
值得庆幸的是ubuntu官网有提供自身带有调试符号信息的内核镜像,链接是 http://ddebs.ubuntu.com/pool/main/l/linux/
这里我选择的是3.13.0-24.47的i386版本,下载之后适用dpkg进行安装.
安装之后,可以通过如下的路径找到带有调试符号信息的内核镜像,
[07/09/2016 20:13] root@ubuntu:/usr/lib/debug/boot# ls
vmlinux-3.13.0-24-generic
 
此时使用gdb加载该镜像时,
[07/09/2016 20:16] root@ubuntu:/usr/lib/debug/boot# gdb vmlinux-3.13.0-24-generic
Reading symbols from /usr/lib/debug/boot/vmlinux-3.13.0-24-generic…done.
(gdb) list sys_open
1018    /build/buildd/linux-3.13.0/fs/open.c: No such file or directory.
(gdb)
可以看到,已经顺利价值镜像信息,但是并没有在/build/buildd对应的路径下找到代码文件,因此我们需要下载对应的源码加入到该路径当中。
下载的链接: http://security.ubuntu.com/ubuntu/pool/main/l/linux/ ,需要注意对应的版本号。
下载之后,使用dpkg安装。然后在/usr/src目录下查看,将对应版本的的目录名改为linux-3.13.0,进入该目录后,将源文件解压缩,之后将所有源文件
移动到上一层目录。
接着,创建/build目录,创建/buld/buildd目录,在该路径下 创建一个软连接,ln -s /usr/src/linux-3.13.0
这个时候,gdb加载带有调试信息的内核镜像,查看sys_fork函数的源代码。
(gdb) list   sys_fork
1641    #ifdef __ARCH_WANT_SYS_FORK
1642    SYSCALL_DEFINE0(fork)
1643    {
1644    #ifdef CONFIG_MMU
1645        return do_fork(SIGCHLD, 0, 0, NULL, NULL);
1646    #else
1647        /* can not support in nommu mode */
(gdb)
1648        return(-EINVAL);
1649    #endif
1650    }
 
接下来,查看system_call函数的汇编形式。
(gdb) disas  /m   system_call
Dump of assembler code for function system_call:
506        pushl_cfi %eax            # save orig_eax
   0xc165294b <+3>:    push   %eax
507        SAVE_ALL
   0xc165294c <+4>:    cld   
   0xc165294d <+5>:    push   %gs
   0xc165294f <+7>:    push   %fs
   0xc1652951 <+9>:    push   %es
   0xc1652952 <+10>:    push   %ds
   0xc1652953 <+11>:    push   %eax
   0xc1652954 <+12>:    push   %ebp
   0xc1652955 <+13>:    push   %edi
   0xc1652956 <+14>:    push   %esi
   0xc1652957 <+15>:    push   %edx
   0xc1652958 <+16>:    push   %ecx
   0xc1652959 <+17>:    push   %ebx
   0xc165295a <+18>:    mov    $0x7b,%edx
   0xc165295f <+23>:    mov    %edx,%ds
   0xc1652961 <+25>:    mov    %edx,%es
   0xc1652963 <+27>:    mov    $0xd8,%edx
   0xc1652968 <+32>:    mov    %edx,%fs
   0xc165296a <+34>:    mov    $0xe0,%edx
   0xc165296f <+39>:    mov    %edx,%gs
508        GET_THREAD_INFO(%ebp)
   0xc1652971 <+41>:    mov    $0xffffe000,%ebp
   0xc1652976 <+46>:    and    %esp,%ebp
509                        # system call tracing in operation / emulation
510        testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
…..
 
 
参考文献: