2007年4月28日星期六

VMWare 6调试linux kernel(转)

一、环境:

1, 一台Linux机器, 用于运行gdb和VMWare Workstation 6.0, 我们称之为HOST机器。
2, VMWare6.0中安装一个Linux系统, 我们称这个Linux系统为GUEST机器, 它运行被调试的内核。

二、设置:

很简单,在你的HOST Linux中,往GUEST Linux的vmware配置文件(即后缀名为.vmx的文件)追加一个字符串。 在我的机器上是这样的:

# echo "debugStub.listen.guest32=1" >> /root/vmware/FC4\ Linux/FC4\ Linux.vmx

注译, 如果你是的GUEST是在x86-64上运行的, 那么把上面这行的就是debugStub.listen.guest64=1
三、调试:

1, 把GUEST Linux上的内核映像文件(vmlinux)和内核源代码拷贝到HOST机器上。

为了能够用gdb的list命令显示源代码, 看看GUEST机器上的/lib/modules//source (以下简称source) 和/lib/modules//build (以下简称build)这两个符号链接各自指向哪里(注:如果编译内核时没有用O=选项指定输出的路径,那么这两个符号链接就指向同一个路径,通常是/usr/src/linux-2.x.xx)。拷贝到HOST机器上 相应的路径上。
提醒: 编译内核之后build目录下会有很多临时文件, 有上G之大, 可以先把build目录下的vmlinux拷贝到HOST机器上, 然后进入source目录, 运行:
make O=/lib/module//build clean
然后再把build和source拷贝到HOST机器上。

2, 启动安装在VMWare中的GUEST Linux。

3, 在HOST机器上运行gdb, 进行调试:

(gdb) file vmlinux //vmlinux就是从GUEST拷贝过来的内核映像文件
Reading symbols from /root/vmlinux...done.
Using host libthread_db library "/lib/libthread_db.so.1".
(gdb) target remote localhost:8832 //注意,如果你的GUEST Linux是64位的,这里的localhost:8832就改成localhost:8864
Remote debugging using localhost:8832
[New thread 1]
0x000f4299 in ?? ()
warning: shared library handler failed to enable breakpoint

更详细的看http://linux.chinaunix.net/bbs/viewthread.php?tid=896214&extra=page%3D1

2007年4月20日星期五

Linux内核源码中的do while(0)

为什么在内核中碰到很多 #defines ... do{ ... } while(0)?

有以下几点原因:

  • 空语句在编译时候会出现警告,所以有必要用#define FOO do { } while(0).

  • 这样做是为了能够在里面定义局部变量

  • 这样做是为了能够在条件语句中使用复杂的宏定义. 例如下面这段代码:

    #define FOO(x) \
    printf("arg is %s\n", x); \
    do_something_useful(x);
    如果这样用:
    if (blah == 2)
    FOO(blah);
    将会被展开为:
    if (blah == 2)
    printf("arg is %s\n", blah);
    do_something_useful(blah);;

    这样,if条件之包含了printf()语句,而 do_something_useful()调用不能按期望那样工作。而使用 do { ... } while(0)定义后,就会展开成以下语句:

    if (blah == 2)
    do {
    printf("arg is %s\n", blah);
    do_something_useful(blah);
    } while (0);
    这是所期望的状况.
  • 如果你希望定义一个包含多行语句和一些局部变量的时候. 一般的定义方式只能这样:

    #define exch(x,y) { int tmp; tmp=x; x=y; y=tmp; }

    然而在某些情况下,这样并不能正常工作. 下面是包含两个分支的if语句:

    if (x > y)
    exch(x,y); // Branch 1
    else
    do_something(); // Branch 2

    但这样却只能展开成单分支的if语句,如下:

    if (x > y) {                // 单分支if
    int tmp;
    tmp = x;
    x = y;
    y = tmp;
    }
    ; // 空语句
    else // 错误!!! "parse error before else"
    do_something();

    问题是由于在语句块后直接加入分号(;)引起的. 解决办法是将语句块放入 dowhile (0)中间.这样就得到了一条单语句, 而不是被编译器判断为语句块.现在的if语句如下:

    if (x > y)
    do {
    int tmp;
    tmp = x;
    x = y;
    y = tmp;
    } while(0);
    else
    do_something();