我创建了一个pintool,它在 json 文件中输出程序执行的所有基本块。问题是检测程序运行缓慢,所以我试图优化我的 pintool。
我想我可以在调用一次后从块中删除对检测函数的调用,但我一直无法找到如何做到这一点。在官方 PIN 文档中,只有PIN_RemoveInstrumentation()似乎禁用所有仪器的功能。
谁能告诉我如何做到这一点,或者甚至可以使用 PIN 来做到这一点?
我创建了一个pintool,它在 json 文件中输出程序执行的所有基本块。问题是检测程序运行缓慢,所以我试图优化我的 pintool。
我想我可以在调用一次后从块中删除对检测函数的调用,但我一直无法找到如何做到这一点。在官方 PIN 文档中,只有PIN_RemoveInstrumentation()似乎禁用所有仪器的功能。
谁能告诉我如何做到这一点,或者甚至可以使用 PIN 来做到这一点?
PIN 不提供直接 API 来删除特定地址上的基本块检测调用。您可以做的是跟踪至少已执行一次的基本块。
您将只为那些以前未执行过的基本块插入检测调用。
这是基于官方文档的粗略示例。
// The running count of instructions is kept here
// make it static to help the compiler optimize docount
static UINT64 icount = 0;
// Count the number of instructions in this basic block
VOID docount(UINT32 c) { icount += c; }
VOID Trace(TRACE trace, VOID *v)
{
for (BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl))
{
ADDRINT addr = BBL_Address(bbl);
if (alreadyVistited(addr) == false)
{
// Add instrumentation call for this basic block
BBL_InsertCall(bbl, IPOINT_ANYWHERE, (AFUNPTR)docount, IARG_UINT32, BBL_NumIns(bbl), IARG_END);
}
else
{
addToVisitedList(addr);
}
}
}
int main(int argc, char * argv[])
{
...
TRACE_AddInstrumentFunction(Trace, 0);
...
}
这的开销完全取决于添加的检测代码的复杂性。
一般来说,要加快速度,您应该启用最大编译器优化。如果可能,您还可以使用更好的编译器,例如能够生成极快代码的英特尔编译器。
如果您使用dynamoRIO而不是 PIN,您可以更轻松地实现您想做的事情。这是一个示例代码,它记录了程序在主模块中执行的所有基本块。
#define WINDOWS
#define X86_32
#define _CRT_SECURE_NO_DEPRECATE
#include "dr_api.h"
#pragma comment(lib, "dynamorio.lib")
static file_t logFile;
static LPBYTE mainModStartAddr, mainModEndAddr;
// This is called once for each basic block as it's discovered
static dr_emit_flags_t event_basic_block(void *drcontext, void *tag, instrlist_t *ilist, bool for_trace, bool translating)
{
// The IP of the basoc block
LPBYTE addr = dr_fragment_app_pc(tag);
// Basic Block must be within the main module
if (addr >= mainModStartAddr && addr <= mainModEndAddr)
dr_fprintf(logFile, "0x%08X", addr);
return DR_EMIT_DEFAULT;
}
static void event_exit()
{
dr_close_file(logFile);
}
DR_EXPORT void dr_init(client_id_t id)
{
module_data_t *data = dr_get_main_module();
mainModStartAddr = data->start;
mainModEndAddr = data->end;
dr_free_module_data(data);
logFile = dr_open_file("logfile.txt", DR_FILE_WRITE_OVERWRITE);
dr_register_bb_event(event_basic_block);
dr_register_exit_event(event_exit);
}
请注意,根本不需要分析功能。event_basic_block每个基本块将调用一次检测函数。它不会被多次调用,因为从第二次开始,代码将从代码缓存中执行。
dynamoRIO 和 PIN 的区别在于前者直接允许注册基本块生成的回调。另一方面,PIN 允许用于跟踪生成的回调。跟踪基本块的集合。此外,由于并非所有基本块都可以在跟踪中执行,因此在这种情况下使用 PIN 比较困难。