国产日韩欧美一区二区三区三州_亚洲少妇熟女av_久久久久亚洲av国产精品_波多野结衣网站一区二区_亚洲欧美色片在线91_国产亚洲精品精品国产优播av_日本一区二区三区波多野结衣 _久久国产av不卡

?

基于動(dòng)態(tài)二進(jìn)制翻譯和插樁的函數(shù)調(diào)用跟蹤

2019-02-20 08:34盧帥兵林哲超況曉輝
關(guān)鍵詞:指令集二進(jìn)制寄存器

盧帥兵 張 明 林哲超 李 虎 況曉輝 趙 剛

(信息系統(tǒng)安全技術(shù)國(guó)家重點(diǎn)實(shí)驗(yàn)室(軍事科學(xué)院) 北京 100101)

函數(shù)調(diào)用分析在軟件安全[1]、程序邏輯[2]、漏洞挖掘[3]等領(lǐng)域有著廣泛的應(yīng)用.特別是Linux內(nèi)核的開發(fā)與調(diào)試需要處理大量復(fù)雜的函數(shù),其調(diào)用關(guān)系對(duì)內(nèi)核分析與調(diào)試有很大幫助[4].函數(shù)調(diào)用分析包括靜態(tài)分析與動(dòng)態(tài)分析2種方法:

1) 靜態(tài)分析.根據(jù)源代碼進(jìn)行代碼審計(jì),得到從入口函數(shù)到退出函數(shù)的整個(gè)執(zhí)行路徑.靜態(tài)分析面向特定的編程語言源碼,進(jìn)行詞法語法分析,技術(shù)成熟.但是間接分支指令、間接函數(shù)調(diào)用和動(dòng)態(tài)生成代碼在靜態(tài)條件下很難獲取執(zhí)行路徑,因此靜態(tài)調(diào)用關(guān)系并不能反映出真實(shí)的調(diào)用序列信息.

2) 動(dòng)態(tài)分析.為了能獲取程序執(zhí)行時(shí)真實(shí)的函數(shù)調(diào)用關(guān)系,需要在程序運(yùn)行時(shí)記錄函數(shù)調(diào)用信息,動(dòng)態(tài)跟蹤函數(shù)執(zhí)行路徑.動(dòng)態(tài)分析方法解決了間接分支目標(biāo)地址的不確定性問題,可得到軟件實(shí)時(shí)調(diào)用序列、各函數(shù)的運(yùn)行時(shí)間、調(diào)用次數(shù)、前后依賴等信息.

現(xiàn)有函數(shù)調(diào)用動(dòng)態(tài)分析工具包括GNU binutils工具集的gprof[5],ftrace,systemtap,dtrace等.上述工具需要特定的使用條件,不能完全滿足當(dāng)前的開發(fā)調(diào)試需要.gprof僅支持啟動(dòng)用戶態(tài)可執(zhí)行程序,不能用于內(nèi)核分析;ftrace需要編譯內(nèi)核時(shí)打開編譯選項(xiàng),造成多種編譯優(yōu)化手段無法進(jìn)行;systemtap與dtrace需要操作系統(tǒng)運(yùn)行時(shí)提供接口,操作系統(tǒng)啟動(dòng)階段無法使用.

為彌補(bǔ)上述工具的不足,基于模擬器的函數(shù)跟蹤技術(shù)直接分析二進(jìn)制鏡像,不需額外的編譯選項(xiàng),成為內(nèi)核分析技術(shù)的重要方面.使用模擬器對(duì)函數(shù)調(diào)用關(guān)系進(jìn)行動(dòng)態(tài)跟蹤,避免對(duì)內(nèi)核源碼的插樁和編譯過程,減少對(duì)內(nèi)核的影響.S2E(selective symbolic execution)[6]基于QEMU[7]和符號(hào)執(zhí)行技術(shù),提供插件接口獲取操作系統(tǒng)運(yùn)行時(shí)狀態(tài)、函數(shù)調(diào)用關(guān)系等,支持x86,x86-64,arm平臺(tái).但是S2E運(yùn)行速度慢,缺乏對(duì)其他平臺(tái)如MIPS,Alpha等的支持.向勇等人[8]提出基于QEMU的動(dòng)態(tài)函數(shù)調(diào)用跟蹤框架,通過關(guān)閉基本塊鏈接功能,迫使每個(gè)基本塊代碼執(zhí)行結(jié)束后進(jìn)行基本塊切換操作,切換過程中統(tǒng)計(jì)函數(shù)信息,并寫入日志.相比S2E提高了分析性能和支持的CPU平臺(tái)種類,但是該方法依賴于QEMU的日志并必須關(guān)閉QEMU的基本塊鏈接功能,造成3.65倍的性能開銷.

上述工具基于QEMU模擬器進(jìn)行函數(shù)調(diào)用跟蹤,并實(shí)現(xiàn)對(duì)系統(tǒng)狀態(tài)的監(jiān)測(cè)與分析,但是監(jiān)測(cè)數(shù)據(jù)獲得的方法破壞了QEMU的模擬和加速機(jī)制,造成較大的性能開銷.如何精確記錄系統(tǒng)的行為并且不破壞QEMU模擬器的加速機(jī)制是亟待解決的問題.

