我想用更现代的 C++11 风格的 API 包装一个可变参数 C++ 函数。该功能是来自Pin仪表tramework的功能:
VOID LEVEL_PINCLIENT::INS_InsertCall(INS ins,
IPOINT action,
AFUNPTR funptr,
...)
其中AFUNPTR
声明为:
typedef VOID (*AFUNPTR)();
是...
传递 funptr 的参数列表。该列表由参数描述符(IARG_TYPE
枚举)、可选参数值和一个IARG_END
表示列表末尾的终止符构成。
这是一个在给定指令 ( ) 之前检测函数的用法示例,该指令ins
将打印 rAX 寄存器的内容:
void print_rax_and_tid(long rax, THREADID tid) {
cout << rax << endl << tid << endl;
}
...
INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)print_rax_and_tid,
IARG_REG_VALUE, REG_RAX, // the value of rAX register
IARG_THREAD_ID, // the thread id
IARG_END)
在这里,我们声明我们的函数将接受一个参数,该参数将保存一个寄存器值。我们还要求工具将 rAX 寄存器的值传递给函数。
请注意,每个函数参数由一个或两个描述符参数描述:
- (
IARG_REG_VALUE
,REG_RAX
) 描述 (long rax
) - (
IARG_THREAD_ID
) 描述 (THREADID tid
)
Pin 框架设置描述符以了解在运行时传递给用户函数的内容。
另请注意,不能从参数描述符中自动推断出函数参数的类型。在我的示例中,所有描述符都是枚举,但它们描述了一个长的 THREADID 参数。
我想用 C++11 提供的所有东西来设计这个包装 API,可能能够传递 lambda 而不是函数指针,向参数列表添加一些类型安全性,使用可变参数模板等。
用法可能看起来像这样(但我愿意接受建议):
INS_InsertCall(ins, IPOINT_BEFORE,
[](long rax, THREADID tid) { cout << rax << endl << tid << endl; },
IARG_REG_VALUE, REG_RAX,
IARG_THREAD_ID)