GDB Python API: можно ли сделать вызов метода класса / структуры
В Python у меня есть переменная "var" типа gdb.Value, которая соответствует структуре C++. Структура имеет метод "void foo()". Я могу оценить это выражение "var['foo']". Но var['foo']()"будет жаловаться, говоря RuntimeError: Value не вызывается (не TYPE_CODE_FUNC). Я полагаю, что тип значения будет gdb.TYPE_CODE_METHOD (не уверен, но var['foo']. Type.code возвращает 16) в моем случае. Таким образом, я предполагаю, что вопрос заключается в том, поддерживает ли Python API вызовы методов класса, и если нет, есть ли обходной путь? Спасибо!
4 ответа
Хорошо, я думаю, что смог сделать то, что хочу, используя совет Тома и другой обходной путь. Проблема, в которой я нуждался в дополнительном обходном пути, состояла в том (как я упоминал в комментарии выше), что у меня не было имени переменной для составления строки формы: "myval.method()" для передачи в gdb.parse_and_eval. Таким образом, обходной путь для этого состоит в том, чтобы получить адрес переменной и затем привести ее к типу, а затем добавить вызов метода в строку. Тип и адрес существуют в Python API для GDB.Value. Таким образом, решение выглядит следующим образом:
eval_string = "(*("+str(self.val.type)+"*)("+str(self.val.address)+")).method()"
return gdb.parse_and_eval(eval_string);
Это просто отсутствующая функция, которую еще никто не реализовал. Вы можете увидеть, есть ли это в bugzilla, и, если нет, подать ошибку.
Типичный обходной путь - подставить значение "this" аргумента в строку и выполнить вызов через gdb.parse_and_eval. Это обычно работает, но, конечно, заметно лучше.
Вызов метода не поддерживается (пока?) GDB. https://gdb.sourceware.narkive.com/KVTUIAvl/c-method-call-for-a-gdb-value-object-from-within-python
Однако вызов функции поддерживается. Если у вас есть возможность создать оболочку функции, которая будет вызывать ваш метод:
void func(mystruct& arg) { arg.method(); }
Затем вы можете найти эту функцию через глобальный поиск gdb и вызвать:
sym = gdb.lookup_global_symbol('namespace::func(mystruct&)')
result = sym.value()(this.val)
Этот метод не требует получения адреса переменной, что в 50% случаев дает сбой из-за оптимизации компилятора.
Эти методы применимы и к статическим методам.
Используйте переменную удобства.
gdb.set_convenience_variable("tmp", gdb.parse_and_eval("c").address ) gdb.execute("print $tmp->f()")
Если тип известен, вы можете сделать:
gdb.parse_and_eval("C::f")( gdb.parse_and_eval("c").address )
(в качестве альтернативы используйте искаженное имя
_ZN1C1fEv
.nm --demangle
можно использовать например для этого)Если известен только тип целевой функции, вы можете сделать
cftype=gdb.parse_and_eval("C::f").type # ← this is known gdb.parse_and_eval("c")["f"].cast(cftype)( gdb.parse_and_eval("c").address )
Некоторая гибкость не допускается gdb, но не гарантируется:
cftype=gdb.parse_and_eval("* (void (*) (void*)) 0").type gdb.parse_and_eval("c")["f"].cast(cftype)( gdb.parse_and_eval("c").address )
(если это статическая функция, вам не нужно «подделывать» ее как
void const*
, также может выполняться непосредственно в коде C++)
Пример кода С++:
#include<iostream>
struct C{
int x;
void f() {
++x;
std::cout<<x<<"\n";
}
};
int main(){
C c{5};
c.f();
__builtin_trap();
}
Кроме того, если структура является локальной , вам придется применить некоторые обходные пути, описанные в /questions/19438920/vyizov-lyambda-funktsii-v-gdb/60447822#60447822.
Пример кода C++
int main(){
struct C{
int x;
void f() {
++x;
std::cout<<x<<"\n";
}
};
C c{5};
c.f();
__builtin_trap();
}
Пример кода Python
gdb.parse_and_eval("'main::C::f'")(gdb.parse_and_eval("c").address)
В качестве альтернативы используйте
_ZZ4mainEN1C1fEv
.