通過分析QEMU的運(yùn)行機(jī)制,我們發(fā)現(xiàn)QEMU使用平臺(tái)無關(guān)的中間表示進(jìn)行不同平臺(tái)指令集的支持,而源指令到中間表示的翻譯過程和中間表示到宿主機(jī)平臺(tái)指令的過程都可以在中間表示層進(jìn)行插樁獲取翻譯記錄.據(jù)此,本文提出基于動(dòng)態(tài)二進(jìn)制翻譯和代碼插樁的函數(shù)調(diào)用跟蹤框架,在二進(jìn)制翻譯的中間代碼階段,針對(duì)特定函數(shù)調(diào)用和返回指令進(jìn)行特殊處理,插入性能分析和信息獲取樁指令塊,從而在運(yùn)行時(shí)獲取系統(tǒng)啟動(dòng)與函數(shù)調(diào)用順序.基于二進(jìn)制翻譯技術(shù),避免了對(duì)源碼的依賴,并提供跨平臺(tái)支持;在中間代碼階段的代碼插入技術(shù),減少了對(duì)源平臺(tái)和目標(biāo)平臺(tái)的依賴,降低了系統(tǒng)復(fù)雜度,性能開銷.

本文的主要貢獻(xiàn)如下:

1) 提出一種基于二進(jìn)制翻譯的支持多平臺(tái)的內(nèi)核函數(shù)調(diào)用跟蹤框架,在二進(jìn)制翻譯的中間代碼階段,生成用于特定信息獲取的指令,而不需重編譯內(nèi)核鏡像文件;

2) 基于二進(jìn)制翻譯的方法,大大擴(kuò)展了可支持平臺(tái)的種類,便于支持新型平臺(tái);

3) 不影響二進(jìn)制翻譯技術(shù)中基本塊鏈接、冗余代碼消除、熱路徑分析等優(yōu)化技術(shù),運(yùn)行效率高.

1 基于動(dòng)態(tài)二進(jìn)制翻譯和代碼插樁的函數(shù)調(diào)用跟蹤框架

1.1 動(dòng)態(tài)二進(jìn)制翻譯

二進(jìn)制翻譯是軟件安全分析[9]、系統(tǒng)分析[10]、軟件優(yōu)化[11]等領(lǐng)域的關(guān)鍵技術(shù).主流的二進(jìn)制翻譯分為靜態(tài)二進(jìn)制翻譯和動(dòng)態(tài)二進(jìn)制翻譯.動(dòng)態(tài)二進(jìn)制翻譯在執(zhí)行時(shí)根據(jù)程序執(zhí)行路徑以基本塊為單位進(jìn)行實(shí)時(shí)加載、翻譯、生成目標(biāo)代碼、執(zhí)行、緩存管理、代碼優(yōu)化等任務(wù),解決了間接分支指令目的地址不確定性、動(dòng)態(tài)生成代碼的翻譯問題,具有較好的完備性,是二進(jìn)制翻譯的主流技術(shù),其工作原理如圖1所示:

Fig. 1 Dynamic binary translation圖1 動(dòng)態(tài)二進(jìn)制翻譯

Fig. 2 Dynamic binary translation and code instrumentation based function call tracing framework圖2 基于動(dòng)態(tài)二進(jìn)制翻譯和代碼插樁的函數(shù)調(diào)用跟蹤框架

首先,加載二進(jìn)制鏡像文件,二進(jìn)制文件通常為ELF,PE或者Linux內(nèi)核格式,分析指令入口點(diǎn)PC(program counter),完成內(nèi)存映射、CPU初始化、虛擬設(shè)備創(chuàng)建等工作,并進(jìn)入翻譯過程.由于程序運(yùn)行的局部性,對(duì)已翻譯的基本塊進(jìn)行緩存可大大節(jié)省翻譯開銷.動(dòng)態(tài)二進(jìn)制翻譯在執(zhí)行某一基本塊前,首先從緩存中查找,若該基本塊已經(jīng)翻譯,則切換環(huán)境后進(jìn)入執(zhí)行階段;否則,需要根據(jù)當(dāng)前指令基本塊首地址讀取指令直到下一條分支指令,轉(zhuǎn)化為中間代碼(intermediate representation, IR),最后生成目標(biāo)指令集(instruction set architecture, ISA)代碼并執(zhí)行.執(zhí)行完當(dāng)前基本塊后進(jìn)入下一個(gè)基本塊并重復(fù)上述查找、翻譯、執(zhí)行過程,直到程序結(jié)束.從動(dòng)態(tài)二進(jìn)制翻譯的翻譯執(zhí)行流程可以看出,以基本塊為單位,翻譯過程與執(zhí)行過程交替進(jìn)行,能夠?qū)Σ煌脚_(tái)的代碼進(jìn)行翻譯轉(zhuǎn)換,解決了多平臺(tái)指令集支持的問題,極大地增大了軟件的適用性.

