Debug of the kernel with VMWare and kgdb

转自(部分修改):http://blog.csdn.net/jie12310/archive/2009/09/18/4564853.aspx          

1.前言

最近几天学习Linux-2.6平台上的设备驱动,所以要建立内核及内核模块的调试平台.虽然网上有很多相关教程,但多是基于2.6.26以前的通过补丁安装的,过程非常复杂,而且问题比较多.linux从 2.6.26开始已经集成了kgdb,只需要重新编译2.6.26(或更高)内核即可.kgdb安装及模块调试过程也遇到不少问题,网上网下不断的搜索与探索,才算调通.现在记录下来,供朋友们参考。
首先说一下,开始本打算安装kdb进行内核调试,后来听说kdb只能进行汇编级别的调试,所以放弃,改用kgdb

2.系统环境:
虚拟环境:   VMWare Workstation 5.0(英文版)
操作系统:   RHEL-V5-Server-i386(原内核2.6.18,将会把内核升级至2.6.26)
注:(由于我们采用的linux kernel 2.6.26已经集成kgdb,kgdb再不需要单独下载)

3.系统的安装:
在VMWare中新建一台计算机:

点击 Next 
选中Custom 点击 Next 
选中 New-Workstation 5,点击Next 
选中Linux ,Version选中Other Linux 2.6.x kernel 点击Next 
Virt l machine name 输入Client(Development) 点击Next 
Processors 选中 One, 点击Next 
Memory 输入256,点击Next 
Network connection 选中Use network address translation(NAT) (选第一个貌似也可以) 点击Next 
I/O adapter types 
SCSI Adapters 选中默认的LSI Logic(这里如果你后面使用了SCSI格式的Disk,编译内核时需要添加相应的驱动,我选择的是IDE的硬盘,kernel默认就支持了) 
Disk 选中Create a new virt l disk 点击Next 
Virt l Disk Type 选中IDE,点击Next 
Disk capacity Disk size 输入80G (下面的Allocate all disk space now不要选中,表示在真正使用才分配磁盘空间, Split disk into 2 GB files项,可不选,如果你的系统分区为fat32格式,最好选中) 点击Next. 
Disk file ,输入Disk的名称,如:disk1.vmdk ,点击Finish.完成 
安装RHES 5.0(过程略过)
安装完成后,关闭计算机,然后Clone一台同样的计算机.步骤如下:

点击VM->Clone 
选中默认的From current state,点击Next 
选中Create a full clone, 点击Next 
Virt l Machine name 输入Server(Targe),将克隆的机器命令为目标机. 
说明一下,kgdb 需要两台计算机通过串口进行远程调试,两台计算机分别为: 
Client(Development):开发机,也称客户机,将在该计算机上进行程序的开发,GDB将在本计算机上运行.用于输入命令控制Server(target)的运行. 
Server(Target): 目标机,也称服务器,就是被调试的计算机,在Development机上开发好的内核模块程序将拷贝到Target上运行,其运行受到Development命令的控制. 
分别为两个系统增加一个串口,以"Output to named pipe"方式,其中:

Client端选择"this end is the client", "the other end is a virt l machine" 
Server端选择"this end is the server", "the other end is a virt l machine" 
备注: 两个pipe的名称要相同,并且选中下面的Connect at power on,及Advanced里面的Yield CPU on poll

以后的部分,Server上的操作与Client上的操作将以不同的背景色显示,输入的命令将以不同的字体颜色并带下划线显示.请注意:

  • Server(Target) 输入: cat /dev/ttyS0

    系统输出的信息: hello

  • Client(Development) 输入: echo "hello" >/dev/ttuS0
  • 串口添加完成后,使用如果命令测试:
  • 在Server上cat /dev/ttyS0
  • 然后到Client上 echo "hello" > /dev/ttyS0
  • 这时回到Server上,如果能看到输入的hello,说明串口通讯正常.

4.升级内核2.6.26(添加关于KGDB的选项)
      说明一下,这里是要升级Server的内核,因为kgdb是要Server上运行的,但是编译需要在Client完成(或者你也可以在Server上编译,之后再拷贝到Client上),因为调试时Client上的gdb会用到编译的内核及源代码.Client也需要升级,保证Client同Server上的内核一致,这样Client上编译的模块拿到Server上加载就不会有什么问题.

