BWDSP是一款我國自主研發的多核高性能通用DSP。BWDSP的體系結構、指令集、配套基礎軟件全部由中電38所自主設計開發。BWDSP的配套基礎軟件包括匯編器、編譯器、調試器、集成開發環境、芯片模擬器等等。BWDSP芯片的調試器軟件包括主機調試器軟件和調試鏈接服務軟件兩部分。調試鏈接服務軟件運行于ICE(In Circuit Emulator)上,起到主機與芯片之間通信互聯的功能。而主機調試器軟件是調試系統的核心,負責解析用戶命令、分析調試信息、管理可執行文件、管理斷點(和觀察點)、單步調試控制等等[1]。BWDSP的調試系統支持匯編級調試和C語言級調試。在開發BWDSP芯片調試系統的C語言單步調試功能的過程中,研發人員分析了國內外類似工作的可取之外和不足之處,自主創新開發出實現方案。 國內已經陸續有研究機構自主創新開始調試系統的研發工作[2-7],但這些工作在實現C語言單步調試方面都存在一些不足。文獻[2-3]中的單步調試功能是匯編語言級的單步調試。文獻[7]中的調試系統雖然實現了C語言級單步調試功能,但并未充分考慮到C語言一行代碼可能的復雜性,只能實現簡單C語言代碼的單步調試功能。本文提出的方案充分考慮了C語言單步調試需要面臨的問題,可以實現任意復雜程序的C語言代碼行的單步調試功能。本方案原理簡單,容易理解,并經過大量BWDSP芯片調試過程的檢驗,已經證明了其正確性。 1。單步調試功能簡介 單步調試指以源代碼行為單位對被調試程序的運行進行控制的調試功能。單步調試不需要用戶顯式地設置斷點,可以控制程序運行一個或若干個代碼行。通過這種方式,用戶可以結合變量查看、堆棧查看、觀察點等調試功能,把潛在的程序錯誤定位至某個代碼行。單步調試功能一般分為兩大類:匯編級單步調試功能和源代碼級單步調試功能。匯編級單步調試功能指單步調試控制運行的單位是匯編語言的代碼行。源代碼級單步調試指單步調試控制運行的單位是高級語言源代碼中的代碼行。每類單步調試功能一般又包括三種:跳入、跳過、跳出。 對于匯編級單步調試,三種單步調試功能的實現較為簡單,其功能概述如下: 跳入調試功能控制被調試程序運行至當前代碼行中調用的函數內部。若當前代碼行中無函數調用,則控制被調試程序運行完當前代碼行。 跳過指控制被調試程序運行完當前代碼行。若當前代碼行中有函數調用,則控制被調試程序執行完該函數調用并繼續運行完當前代碼行。 跳出指控制被調試程序運行至當前函數的返回地址處。 對于高級語言如C語言,其三種單步調試功能從總體概念上和匯編級單步調試功能類似。但由于C語言一行代碼經編譯后生成一段匯編指令,且一行代碼中的語句可能非常復雜,其單步調試功能相對于匯編級單步調試更為復雜。C語言單步調試功能的實現要面對如下幾個問題: 1.程序當前PC(Program Counter,指程序地址)并不一定在一行代碼的最開始處,而有可能在一行代碼生成的一段匯編指令的中間位置。用戶有可能先通過匯編級調試功能使PC停在C語言代碼行的中間位置,然后再進行C語言級單步調試。 2.一行代碼中可能不止一個函數調用。C語言中一行代碼中可以有任意多個函數調用。 3.一行代碼可能有多個return語句。C語言中,一行代碼中可以寫任意長的代碼,其中可能包含若干個條件控制語句(if…else…),每種條件下都可能有一個return語句,程序有可能從其中任意一個return語句處從本函數返回。 4.一行代碼可能有多個出口。若代碼行處于循環之中,則代碼行中每個break(或continue)語句都可以跳出本行。若代碼行中有多個break(或continue)語句,則程序可能從其中任意一個位置離開本行。 5.一行代碼中的出口有可能是條件跳轉的出口,程序并不一定從該出口跳出。條件跳轉根據運行時的具體情況來判斷是否需要跳轉,有可能跳轉,也有可能不跳轉。 6.函數調用有可能以函數指針的方式實現。C語言中定義有函數指針,通過函數指針進行函數調用同樣是函數調用的一種方式,跳入功能的實現必須考慮這種情況。 7.程序的執行可能不是簡單的順序執行。用戶可以把一個完整的循環寫到一行代碼中,因此程序流可能不是順序執行的,有可能回到本代碼行中已經執行過的某個程序位置繼續執行。C語言級單步調試功能的實現不能依賴于程序流的順序執行。 8.一行代碼有可能沒有下一行代碼。如一行代碼位于函數體或源文件的最后一行,則該行代碼是沒有下一行代碼的。運行完該行代碼后程序流只會返回到上一層函數,或跳轉至本函數中其他位置。 9.單步調試過程中可能由于其他原因使調試過程提前結束。若用戶設置了斷點或觀察點,單步調試過程中可能引起這些斷點(或觀察點)的觸發,使單步調試過程提前結束。 由于C語言單步調試功能面臨這些復雜的問題,因此C語言單步調試功能的實現遠比匯編級單步調試功能的實現要復雜。 2 方案概述 2.1 已有方案介紹 目前,單步調試功能的實現方案分為兩大類。一類通過不斷控制程序流按匯編指令行逐行執行,進行匯編級單步執行,每執行一行匯編代碼就控制被調試程序停下來,分析程序地址,根據當前程序地址判斷單步調試功能是否完成。另一類方案通過反匯編當前源代碼行生成的匯編程序段,尋找其中的函數調用、出口地址,在這些位置設置臨時斷點。設置完臨時斷點后,控制程序正常運行,直至遇到斷點停止為止。程序遇到斷點停止又有分為幾種情況,若斷點是用戶顯式設置的斷點,說明在單步調試的過程中遇到用戶斷點,一次單步調試結束。若斷點是為本次單步調試設置的臨時斷點,一次單步調試正常結束。單步調試結束后,還要把為本次單步調試設置的臨時斷點全部刪除。 第一種方案的優點是實現簡單,容易理解。但是,若源代碼行中的代碼很復雜,生成的匯編程序段內容很大,使用第一種方案將使程序反復處于運行和停止狀態,調試效率不高。芯片執行匯編級單步運行的速度也遠遠小于正常運行的速度。尤其是針對嵌入式系統的一些遠程調試系統,調試器和被調試程序運行在不同的機器上,通過串口或網口進行通信,第一種方法將帶來大量的通信負擔。顯然,對于一個高效的嵌入式系統調試器,使用第一種方法是不可行的。本文介紹的單步調試功能實現方法屬于第二類方案。 國內已經有少數研究機構開展單步調試功能的研究,但這些研究并未能完全解決C語言單步調試功能面臨的所有問題。文獻[4-5]按第一種方案實現了一款調試器的單步調試功能,顯然這種實現方式具有不可避免的通信負擔。文獻[6]實現了一款基于串口通信的嵌入式調試系統,其單步調試功能也是基于第一種方案。文獻[7]較為完整地介紹了一款調試器中單步調試功能的實現,其實現方案屬于上述第二類方案,基本完成了C語言調試的主要功能。但該項工作并未考慮到C語言中單步調試功能的復雜性,未能解決上節介紹的第1、6、7、8、9等問題。若被調試代碼中包含較為復雜的代碼,該款調試器的單步調試功能將不能正確完成。 2.2 幾種出口類型介紹 BWDSP芯片調試系統軟件在充分調研了國內外前人工作的基礎上,參考已經成功實現的方案,自主實現了C語言單步調試功能。BWDSP芯片配套調試系統軟件的單步調試功能基于在代碼行出口處設置臨時斷點的方案實現。與國內外已有工作相比,該方案充分考慮了C語言代碼行中的代碼復雜性,可以解決第1節中列舉的9種問題。 BWDSP芯片配套調試系統把一行C語言代碼行的出口分為如下幾類: 1:通過for、while循環、break、continue語句跳轉至其他代碼行,該類出口稱為L(Label)類出口,其出口地址集記為L。C語言中的這些跳轉指令最終編碼為BWDSP芯片指令集中的跳轉指令。BWDSP芯片指令集中的跳轉指令分為四類:①條件跳轉:跳轉有可能發生,也可能不發生,根據運行時的計算結果或寄存器值確定;②絕對跳轉:跳轉一定會發生,跳轉目的地址在指令機器碼中編碼;③相對跳轉:跳轉一定會發生,跳轉目的地址是當前地址加上一個偏移;④寄存器跳轉,跳轉一定會發生,跳轉目的地址是某個寄存器中的值,不能從可執行文件程序段獲取。對于第①②③類跳轉,其目的地址可以從程序段反匯編得到。而對第④類跳轉,其目的地址不能從程序段得到,需要在運行時從某個寄存器中讀取。 2:通過函數調用跳轉至其他行,這類出口稱為F(Function)類出口,這些函數的入口地址集記為F。C語言中的函數調用最終被編碼為BWDSP芯片指令集中的函數調用指令。BWDSP指令集中的函數調用指令分為兩類:①絕對地址函數調用:函數調用的入口地址編碼在指令中,可以從程序段得到;②寄存器函數調用:函數調用的入口地址是調用時某個寄存器中的值。一般,直接調用C語言中的函數會編譯為第一類函數調用指令;通過函數指針調用函數會編譯為第二類函數調用指令。同樣,第一類函數調用的入口地址可以通過反匯編程序段得到,而第二類函數調用的入口地址只能在運行時讀取某個寄存器中的值獲得。 3:通過return語句跳轉至本幀的返回地址,這類出口稱為R(Return)類出口,返回地址記為R。一個函數可能有多個retrun語句,一行C語言代碼中也可能有多處函數返回。但由于程序流一定處于函數調用棧中的棧頂,該函數返回后肯定返回至上一幀的現場,所以當前PC所處的函數中的多處return語句其實返回到同一個地址。而且,由于函數可能在多處被調用,所以該返回地址不能通過反匯編程序段獲得,只能通過運行時函數調用棧獲得。 4:直接運行完本行代碼來到的程序地址,這類出口稱為N(Next),其出口地址記為N。程序運行完當前行后,會自然地運行下一行的指令,因此下一行指令的開始地址也是本行代碼的一個出口地址。對于部分C語言代碼行,并沒有下一行出口地址。例如,若一個代碼行是一函數的最后一行,若執行該行代碼時,或者跳轉至其他行,或返回調用函數,肯定不會進入下一行代碼執行。所以,本類出口可能存在,也可能不存在。 在將一行C語言代碼行的出口分為以上四類的基礎上,BWDSP調試系統通過在這些出口上設置臨時斷點實現單步調試功能。設置的臨時斷點位置不同,實現的單步調試功能也不同。對有些特殊的出口,除了設置臨時斷點,還要做一些特殊處理。下一節將對三種單步調試功能的實現方法進行具體介紹。 3 具體實現 3.1 跳出 跳出是實現方式最簡單的單步調試功能,其功能是跳出當前函數,來到其返回地址處。由于一個函數在運行時返回地址只有一個,即R,所以只需要在R處設置一個臨時斷點,然后讓被調試程序正常運行即可。當程序遇到斷點停下時,若該斷點為用戶設置的斷點,說明單步調試過程中用戶斷點觸發,跳出單步調試結束。若該斷點為臨時斷點R,說明跳出功能正常實現,單步調試結束。該方案可以解決第1節中介紹的第3、9點問題,而其他問題對跳出單步調試功能沒有影響。 圖1 跳出單步調試功能實現流程圖 若當前函數是主函數main函數,則函數棧中只有一幀,無需設置臨時斷點,直接運行即可。 跳出單步調試功能的實現方案流程如圖1所示。 3.2 跳過 跳過功能使程序執行完當前代碼行。若本代碼行中有函數調用,則執行完該函數,并返回本代碼行繼續運行,直至程序自然地跳出該代碼行為止。所以,跳過單步調試功能應在L、N類出口設置臨時斷點。 圖2 跳過單步調試功能實現流程圖 一般,C語言程序在進入函數和跳出函數時會有一小段代碼用來進行函數棧入棧和出棧的操作。這一小段代碼在調試信息中一般與源代碼中函數開始和結束時的正反大括號對應。單步調試時,若代碼行中有return語句,該語句實際上被編譯為一個跳轉語句,跳轉至函數結尾的大括號處,并不會真正返回上一層調用函數。若代碼行中有函數結束時的大括號,則程序在該代碼行中真正有可能返回調用函數。返回上一層調用函數的指令在BWDSP指令集中被編碼為RET指令,因此可以通過檢查代碼行中是否有RET指令判斷該代碼行是否有可能返回調用函數。若代碼行中有RET指令,還要在R類出口處設置斷點。該方法可以解決第1節中介紹的第8個問題。 程序PC即使在一行代碼中間某個位置,也有可能跳回到該行代碼的開始位置繼續執行。設置臨時斷點時,需要在該行代碼中的全部L類出口處都設置斷點,不管該跳轉指令是在當前PC之前還是之后。這種方案可以解決第1、7個問題。 對于L類出口中的第①類跳轉(條件跳轉)出口,不論該跳轉是否會發生,都在該出口處設置臨時斷點。若程序執行了該條件跳轉,本方案可以使跳過單步調試功能正常結束。若程序沒有執行該條件跳轉,設置的該臨時斷點也不會對單步調試功能產生影響。這種方案解決了第5個問題。 對于L類出口中的第④類跳轉(寄存器跳轉),其出口地址不能在運行之前獲得,因此也不能在出口處設置臨時斷點。對這類跳轉,需要在其跳轉指令處設置臨時斷點,若該臨時斷點觸發,讀取其跳轉目的地址寄存器的值。若讀到的跳轉目的地址在本行代碼中,則保留所有已經設置的臨時斷點,繼續運行程序。若該跳轉的目的地址不在本行代碼中,則控制程序進行一次匯編級指令行單步以執行該跳轉,然后結束本次單步調試過程。 由于本方案沒有在函數調用出口出設置斷點,若源代碼行中有多個函數調用,這些函數調用會依次執行,不會觸發斷點。因此,本方案可以解決第2個問題。 被調試程序觸發以上設置的臨時斷點中的任意一個,都意味著單步跳過調試過程的結束。所以,只要臨時斷點位置是代碼行的合法可能出口,設置多個臨時斷點不會對單步調試功能的正確性產生影響。顯然,該方案可以解決第4個問題。 本方案解決了第1節中介紹的第1、2、3、4、5、7、8、9問題,而第6個問題不會對跳過單步調試功能產生影響。跳過單步調試的實現方案流程如圖2所示。 3.3跳入 跳入調試功能使程序可以進入代碼行中調用的函數內部。若程序在當前代碼行中的執行過程中沒有遇到函數調用,則執行完本代碼行即完成單步調試功能,此時其調試功能與跳過單步調試類似。顯然,實現單步跳入調試功能需要在L、F、R、N處都設置臨時斷點。 對于F類出口中的第②類函數調用(寄存器函數調用),同樣需要在函數調用指令處設置臨時斷點。當該臨時斷點觸發時,控制程序進行一次匯編級指令行單步,使程序進入調用函數。該方法可以解決第6個問題。 圖3 跳入單步調試功能實現流程圖 由于本方案在所有函數調用處都設置了斷點,所以程序會停止在執行過程中的第一個函數調用出口。調試行為表現為程序會跳入執行過程中遇到的第一個函數。 第1節中介紹的所有問題都對跳入單步調試功能有影響,而本方案可以解決所有9個問題。 跳入調試功能的實現流程如圖3所示。 3.4 實驗結果 BWDSP芯片配套調試系統的C語言單步調試功能按照本文介紹的方案實施。開發人員以任意復雜的C語言代碼行在各種復雜的調試場景下對單步調試功能進行測試,調試系統均可按單步調試預定義的功能完成調試過程。目前,在BWDSP芯片的模擬器、編譯器、操作系統開發過程中,均已經在項目組內部試用本調試器進行C語言級調試。經過反復測試、試用、修改,本方案已經證實是一個健壯的實施方案,可以實現任意復雜C語言代碼行的單步調試功能。 總結 本文介紹了BWDSP芯片調試系統中C語言單步調試功能的實現方案。該方案充分研究了C語言一行源代碼中可能對單步調試功能產生影響的各種情況,充分考慮了C語言代碼行的復雜性,可以實現任意復雜C語言代碼行的單步調試功能。經BWDSP芯片調試過程的驗證,證實了本方案的有效性。 [1]黃光紅,劉冠南。可配置多核處理器的調試器模塊化分層設計[J]。單片機與嵌入式系統應用,2014,14(7):13-15。 [2]向征。基于C30的嵌入式計算機自主調試環境的建立和軟件設計[J]。微電子學與計算機,1999,3,18-20,56。 [3]文躍榮。基于UART的電能芯片在線調試設計[D]。湖南大學,2012。 [4]劉曉升,王宜懷。HC08系列微控制器在線調試的關鍵技術分析[J]。計算機工程與設計,2009,30(3),532-535。 [5]龔蘭蘭,劉曉升,朱巧明。遠程調試系統的關鍵技術分析[J]。計算機應用與軟件,2010,27(10),258-261。 [6]梁泉。嵌入式系統交叉調試器的設計與實現[D]。電子科技大學,2008。 [7]趙民棟。嵌入式軟件集成開發環境中調試器的設計與實現[D]。西北工業大學,2004。 |