DyninstAPI官方手冊翻譯

最近這段時間學習使用DyninstAPI進行插樁,而網上對於Dyninst的介紹少之又少,只好自己找出官方手冊查看,學習內容如下:

先說說Dyninst的功能,如下圖所示:


1.介紹

開發一個程序的正常循環是編輯源代碼,編譯它,然後執行生成的二進制文件。 但是,有時這個週期可能過於嚴格。我們可能希望在程序執行時或鏈接後更改程序,從而避免重新編譯,重新鏈接或甚至重新執行程序以更改二進制文件的過程。 起初,這可能看起來是一個奇怪的目標,然而,我們可能希望有這樣一個系統的幾個實際原因。例如,如果我們測量程序的性能並發現性能問題,則可能需要在程序中插入其他儀器以瞭解問題。另一個應用是性能指導; 對於大型仿真,計算科學家通常發現在仿真執行時能夠修改代碼和數據是有利的。

本文檔描述了一個應用程序接口(API),允許將代碼插入正在運行的計算機應用程序或磁盤上。用於將代碼插入正在運行的應用程序(稱爲動態檢測)的API與用於將代碼插入可執行文件或庫(稱爲靜態檢測)的API共享許多相同的結構。該API還允許更改或刪除應用程序中的子進程調用。二進制代碼更改對於支持各種應用程序非常有用,包括調試,性能監視以及支持從現有軟件包中編寫應用程序。這個API的目標是提供一個獨立於機器的接口,以允許創建使用運行時和靜態代碼修補的工具和應用程序。API和一個簡單的測試應用程序在[1]中描述。該API基於[3]中描述的動態檢測的思想。

這個接口的主要特點是能夠:

•在正在運行的程序中插入和更改插樁。

•將檢測插入磁盤上的二進制文件,並將該二進制文件的新副本寫回磁盤。

•對二進制文件和進程執行靜態和動態分析。

這個API的目標是保持接口小而易於理解。 同時,它需要有足夠的表現力以適用於各種應用。 我們通過提供一組簡單的抽象集和一種方法來指定將哪些代碼插入到應用程序中來實現這一目標。

2.摘要

DyninstAPI庫提供了一個接口,用於插樁和處理二進制文件和進程。用戶編寫一個mutator,它使用DyninstAPI庫在應用程序上進行操作。 包含mutatorDyninstAPI庫的進程稱爲mutator進程。mutator進程對其他進程或磁盤上的二進制文件進行操作,這些二進制文件稱爲mutatees

API基於程序的抽象。對於動態檢測,它可以基於執行時的狀態。API中的兩個主要抽象是點和片段。一個點是程序中可以插入儀表的位置。片段是某個可執行代碼的插入,以便在某個點插入到程序中。例如,如果我們希望記錄某個過程被調用的次數,那麼該過程將成爲該過程的入口點,並且片段將成爲增加計數器的語句。片段可以包含條件和函數調用。

使用地址空間抽象來表示mutatee。對於動態插樁,地址空間表示一個進程,幷包含加載進程的所有動態庫。對於靜態檢測,地址空間包括磁盤可執行文件,幷包含可執行文件依賴的任何動態庫文件。 地址空間抽象擴展了動態和靜態工具的進程和二進制抽象。 進程抽象表示有關正在運行的進程的信息,例如線程或堆棧狀態。 二進制抽象表示有關在磁盤上找到的二進制文件的信息。

由地址空間表示的代碼和數據被分解爲函數和變量抽象。函數包含指定要插入檢測的位置的點。函數還包含控制流圖抽象,其中包含有關基本塊,邊,循環和指令的信息。如果mutatee包含調試信息,DyninstAPI還將提供有關變量和函數類型,局部變量,函數參數和源代碼行信息的抽象。mutatee中函數和變量的集合被表示爲一個圖像。

