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

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值