本文基于動(dòng)態(tài)二進(jìn)制翻譯的系統(tǒng)調(diào)用跟蹤,方便地支持多種指令集,并提供了指令和基本塊粒度的信息統(tǒng)計(jì)和代碼插入方法,可獲取的信息量大大增加.

1.2 代碼插樁

代碼插樁技術(shù)是軟件調(diào)試中采用的代碼修改機(jī)值,包括目標(biāo)代碼插樁和源代碼插樁,通過插樁點(diǎn)實(shí)時(shí)獲取程序狀態(tài),廣泛應(yīng)用于性能分析、覆蓋測(cè)試、軟件調(diào)試等領(lǐng)域[12-13].

源代碼插樁技術(shù)通過對(duì)程序源代碼的詞法分析、語法分析、語義分析等,確定插樁位置,依賴于特定的編程語言,工作量大.例如gprof,ftrace,systemtap都使用到了源代碼插樁技術(shù).

目標(biāo)代碼插樁技術(shù)通過對(duì)目標(biāo)代碼進(jìn)行相應(yīng)的分析,分析確定插樁點(diǎn),與具體的指令集相關(guān),不依賴程序源碼,與具體的編程語言和版本無關(guān).本文針對(duì)目標(biāo)代碼,在指令粒度進(jìn)行插樁,提升了檢測(cè)信息的精確度.

1.3 框架設(shè)計(jì)思路

為支持多種平臺(tái)二進(jìn)制鏡像,實(shí)現(xiàn)指令粒度的代碼插樁,實(shí)時(shí)獲取執(zhí)行信息、內(nèi)核加載過程信息、函數(shù)調(diào)用關(guān)系信息等,提出基于動(dòng)態(tài)二進(jìn)制翻譯和代碼插樁的函數(shù)調(diào)用跟蹤框架,框架模塊如圖2所示.

1) 通過二進(jìn)制翻譯系統(tǒng),載入內(nèi)核鏡像;

2) 對(duì)操作系統(tǒng)內(nèi)核進(jìn)行分析并確定指令集類型、入口點(diǎn);

3) 對(duì)需要執(zhí)行的基本塊進(jìn)行二進(jìn)制翻譯,在中間代碼階段,針對(duì)特殊的函數(shù)調(diào)用與返回指令插入樁指令;

4) 最后在執(zhí)行階段,每次執(zhí)行函數(shù)調(diào)用和返回指令,都會(huì)執(zhí)行插入的樁代碼,獲取模擬時(shí)鐘、進(jìn)程地址、函數(shù)地址等.

該框架充分利用了動(dòng)態(tài)二進(jìn)制翻譯系統(tǒng)的整體流程,以指令粒度分析插樁點(diǎn),動(dòng)態(tài)將樁代碼插入到生成的目標(biāo)碼中,實(shí)現(xiàn)了實(shí)時(shí)信息獲取功能.

2 基于QEMU和代碼插樁的函數(shù)調(diào)用跟蹤系統(tǒng)實(shí)現(xiàn)

根據(jù)第1節(jié)函數(shù)調(diào)用跟蹤框架的原理,基于開源的二進(jìn)制翻譯系統(tǒng)QEMU,進(jìn)行樁代碼設(shè)計(jì)、中間代碼樁標(biāo)記碼和目標(biāo)代碼的進(jìn)入樁插入、監(jiān)測(cè)信息處理等開發(fā)工作,實(shí)現(xiàn)了基于QEMU和代碼插樁的函數(shù)調(diào)用跟蹤系統(tǒng).

2.1 快速的處理器模擬器QEMU

QEMU是一個(gè)快速的處理器模擬器,支持多種源平臺(tái)和多種目標(biāo)平臺(tái)[14].利用平臺(tái)無關(guān)的中間表示形式TCG(tiny code generator),實(shí)現(xiàn)將x86,arm,Alpha,PowerPC等指令集轉(zhuǎn)換為TCG中間表示,然后翻譯為宿主機(jī)的指令集,具備快速模擬和跨平臺(tái)支持特性.作為模擬器可模擬多種設(shè)備、硬件,支持全系統(tǒng)運(yùn)行,可在宿主機(jī)運(yùn)行不同指令集的客戶機(jī).