API包含一個基於結構等價的簡單類型系統。如果mutatee程序已經用調試符號編譯,並且這些符號採用Dyninst可以理解的格式,那麼對要插入到mutatee中的代碼執行類型檢查。有關類型系統的完整說明,請參見第4.28節。

由於語言結構或編譯器優化,多個函數可能會重疊(即共享同一個函數體的一部分),或者使單個函數具有多個入口點。在實踐中,不可能確定多個重疊函數和具有多個入口點的單個函數之間的差異。DyninstAPI使用一個模型,其中每個函數(BPatch_function對象)具有單個入口點,並且多個函數可以重疊(共享代碼)。我們保證插入特定函數的插裝僅在該函數的上下文中執行,即使插裝插入到存在多個函數的位置中。

3. 例子

4. 接口

本節介紹API中的功能。 該API被組織爲C ++類的集合。主要類是BPatchBpatch_processBPatch_binaryEditBPatch_threadBPatch_imageBPatch_pointBPatch_snippetAPI還使用稱爲std :: vector的模板類。該類基於標準模板庫(STL)矢量類。

4.1   Class BPatch

BPatch類表示整個Dyninst庫。一次只能有一個這個類的實例。該類用於執行函數並獲取不特定於特定線程或圖像的信息。

該類包含的函數的作用:

1. 返回當前定義的進程列表(此列表包括通過調用processCreate / processAttach直接創建的進程,以及UNIX forkWindows CreateProcess系統調用的間接進程。)

2. 打開二進制重寫路徑指向的可執行文件或庫文件

3. 定期檢查線程的狀態,並且不需要獨立檢查每個進程的狀態

4. 打開或關閉調試器信息的解析。

5. 打開或關閉蹦牀遞歸。

6. 打開或關閉插入代碼片段的類型檢查。

7. 設置浮點寄存器是否保存,是否只保存活躍的寄存器。

8. 創建一個新的數組、枚舉、結構體、聯合體、自定義類型、指針。

4.2   Callbacks

以下功能旨在爲發生錯誤或重要事件時通知API用戶提供方法。每個功能都允許用戶爲事件註冊處理程序。所有回調註冊函數的返回碼都是先前註冊的處理程序的地址(如果之前沒有註冊處理程序,則可能爲NULL)。出於向後兼容的原因,當BPatch_process可能更合適時,某些回調可能會傳遞BPatch_thread對象。可以使用BPatch_thread :: getProcess()將BPatch_thread轉換爲BPatch_process

4.3   Class BPatch_addressSpace

BPatch_addressSpace類是BPatch_processBPatch_binaryEdit類的超類。它包含兩個子類之間通用的功能。

1. BPatch_image *getImage()返回與此BPatch_process對象關聯的可執行文件的句柄。

2. 分配內存,釋放內存

3. 創建變量

4. 在指定插入點處插入代碼片段

5. 刪除與已傳遞句柄相關聯的代碼片段

6. 將一組代碼片段作爲單個批處理操作插入

7. 在指定位置禁用mutatee函數調用

8. 替換執行的函數

9. 將動態鏈接的庫加載到進程地址空間中

4.4   Class BPatch_process

BPatch_process類表示正在運行的進程,其中包含一個或多個執行線程和地址空間。

1. 改變進程的執行狀態: stopExecutioncontinueExecutionterminateExecution

2. 獲取進程的狀態

3. 返回mutatee進程的系統ID

4. mutatee立即執行插入的代碼片段

5. 得到線程列表

4.5   Class BPatch_thread

BPatch_thread類表示並控制在進程中運行的執行線程。

1. 得到線程獨立於平臺的、特定的標識符

2. 指定線程立即執行插入的代碼表達式

4.6   Class BPatch_binaryEdit

BPatch_binaryEdit類表示用於二進制重寫的一組可執行文件和庫文件。BPatch_binaryEdit繼承自BPatch_addressSpace類,在這個類中找到了二進制重寫的大部分函數。

1.將一個BPatch_binaryEdit重寫到磁盤。

