首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使BFD库找到类成员函数的位置

使BFD库找到类成员函数的位置
EN

Stack Overflow用户
提问于 2016-05-04 18:58:51
回答 2查看 461关注 0票数 0

我使用函数bfd_find_nearest_line查找函数的源位置(从带有调试符号的可执行文件--用-g编译)。当然,其中一个参数是指向我想要定位的函数的指针:

代码语言:javascript
复制
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)。

例如,这起作用是:

代码语言:javascript
复制
int my_function(){return 5;}

int main(){
    _bfd_elf_find_nearest_line (...,
                (void*)(&my_function), 
                ...);
}

问题是,是否可以使用bfd_find_nearest_line来定位类成员函数的源代码。

代码语言:javascript
复制
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++是如何工作的,编译器会默默地生成一个等价的免费C函数,

代码语言:javascript
复制
__A_my_member_function(A* this){...}

但是,我不知道如何访问这个自由函数的地址,甚至不知道这是否可能,以及bfd库是否能够通过这个指针定位原始my_member_function的源位置。(至少目前我对虚拟函数不感兴趣。)

换句话说,

1)我需要知道bfd是否能够找到一个成员函数,

2)如果可以,如何将int (A::*)()类型的成员函数指针映射到bfd可以接受的参数(void*)。

通过其他方法(堆栈跟踪),我知道指针是存在的,例如,我可以得到在本例中调用空闲函数的_ZN1A18my_member_functionEv,但问题是如何从&(A::my_member_function)获得这个结果。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-05-05 19:08:59

好吧,我找到办法了。首先,我发现bfd很乐意从成员指针中检测成员函数调试信息,只要指针可以转换为void*

我使用的是clang,它不允许我将成员函数指针转换为任何类型的指针或整数。GCC允许这样做,但会发出警告。甚至还有一个标志可以允许指向成员强制转换的指针,称为-Wno-pmf-conversions

考虑到这些信息,我尽了最大努力将一个成员函数指针转换为void*,最后我使用联合完成了这个任务。

代码语言:javascript
复制
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能够向我提供成员函数的调试信息。

我还没有弄清楚的是,如何获得指向构造函数和析构函数成员函数的指针.

例如

代码语言:javascript
复制
void_caster_t void_caster = {&A::~A};

给出编译器错误:“您不能获取析构函数的地址”。

对于构造函数,我甚至无法找到正确的语法,因为这是一个语法错误。

代码语言:javascript
复制
void_caster_t void_caster = {&A::A};

同样,所有无法实现的逻辑都涉及无意义的回调,但这是不同的,因为我希望指针(或地址)获得调试信息,而不是回调。

票数 0
EN

Stack Overflow用户

发布于 2016-05-05 02:38:47

好吧,有好消息也有坏消息。

好消息是:这是可能的。

坏消息是:这并不是直接的。

您将需要c++filt实用程序。

还有,以某种方式读取可执行文件的符号表,例如readelf。如果可以使用bfd_*调用枚举损坏的符号,则可以为自己节省一步。

另外,这里是一个大的:您需要在文本字符串中使用符号的c++名称。因此,对于&(A::my_member_function),您将需要一种形式:"A::my_member_function()" --这不应该太困难,因为我认为您关心的数量有限。

您需要从readelf -s <executable>获取符号及其地址的列表。准备解析此输出。您需要对字符串中的十六进制地址进行解码,以获得其二进制值。

这些将是残缺的名字。对于每个符号,执行c++filt -n mangled_name并将输出(即管道)捕获为某物(例如nice_name)。它会给出你需要的名字(也就是你想要的漂亮的c++名字)。

现在,如果nice_name与"A:my_member_function()“匹配,那么现在就有了匹配的名称,但是更重要的是,已经有了符号的十六进制地址。适当地将此十六进制值添加到填充functionname_ptr的bfd中。

注:上面的工作,但可能是缓慢的重复调用的c++filt

一种更快的方法是捕获以下命令的管道输出:

代码语言:javascript
复制
readelf -s <executable> | c++filt

这样做也可能更容易,因为您只需解析筛选的输出并查找匹配的好名称。

另外,如果您有多个您关心的符号,那么您可以在一次调用中获得所有地址。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37035842

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档