QEMU以基本塊為單位對(duì)源指令進(jìn)行翻譯,提供了代碼緩存管理、基本塊鏈接、冗余代碼消除等優(yōu)化,提升了模擬器速度.QEMU的執(zhí)行流程如圖3所示.首先,QEMU加載源指令集的可執(zhí)行文件或者內(nèi)核鏡像,完成空間申請(qǐng)、地址映射、入口點(diǎn)分析等工作后從第1條指令開始進(jìn)入翻譯執(zhí)行的過程.以基本塊為單位,讀取源指令集的指令序列,生成對(duì)應(yīng)的TCG中間表示,然后分析優(yōu)化后生產(chǎn)宿主機(jī)指令集的代碼,并將動(dòng)態(tài)生成的代碼存入緩存,實(shí)現(xiàn)一次翻譯多次使用.在基本塊執(zhí)行完畢后,模擬器試圖查找下一個(gè)基本塊對(duì)應(yīng)的代碼,如果在緩存代碼區(qū)找到需要的代碼塊,則直接跳轉(zhuǎn)執(zhí)行,否則需要啟動(dòng)翻譯過程.由于每次基本塊執(zhí)行完畢后進(jìn)行查找下一個(gè)基本塊引起較大開銷,QEMU實(shí)現(xiàn)基本塊鏈接功能,把下一個(gè)基本塊和當(dāng)前塊直接使用跳轉(zhuǎn)指令連接起來,避免了查找消耗.基本塊鏈接技術(shù)極大地提高了模擬器的運(yùn)行效率,是QEMU模擬器的高效率關(guān)鍵技術(shù).

Fig. 3 Framework of QEMU圖3 QEMU框架結(jié)構(gòu)

從QEMU的運(yùn)行原理可以看出,QEMU使用了平臺(tái)無關(guān)中間表示TCG,是典型的動(dòng)態(tài)二進(jìn)制翻譯系統(tǒng).可在TCG階段對(duì)需要檢測(cè)的指令進(jìn)行操作,插入所需統(tǒng)計(jì)信息樁代碼,在運(yùn)行時(shí)獲取函數(shù)調(diào)用信息.

2.2 函數(shù)調(diào)用指令翻譯

QEMU進(jìn)行二進(jìn)制翻譯采用的平臺(tái)無關(guān)中間表示是TCG,曾作為支持多平臺(tái)的C語言交叉編譯器的后端,是一種類似于RISC的指令集.TCG僅支持32 b和64 b整型,指針類型是根據(jù)宿主機(jī)的位數(shù)按照32 b或64 b整型定義的.QEMU把源指令變換為TCG操作,進(jìn)行活性分析、常量計(jì)算優(yōu)化,然后變換為對(duì)應(yīng)宿主機(jī)指令集的指令序列.例如指令add_i32t0,t1,t2表示t1+t2的和放到t0寄存器中,操作數(shù)t0,t1,t2都是32 b整型.

函數(shù)調(diào)用指令會(huì)更改程序執(zhí)行順序,并修改棧內(nèi)容,TCG針對(duì)函數(shù)調(diào)用遵循以下規(guī)則:

1) 參數(shù)和返回值的類型僅支持32 b,64 b整型和指針.

2) 棧向下填充.

3) 前N個(gè)參數(shù)通過寄存器傳遞,超過N個(gè)參數(shù)的以字為單位放入棧傳遞.N在文件中可根據(jù)具體平臺(tái)自定義.

4) 一些寄存器在函數(shù)調(diào)用過程中會(huì)被重復(fù)使用.

5) 函數(shù)可以使用寄存器返回0或1.在32 b宿主機(jī)上運(yùn)行64 b系統(tǒng)時(shí),為了能夠返回64 b值,必須使用寄存器返回2個(gè)32 b值.

這些規(guī)則限定了函數(shù)調(diào)用指令處理的方法,一條函數(shù)調(diào)用指令會(huì)被分解為參數(shù)傳遞操作、棧修改操作、分支跳轉(zhuǎn)操作3部分.

為了插入用于信息統(tǒng)計(jì)的樁代碼,添加新的TCG中間表示,在分支跳轉(zhuǎn)操作前插入gen_stubc TCG指令,用以生成調(diào)用樁代碼的指令序列.例如指令call 0x7fac6ee插入gen_stubc后的翻譯過程如圖4所示,可以看到生成了call stubc的中間代碼指令和對(duì)應(yīng)的目標(biāo)平臺(tái)指令“mov $0x56333978b660,%r10;callq*%r10”,其中地址$0x56333978b660為樁代碼helper_stubc在內(nèi)存中的位置.

Fig. 4 Translation of call instruction with instrumentation code圖4 插樁后的call指令翻譯過程

2.3 樁代碼設(shè)計(jì)

樁代碼是在動(dòng)態(tài)翻譯的過程中,插入到函數(shù)調(diào)用和返回指令對(duì)應(yīng)目標(biāo)代碼中,完成信息獲取的代碼段.樁代碼需要完成信息監(jiān)測(cè)功能,同時(shí)不能對(duì)原有代碼的語義造成影響.

每次函數(shù)調(diào)用和函數(shù)返回都調(diào)用樁代碼,記錄實(shí)時(shí)操作信息,使得獲取從第1條指令到最后啟動(dòng)完成全局的調(diào)用信息;需要完成信息監(jiān)測(cè)功能,同時(shí)不能對(duì)原有代碼的語義造成影響;執(zhí)行的次數(shù)非常多,盡量保持簡(jiǎn)短.

