Gdb/Armulator 源代碼分析
作者Email: Anti_chen2000@sohu.com 摘要 Gdb/Armulator 是Gdb自帶的arm7模擬器,是調(diào)試arm程序的一個(gè)好工具.而了解它的原碼結(jié)構(gòu)對(duì)擴(kuò)展它的IO功能有重要意義.本文介紹了從Armulator的啟動(dòng)到其內(nèi)部運(yùn)作和IO擴(kuò)展的大部分原代碼功能. 說(shuō)明 源代碼用的是gdb-5.0.tar+ gdb-5.0-uclinux-armulator-20021127.patch A. 和GDB間的通迅 Armulator一般和Gdb通訊有兩種方式,其一是在Gdb內(nèi)部直接調(diào)用模擬器的相關(guān)函數(shù),另一方法則是用pipe或socket傳遞RDP協(xié)議來(lái)連接Gdb和Amulator.而第一種方法是現(xiàn)在Gdb/Armulator所真正使用的(第二種是早期使用的方法),下面就分析了函數(shù)直接調(diào)用法. 函數(shù)直接調(diào)用 這個(gè)方法是由Steve (sac@cygnus.com) 修改原RDP方法而來(lái)的,Steve本人的描述如下: It likes to use TCP/IP between the simulator and the host, which is I've added created a new Makefile.in (the original in Makefile.orig) It should be possible (barring major changes in the layout of (Except that I changed armos.c to work more simply with our 以下是RDP 通訊和直接函數(shù)調(diào)用的圖示: 要清楚Armulator的執(zhí)行過(guò)程就要從它的啟動(dòng)說(shuō)起,當(dāng)你在Gdb中鍵入target sim 去激活A(yù)mulator后Gdb首先進(jìn)行命令行解釋,并將current_target指針指向sim變量,即將Armulator的調(diào)試函數(shù)集賦予Gdb,隨后的函數(shù)調(diào)用堆棧如下: --àgdbsim_open (…) in remote-sim.c. 至此Armulator被裝載完畢,其后Gdb就是通過(guò)target_ops(定義在target.h)結(jié)構(gòu)中的各個(gè)函數(shù)指針來(lái)完成對(duì)它的調(diào)試工. B. Armulator 內(nèi)部機(jī)制 a. 初始化 從上述可知整個(gè)模擬器的初始化入口是在wrapper.c中的init( )函數(shù),那么它到底又做了些什么呢? (原始的Gdb5.0中的Armulator是模擬ARM7DTMI 的,而補(bǔ)丁代碼修改了memory map 并添加了timer 和uart 的IO能力使其能夠模擬AT91.因?yàn)楹笳呤菍?duì)前者的增強(qiáng),所以我們的分析以后者為準(zhǔn)) Once the armulator to reset ,the ARMul_NewState will be called.And its task is to malloc a ARMul_state stuct which saves the armulator’s states and initialize it .And the ARMul_MemoryInit() will malloc 4m ram for you. 因?yàn)檫@是補(bǔ)丁代碼,難免又冗余出現(xiàn),實(shí)際10-11行的兩處掉用是沒(méi)有實(shí)際意義的,而12行是協(xié)處理器的初始化,因?yàn)椴](méi)又模擬協(xié)處理器所以此處只是以備擴(kuò)展. 重點(diǎn)的初始化過(guò)程是在ARMul_NewState(…)中的.首先它給模擬器的核心狀態(tài)結(jié)構(gòu)ARMul_State分配了空間,這個(gè)結(jié)構(gòu)里保存了Armulator的所有方面的狀態(tài),包括arm寄存器,流水線狀態(tài)等等. 并賦予初值,我們以后就用state表示之.然后調(diào)用ARMul_Reset(…)進(jìn)行更近一步的設(shè)置.而后者又主要完成模擬器內(nèi)存結(jié)構(gòu)的分配和rom映象的加載--/sim/arm/armmem.c/mem_reset(…),IO設(shè)備的狀態(tài)初始—/sim/arm/armio.c/io_reset(…),你也可在這添加你的初始代碼.到這就完成了Armulator的裝載. (大家注意到18行也調(diào)用了ARMul_Reset(…),這是一個(gè)BUG,使得模擬器進(jìn)行了兩次內(nèi)存分配,而浪費(fèi)了系統(tǒng)內(nèi)存.此處可刪去.) Memory map 是所有模擬器的關(guān)鍵.Armulator由AT91向其他MCU移植時(shí)Memory map又是首先要處理的.Armulator的各個(gè)內(nèi)存區(qū)是由mem_bank_t結(jié)構(gòu)來(lái)描述的: typedef struct mem_bank_t { 根據(jù)mem_banks,mem_reset( )將分配空間,加載boot.rom文件. (原來(lái)的內(nèi)存是由ARMul_MemoryExit( )釋放的,但補(bǔ)丁后的代碼就沒(méi)了釋放功能,這也是需要糾正的地方) a. 指令流 Armulator 加載完成后,就開(kāi)始等待Gdb的運(yùn)行命令了.最終/sim/wrapper.c/sim_resume( )是啟動(dòng)arm指令執(zhí)行的地方. Sim_resume( )根據(jù)Gdb的要求選擇用/sim/arm/arminit.c/ARMul_DoInstr()還是用/sim/arm/arminit.c/ARMul_DoProg()來(lái)調(diào)用 流水線模擬函數(shù)/sim/arm/armemu.c/ARMul_Emulate32().ARMul_DoInstr()和ARMul_DoProg()的區(qū)別就是一個(gè)單步執(zhí)行,一個(gè)連續(xù)執(zhí)行指令. ARMul_DoProg()又不停的判斷state->Emulate是否為STOP,如果是,模擬器又將停下等待Gdb的調(diào)試. 而在arm/armemu.c, /arm/armvirt.c 和 /arm/armsupp.c中的函數(shù)則模擬指令預(yù)取,指令譯碼,指令執(zhí)行以及數(shù)據(jù)回寫(xiě)的功能.這三個(gè)文件時(shí)可以說(shuō)時(shí)Armulator的核心! b. 中斷 Armulator 的中斷機(jī)制主要靠以下兩個(gè)例程實(shí)現(xiàn): 1.IntPending(): 用來(lái)檢測(cè)state中的各個(gè)中斷標(biāo)志是否置位,從而判斷是否又需要中斷. 2.ARMul_Abort():當(dāng)需要中斷時(shí),用來(lái)改變處理器模式,并將pc指向相應(yīng)的中斷向量. 在流水線函數(shù)ARMul_Emulate32()執(zhí)行當(dāng)中,有多處調(diào)用IntPending() 去檢測(cè)中斷.而Ispending() 也十分簡(jiǎn)單,它僅僅判斷state中的四個(gè)變量: State->Exception : 中斷使能標(biāo)志. b. 讀寫(xiě)操作 無(wú)論是CPU指令還是Gdb調(diào)試時(shí)讀寫(xiě)內(nèi)存或IO空間,最后都將要落到/armvirt.c/getword(), /armvirt.c/putword()這兩個(gè)函數(shù)身上. 在原始代碼中這兩個(gè)函數(shù)馬上就進(jìn)行內(nèi)存數(shù)組的讀寫(xiě)了.而補(bǔ)丁代碼的流程如下: --àgetword()/putword() 可以看出最后幾個(gè)函數(shù)的選擇是由讀寫(xiě)地址在相應(yīng)的mem_bank_t結(jié)構(gòu)中的讀寫(xiě)函數(shù)指針決定的. c. 設(shè)備同步 寫(xiě)這篇文章的初衷是讓讀者能很快進(jìn)入Armulator的移植和IO擴(kuò)展的實(shí)際工作中去.所以這里有必要討論一下IO設(shè)備和CPU的同步問(wèn)題.很顯然我們模擬的設(shè)備不能太快,也不能太慢.快了CPU正常的指令流將被堵塞,慢了就無(wú)法反映操作系統(tǒng)的實(shí)時(shí)性.也就是說(shuō)設(shè)備的速度和指令流要有個(gè)比例關(guān)系,即要有一定的同步. Armulator 中有個(gè)很好的接口: ARMul_ScheduleEvent (ARMul_State * state, unsigned long delay, unsigned (*what) ()) in armvirt.c 它的目的就是注冊(cè)你的同步例程,并且每個(gè)時(shí)鐘周期即ARMul_Emulate32()將調(diào)用ARMul_ScheduleEvent()查看是否需要同步你的設(shè)備. 也許你在ARMul_Emulate32()中還發(fā)現(xiàn)了/sim/arm/armio.c/io_do_cycle(),沒(méi)錯(cuò)它是AT91的timer和uart用來(lái)和指令流同步的函數(shù),但我并不贊成你象這樣把自己的同步例程直接放入指令執(zhí)行過(guò)程中,破壞代碼的結(jié)構(gòu)性. a. 源文件描述
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|