Заставить библиотеку BFD найти расположение функции-члена класса

Я использую функцию 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 библиотека сможет найти исходное местоположение оригинала my_member_function через этот указатель.
(По крайней мере, на данный момент меня не интересуют виртуальные функции.)

Другими словами,

1) мне нужно знать, если bfd сможет найти функцию-член,

2) и если это возможно, как я могу отобразить указатель на функцию-член типа int (A::*)() на аргумент, который bfd могу взять (void*).


Я знаю другими средствами (трассировка стека), что указатель существует, например, я могу получить, что в этом случае вызывается свободная функция _ZN1A18my_member_functionEv, но проблема в том, как я могу получить это от &(A::my_member_function),

0

Решение

Хорошо, есть хорошие новости и плохие новости.

Хорошая новость: это является возможный.

Плохая новость: это не так просто.

Вам понадобится c++filt полезность.

И какой-то способ чтения таблицы символов вашего исполняемого файла, например readelf, Если вы можете перечислить [искаженные] символы с bfd_* позвоните, вы можете быть в состоянии сохранить себе шаг.

Кроме того, вот Biggie: Вам понадобится 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 ()», теперь у вас есть совпадение, у вас уже есть искаженное имя, но, что более важно, шестнадцатеричный адрес символа. Подайте это шестнадцатеричное значение [соответственно приведенное] к BFD, где вы набивали functionname_ptr


Замечания: Вышеуказанное работает, но может быть медленным с повторными вызовами c++filt

Более быстрый способ сделать это состоит в том, чтобы захватить поток данных:

readelf -s <executable> | c++filt

Это также [вероятно] проще сделать таким образом, поскольку вам нужно только проанализировать отфильтрованный вывод и найти подходящее имя.

Кроме того, если у вас есть несколько символов, о которых вы заботитесь, вы можете получить все адреса за один вызов.

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};

Выдает ошибку компилятора: «Вы не можете взять адрес деструктора».

Для конструктора я даже не смог найти правильный синтаксис, так как это приводит к ошибке синтаксиса.

void_caster_t void_caster = {&A::A};

Опять же, вся логика, лежащая в основе неспособности, связана с бессмысленными обратными вызовами, но это не так, потому что я хочу, чтобы указатель (или адрес) получал отладочную информацию, а не обратные вызовы.

0

По вопросам рекламы [email protected]