考慮以上因素,結(jié)合QEMU具體實(shí)現(xiàn),采用helper機(jī)制調(diào)用樁代碼.QEMU在進(jìn)行指令翻譯的過程中,會(huì)遇到語義復(fù)雜的指令,例如,這類指令如果使用宿主平臺(tái)匯編指令實(shí)現(xiàn)其功能非常復(fù)雜,以至于生成的目標(biāo)代碼極其龐大,易出錯(cuò).為了兼顧效率與靈活性,QEMU使用特定的helper函數(shù)實(shí)現(xiàn)此類功能復(fù)雜型指令的模擬操作.例如使用tcg_gen_helper_x_y可以生成調(diào)用參數(shù)為32 b,64 b或指針的函數(shù).默認(rèn)情況下,在調(diào)用helper函數(shù)時(shí),所有的全局變量將會(huì)保存到對(duì)應(yīng)env的位置,以防helper修改某些寄存器的值.一個(gè)helper函數(shù)是可以訪問模擬器CPU狀態(tài)變量env的.利用helper機(jī)制,可方便的在函數(shù)調(diào)用和返回處調(diào)用helper的stub樁代碼,訪問全局CPU狀態(tài)變量env,完成信息記錄功能.

2.4 針對(duì)x86指令集的樁代碼設(shè)計(jì)

使用QEMU的helper機(jī)制,針對(duì)x86指令集進(jìn)行代碼插樁的方法如下,首先在targeti386helper.h中添加定義DEF_HELPER_2(stub_call,void,env,tl)其中stub_call是helper函數(shù)名,void是返回值,env,tl是參數(shù)類型,表示函數(shù)voidhelper_stub_call(CPUx86State*env,target_ulongval)的聲明,類似的DEF_HELPER_2(stub_ret,void,env,tl)表示ret指令的返回嵌入樁代碼.然后,在translate.c中對(duì)call,ret指令翻譯的響應(yīng)位置,插入gen_helper生成調(diào)用helper_stub_call,helper_stub_ret的TCG指令,其中使用gen_helper在翻譯時(shí)首先會(huì)把模擬CPU的寄存器值保存到內(nèi)存中,防止內(nèi)部代碼執(zhí)行影響寄存器內(nèi)容;最后,在targeti386misc_helper.c中實(shí)現(xiàn)2個(gè)函數(shù).樁代碼的功能如圖5所示,使用全局的信息結(jié)構(gòu)體env保存包括時(shí)間戳、進(jìn)程ID、調(diào)用地址、當(dāng)前函數(shù)地址、函數(shù)名稱等信息,并使用全局的call_info_arr數(shù)組把所有函數(shù)調(diào)用和返回的信息進(jìn)行保存.然后調(diào)用QEMU內(nèi)置函數(shù)QEMU_clock_get_ns()獲取模擬時(shí)鐘,通過CPUx86State結(jié)構(gòu)體的寄存器值,分別獲取ESP值、進(jìn)程ID、調(diào)用函數(shù)地址、當(dāng)前函數(shù)地址并存入全局?jǐn)?shù)組;最后樁代碼執(zhí)行完畢,回到基本塊,繼續(xù)執(zhí)行后續(xù)代碼.

Fig. 5 Instrumentation code of x86
圖5 針對(duì)x86平臺(tái)的樁代碼

2.5 針對(duì)ARM指令集的樁代碼設(shè)計(jì)

ARM指令集是目前移動(dòng)平臺(tái)使用最廣泛的指令集,ARM屬于精簡(jiǎn)指令集,有31個(gè)32 b的通用寄存器,其中有3個(gè)寄存器SP(stack pointer)、LR(link register)、PC有特殊的用途.

通常R13作為棧指針寄存器存儲(chǔ)棧指針SP,pop和push指令使用R13的值訪問棧空間.

R14作為鏈接寄存器LR.當(dāng)使用分支鏈接指令(BL,BLX)指令時(shí),該寄存器保存當(dāng)前分支鏈接指令的下一條指令的地址.在函數(shù)調(diào)用結(jié)束返回時(shí),R14作為返回的地址,其他時(shí)候R14可作為通用寄存器使用.因此在進(jìn)行函數(shù)調(diào)用跟蹤時(shí),可通過訪問R14獲得返回地址.

R15作為程序計(jì)數(shù)器PC,由于ARM體系結(jié)構(gòu)采用了多級(jí)流水線技術(shù),對(duì)于ARM指令集而言,PC總是指向當(dāng)前指令的下2條指令的地址,即PC的值為當(dāng)前指令的地址值加8 B程序狀態(tài)寄存器.

頁(yè)表轉(zhuǎn)換基寄存器(TTBR),CP15的第2個(gè)寄存器存放當(dāng)前進(jìn)程的物理基地址,在QEMU模擬ARM類型的CPU時(shí)使用CP15.ttbr0_el[2]表示該值.

ARM指令集使用BL,BLX進(jìn)行子程序調(diào)用時(shí),把返回地址存儲(chǔ)到LR,但是沒有專門的返回指令,而是通過把LR的值傳入PC寄存器中的方法.通常使用如下4種函數(shù)返回方法:

MOV PC,LR或BX LR

