在前文,我們介紹了如何創(chuàng)建自己的啟動鏡像朋魔,并在屏幕輸出了"Hello bochs!"打印,本文將以這個啟動鏡像為對象站玄,介紹如何使用bochs提供的調(diào)試功能掖举,本文將介紹如何使用命令行調(diào)試功能朗徊。
bochs提供的調(diào)試功能主要分為執(zhí)行控制夷野、斷點功能、內(nèi)存監(jiān)測荣倾、內(nèi)存操作悯搔、信息查詢、CPU寄存器操作舌仍、反匯編妒貌、指令跟蹤等,本文的示例將會介紹最簡單和常用的一些命令功能铸豁,調(diào)試功能的具體命令可以參考這里灌曙,更多細節(jié)請參考官網(wǎng)。
跟蹤調(diào)測我們的程序
首先节芥,啟動我們的程序在刺,可以參考創(chuàng)建可使用的鏡像,使用bochs -f bochsrc
啟動后如下头镊,選擇6進入調(diào)試界面:
$ bochs -f bochsrc
========================================================================
Bochs x86 Emulator 2.7
Built from SVN snapshot on August 1, 2021
Timestamp: Sun Aug 1 10:07:00 CEST 2021
========================================================================
00000000000i[ ] BXSHARE not set. using compile time default '/usr/local/share/bochs'
00000000000i[ ] reading configuration from bochsrc
------------------------------
Bochs Configuration: Main Menu
------------------------------
This is the Bochs Configuration Interface, where you can describe the
machine that you want to simulate. Bochs has already searched for a
configuration file (typically called bochsrc.txt) and loaded it if it
could be found. When you are satisfied with the configuration, go
ahead and start the simulation.
You can also start bochs with the -q option to skip these menus.
1. Restore factory default configuration
2. Read options from...
3. Edit options
4. Save options to...
5. Restore the Bochs state from...
6. Begin simulation
7. Quit now
Please choose one: [6] 6
00000000000i[ ] installing x module as the Bochs GUI
00000000000i[ ] using log file bochsout.txt
Next at t=0
(0) [0x0000fffffff0] f000:fff0 (unk. ctxt): jmpf 0xf000:e05b ; ea5be000f0
<bochs:1>
程序此時會停留蚣驼,等待我們進一步的指令,我們來稍微看一下輸出的信息相艇,注意到這樣一行[0x0000fffffff0] f000:fff0 (unk. ctxt): jmpf 0xf000:e05b ; ea5be000f0
颖杏,這個也就是BIOS啟動引導分區(qū)過程簡介中提到的,上電后BIOS會加載到0xf000:0xfff0處坛芽,然后處理器跳到CS:IP=0xf000:fff0處執(zhí)行BIOS代碼留储。我們可以使用sreg
命令查看一下段寄存器,使用reg
查看一下普通寄存器的內(nèi)容咙轩,結(jié)果如下:
Please choose one: [6] 6
00000000000i[ ] installing x module as the Bochs GUI
00000000000i[ ] using log file bochsout.txt
Next at t=0
(0) [0x0000fffffff0] f000:fff0 (unk. ctxt): jmpf 0xf000:e05b ; ea5be000f0
<bochs:1> sreg
es:0x0000, dh=0x00009300, dl=0x0000ffff, valid=7
Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed
cs:0xf000, dh=0xff0093ff, dl=0x0000ffff, valid=7
Data segment, base=0xffff0000, limit=0x0000ffff, Read/Write, Accessed
ss:0x0000, dh=0x00009300, dl=0x0000ffff, valid=7
Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed
ds:0x0000, dh=0x00009300, dl=0x0000ffff, valid=7
Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed
fs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=7
Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed
gs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=7
Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed
ldtr:0x0000, dh=0x00008200, dl=0x0000ffff, valid=1
tr:0x0000, dh=0x00008b00, dl=0x0000ffff, valid=1
gdtr:base=0x00000000, limit=0xffff
idtr:base=0x00000000, limit=0xffff
<bochs:2> reg
eax: 0x00000000 0
ebx: 0x00000000 0
ecx: 0x00000000 0
edx: 0x00000000 0
esp: 0x00000000 0
ebp: 0x00000000 0
esi: 0x00000000 0
edi: 0x00000000 0
eip: 0x0000fff0
eflags 0x00000002: id vip vif ac vm rf nt IOPL=0 of df if tf sf zf af pf cf
<bochs:3>
可以看到cs:0xf000
获讳,eip: 0x0000fff0
,與理論過程完全一致活喊。此時丐膝,還并未執(zhí)行到我們編寫的程序,為了讓程序在進入我們編寫的Hello bochs!
(如何編寫參考這里)時停止,我們需要打一個斷點尤误,從BIOS啟動引導分區(qū)過程簡介我們知道,BIOS會把我們編寫的啟動扇區(qū)加載到0x7c00地址處執(zhí)行结缚,因此我們在此處打一個斷點损晤,命令為b 0x7c00
,執(zhí)行完后可以使用命令info break
查看目前有哪些斷點:
<bochs:3> b 0x7c00
<bochs:4> info break
Num Type Disp Enb Address
1 pbreakpoint keep y 0x000000007c00
<bochs:5>
可以看到红竭,成功的在0x7c00處打了斷點尤勋,預期程序會在執(zhí)行到該地址時停止,此時需要我們讓程序繼續(xù)執(zhí)行下去指導斷點停止茵宪,輸入c
(意為continue)繼續(xù)執(zhí)行程序直到遇到一個斷點最冰。
<bochs:5> c
(0) Breakpoint 1, 0x00007c00 in ?? ()
Next at t=47628826
(0) [0x000000007c00] 0000:7c00 (unk. ctxt): mov ax, cs ; 8cc8
<bochs:6>
如預期,程序在0x7c00處停了下來稀火,說明斷點生效了暖哨,并且可以看到此處的代碼是mov ax, cs
,也正是我們編寫的Hello bochs!
程序的第一行代碼凰狞∑茫可以執(zhí)行reg
和sreg
看一下寄存器的情況,可以看到BIOS執(zhí)行完后赡若,程序跳到了CS:IP=0x0000:0x7c00位置執(zhí)行:
<bochs:6> reg
eax: 0x0000aa55 43605
ebx: 0x00000000 0
ecx: 0x00090000 589824
edx: 0x00000000 0
esp: 0x0000ffd6 65494
ebp: 0x00000000 0
esi: 0x000e0000 917504
edi: 0x0000ffac 65452
eip: 0x00007c00
eflags 0x00000082: id vip vif ac vm rf nt IOPL=0 of df if tf SF zf af pf cf
<bochs:7> sreg
es:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1
Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed
cs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1
Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed
ss:0x0000, dh=0x00009300, dl=0x0000ffff, valid=7
Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed
ds:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1
Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed
fs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1
Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed
gs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1
Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed
ldtr:0x0000, dh=0x00008200, dl=0x0000ffff, valid=1
tr:0x0000, dh=0x00008b00, dl=0x0000ffff, valid=1
gdtr:base=0x000f9ad7, limit=0x30
idtr:base=0x00000000, limit=0x3ff
<bochs:8>
bochs有個細節(jié)做的很好达布,就是每一次暫停程序執(zhí)行等待用戶輸入調(diào)試指令,都會在<bochs: 數(shù)字>提示符中顯示一個遞增的數(shù)字逾冬,表示當前是多少次暫停了黍聂。
使用n
(next)可以繼續(xù)執(zhí)行:
<bochs:10> n
Next at t=47628827
(0) [0x000000007c02] 0000:7c02 (unk. ctxt): mov ds, ax ; 8ed8
<bochs:11>
可以使用x
或xp
來查看對應(yīng)地址(物理地址)的內(nèi)容:
<bochs:15> xp /16bx 0x7c00
[bochs]:
0x00007c00 <bogus+ 0>: 0x8c 0xc8 0x8e 0xd8 0x8e 0xc0 0xbd 0x1b
0x00007c08 <bogus+ 8>: 0x7c 0xb9 0x0c 0x00 0xb4 0x13 0xb0 0x01
<bochs:16>
使用exit
退出調(diào)試。