專利名稱:于一計算機系統(tǒng)執(zhí)行一函數時找出函數呼叫堆棧的方法
技術領域:
本發(fā)明涉及一種可于一計算機系統(tǒng)執(zhí)行一函數時找出函數呼叫堆棧的方法,特別是涉及一種在不增加任何額外的系統(tǒng)負擔下可于一計算機系統(tǒng)執(zhí)行一函數時找出函數呼叫堆棧的方法。
背景技術:
在一計算機系統(tǒng)中,動態(tài)配置一內存區(qū)塊給一函數使用是一個基本的系統(tǒng)服務,各個函數可在需要的時候去要求該計算機系統(tǒng)動態(tài)地配置一內存區(qū)塊給它,然后在確定不需要使用該內存區(qū)塊后,將該已配置的內存區(qū)塊歸還給該計算機系統(tǒng),以實現內存資源共享的目的。而在各執(zhí)行線程(thread)或程序(process)由主函數開始執(zhí)行時,會依據動態(tài)時期的外界輸入(input)、系統(tǒng)的訊息(message)或硬件的中斷,依需要呼叫其它的子函數來執(zhí)行其它功能,而子函數亦可根據程序邏輯繼續(xù)巢狀地呼叫其它函數,如此反復組合各種函數則可實現程序執(zhí)行的目的。因為一個函數被呼叫的時機有各種可能,故當該計算機系統(tǒng)的處理器正在執(zhí)行某一函數時,若能取得整個函數呼叫堆棧,方能清楚得知此時函數被呼叫的原因與時機,即此一信息特別有利于軟件除錯時問題的追蹤與判斷。
請參閱圖1,圖1為現有一計算機系統(tǒng)10的功能方塊圖。計算機系統(tǒng)10包含有一微處理器12、一閃存(flash memory)14、一隨機儲存內存(randomaceess memory,RAM)16與一暫存內存18。于計算機系統(tǒng)10的運作為微處理器12存取閃存14、隨機儲存內存16或暫存內存18內所儲存的數據,并執(zhí)行必要的運算。閃存14為一非易失性(non-volatile)內存,儲存有一第一函數F1的原始碼FS1、一第二函數F2的原始碼FS2以及兩個對應第一函數的假指令(pre-process directive),分別為“__FILE__”以及“__LINE__”,這些假指令的功用會于之后的篇幅解釋。隨機儲存內存16為一易失性(volatile)內存,其包含有多個內存區(qū)塊(memory block)16a、16b、16c,內存區(qū)塊16a擁有一文件頭16ah,內存區(qū)塊16b擁有一標題16bh,而內存區(qū)塊16c擁有一標題16ch。此外,計算機系統(tǒng)10中,暫存內存18用來儲存微處理器12對一函數進行編譯(compile)后所產生的執(zhí)行碼。
請同時參閱圖1與圖2,圖2為圖1所示的第一函數F1呼叫第二函數F2的示意圖。當微處理器12編譯一個包含有第一函數F1與第二函數F2的程序,于程序編譯(compile time)的過程中,可知第一函數F1中的第L1行程序代碼的內容為呼叫第二函數F2,此時,依據現有技術,微處理器12會將第一函數F1的函數名稱(例如F1)紀錄于假指令__FILE__內,而將行號L1紀錄于假指令__LINE__內。在程序編譯完成之后,微處理器12便產生一對應第一函數F1的第一函數執(zhí)行碼FE1以及一對應第二函數F2的第二函數執(zhí)行碼FE2,此時第一函數執(zhí)行碼FE1與第二函數執(zhí)行碼FE2皆儲存于暫存內存18內。
于本實施例中,第一函數F1呼叫第二函數F2的目的為要求計算機系統(tǒng)10將某一內存區(qū)塊配置予第一函數F1,因此,在程序編譯完成后,接下來于程序執(zhí)行(run time)時,當計算機系統(tǒng)10執(zhí)行第一函數執(zhí)行碼FE1的內容到了對應行號L1的部分,程序執(zhí)行點會跳躍(branch)到第二函數執(zhí)行碼FE2所在的地址,亦即從第二函數F2的起點開始執(zhí)行第二函數執(zhí)行碼FE2的內容,假設目前計算機系統(tǒng)10應第一函數F1的要求配置給第一函數F1使用的內存區(qū)塊為內存區(qū)塊16b,此時,計算機系統(tǒng)10將內存配置信息記錄在內存區(qū)塊16b的標題(header),也就是將假指令__FILE__與__LINE__所紀錄的內容,分別為第一函數F1的函數名稱(亦即F1)與行號L1,拷貝至內存區(qū)塊16b的標題。如業(yè)界所現有,假指令__FILE__的數據儲存型別(data type)是字符(character),因此若需儲存的函數名稱愈長,即代表假指令__FILE__需占用的儲存空間愈大,而假指令__LINE__內所儲存的行號的數據儲存型別為一整數(integer),通常一整數所占用的空間為四個字節(jié)(4bytes)。在計算機系統(tǒng)10執(zhí)行完第二函數執(zhí)行碼FE2之后,程序執(zhí)行點會跳躍回第一函數F1,繼續(xù)執(zhí)行第一函數F1的第L2行(第L1行的下一行),亦即執(zhí)行第一函數執(zhí)行碼FE1中對應于行號L2的部分。
由上可知,程序設計師可藉由查看內存區(qū)塊16b的文件頭以得知內存區(qū)塊16b是由第一函數F1要求計算機系統(tǒng)10所配置給其使用的內存區(qū)塊。因此,利用現有方法可得知所有內存區(qū)塊的配置情形,檢視內存區(qū)塊為哪一函數要求計算機系統(tǒng)來配置使用,藉以找出計算機死機或程序錯誤的問題根源。然而現有方法于程序編譯時需要占用非易失性內存的空間來紀錄內存配置信息,亦即假指令__FILE__與__LINE__的內容,且于程序執(zhí)行時亦需要拷貝該內存配置信息至隨機儲存內存內,因此提高了計算機系統(tǒng)于時間與內存空間的成本而提高計算機系統(tǒng)的系統(tǒng)負擔(system overhand),而并非有效率的分析死機問題或程序除錯的方法。
發(fā)明內容
本發(fā)明提供一種在不增加任何額外的系統(tǒng)負擔下可于一計算機系統(tǒng)執(zhí)行一函數時找出函數呼叫堆棧的方法,以解決上述的問題。
本發(fā)明披露了一種可于一計算機系統(tǒng)執(zhí)行一函數時找出一函數呼叫堆棧的方法,該方法包含有下列步驟(a)取得執(zhí)行該函數時所產生的一程序指針;(b)依據該程序指針取得相對應的一指令;(c)檢測步驟(b)所取得的該指令是否與一返回地址指令相符;以及(d)當步驟(b)所取得的該指令與該返回地址指令相符時,儲存該程序指針所指向的一指令地址。
本發(fā)明還披露了一種可于一計算機系統(tǒng)執(zhí)行一函數時找出一函數呼叫堆棧的方法,該方法包含有下列步驟(a)取得執(zhí)行該函數時所產生的一程序指針與一堆棧指針;(b)依據該程序指針取得相對應的一指令;(c)檢測步驟(b)所取得的該指令是否與一返回地址指令相符;(d)當步驟(b)所取得的該指令與該返回地址指令不相符時,將該程序指針設成指向于步驟(b)所取得的該指令的一前一指令;(e)檢測步驟(d)所取得的該前一指令是否與該返回地址指令相符;以及(f)當步驟(d)所取得的該前一指令與該返回地址指令相符時,儲存該程序指針于步驟(d)所指向的一指令地址。
圖1為現有計算機系統(tǒng)的功能方塊圖。
圖2為圖1所示的第一函數F1呼叫第二函數F2的示意圖。
圖3為本發(fā)明于計算機系統(tǒng)執(zhí)行函數時找出函數呼叫堆棧的流程圖。
附圖符號說明10計算機系統(tǒng)12微處理器
14 閃存16隨機存取內存16a、16b、16c 內存區(qū)塊16ah、16bh、16ch標題18 暫存內存具體實施方式
請參閱圖3,圖3為本發(fā)明于一計算機系統(tǒng)執(zhí)行一函數(function)時找出函數呼叫堆棧(function call stack)的流程圖,該方法包含有下列步驟步驟100開始。
步驟102取得執(zhí)行該函數時所產生的程序指針(program counter)與堆棧指針(stack pointer)。
步驟104依據該程序指針取得相對應的指令(instruction)。
步驟106檢測步驟104所取得的指令是否與一返回地址指令(Push-LR-to-Stack instruction)相符,若相符執(zhí)行步驟108,若不相符則執(zhí)行步驟110。
步驟108儲存該程序指針所指向的指令地址(address),并跳至步驟116。
步驟110檢測于步驟104所取得的指令是否與一堆棧指針操作指令(stack operation instruction)相符,若相符執(zhí)行步驟112,若不相符則執(zhí)行步驟114。
步驟112復原步驟104所取得的指令對該堆棧指針所做的改變,并跳至步驟114。
步驟114將該程序指針設成指向于步驟104所取得的指令的前一指令,并重新執(zhí)行步驟104。
步驟116比較步驟108所儲存的指令地址是否與該函數的主函數名稱的儲存地址相符,若相符執(zhí)行步驟122,若不相符則執(zhí)行步驟118。
步驟118依據該堆棧指針以取得相對應的返回地址。
步驟120將該程序指針設成指向由步驟118取得的返回地址,并重新執(zhí)行步驟104。
步驟122結束流程。
于此對上述步驟作一詳細說明,首先執(zhí)行該函數時所產生的程序指針與堆棧指針可由數種方式來取得,例如可于該計算機系統(tǒng)死機時由讀取程序指針緩存器與堆棧指針緩存器而得;或于該計算機系統(tǒng)執(zhí)行上下文交換(context switch)時由保留于堆棧(stack)中的程序指針暫存值與堆棧指針暫存值所取得;或如現有技術的圖2利用第一函數F1呼叫第二函數F2時,由第二函數F2取得呼叫者第一函數F1的返回位置,也就是說可得出第一函數F1呼叫第二函數F2后的當下程序指針值,且第二函數F2中的區(qū)域變量的地址便是當下的堆棧指針值,可藉由檢查第二函數F2的組譯文件來得知進入第二函數F2后,堆棧指針會以多少的平移(offset)成為此區(qū)域變量,而反推出第一函數F1呼叫后的堆棧指針。
接下來便可依據該程序指針進行取值操作而得出相對應的指令,而再依據該指令碼來比對檢查此指令是否為將返回緩存器(LR register)所儲存的返回位置存到堆棧的指令。依據編譯器(compiler)處理巢狀函數(nestfunction)的原理,此將返回緩存器所儲存的返回位置存到堆棧的指令就是被呼叫函數(callee)的第一個指令,而可依據不同編譯器所編譯出的組譯文件對微小差異稍做修正。若步驟104所取得的指令與該返回地址指令相符,則代表目前的程序指針已經指到了函數的起點,此時便儲存該程序指針所指向的指令地址,如此一來便可儲存該函數所相對應的內存地址;若步驟104所取得的指令與該返回地址指令不相符,接下來則比對于步驟104所取得的指令是否與一堆棧指針操作指令(stack operation instruction)有關,若為有關,則復原步驟104所取得的指令對該堆棧指針所做的改變。舉例來說,若是該指令對堆棧指針實質上平移了+8,則于此便還原該指令對堆棧指針的影響,而對堆棧指針做出實質上平移-8的操作。之后再將該程序指針設成指向于步驟104所取得的指令的前一指令,并利用更新后的程序指針重新執(zhí)行步驟104,也就是說將目前的程序指針根據該指令的長度,減少一個指令的值。舉例來說,若該指令為32位,則將目前的程序指針實質上減去4,若該指令為16位,則將目前的程序指針實質上減去2,以此類推。若于步驟104所取得的指令與該堆棧指針操作指令無關,則便可將該程序指針設成指向于步驟104所取得的指令的前一指令,并利用更新后的程序指針重新執(zhí)行步驟104。
當步驟104所取得的指令與該返回地址指令相符,且已儲存該程序指針所指向的指令地址,則比較步驟108所儲存的指令地址是否與該函數的主函數名稱的儲存地址相符,也就是說目前程序指針所指向的指令地址是否符合于主函數名稱的儲存地址,若相符,則代表主函數的所有函數呼叫堆棧的地址均已全部取得,故可結束整個流程。若步驟108所儲存的指令地址與該函數的主函數名稱的儲存地址不相符時,則代表主函數的所有函數呼叫堆棧的地址并未全部取得,故此時便必須跳回目前所在函數的上一層函數繼續(xù)進行反推出函數呼叫堆棧的操作,直到跳回一開始的執(zhí)行線程主函數(threadmain function),以取得主函數的所有函數呼叫堆棧的地址。其執(zhí)行程序為根據該返回地址指令對堆棧指針所做的操作進行還原的操作,然后再由還原后的堆棧指針取出返回緩存器所儲存的返回位置。此還原的操作一般是指當該返回地址指令將返回緩存器所儲存的返回位置存入堆棧之后,通常還是會去存取其它緩存器,故必須于該堆棧中額外還原存取其它緩存器對堆棧指針所造成的改變,如此一來方能正確地從堆棧的內存中取出函數呼叫返回地址的值。此外,若是堆棧為不連續(xù)的堆棧幀(stack frame)所組成,亦需根據數據結構找到下一個堆棧幀。最后再將程序指針設成指向還原后的堆棧指針所取出的返回位置,此操作亦即代表由目前函數跳躍回上一層函數的呼叫處,并重新開始遞歸計算。
于得出主函數的所有函數呼叫堆棧的地址后,便可依據一符號配置表(linker map)判斷出所儲存的程序指針所指向的指令地址所對應的函數指令,也就是說可查出各函數地址所代表的函數名稱,如此一來便可在需要的時候找出執(zhí)行線程或程序(process)當下動態(tài)執(zhí)行時期的各函數呼叫堆棧與函數歷史路徑。
相較于現有的找出函數呼叫堆棧的方法,本發(fā)明的方法可在需要的時候以不增加任何額外的系統(tǒng)負擔下于計算機系統(tǒng)執(zhí)行函數時找出函數呼叫堆棧與其相對應的函數名稱,而于不需要的時候,則完全沒有任何系統(tǒng)負擔,至于所找出的函數呼叫堆棧可用以幫助分析該計算機系統(tǒng)死機時執(zhí)行線程的最后執(zhí)行狀態(tài),意即提供一有效率的分析死機問題或程序除錯的方法。
以上所述僅為本發(fā)明的較佳實施例,凡依本發(fā)明的權利要求所做的均等變化與修飾,皆應屬本發(fā)明專利的涵蓋范圍。
權利要求
1.一種可于一計算機系統(tǒng)執(zhí)行一函數時找出一函數呼叫堆棧的方法,該方法包含有下列步驟(a)取得執(zhí)行該函數時所產生的一程序指針;(b)依據該程序指針取得相對應的一指令;(c)檢測步驟(b)所取得的該指令是否與一返回地址指令相符;以及(d)當步驟(b)所取得的該指令與該返回地址指令相符時,儲存該程序指針所指向的一指令地址。
2.如權利要求1所述的方法,其還包含下列步驟(e)取得執(zhí)行該函數時所產生的一堆棧指針;(f)比較步驟(d)所儲存的該指令地址與該函數的一主函數名稱的一儲存地址;(g)當步驟(d)所儲存的該指令地址與該主函數名稱的該儲存地址不相符時,依據該堆棧指針取得相對應的一返回地址;以及(h)將該程序指針設成由步驟(g)取得的該返回地址。
3.如權利要求1所述的方法,其于步驟(a)中該程序指針是于該計算機系統(tǒng)死機時由該計算機系統(tǒng)的一程序指針緩存器取得。
4.如權利要求1所述的方法,其于步驟(a)中該程序指針是于該計算機系統(tǒng)執(zhí)行上下文交換時由保留于一堆棧中的一程序指針暫存值所取得。
5.如權利要求1所述的方法,其還包含依據一符號配置表判斷出于步驟(d)中所儲存的該程序指針所指向的該指令地址所對應的一函數指令。
6.一種可于一計算機系統(tǒng)執(zhí)行一函數時找出一函數呼叫堆棧的方法,該方法包含有下列步驟(a)取得執(zhí)行該函數時所產生的一程序指針與一堆棧指針;(b)依據該程序指針取得相對應的一指令;(c)檢測步驟(b)所取得的該指令是否與一返回地址指令相符;(d)當步驟(b)所取得的該指令與該返回地址指令不相符時,將該程序指針設成指向于步驟(b)所取得的該指令的一前一指令;(e)檢測步驟(d)所取得的該前一指令是否與該返回地址指令相符;以及(f)當步驟(d)所取得的該前一指令與該返回地址指令相符時,儲存該程序指針于步驟(d)所指向的一指令地址。
7.如權利要求6所述的方法,其還包含下列步驟(g)當步驟(b)所取得的該指令與該返回地址指令不相符時,檢測于步驟(b)所取得的該指令是否與一堆棧指針操作指令相符;(h)當步驟(b)所取得的該指令與該堆棧指針操作指令相符時,復原步驟(b)所取得的該指令對該堆棧指針所做的改變。
8.如權利要求6所述的方法,其還包含下列步驟(i)比較步驟(f)所儲存的該指令地址與該函數的一主函數名稱的一儲存地址;(j)當步驟(f)所儲存的該指令地址與該主函數名稱的該儲存地址不相符時,依據該堆棧指針取得相對應的該返回地址;以及(k)將于步驟(d)中所設定的該程序指針改設成由步驟(j)取得的該返回地址。
9.如權利要求6所述的方法,其于步驟(a)中該程序指針是于該計算機系統(tǒng)死機時由該計算機系統(tǒng)的一程序指針緩存器取得。
10.如權利要求6所述的方法,其于步驟(a)中該程序指針是于該計算機系統(tǒng)執(zhí)行上下文交換時由保留于一堆棧中的一程序指針暫存值所取得。
全文摘要
一種可于一計算機系統(tǒng)執(zhí)行一函數時找出一函數呼叫堆棧的方法,該方法包含有下列步驟(a)取得執(zhí)行該函數時所產生的一程序指針;(b)依據該程序指針取得相對應的一指令;(c)檢測步驟(b)所取得的該指令是否與一返回地址指令相符;以及(d)當步驟(b)所取得的該指令與該返回地址指令相符時,儲存該程序指針所指向的一指令地址。
文檔編號G06F9/42GK1877518SQ20051007616
公開日2006年12月13日 申請日期2005年6月8日 優(yōu)先權日2005年6月8日
發(fā)明者林昂賢 申請人:明基電通股份有限公司