該MOV指令直接把LR寄存器的值復(fù)制到PC寄存器,更改程序執(zhí)行流程,使函數(shù)返回到LR存儲(chǔ)的地址處.同樣BX LR直接把LR寄存器中的返回地址作為無條件跳轉(zhuǎn)目的地址,完成函數(shù)返回操作.

或者stmfd與ldmfd,push,pop指令在函數(shù)入口處執(zhí)行入棧并在函數(shù)結(jié)束時(shí)執(zhí)行出棧操作來更改程序執(zhí)行流程.使用在函數(shù)入口處使用如下指令保存寄存器狀態(tài):

即保存通用寄存器和LR的值到棧中,函數(shù)體執(zhí)行完畢需要返回時(shí),恢復(fù)CPU狀態(tài),

以上4種方式是常用的函數(shù)返回方法,在進(jìn)行函數(shù)調(diào)用跟蹤時(shí),需要在翻譯階段判斷這4種情況,并生成調(diào)用的樁代碼的TCG指令.

根據(jù)ARM指令的函數(shù)調(diào)用和返回方法以及特殊寄存器的使用方式,設(shè)計(jì)ARM平臺(tái)的樁代碼如圖6所示:

Fig. 6 Instrumentation code of ARM
圖6 針對(duì)ARM平臺(tái)的樁代碼

2.6 針對(duì)MIPS指令集的樁代碼設(shè)計(jì)

MIPS指令集廣泛應(yīng)用在交換設(shè)備、移動(dòng)設(shè)備、嵌入式微控制器等產(chǎn)品,屬于精簡(jiǎn)指令集,有32個(gè)通用寄存器,其中寄存器$29用作棧寄存器$sp,$31寄存器用作返回地址寄存器$ra.函數(shù)調(diào)用指令使用Motorala命名法,子程序調(diào)用成為跳轉(zhuǎn)并鏈接,助記符以al結(jié)尾,例如jal imm或jalr $reg該指令首先把C寄存器保存到$ra,然后跳轉(zhuǎn)到立即數(shù)imm或$reg指向的指令塊.函數(shù)返回時(shí),使用jr $ra跳轉(zhuǎn)到保存的指令地址$ra,完成函數(shù)返回操作.若被調(diào)用函數(shù)再次調(diào)用其他函數(shù),那么$ra的值會(huì)先存入棧空間,子函數(shù)執(zhí)行結(jié)束后,重新載入$ra的值,進(jìn)行返回.類似的,使用bal,bgezal,bltzal進(jìn)行相對(duì)PC偏移的函數(shù)調(diào)用,返回值會(huì)存儲(chǔ)到$ra中.在翻譯階段對(duì)上述子程序調(diào)用指令和函數(shù)返回指令生成調(diào)用樁代碼的TCG指令,實(shí)現(xiàn)函數(shù)調(diào)用跟蹤.

我們使用當(dāng)前進(jìn)程的物理地址作為唯一標(biāo)識(shí),以區(qū)分不同的進(jìn)程.MIPS為每個(gè)進(jìn)程分配了地址空間ID,稱為ASID(address space id),在進(jìn)行TLB轉(zhuǎn)換時(shí),使用ASID和虛擬頁(yè)號(hào)(virtual page number, VPN)拼接成唯一的頁(yè)地址,映射到物理地址,因此可以使用ASID拼接VPN作為當(dāng)前進(jìn)程的標(biāo)識(shí).QEMU實(shí)現(xiàn)了MIPS的ASID,VPN保存在env→CP0_EntryHi中.根據(jù)MIPS指令集和寄存器特點(diǎn),針對(duì)MIPS指令集的樁代碼設(shè)計(jì)如圖7所示:

Fig. 7 Instrumentation code of MIPS
圖7 針對(duì)MIPS平臺(tái)的樁代碼

以上給出了x86,ARM,MIPS指令集的樁代碼設(shè)計(jì)方法,可以看出樁代碼從全局環(huán)境結(jié)構(gòu)體env中直接讀取相應(yīng)信息,代碼簡(jiǎn)短、直接,可很快根據(jù)具體平臺(tái)要求,具有多平臺(tái)支持的特點(diǎn),其他平臺(tái)可根據(jù)寄存器的使用特點(diǎn),很方便地移植到需要支持的指令集構(gòu)架平臺(tái)上.

2.7 日志記錄與函數(shù)調(diào)用圖

日志記錄包括call記錄和ret記錄,call記錄需保存調(diào)用時(shí)間、進(jìn)程標(biāo)識(shí)、線程標(biāo)識(shí)、被調(diào)用函數(shù)地址、被調(diào)用函數(shù)名稱;而ret記錄包括調(diào)用時(shí)間、進(jìn)程標(biāo)識(shí)、線程標(biāo)識(shí)即可.例如在時(shí)刻592092451ns函數(shù)start_kernel被調(diào)用,接著函數(shù)start_kernel調(diào)用了set_task_stack_end_magic,smp_setup_processor_id記錄如圖8所示:

Fig. 8 Example of the logs
圖8 日志記錄示例

