【发布时间】:2013-07-27 13:20:31
【问题描述】:
我想用更现代的 C++11 风格的 API 包装一个可变参数 C++ 函数。 函数是this one,来自Pin instrumentation 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)
【问题讨论】:
-
“插入”一个类似 lambda 的函数需要将状态存储在某个地方。如果
INS_InsertCall不会存储状态,API 将不得不要求调用者存储状态。 -
这看起来是一个非常有趣的问题,我必须在几个小时后回到我的电脑前回来回答它
-
如果您谈论捕获的状态,我可以接受 lambda 是无状态的。状态可以作为 lambda 的参数来处理。今天也是如此,因为 AFUNPTR 是一个静态函数指针。
-
我不知道如何区分无状态 lambda 和有状态,也没有真正的方法可以在其他地方“存储”状态。被调用者必须将 lambda 本身存储在
INS_InsertCall和实际调用之间(无论何时)。不是大问题。
标签: c++ api c++11 variadic-functions