我正在使用函数bfd_find_nearest_line
来查找函数的源位置(来自带有调试符号的可执行文件 - 使用-g
编译)。当然,其中一个参数是指向我想要找到的函数的指针:
boolean
_bfd_elf_find_nearest_line (abfd,
section,
symbols,
offset,
filename_ptr,
functionname_ptr, // <- HERE!
line_ptr)
https://sourceware.org/ml/binutils/2000-08/msg00248.html
在相当多的(纯C)锅炉板之后,我设法使用普通函数(正常函数指针被转换为*void
)。
例如,这有效:
int my_function(){return 5;}
int main(){
_bfd_elf_find_nearest_line (...,
(void*)(&my_function),
...);
}
问题是如果可以使用bfd_find_nearest_line
来查找类成员函数的源代码。
struct A{
int my_member_function(){return 5.;}
};
_bfd_elf_find_nearest_line (...,
what_should_I_put_here??,
...)
类成员函数(在这种情况下,如果类型int (A::*)()
)不是函数,特别是不能转换为任何函数指针,甚至不能转换为void*
。见这里:https://isocpp.org/wiki/faq/pointers-to-members#cant-cvt-memfnptr-to-voidptr
我完全理解这背后的逻辑,如何成员函数指针是唯一一个我有成员函数信息的句柄,以便使BFD识别该函数。我不希望这个指针调用一个函数。
我或多或少知道C ++是如何工作的,编译器会静默生成一个等效的free-C函数,
__A_my_member_function(A* this){...}
但我不知道如何访问此免费功能的地址,或者如果可能的话,以及bfd
库是否能够找到原始{{1}的源位置通过这个指针。
(目前至少我对虚函数不感兴趣。)
换句话说,
1)我需要知道my_member_function
是否能够找到成员函数,
2)如果可以,我如何将bfd
类型的成员函数指针映射到int (A::*)()
可以采用的参数(bfd
)。
我通过其他方式(堆栈跟踪)知道指针存在,例如我可以得到在这种情况下void*
调用自由函数,但问题是如何从{{1 }}
答案 0 :(得分:0)
好的,有好消息和坏消息。
好消息: 可能。
坏消息:这不是直截了当的。
您需要c++filt
实用程序。
并且,有些方法可以读取可执行文件的符号表,例如readelf
。如果您可以通过bfd_*
调用枚举[损坏的]符号,则可以为自己节省一步。
此外,还有 biggie :您需要在文本字符串中使用符号的c ++名称。因此,对于&(A::my_member_function)
,您需要采用以下形式:"A::my_member_function()"
这不应该太困难,因为我认为您关注的数量有限。< / p>
您需要从readelf -s <executable>
获取符号及其地址列表。准备解析此输出。您需要从字符串中解码十六进制地址以获取其二进制值。
这些将是受损的名字。对于每个符号,执行c++filt -n mangled_name
并将输出(即管道)捕获到某些内容(例如nice_name
)。它将返回解码后的名称(即您喜欢的漂亮的c ++名称)。
现在,如果nice_name
匹配&#34; A:my_member_function()&#34;,您现在有匹配,您已经有了错位的名称,但更重要的是,符号的十六进制地址。将此十六进制值[适当强制转换]提供给填充functionname_ptr
注意:上述工作有效,但重复调用c++filt
更快的方法是捕获管道输出:
readelf -s <executable> | c++filt
这样做[可能]也更容易,因为您只需解析过滤后的输出并查找匹配的好名称。
此外,如果你有多个你关心的符号,你可以在一次调用中获得所有地址。
答案 1 :(得分:0)
好的,我找到了办法。首先,我发现bfd
非常高兴检测成员函数从成员指针调试信息,只要指针可以转换为void*
。
我正在使用clang
,它不允许我将成员函数指针强制转换为任何类型的指针或整数。
GCC
允许执行此操作但会发出警告。
甚至还有一个标志允许指向名为-Wno-pmf-conversions
的成员演员。
记住这些信息后,我尽力将成员函数指针转换为void*
,最后我使用了工会。
struct A{
int my_member_function(){return 5.;}
};
union void_caster_t{
int (A::*p)(void) value;
void* casted_value;
};
void_caster_t void_caster = {&A::my_member_function};
_bfd_elf_find_nearest_line (...,
void_caster.casted_value,
...)
最后bfd
能够给我一个成员函数的调试信息。
我还没弄清楚,是如何获得指向构造函数和析构函数成员函数的指针。
例如
void_caster_t void_caster = {&A::~A};
给出了编译错误:&#34;你不能获取析构函数的地址&#34;。
对于构造函数,我甚至无法找到正确的语法,因为这会因语法错误而失败。
void_caster_t void_caster = {&A::A};
所有背后的逻辑都不能涉及非语义回调,但这是不同的,因为我希望指针(或地址)获取调试信息,而不是回调。