首先下载kernel 2.6.26
      我习惯在windows上下载,然后共享,再到linux使用smbclient连接,拷贝到Linux上.你也可以直接在linux上下载. 
      smbclient用法 : smbclient //192.168.0.100/share - dministrator 回车后,会提示输入admin的密码.之后就可以通过get获取了 192.168.0.100是我在windows主机的IP,share为共享名,-U后面是用户名

编译Kernel2.6.26

进入Client(Development)系统,将linux-2.6.26.tar.bz2拷贝到/usr/src目录下: 
cd /usr/src 
tar jxvf linux-2.6.26.tar.bz2 
ln -s linux-2.6.26 linux 
cd linux 
make men onfig
 
File System --> 下面把ext3,ext2都编译进内核(就是把前面的M变成*) 
Kernel Hacking --> 
      选中Compile the kernel with frame pointers
      选中KGDB:kernel debugging with remote gdb 
      并确认以下两项也是选中的(他们应该默认是选中的) 
      > kernel debugging 
      > Compile the kernel with debug info

Device-->

选中Multiple device support(RAID and LVM)/ Device mapper support
对于其它选项,请按实际情况,或你的要求定制. 
在其它网友的说明里面,会有Serial port number for KGDB等选项,但是我使用的版本未找到这些选项,所以忽略过. 
保存退出 
Makefile文件修改


make -j10 bzImage
-j10表示使用10个线程进行编译. 
make modules
编译内核模块 
make modules install
安装内核模块 
make install 
安装内核 
将Client系统中的linux-2.6.26整个目录同步到Server上.

在Client系统上运行下列命令: 
cd /usr/src/linux   
scp -r linux-2.6.26 root@Server(Target)IP:/usr/src/
     系统会提示输入root的密码,输入完了就会开始复制文件了,(这里要注意,如果原系统已经是2.6.26的内核,可以只拷贝arch/i386/boot/bzImage,及System.map文件到Server上,然后修改/boot/gr /gr .conf,但由于我是从2.6.9升级上来,所以需要将整个linux原代码目录拷贝到Server上进行升级) 
升级Srever系统的内核 
进入Server(Target)系统,usr/src目录: 
ln -s linux-2.6.26 linux   
cd linux   
make modules_install
安装内核模块 
make install
安装内核 
安装完成后,在/boot/目录下会有即个新添加的文件./boot/gr /gr .conf文件也会添加一个新的启动项,我的如下(行号不是文件的一部分):

 1 # gr .conf generated by anaconda
 2 #
 3 # Note that you do not have to rerun gr after making changes to this file
 4 # NOTICE:  You have a /boot partition.  This means that
 5 #          all kernel and initrd paths are relative to /boot/, eg.
 6 #          root (hd0,0)
 7 #          kernel /vmlinuz-version ro root=/dev/VolGroup00/LogVol00
 8 #          initrd /initrd-version.img
 9 #boot=/dev/hda
10 default=0
11 timeout=5
12 splashimage=(hd0,0)/gr /splash.xpm.gz
13 hiddenmenu
14 title RHES5 (2.6.26)
15     root (hd0,0)
16     kernel /vmlinuz-2.6.26 ro root=/dev/VolGroup00/LogVol00
17     initrd /initrd-2.6.26.img
18 title RHES5 (2.6.9-67.ELsmp)
19     root (hd0,0)
20     kernel /vmlinuz-2.6.9-67.ELsmp ro root=/dev/VolGroup00/LogVol00
21     initrd /initrd-2.6.9-67.ELsmp.img
 
       注意里面的NOTICE说明,我的系统/boot是一个独立的分区,所以下面配置的文件路径都是相对于/boot/目录的,像 /vmlinuz-2.6.26,实际到它的绝对位置应该是/boot/vmlinuz-2.6.26. 在你的系统上请根据实际情况处理.

修改一下gr .conf,修改成下面这样:
 1 # gr .conf generated by anaconda
 2 #
 3 # Note that you do not have to rerun gr after making changes to this file
 4 # NOTICE:  You have a /boot partition.  This means that
 5 #          all kernel and initrd paths are relative to /boot/, eg.
 6 #          root (hd0,0)
 7 #          kernel /vmlinuz-version ro root=/dev/VolGroup00/LogVol00
 8 #          initrd /initrd-version.img
 9 #boot=/dev/hda
