最近頭大之至,一直想用bochs調試,結果她的魅力遠勝於想象。網上流傳很多bochs的調試大多盲目轉載且內容大爲英文 幫助的翻譯,下面是我在一大師的博客上轉帖過來的,關於用bochs進行調試的步驟和實踐過程中使用的例子。
注:1.大師博客:http://www.cnblogs.com/smwikipedia/
2.本文中所使用的bochs的版本爲v2.1.1,否則有些命令不兼容
正文----------------------------------------------------------------------------------------------- ------------------------------
----------------------------------------------------------------------------------------------- -----------------------------------
Bochs具有非常強大的操作系統內核調試功能。這也是本文選擇Bochs作爲首選實驗環境的主要原因之一。有關Bochs調試功能的說明參見前面14.2節,這裏基於Linux 0.11內核來說明Windows環境下Bochs系統調試操作的基本方法。
14.8.1 運行Bochs調試程序
我們假設Bochs系統已被安裝在目錄“C:/Program Files/Bochs-2.1.1/”中,並且Linux 0.11系統的Bochs配置文件名稱是bochsrc-hd.bxrc。現在在包含內核Image文件的目錄下建立一個簡單的批處理文件run.bat,其內容如下:
"C:/Program Files/Bochs-2.1.1/bochsdbg" -q -f bochsrc-hd.bxrc
其中bochsdbg是Bochs系統的調試執行程序。運行該批處理命令即可進入調試環境。此時Bochs的主顯示窗口空白,而控制窗口將顯示以下類似內容:
C:/Documents and Settings/john1/桌面/Linux-0.11>"C:/Program Files/Bochs-2.1.1/bo
chsdbg" -q -f bochsrc-hd.bxrc
========================================================================
Bochs x86 Emulator 2.1.1
February 08, 2004
========================================================================
00000000000i[ ] reading configuration from bochsrc-hd.bxrc
00000000000i[ ] installing win32 module as the Bochs GUI
00000000000i[ ] Warning: no rc file specified.
00000000000i[ ] using log file bochsout.txt
Next at t=0
(0) context not implemented because BX_HAVE_HASH_MAP=0
[0x000ffff0] f000:fff0 (unk. ctxt): jmp f000:e05b ; ea5be000f0
<bochs:1>
此時Bochs調試系統已經準備好開始運行,CPU執行指針已指向ROM BIOS中地址0x000fffff0處的指令處。其中'<bochs:1>'是命令輸入提示符,其中的數字表示當前的命令序列號。在命令提示符'<bochs:1>'後面鍵入'help'命令,可以列出調試系統的基本命令。若要了解某個命令的具體使用方法,可以鍵入'help'命令並且後面跟隨一個用單引號括住的具體命令,例如:“help 'vbreak'”,如下面所示。
<bochs:1> help
help - show list of debugger commands
help 'command'- show short command description
-*- Debugger control -*-
help, q|quit|exit, set, instrument, show, trace-on, trace-off,
record, playback, load-symbols, slist
-*- Execution control -*-
c|cont, s|step|stepi, p|n|next, modebp
-*- Breakpoint management -*-
v|vbreak, lb|lbreak, pb|pbreak|b|break, sb, sba, blist,
bpe, bpd, d|del|delete
-*- CPU and memory contents -*-
x, xp, u|disas|disassemble, r|reg|registers, setpmem, crc, info, dump_cpu,
set_cpu, ptime, print-stack, watch, unwatch, ?|calc
<bochs:2> help 'vbreak'
help vbreak
vbreak seg:off - set a virtual address instruction breakpoint
<bochs:3>
爲了讓Bochs直接模擬執行到Linux的引導啓動程序開始處,我們可以先使用斷點命令在0x7c00處設置一個斷點,然後讓系統連續運行到0x7c00處停下來。執行的命令序列如下:
<bochs:3> vbreak 0x0000:0x7c00
<bochs:4> c
(0) Breakpoint 1, 0x7c00 (0x0:0x7c00)
Next at t=4409138
(0) [0x00007c00] 0000:7c00 (unk. ctxt): mov ax, 0x7c0 ; b8c007
<bochs:5>
此時,CPU執行到boot.s程序開始處的第1條指令處,Bochs主窗口將顯示出“Boot From floppy...”等一些信息。現在,我們可以利用單步執行命令's'或'n'(不跟蹤進入子程序)來跟蹤調試程序了。在調試時可以使用Bochs的斷點設置命令、反彙編命令、信息顯示命令等來輔助我們的調試操作。下面是一些常用命令的示例:
<bochs:8> u /10 # 反彙編從當前地址開始的10條指令。
00007c00: ( ): mov ax, 0x7c0 ; b8c007
00007c03: ( ): mov ds, ax ; 8ed8
00007c05: ( ): mov ax, 0x9000 ; b80090
00007c08: ( ): mov es, ax ; 8ec0
00007c0a: ( ): mov cx, 0x100 ; b90001
00007c0d: ( ): sub si, si ; 29f6
00007c0f: ( ): sub di, di ; 29ff
00007c11: ( ): rep movs word ptr [di], word ptr [si] ; f3a5
00007c13: ( ): jmp 9000:0018 ; ea18000090
00007c18: ( ): mov ax, cs ; 8cc8
<bochs:9> info r # 查看當前CPU寄存器的內容
eax 0xaa55 43605
ecx 0x110001 1114113
edx 0x0 0
ebx 0x0 0
esp 0xfffe 0xfffe
ebp 0x0 0x0
esi 0x0 0
edi 0xffe4 65508
eip 0x7c00 0x7c00
eflags 0x282 642
cs 0x0 0
ss 0x0 0
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
<bochs:10> print-stack # 顯示當前堆棧的內容
0000fffe [0000fffe] 0000
00010000 [00010000] 0000
00010002 [00010002] 0000
00010004 [00010004] 0000
00010006 [00010006] 0000
00010008 [00010008] 0000
0001000a [0001000a] 0000
...
<bochs:11> dump_cpu # 顯示CPU中的所有寄存器和狀態值。
eax:0xaa55
ebx:0x0
ecx:0x110001
edx:0x0
ebp:0x0
esi:0x0
edi:0xffe4
esp:0xfffe
eflags:0x282
eip:0x7c00
cs:s=0x0, dl=0xffff, dh=0x9b00, valid=1
ss:s=0x0, dl=0xffff, dh=0x9300, valid=7
ds:s=0x0, dl=0xffff, dh=0x9300, valid=1
es:s=0x0, dl=0xffff, dh=0x9300, valid=1
fs:s=0x0, dl=0xffff, dh=0x9300, valid=1
gs:s=0x0, dl=0xffff, dh=0x9300, valid=1
ldtr:s=0x0, dl=0x0, dh=0x0, valid=0
tr:s=0x0, dl=0x0, dh=0x0, valid=0
gdtr:base=0x0, limit=0x0
idtr:base=0x0, limit=0x3ff
dr0:0x0
dr1:0x0
dr2:0x0
dr3:0x0
dr6:0xffff0ff0
dr7:0x400
tr3:0x0
tr4:0x0
tr5:0x0
tr6:0x0
tr7:0x0
cr0:0x60000010
cr1:0x0
cr2:0x0
cr3:0x0
cr4:0x0
inhibit_mask:0
done
<bochs:12>
由於Linux 0.11內核的32位代碼是從絕對物理地址0處開始存放的,因此若想直接執行到32位代碼開始處,即head.s程序開始處,我們可以在線性地址0x0000處設置一個斷點並運行命令'c'執行到那個位置處。
另外,當直接在命令提示符下打回車鍵時會重複執行上一個命令;按向上方向鍵會顯示上一命令。其他命令的使用方法請參考'help'命令。
14.8.2 定位內核中的變量或數據結構
在編譯內核時會產生一個system.map文件。該文件列出了內核Image (bootimage)文件中全局變量和各個模塊中的局部變量的偏移地址位置。在內核編譯完成後可以使用前面介紹的文件導出方法把system.map文件抽取到主機環境(windows)中。有關system.map文件的詳細功能和作用請參見2.10.3節。system.map樣例文件中的部分內容見如下所示。利用這個文件,我們可以在Bochs調試系統中快速地定位某個變量或跳轉到指定的函數代碼處。
...
Global symbols:
_dup: 0x16e2c
_nmi: 0x8e08
_bmap: 0xc364
_iput: 0xc3b4
_blk_dev_init: 0x10ed0
_open: 0x16dbc
_do_execve: 0xe3d4
_con_init: 0x15ccc
_put_super: 0xd394
_sys_setgid: 0x9b54
_sys_umask: 0x9f54
_con_write: 0x14f64
_show_task: 0x6a54
_buffer_init: 0xd1ec
_sys_settimeofday: 0x9f4c
_sys_getgroups: 0x9edc
...
同樣,由於Linux 0.11內核的32位代碼是從絕對物理地址0處開始存放的,system.map中全局變量的偏移位置值就是CPU中線性地址位置,因此我們可以直接在感興趣的變量或函數名位置處設置斷點,並讓程序連續執行到指定的位置處。例如若我們想調試函數buffer_init(),那麼從system.map文件中可以知道它位於0xd1ec處。此時我們可以在該處設置一個線性地址斷點,並執行命令'c'讓CPU執行到這個指定的函數開始處,見如下所示。
<bochs:12> lb 0xd1ec # 設置線性地址斷點。
<bochs:13> c # 連續執行。
(0) Breakpoint 2, 0xd1ec in ?? ()
Next at t=16689666
(0) [0x0000d1ec] 0008:0000d1ec (unk. ctxt): push ebx ; 53
<bochs:14> n # 執行下一指令。
Next at t=16689667
(0) [0x0000d1ed] 0008:0000d1ed (unk. ctxt): mov eax, dword ptr ss:[esp+0x8] ; 8b442408
<bochs:15> n # 執行下一指令。
Next at t=16689668
(0) [0x0000d1f1] 0008:0000d1f1 (unk. ctxt): mov edx, dword ptr [ds:0x19958] ; 8b1558990100
<bochs:16>
程序調試是一種技能,需要多練習才能熟能生巧。上面介紹的一些基本命令需要組合在一起使用才能靈活地觀察到內核代碼執行的整體環境情況。
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/Hou_Rj/archive/2009/02/21/3918347.aspx