code2012

加油,坚持,努力,自信
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

gdb 调试 内核

Posted on 2011-06-15 12:35  code2012  阅读(2912)  评论(0编辑  收藏  举报
以下 是YY 的文章, 感谢 YY
但是 文中漏了 一点很重要的  要把  
LDFLAGS  中 -s 去掉! 
---------------------------------
文章
使用Bochs和GDB对内核进行源代码级调试
Written by YY   
Wednesday, 21 April 2010 12:49

1. 安装 Bochs

编译 Bochs 要加入 --enable-gdb-stub 选项:

$ ./configure --enable-gdb-stub
$ make
$ sudo make install
    

2. 生成内核

修改 Makefile

  1. 将 CFLAGS 加入 -g 选项,以便加入调试符号

    CFLAGS = -I include/ -I include/sys/ -c -g -fno-builtin -Wall
  2. 由于加了调试符号之后 kernel.bin 太大,所以将其 strip 之后在拷贝入磁盘映像

    sudo cp -fv kernel.bin /mnt/floppy
    	  

    改为:

    strip kernel.bin -o kernel.bin.stripped
    sudo cp -fv kernel.bin.stripped /mnt/floppy/kernel.bin
    	  

    如此一来,在 bochs 虚拟机里面执行的 kernel.bin 是 strip 之后的,过会儿用来交给 gdb 的 kernel.bin 是带调试符号的。

编译内核

$ make image
      

3. 启动 Orange'S

修改 bochsrc

加入这么一行:

gdbstub: enabled=1, port=1234, text_base=0, data_base=0, bss_base=0
      

运行

$ bochs -q -f bochsrc.gdb	# 注意必须用加入了 --enable-gdb-stub 编译选项的 bochs
      

4. 用 gdb 调试

打开另一控制台,运行 gdb

$ gdb
    

在 gdb 中调试

(gdb) file kernel.bin			← 注意这里的 kernel.bin 必须是加入了 -g 编译选项的带调试符号的内核
Reading symbols from /home/forrest/local/src/osfs/oranges/phases/chapter11/a/kernel.bin...done.
(gdb) target remote localhost:1234
Remote debugging using localhost:1234
0x0000fff0 in ?? ()
(gdb) b start.c:26
Breakpoint 1 at 0x14a6: file kernel/start.c, line 26.
(gdb) c
Continuing.
	Breakpoint 1, cstart () at kernel/start.c:26
26		disp_str("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n-----\"cstart\" begins-----\n");
(gdb) n
29		memcpy(	&gdt,				   /* New GDT */
(gdb) 
    

.gdbinit

由于每次都需要执行 file kernel.bin 和 target remote localhost:1234 两个命令,所以可以建立一个 .gdbinit 文件,比如:

$ vi .gdbinit
file kernel.bin
target remote localhost:1234
set disassembly-flavor intel
b start.c:26
b kernel/main.c:183
      

这样下次直接执行 gdb 这个文件里的命令即可自动执行。

.gdbinit 可以做许多事,比如上例中就加了俩断点。

在 .gdbinit 中自定义函数

在 .gdbinit 中可添加自定义函数,比如:

define lsproc
  set $count = 16
  set $idx = 0
  printf "The first %d TASKS/PROCS:\n",$count
  while($idx < $count)
    if(proc_table[$idx].p_flags != 0x20)
      if($idx < 5)
	printf "[%2d] TASK: %8s",$idx,proc_table[$idx].name
	printf "\t p_flags: %8Xh\n",proc_table[$idx].p_flags
      else
	printf "[%2d] PROC: %8s",$idx,proc_table[$idx].name
	printf "\t p_flags: %8Xh\n",proc_table[$idx].p_flags
      end
    end
    set $idx++
  end
end 
    

这样在 gdb 中执行一个 lsproc,便可打印出所有进程的信息,巨方便:

(gdb) lsproc 
The first 16 TASKS/PROCS:
[ 0] TASK:      TTY	 p_flags:        4h
[ 1] TASK:      SYS	 p_flags:        4h
[ 2] TASK:       HD	 p_flags:        4h
[ 3] TASK:       FS	 p_flags:        4h
[ 4] TASK:       MM	 p_flags:        4h
[ 5] PROC:     INIT	 p_flags:        Ch
[ 6] PROC:    TestA	 p_flags:        0h
[ 7] PROC:    TestB	 p_flags:        0h
[ 8] PROC:    TestC	 p_flags:        0h
[ 9] PROC:   INIT_9	 p_flags:        4h
[10] PROC:  INIT_10	 p_flags:        4h


--------------------------------------转 网文-----------------------------------------------