10 default=0
11 timeout=5
12 splashimage=(hd0,0)/gr /splash.xpm.gz
13 hiddenmenu
14 title RHES5 (2.6.26)
15     root (hd0,0)
16     kernel /vmlinuz-2.6.26 ro root=/dev/VolGroup00/LogVol00 kgdboc=ttyS0,115200
17     initrd /initrd-2.6.26.img
18 title RHES5  (2.6.26) Wait...(kernel debug)
19     root (hd0,0)
20     kernel /vmlinuz-2.6.26 ro root=/dev/VolGroup00/LogVol00 kgdboc=ttyS0,115200 kgdbwait
21     initrd /initrd-2.6.26.img
22 title RHES5 i386 (2.6.9-67.ELsmp)
23     root (hd0,0)
24     kernel /vmlinuz-2.6.9-67.ELsmp ro root=/dev/VolGroup00/LogVol00
25     initrd /initrd-2.6.9-67.ELsmp.img
 

说明:

第一个启动项在原来的基础上添加了kgdb的参数kgdboc=ttyS0,115200
kgdboc 的意思是 kgdb over console,这里将kgdb连接的console设置为ttyS0,波特率为115200,如果不在内核启动项中配置该参数,可以在进入系统后执行命令: 
echo ttyS0 > /sys/module/kgdboc/parameters/kgdboc    
第二个启动项,同第一个使用同一个内核,只是添加了kgdbwait参数
kgdbwait 使 kernel 在启动过程中等待 gdb 的连接。

我的启动菜单如下: 
RHES5 (2.6.26) 
RHES5 (2.6.26)Wait...(kernel debug) 
RHES5 i386(2.6.9-67.ELsmp) 
调用内核模块,就选择第一个,如果要调试内核启动过程,选择第二个.

5.内核调试

系统过程中的内核调试
重启Server,通过启动菜单第二项RHES5 (2.6.26)Wait...(kernel debug)进入系统. 只到系统出现:

     kgdb: Registered I/O driver kgdboc
     kgdb: Waiting for connection from remote gdb   
进入Client系统.

cd /usr/src/linux   
gdb vmlinux
  
启动gdb开始准备调试:输出大致如下:

GNU gdb Red Hat Linux (6.3.0.0-1.153.el4rh)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General P lic License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db 
library "/lib/tls/libthread_db.so.1" (gdb) set remoteba 115200 
(gdb) target remote /dev/ttyS0
注意:有的文章讲:因为vmware的named piped不能被gdb直接使用,需要使用 socat -d -d /tmp/com_1 /dev/ttyS0转换,然后使用转换后的设备. socat需要自己下载安装. 但在我的环境中,直接使用并没有出错.
执行该命令后输出如下: 
Remote debugging using /dev/ttyS0
kgdb_breakpoint () at kernel/kgdb.c:1674
1674  wmb(); /*Sync point after breakpoint */
warning: shared library handler failed to enable breakpoint看到上面的内容说明已经连接成功,但Server上依然是假死状态,这时你可以像使用本地gdb一样设置断点(break),单步执行(step),或其它命令. 
到这时,内核已经完成了大多数初始化工作,i386_start_kernel->start_kernel->rest_init->kernel_thread->kernel_init...->kgdb_breakpoint

kgdb可以在内核引导时就对其进行调试,但并不是所有引导过程都是可调试的,如在kgdb 1.9版中,它在init/main.c的start_kernel()函数中插入以下代码:
start_kernel()
{
    ......
        smp_init();
#ifdef CONFIG_KGDB
        if (gdb_enter) {
                gdb_hook();             /* right at boot time */
        }
#endif
    ......
}

所以在smp_init()之前的初始化引导过程是不能调试的。

(gdb) cont
继续执行,Server就继续下面的系统初始化了. 

系统启动完成后的内核调试:
 进入Server后,执行命令

echo g > /proc/sysrq-trigger 
系统同样会中断,进入假死状态,等待远程gdb的连接.KGDB可能会输出如下信息: 
SysRq: GDB    上面的命令(echo g > /proc/sysrq-trigger)可以有一个快捷键(ALT-SysRq-G)代替,当然前提是你编译内核时需要选中相关选项,并且需要修改配置文件:/etc/sysctl.conf , 我用了一下,不太好用.因为有的桌面系统中PrintScreen/SysRq键是用于截屏的.所以还是直接用命令来的好! 
我在~/.bashrc中添加了一句(添加完保存后,要执行source ~/.bashrc应用该配置):
alias debug='echo g > /proc/sysrq-trigger'
之后就可以直接输入debug来使内核进入调试状态. 
Server进入调试状态后,转换到Client系统,重复上面的步骤.