4.7   Class BPatch_sourceObj

BPatch_sourceObj類是BPatch_functionBPatch_moduleBPatch_image類的C ++超類。 它爲這三個類提供了一套通用的方法。 另外,它可以用於使用getObjParentgetSourceObj方法構建一個“通用”源代碼導航器,以獲取給定級別的父代和子代(即,模塊的父代是圖像,子代將是函數)。

1.返回源碼的類型

4.8   Class BPatch_function

該類的一個對象表示應用程序中的一個函數。 一個BPatch_image對象(見下面的描述)可以用來檢索一個表示給定函數的BPatch_function對象。

std::string getName();

std::string getDemangledName();

std::string getMangledName();

std::string getTypedName();

void getNames(std::vector<std::string> &names);

void getDemangledNames(std::vector<std::string> &names);

void getMangledNames(std::vector<std::string> &names);

void getTypedNames(std::vector<std::string> &names);

1. 獲取函數名

2. 返回引用此函數參數的BPatch_localVar片斷的向量。

4.9   Class BPatch_point

此類的一個對象表示應用程序代碼中庫的插入檢測的位置。 一個BPatch_image對象(見4.10節)用於檢索代表應用程序中所需點的BPatch_point

4.10   Class BPatch_image

該類定義了一個程序映像(與進程關聯的可執行文件)。 獲取BPatch_image句柄的唯一方法是通過BPatch_process成員函數getImage

4.11   Class BPatch_object

此類的一個對象表示原始可執行文件或庫。 它充當BPatch_module對象的容器。

4.12   Class BPatch_module

該類的一個對象表示一個程序模塊,它是程序可執行映像的一部分。 BPatch_module表示可執行文件或共享庫中的源文件。 Dyninst會在每個可執行文件中自動創建一個名爲DEFAULT_MODULE的模塊,以容納任何不匹配源文件的對象。 通過調用BPatch_image成員函數getModules獲取BPatch_module對象。

4.13   Class BPatch_snippet

片段是要插入程序的代碼的抽象表示形式。片段是通過創建片段的正確子類的新實例來定義的。例如,要創建一個片段來調用函數,請創建類BPatch_funcCallExpr的新實例。創建代碼片段不會導致代碼被插入到應用程序中。當請求在程序中的特定點處插入片段時,會生成代碼。子片段可以由不同的片段共享(即片段的句柄可以作爲參數傳遞以創建兩個不同的片段),但是生成的代碼是否在兩個片段之間共享(或複製)取決於實施。

4.14   Class BPatch_type

BPatch_type類用於描述變量,參數,返回值和函數的類型。 類的實例可以表示語言預定義類型(例如intfloat),mutatee定義的類型(例如,編譯到mutatee應用程序中的結構)或者mutator定義的類型(使用BPatch類的create *方法創建)。

4.15   Class BPatch_variableExpr

BPatch_variableExpr類是從BPatch_snippet派生的另一個類。它表示進程地址空間中的變量或內存區域。可以使用malloc成員函數從BPatch_process獲取BPatch_variableExpr,也可以使用findVariable成員函數從BPatch_image獲取BPatch_variableExpr。一些BPatch_variableExpr有一個關聯的BPatch_type,可以從BPatch_snippet繼承的函數訪問它。 如果BPatch_variableExpr對象源自帶有足夠調試信息的二進制文件,這些二進制文件描述了類型,或者在由Dyninst創建時提供了BPatch_type,則BPatch_variableExpr對象將具有關聯的BPatch_type

4.16   Class BPatch_flowGraph

BPatch_flowGraph類表示一個函數的控制流圖。它提供了用於發現函數內的基本塊和循環(調用者可以使用它來導航圖)的方法。可以通過調用BPatch_function對象的getCFG方法來獲得BPatch_flowGraph對象。

4.17   Class BPatch_basicBlock