通過樁代碼的統(tǒng)計(jì),獲取了對(duì)應(yīng)信息,需結(jié)合分析二進(jìn)制鏡像獲取符號(hào)表中函數(shù)名稱,即可把call_info結(jié)構(gòu)體中的function_name確定,從而形成完整的統(tǒng)計(jì),按照相關(guān)工具進(jìn)行輸出,生成函數(shù)調(diào)用圖,本文使用graphviz[15]工具生成函數(shù)調(diào)用圖,如圖9所示start_kernel執(zhí)行時(shí)的函數(shù)調(diào)用關(guān)系.該可視化工作已有相關(guān)研究,可結(jié)合已有相關(guān)解析工具和算法[16],不作為本文的主要工作.

Fig. 9 Example of function call map of Linux 4.9 kernel圖9 函數(shù)調(diào)用跟蹤Linux 4.9內(nèi)核繪圖示例

3 與現(xiàn)有工作的比較

現(xiàn)有的基于模擬器的函數(shù)調(diào)用跟蹤工具有S2E和向勇所提出的基于QEMU的動(dòng)態(tài)函數(shù)調(diào)用跟蹤框架不妨記為QEMU-DFCT(QEMU-based dynamic function call tracing).下面將本文所提出的方案分別與S2E,QEMU-DFCT進(jìn)行對(duì)比.

3.1 與S2E對(duì)比

3.1.1 功能性比較

S2E結(jié)合了符號(hào)執(zhí)行和QEMU,并提供插件發(fā)布、訂閱、處理事件.可通過編寫回調(diào)函數(shù),注冊(cè)某類型事件即可完成訂閱.當(dāng)所注冊(cè)時(shí)間類型觸發(fā)如函數(shù)調(diào)用,則回調(diào)函數(shù)會(huì)接收到調(diào)用信息、執(zhí)行回調(diào)函數(shù)定義的功能.

由于S2E對(duì)QEMU本身做了較大量的修改,目前可支持x86,ARM指令集,未能對(duì)QEMU所支持的多種平臺(tái)進(jìn)行繼承,丟棄原始QEMU的諸多特性.

3.1.2 性能比較

S2E的符號(hào)執(zhí)行模塊會(huì)對(duì)分析對(duì)象的每一個(gè)執(zhí)行路徑進(jìn)行分析,對(duì)指定模塊的路徑屬性、條件進(jìn)行監(jiān)測(cè)和操縱,功能復(fù)雜,導(dǎo)致性能很低.本文提出的方案直接對(duì)QEMU的中間表示TCG,helper機(jī)制進(jìn)行利用,實(shí)現(xiàn)了函數(shù)調(diào)用與返回跟蹤技術(shù),繼承了QEMU原生的多平臺(tái)、速度快的特性.

3.2 與QEMU-DFCT對(duì)比

本文提出的方法所實(shí)現(xiàn)的函數(shù)調(diào)用記錄的功能與QEMU-DFCT一致.

QEMU-DFCT繼承了原生QEMU的諸多優(yōu)點(diǎn),如跨平臺(tái)、易拓展,同時(shí)以很小的修改代碼實(shí)現(xiàn)了函數(shù)調(diào)用跟蹤技術(shù).QEMU-DFCT直接讀取QEMU原始數(shù)據(jù)結(jié)構(gòu),并并行解析,提高了處理速度.

但是,QEMU-DFCT必須強(qiáng)制關(guān)閉基本塊鏈接功能,在每一個(gè)基本塊執(zhí)行結(jié)束后進(jìn)行基本塊切換操作,都必須檢查是否為函數(shù)調(diào)用或返回基本塊,造成了3.65倍的性能開銷.本文提出的方案不是在基本塊切換階段記錄信息,而是將以樁代碼的形式,插入到函數(shù)調(diào)用和返回指令生成的宿主機(jī)代碼中,支持基本塊鏈接功能,降低了性能開銷.

4 實(shí) 驗(yàn)

本文在QEMU 2.9.92版本進(jìn)行實(shí)驗(yàn),相關(guān)實(shí)驗(yàn)環(huán)境如表1所示.其中Linux 內(nèi)核是使用QEMU加載分析的內(nèi)核,文件系統(tǒng)是使用QEMU加載時(shí)指定的文件系統(tǒng).宿主機(jī)是指運(yùn)行QEMU的計(jì)算機(jī).

Table 1 Experiment Setup表1 實(shí)驗(yàn)環(huán)境

本文實(shí)現(xiàn)了所提出的插樁算法(QEMU helper stub,QHS)和QEMU-DFCT算法的記錄函數(shù)調(diào)用信息和輸出部分,并在x86,ARM,MIPS平臺(tái)進(jìn)行了性能對(duì)比實(shí)驗(yàn),實(shí)驗(yàn)結(jié)果如圖10所示:

Fig. 10 Performance comparison of QHS and DFCT圖10 QHS,DFCT的性能比較