这时如果想继续调试内核的函数,需要编译内核时选择相关参数,比如需要调试slab,就把slab调试开关打开。另外,还需要关闭CONFIG_DEBUG_RODATA。 

Sample1:

client:
(gdb)b tcp_v4_connect

OR

(gdb)b /net/ipv4/tcp_ipv4.c:744  (gdb)c
target:
w3m  www.google.com
In w3m the screen just displayed "Opening socket..." but this will vary depending on which browser you choose to make a connection with. 

Then we ran the command "bt"(backtrace) on the gdb command line, it will be something like

Sample2:
gdb vmlinux /proc/kcore to get the function of the binary address 
or nm vmlinux | sort | less
Sample3:
client:
(gdb) b find_get_page
Breakpoint 2 at 0xc0457d1f: file mm/filemap.c, line 642.
(gdb) c
Continuing.
[New thread 2778]
[Switching to thread 2778]
Breakpoint 2, find_get_page (mapping=0xf76d1ebc, offset=1998917)
    at mm/filemap.c:642
642             read_lock_irq(&mapping->tree_lock);
(gdb) p mapping
$1 = (struct address_space *) 0xf76d1ebc
(gdb) b __kmalloc
Breakpoint 5 at 0xc04736e6: file mm/slab.c, line 3736.
Breakpoint 5, __kmalloc (size=752, flags=32976) at mm/slab.c:3736
3736    {
(gdb) n
3737            return __do_kmalloc(size, flags, __builtin_return_address(0));
(gdb) s
773             BUG_ON(malloc_sizes[INDEX_AC].cs_cachep == NULL);
(gdb) n
3737            return __do_kmalloc(size, flags, __builtin_return_address(0));
(gdb) c
Continuing.
[Switching to thread 3800]
Breakpoint 5, __kmalloc (size=58, flags=32976) at mm/slab.c:3736
3736    {
Program received signal SIGTRAP, Trace/breakpoint trap.
[Switching to thread 3811]
kgdb_breakpoint () at kernel/kgdb.c:1674
1674            wmb(); /* Sync point after breakpoint */
(gdb) b schedule
Breakpoint 2 at 0xc0658ad2: file kernel/sched.c, line 4150.
(gdb) c
Continuing.
[New thread -1]
Program received signal SIGTRAP, Trace/breakpoint trap.
__do_softirq () at kernel/softirq.c:233
233                     if (pending & 1) {
(gdb)

6. Linux内核模块(设备驱动)的调试
编写内核模块,及Makefile
      我使用的例子是Linux Device Driver 3中的例子scull. 你可以从这里下载LDD3的所有例子程序.

进入Client系统,解压example.tar.gz,将其中的example/scull目录拷贝到/root/scull 
然后执行: 
cd /root/scull   
make  
编译应该会出错,因为Linux Device Driver 3的例子程序是基于2.6.10内核的,请参靠下面的说明修改这些错误:
编译scull驱动,完成后,scull目录应该多出了scull.ko及其它中间文件. 
scp scull.ko root@targetIp:/root/
将scull.ko模块文件拷贝到Server上.系统应该会提示输入密码:

root@targetIp's password:输入正确密码后,应该能看到如下信息,表示复制成功了: 
scull.ko    100%  258k 258.0kb/s 00:00进入Server系统输入: 
cd /root/   
insmod scull.ko  
加载scull模块. 
cat /sys/module/globalmem/sections/.text  
显示scull模块的.text段地址.运行该命令后,会返回一个16进制的地址,如: 
0xd099a000echo g > /proc/sysrq-trigger  
现在Server系统变成等待状态. 
再次进入Client系统: 
cd /usr/src/linux   
gdb vmlinux   
(gdb) set remoteba 115200   
(gdb) target remote /dev/ttyS0 
Remote debugging using /dev/ttyS0
kgdb_breakpoint () at kernel/kgdb.c:1674
1674  wmb(); /*Sync point after breakpoint */
warning: shared library handler failed to enable breakpoint出现上面的信息表示连接成功,但此时还不可以设置断点.我试了N次,现在设置端点后,无论Server上对scull做什么操作,Client上的gdb都不会停止.也有人说这是gdb的BUG,gdb无法正常解析内核模块的符号信息. 说是下载kgdb网站上的gdbmod可以解决该问题,但我试了之后发现根本没有用. 所以只能通过命令手动加载相关符号信息: 
(gdb) add-symbol-file /root/scull/scull.ko 0xd099a000 
注意: 0xd099a000地址是在上面获取的,命令输入完了,系统会有如下提示信息(第二行后面的y是自己输入的: 
add symbol table from file "/root/scull/scull.ko" at .text_addr = 0xd099a000
(y or n)y
Reading symbols from /root/scull/scull.ko...done.        (gdb)break scull_write

Breakpoint 1 at 0xd099a2d9: file /root/scull/main.c,line 338.(gdb)break scull_read

Breakpoint 2 at 0xd099a1a2: file /root/scull/main.c,line 294(gdb)cont  

ContinuingClient上的工作暂停,回到Server系统上: 
Server现在处于运行状态,在Server上运行下面的命令: 
cat /proc/devices | grep "scull"
查看scull模块分配的major.我的系统中返回如下: 
253 scull
253 scullp
253 scullamknod /dev/scull c 253 0
253是刚才查询到的版本号. 
echo "this is a test " > /dev/scull
测试输入函数:scull_write. 该命令输入完成后,进程应该会停下来, 请切换到Client系统. 
cat /dev/scull
测试输出函数:scull_read. 该命令输入完成后,进程应该会停下来, 请切换到Client系统. 
回到Client系统,应该能看到gdb的输出信息:

Breakpoint 1, scull_write (filp=0xce5870c0,b=0xb7f44000 
      "this is a test\nias | /usr/bin/which --tty-only --read-alias 
      --show-dot --show-tilde'\n",count=15,f_pos=0xce5c5f9c)
  at /root/scull/main.c:338
338   {    
(gdb)_  现在就可以像调试本地程序一样调试scull.ko模块了. 
以同样的方法也可以调试其它函数.(初始化函数暂时没想到办法调试,因为使用这种方法需要先加载后,才可以进行调试)

你可以自由使用和转载本文档,转载时请注明出处. (jie123108@163.com)

如果可以,我想写一个脚本自动完成这个添加符号文件的过程,简化调试过程.

7.Q&A

Linux Device Driver 3rd中的scull 例程在2.6.26上编译出错的问题
(1)scripts

Makefile.build:46: *** CFLAGS was changed in "examples/scull/Makefile". Fix it to use EXTRA_CFLAGS。 停止。
    解决方法:将 Makefile 中的 CFLAGS 改为 EXTRA_CFLAGS 
(2) examples/scull/main.c:17:26: error: linux/config.h: 没有该文件或目录
    解决方法: 将 main.c 中的这条 incl e 语句注释掉。 
(3) examples/scull/access.c: 在函数‘scull_u_open’中:    examples/scull/access.c:107: 错误: 提领指向不完全类型的指针
    解决方法:access.c 中添加:#incl e <linux/sched.h> 
(4) examples/scull/access.c: 在函数‘scull_access_setup’中:
    examples/scull/access.c:355: 警告: 格式字符串不是一个字面字符串而且没有待格式化的实参
    解决方法:将  kobject_set_name(&dev->cdev.kobj,  devinfo->name); 改为:
                   kobject_set_name(&dev->cdev.kobj, "%s", devinfo->name);
因为 kobject_set_name 有一个像 printf 一样的参数表。 
补充 : 老外作的改动
http://www.cs.fsu.edu/~baker/devices/lxr/source/2.6.25/ldd-examples/基本上已经可以编译了 
摘录自: <<Linux Device Driver 3 中的代码在 2.6.27 中编译不能通过的问题>>

VMWare问题

(1) VMWare 6.0无法串口调试

解决方法:

client的 .vmx 文件中加入debugSt .listen.gst32=1

同时查看kernel中有没有xen支持,或按照host时不要选择virt lization.

编译内核

(1) 安装重启,出现以下错误:

Unable to find device-mapper major/minor ...

Panic during booting for devices mapper missed 

解决方法:

Device-->

选中Multiple device support(RAID and LVM)/ Device mapper support 

kgdb无法断点

shared library handler failed to enable breakpoint 

Kernel Hacking -->选择更多调试选项,enable the modules such as slab,etc.

更多内核调试配置选项

Page alloc debugging :CONFIG_DEBUG_PAGEALLOC:

不使用该选项时,释放的内存页将从内核地址空间中移出。使用该选项后,内核推迟移出内存页的过程,因此能够发现内存泄漏的错误。

Debug memory allocations :CONFIG_DEBUG_SLAB:

该打开该选项时,在内核执行内存分配之前将执行多种类型检查,通过这些类型检查可以发现诸如内核过量分配或者未初始化等错误。内核将会在每次分配内存前后时设置一些警戒值,如果这些值发生了变化那么内核就会知道内存已经被操作过并给出明确的提示,从而使各种隐晦的错误变得容易被跟踪。

Spinlock debugging :CONFIG_DEBUG_SPINLOCK:

打开此选项时,内核将能够发现spinlock未初始化及各种其他的错误,能用于排除一些死锁引起的错误。

Sleep-inside-spinlock checking:CONFIG_DEBUG_SPINLOCK_SLEEP:

打开该选项时,当spinlock的持有者要睡眠时会执行相应的检查。实际上即使调用者目前没有睡眠,而只是存在睡眠的可能性时也会给出提示。

Compile the kernel with debug info :CONFIG_DEBUG_INFO:

打开该选项时,编译出的内核将会包含全部的调试信息,使用gdb时需要这些调试信息。

Stack utilization instrumentation :CONFIG_DEBUG_STACK_USAGE:

该选项用于跟踪内核栈的溢出错误,一个内核栈溢出错误的明显的现象是产生oops错误却没有列出系统的调用栈信息。该选项将使内核进行栈溢出检查,并使内核进行栈使用的统计。

Driver Core verbose debug messages:CONFIG_DEBUG_DRIVER:

该选项位于"Device drivers-> Generic Driver Options"下,打开该选项使得内核驱动核心产生大量的调试信息,并将他们记录到系统日志中。

Verbose SCSI error reporting (kernel size +=12K) :CONFIG_SCSI_CONSTANTS:

该选项位于"Device drivers/SCSI device support"下。当SCSI设备出错时内核将给出详细的出错信息。

Event debugging:CONFIG_INPUT_EVBUG:

打开该选项时,会将输入子系统的错误及所有事件都输出到系统日志中。该选项在产生了详细的输入报告的同时,也会导致一定的安全问题。

以上内核编译选项需要读者根据自己所进行的内核编程的实际情况,灵活选取。在使用以上介绍的三种源代码级的内核调试工具时,一般需要选取CONFIG_DEBUG_INFO选项,以使编译的内核包含调试信息。

 

如果想知道某模块变更后的名字,可以首先在“make menuconfig”时找到该选项,选择Help找到它的配置名称(CONFIG_*),然后到源代码相关目录下的makefile中寻找CONFIG_*。一般可以找到obj-$(CONFIG_*)一项,其值就是该模块的名字。

Make sure that CONFIG_DEBUG_RODATA is off, or can not get breakpoint after bootup. Refer to :http://comments.gmane.org/gmane.linux.kernel.debugging.kgdb.bugs/5116

 

参考资料:

1.Using 2.6.26 Linux Kernel Debugger (KGDB) with VM

2.VMware环境下用kgdb调试内核

3.Using 2.6.26 Linux Kernel Debugger (KGDB) with VM

4.试玩UML(User Mode Linux) 收藏http://blog.chinaunix.net//103651/showart_2124740.html

5.制作UML(user mode linux)http://hi.baidu.com/caveman/blog/item/aa724b607d0de145ebf8f8f2.html

6.在vmware上建立kgdb调试linux kernel源码的平台http://blog.chinaunix.net//40405/showart_374221.html

7.UML fails to locate address space - Kernel http://fixunix.com/kernel/399386-uml-fails-locate-address-space.html

8.User-Mode Linux http://www.docstoc.com/docs/27890521/Laboratory-Assignment-2_-Part-1-User-Mode-Linux

9.Linux 内核中的 Device Mapper 机制 http://www.ibm.com/developerworks/cn/linux/l-devmapper/index.html

10.VMWare Workstation 6.0调试Linux Kernel http://linux.chinaunix.net/bbs/archiver/tid-896214-page-1.html 

11.System.map文件的作用http://blog.chinaunix.net/u/22617/showart_1777865.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值