UML调试linux2.6.34.14中的sys_socketcall

来源:互联网 发布:如何建立网络链接 编辑:程序博客网 时间:2024/05/17 23:09

1 工具

    vmware9+Fedora8+linux2.6.34.14的内核源代码+ext3文件系统(网上下载的)

    题中所说的UML不是建模用的那玩意,它指User mode linux,可以让linux在用户模式下运行!


2 安装虚拟机与Fedora8系统

   安装vmware,然后在vmware中安装Fedora8!十分简单,略……


3 构建UML

   在http://www.kernel.org点击打开链接下载2.6.34.14的内核源代码,在Fedora8中以root身份,将内核源代码包拷贝到/usr/src目录。

   如果包是.tar.xz后缀的包,需要执行以下命令解压:

     xz -d linux-2.6.34.14.tar.xz

     tar xvf linux-2.6.34.14.tar   此时/usr/src目录里面会有一个linux-2.6.34.14的文件夹。

   进入linux-2.6.34.14目录,以root运行

     make defconfig ARCH=um(如果提示没有gcc和相关包,用yum安装就可以了!) 

     make ARCH=um 

     make modules ARCH=um

   等编译完毕,在此目录会生成一个linux的可执行文件,要让它能够运行起来,还需要一个文件系统,在http://fs.devloop.org.uk/点击打开链接下载一个比较小的文件系统就足够了(要支持UML,推荐Debian Squeeze 32位的文件系统)


4 编译和运行UML

    文件系统下载完毕以后,将Debian-Squeeze-x86-root_fs.bz2拷贝到/usr/src目录,用

     bzip2 -d Debian-Squeeze-x86-root_fs.bz2

    解压,并将其重命名为root_fs(要不以后要输入很长的字符串!!)

    进入linux-2.6.34.14目录,以root身份运行

    ./linux ubda=../root_fs

   

此时,输入root便能能进入系统,如果要退出UML,输入shutdown -h now即可!

  


5 调试

    在调试内核的sys_socketcall之前,最好先编写一个socket的程序并进行编译,让其能在UML中运行,下面我给出一个能编译的例子(出自《追踪Linux TCP/IP代码运行》),最后将其编译成一个名为socket的可执行文件!

#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <string.h>int main(){int server_fd,client_fd;int server_len,client_len;struct sockaddr_in server_address;struct sockaddr_in client_address;char back[]={"I am server"};server_fd=socket(AF_INET,SOCK_STREAM,0);server_address.sin_family=AF_INET;server_address.sin_addr.s_addr=inet_addr("127.0.0.1");server_address.sin_port=htons(9266);server_len=sizeof(server_address);bind(server_fd,(struct sockaddr*)&server_address,server_len);listen(server_fd,10);while(1){char recv[20];printf("server is wating!\n"); client_len=sizeof(client_address);client_fd=accept(server_fd,(struct sockaddr*)&client_address,&client_len);read(client_fd,recv,20);write(client_fd,back,20);printf("received from client=%s\n",recv);close(client_fd);}close(server_fd);exit(0);}

      将这个socket的可执行文件拷贝到root_fs文件系统。要实现拷贝,得先挂载文件系统,以root身份依次执行

      mkdir /mnt/my_fs

       cd /usr/src 

       mount -o loop root_fs /mnt/my_fs

       cp socket /mnt/my_fs/root

       完成拷贝之后:

      cd   /usr/src/linux-2.6.34.14

      ./linux ubda=root_fs


从这个图中可以看出,socket文件能够在root_fs文件系统正常的运行。


显然,这个socket文件在执行的时候一定会调用sys_socketcall这个系统调用,现在开始调试

cd /usr/src/linux-2.6.34.14

gdb linux

进入gdb以后依次输入:

break sys_socketcall (在sys_socketcall设置断点)

run ubda=../root_fs


此时会收到一个SIGSEGV的信号,此时输入

handle SIGSEGV pass nostop noprint  就可以了(这条语句也可以在run之前输入)

输入continue。程序就会正常的停在sys_socketcall


不过此时内核并不是在执行socket时停住的,而是在系统初始化时停住的!要让系统完全执行起来,得继续执行continue,这个断点会让内核停很多次。按住回车就好(耐心,期间会让输入root),直到出现如下画面



之后输入./socket,内核就好停在sys_socketcall这个系统调用,之后就可以参照《追中Linux TCP/IP代码运行》来单步调试了!!!




可以用GNU的DDD调试器来调试,效果更好!(此方法不限于调试sys_socketcall,还可以调试其它函数,如start_kernel()函数)


能让内核执行到这里很是不容易,所以以后就不要关掉Fedora8了,Suspend就好,下次要用Resume就可以了!

ps: 阅读linux内核源代码是一项非常艰难的工作,调试是高效阅读代码的一种方式,在阅读源代码时对于一些可重用函数,要弄清楚它是在哪里被声明;函数跳转时,要记住是哪些参数被带入到了下级函数(返回值也可以看作带入下级函数的特殊参数)!