以QHS-x86為例,使用未修改的QEMU加載x86指令集Linux 4.9內(nèi)核、busybox 1.27.0文件系統(tǒng),從啟動(dòng)到出現(xiàn)shell提示符時(shí)間消耗是4.33 s.使用修改后的用于函數(shù)調(diào)用跟蹤的版本,從啟動(dòng)到出現(xiàn)shell提示符,同時(shí)完成函數(shù)調(diào)用信息記錄,并將信息處理并輸出到磁盤文件中,所用時(shí)間是12.16 s,其中,樁代碼執(zhí)行總時(shí)間是0.66 s,信息處理并輸出使用時(shí)間是7.17 s.樁代碼執(zhí)行信息記錄增加了15.24%的開銷,而信息處理并輸出到磁盤文件增加了165.59%的開銷;DFCT-x86信息記錄增加了210.62%的開銷,記錄輸出開銷是166.51%.由于ARM和MIPS平臺(tái)寄存器數(shù)目多,DFCT進(jìn)行基本塊切換操作需要保存或恢復(fù)的寄存器數(shù)目多,造成調(diào)用記錄開銷高于x86平臺(tái),而寄存器數(shù)目并不影響QHS算法的性能.

而使用S2E對(duì)x86指令集的內(nèi)核進(jìn)行加載分析,總時(shí)長(zhǎng)達(dá)3 429.34 s,是因?yàn)镾2E會(huì)對(duì)內(nèi)核使用KLEE模塊進(jìn)行符號(hào)分析,對(duì)內(nèi)核的海量的執(zhí)行路徑進(jìn)行路徑屬性、執(zhí)行條件分析,并在每個(gè)路徑和函數(shù)調(diào)用部分保存并檢查系統(tǒng)狀態(tài)、反饋插件調(diào)用等任務(wù).所以造成內(nèi)核啟動(dòng)很慢.

從實(shí)驗(yàn)結(jié)果可以看出,本文實(shí)現(xiàn)的基于動(dòng)態(tài)二進(jìn)制翻譯和代碼插樁的函數(shù)調(diào)用跟蹤工具的開銷要遠(yuǎn)遠(yuǎn)優(yōu)于現(xiàn)有的S2E,QEMU-DFCT跟蹤工具.

5 總 結(jié)

本文提出了基于動(dòng)態(tài)二進(jìn)制翻譯和代碼插樁的函數(shù)調(diào)用跟蹤,給出了系統(tǒng)框架設(shè)計(jì)并基于QEMU開發(fā)了函數(shù)調(diào)用跟蹤系統(tǒng),可針對(duì)Linux內(nèi)核跟蹤所有函數(shù)調(diào)用,并在x86,ARM,MIPS平臺(tái)進(jìn)行了實(shí)現(xiàn),驗(yàn)證了系統(tǒng)框架的有效性并評(píng)估了系統(tǒng)性能.針對(duì)QEMU二進(jìn)制翻譯過程的中間表示進(jìn)行設(shè)計(jì),插入信息搜集樁代碼而不影響基本塊鏈接、活性分析、常量計(jì)算等優(yōu)化技術(shù),以盡可能小的性能開銷達(dá)到了動(dòng)態(tài)函數(shù)跟蹤的目的.

本工作還有一些可改進(jìn)的地方,例如樁代碼的實(shí)現(xiàn)可以使用嵌入式匯編或者不使用helper機(jī)制,直接生成完成信息記錄功能的宿主機(jī)指令,進(jìn)一步提高速度,降低開銷.實(shí)現(xiàn)插件機(jī)制,例如注冊(cè)指定函數(shù)調(diào)用事件的回調(diào)函數(shù),在樁代碼進(jìn)行記錄時(shí),若被調(diào)用函數(shù)是指定的監(jiān)測(cè)函數(shù),調(diào)用回調(diào)函數(shù).

猜你喜歡
指令集二進(jìn)制寄存器
基于Kubernetes的RISC-V異構(gòu)集群云任務(wù)調(diào)度系統(tǒng)①
用二進(jìn)制解一道高中數(shù)學(xué)聯(lián)賽數(shù)論題
3DNow指令集被Linux淘汰
有用的二進(jìn)制
Lite寄存器模型的設(shè)計(jì)與實(shí)現(xiàn)
有趣的進(jìn)度
二進(jìn)制翻譯中動(dòng)靜結(jié)合的寄存器分配優(yōu)化方法
移位寄存器及算術(shù)運(yùn)算應(yīng)用
基于Dais—CMX模型機(jī)的斐波那契數(shù)列指令集設(shè)計(jì)
什么是AMD64
湖口县| 温宿县| 元江| 辛集市| 吉隆县| 宿松县| 司法| 济宁市| 侯马市| 绥棱县| 龙口市| 兴业县| 太白县| 新绛县| 土默特左旗| 谢通门县| 上杭县| 宜兴市| 威宁| 潮州市| 肥西县| 秀山| 鲁山县| 浦江县| 罗城| 广昌县| 凯里市| 阿拉善右旗| 河北省| 枣阳市| 全南县| 沅江市| 五华县| 富蕴县| 岢岚县| 赣榆县| 泸水县| 梁河县| 新安县| 南京市| 昌宁县|