BPatch_basicBlock類表示被檢測的應用程序中的基本塊。可以使用該函數的BPatch_flowGraph對象來獲取表示該函數內塊的此類的對象。 BPatch_basicBlock包含用於瀏覽包含功能的控制流程圖的方法。

4.18   Class BPatch_edge

BPatch_edge類表示BPatch_flowGraph中的控制流邊緣。

4.19   Class BPatch_basicBlockLoop

該類的一個對象表示正在檢測的應用程序的代碼中的一個循環。 我們檢測自然循環(單入口循環)和不可約循環(多入口循環)。 對於一個自然循環,它只有一個入口塊,並且該入口塊佔據了循環中的所有塊;因此入口塊也稱爲頭或頭的循環。 然而,對於一個不可約循環,它有多個入口塊,並且它們都不支配循環中的所有塊; 因此沒有不可約循環的頭或頭。 下圖說明了不同之處:

 

上面的圖(a)顯示了一個自然循環,其中塊1表示單個條目,塊1是循環的頭部。塊1支配塊2和塊3.上面的圖(b)顯示了一個不可約循環,其中塊1和塊2是循環的條目。塊1和塊2都不支配塊3

4.20   Class BPatch_loopTreeNode

BPatch_loopTreeNode類爲包含在BPatch_flowGraph中的類BPatch_basicBlockLoop的實例集合提供樹接口。樹的結構遵循函數流圖中的循環的嵌套關係。每個BPatch_loopTreeNode包含一個指向循環的指針(由BPatch_basicBlockLoop表示)和一組子循環(由其他BPatch_loopTreeNode對象表示)。根BPatch_loopTreeNode實例具有一個空循環成員,因爲函數可能包含多個外部循環。外部循環包含在根實例的子節點的向量中。

爲每個BPatch_loopTreeNode實例指定一個名稱,以指示其在循環層次結構中的位置。 每個根循環的名稱採用loop_x的形式,其中x是從1n的整數,其中n是函數中外部循環的數目。每個子循環都有其父級名稱,後跟一個.y,其中y1m,其中m是外循環下的子迴路數量。例如,考慮以下C函數:

 

foo函數將有一個根BPatch_loopTreeNode,它包含一個NULL循環條目和兩個表示外循環函數的BPatch_loopTreeNode子代。這些子代名稱分別爲loop_1loop_2,分別表示xi循環。loop_2沒有childrenloop_1有兩個子BPatch_loopTreeNode對象,名爲loop_1.1loop_1.2,分別代表yz循環。

4.21   Class BPatch_register

BPatch_register表示突變體的單個寄存器。可以使用BPatch_addressSpace :: getRegisters方法檢索BPatch_registers的列表。

4.22   Class BPatch_sourceBlock

該類的一個對象表示一個源代碼級別塊。每個源塊對象由源文件和該源文件中的一組源代碼行組成。該類用於填充控制流程圖中每個基本塊的源代碼行信息。對於控制流程圖中的每個基本塊,都有一個或多個源塊對象與源文件及其對應於基本塊的指令序列的行對應。

4.23   Class BPatch_cblock

這個類用於訪問關於公共塊的信息。

4.24   Class BPatch_frame

一個BPatch_frame對象表示一個堆棧幀。 getCallStack的成員函數BPatch_thread返回表示當前堆棧中的幀的BPatch_frame對象的向量。

4.25   Class StackMod

該類定義對函數的堆棧框架佈局的修改。堆棧修改基於堆棧位置的抽象,而不是這些位置的內容。 即使對單個函數調用多次BPatch_fuction :: addMods,所有的堆棧偏移都是相對於原始堆棧幀而言的。

4.26   Container Classes

4.26.1   Class std::vector

std :: vector類是一個容器,用於容納API使用的其他對象。 從Dyninst5.0開始,std :: vectorC ++標準模板庫(STL)的別名std :: vector

4.26.2   Class BPatch_Set

BPatch_Set是另一個容器類,類似於STL中的set類。 本類已被廢棄,將在下次發佈中刪除。 除了由std :: set提供的方法之外,它還提供了以下兼容性方法:

4.27   Memory Access Classes

通過findPointconst std :: set <BPatch_opCode>ops)創建的檢測點獲取附加的內存訪問信息。此信息由內存訪問片段使用,但也可供API用戶使用。封裝內存訪問信息的類包含在BPatch_memoryAccess_NP.h頭文件中。

4.27.1   Class BPatch_memoryAccess

這個類封裝了一個內存訪問抽象。 它包含描述內存訪問類型的信息:讀取,寫入,讀取/寫入或預取。 它還包含允許確定有效地址和傳輸字節數的信息。

4.27.2   Class BPatch_addrSpec_NP

該類封裝了在運行時確定有效地址所需的信息。地址的一般表示形式是兩個寄存器和一個常量的和; 這可能會在未來的版本中發生變化 一些體系結構僅使用寄存器的某些位(例如Power芯片系列中的XER寄存器的位25:31; 這些被表示爲僞寄存器。 寄存器和僞寄存器的編號方案取決於實現,不應依賴; 它可能在未來的版本中發生變化

4.27.3   Class BPatch_countSpec_NP

該類封裝了確定存儲器訪問傳輸的字節數所需的信息。

4.28   Type System

Dyninst類型系統基於結構等價的概念。選擇了結構等同性,以允許系統在允許用戶編寫與在已啓用或未啓用調試符號時編譯的應用程序一起工作的增變器方面具有最大的靈活性。使用BPatch類的create *方法,可以爲現有的mutatee結構構造類型定義。即使應用程序編譯時沒有調試信息,該信息也允許增變器讀取和寫入複雜類型。 但是,如果應用程序已經用調試信息編譯,Dyninst將驗證mutator執行的操作的類型兼容性。

類型可計算性的規則是兩種類型必須是相同的存儲類(即數組只與其他數組兼容)是類型兼容的。對於每個存儲級別,必須滿足以下附加要求才能使兩種類型兼容:

5.在組件庫中使用DyninstAPI

在本節中,我們將介紹如何從相應的Dyninst抽象中訪問底層組件庫抽象。組件庫(SymtabAPIInstructionAPIParseAPIPatchAPI)通常比Dyninst提供更強大的功能和更清晰的接口,因此用戶可能希望使用混合抽象。通常,用戶可以通過轉換函數訪問組件庫抽象,該函數被重載並且命名空間以提供一致的行爲。所有組件庫抽象的定義位於相應的文檔中。組件轉換函數如下:

PatchAPI::PatchMgrPtr PatchAPI::convert(BPatch_addressSpace *);
PatchAPI::PatchObject *PatchAPI::convert(BPatch_object *);
ParseAPI::CodeObject *ParseAPI::convert(BPatch_object *);
SymtabAPI::Symtab *SymtabAPI::convert(BPatch_object *);
SymtabAPI::Module *SymtabAPI::convert(BPatch_module *);
PatchAPI::PatchFunction *PatchAPI::convert(BPatch_function *);
ParseAPI::Function *ParseAPI::convert(BPatch_function *);
PatchAPI::PatchBlock *PatchAPI::convert(BPatch_basicBlock *);
ParseAPI::Block *ParseAPI::convert(BPatch_basicBlock *);
PatchAPI::PatchEdge *PatchAPI::convert(BPatch_edge *);
ParseAPI::Edge *ParseAPI::convert(BPatch_edge *);
PatchAPI::Point *PatchAPI::convert(BPatch_point *, BPatch_callWhen);
PatchAPI::SnippetPtr PatchAPI::convert(BPatch_snippet *);

SymtabAPI::Type *SymtabAPI::convert(BPatch_type *);

組件間的關係及其作用爲:


另有一個講解Dyninst的PPT和相關英文論文地址爲:https://download.csdn.net/download/touatou/10277761

發佈了29 篇原創文章 · 獲贊 28 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章