Подтвердить что ты не робот

Сценарии GDB-Python: любые образцы, итерации через поля структуры C/С++

Новый API-интерфейс сценариев GDB-Python выглядит достаточно мощным и должен быть очень полезным. Однако писать полезный script для итерации по полям в структуре C или С++ не является тривиальным. Кто-нибудь знает какие-то прочные образцы, которые делают именно это?

Спасибо заранее.


Обновить окончательный образец: Заменить _print_fields() в ранней выборке.

    if l.type.code == gdb.TYPE_CODE_STRUCT:
        print "Found a struct  %s " % n
        #self._print_fields(n, t)
        self._print_deep_items(n, t, l)
    else:
        print "Found no struct"

def _print_deep_items (self, n_, type_, instance_):
    for fld in type_.fields():
        fn = fld.name
        ft = fld.type
        fv = instance_[fn]
        if fv.type.code == gdb.TYPE_CODE_STRUCT:
            print "  Found a sub struct  %s " % fn
            self._print_deep_items(fn, ft, fv)
        else:
            print "    Field %s " % fn, " type %s " % ft.tag, " value %s " % fv

И вывод:

  variable s1   type S1
Found a struct  s1
    Field v1   type None   value 0
    Field v2   type None   value 0
  Found a sub struct  v3
    Field w3   type None   value 0

Обновление с первым образцом: Получил следующий пример кода. Это не является оптимальным, так как он выполняет поиск по каждому полю после создания имени поля строки. abarnert демонстрирует многообещающий и элегантный подход, рабочий код обновляется в последнем разделе последнего обновления.

import gdb
class PrintGList(gdb.Command):
    """print fields of a struct: wzd struct_object

Iterate through the fields of a struct, and display
a human-readable form of the objects."""
    def __init__(self):
        gdb.Command.__init__(self, "wzd", gdb.COMMAND_DATA, gdb.COMPLETE_SYMBOL, True)

    def invoke(self, arg, from_tty):

        arg_list = gdb.string_to_argv(arg)
        if len(arg_list) < 1:
            print "usage: wzd struct"
            return

        n = arg_list[0]
        l = gdb.parse_and_eval(arg_list[0])
        m = l.type.tag

        print "  variable %s " % n, " type %s " % m
        try:
            t = gdb.lookup_type(m)
        except RuntimeError, e:
            print "type %s not found" % t
            return

        if l.type.code == gdb.TYPE_CODE_STRUCT:
            print "Found a struct  %s " % n
            self._print_fields(n, t)
        else:
            print "Found no struct"

    def _print_fields(self, n, typeobject):
        print typeobject
        flds = typeobject.fields()
        for x in flds:
            sn = n + "." + x.name
            print "  field %s" % sn, " code %s " % x.type.code, " type %s " % x.type.tag
            if x.type.code == gdb.TYPE_CODE_STRUCT:
                print "Found sub level struct  %s " % sn
                sl = gdb.parse_and_eval(sn)
                sm = sl.type.tag
                st = gdb.lookup_type( sm )
                self._print_fields(sn, x.type)

    def _deep_items (self, type_):
        for k, v in type_.iteritems():
            if k:
                print " k v %s " % k , " %s " % v
            else:
                print "   v    ",      " %s " % v

PrintGList()

Исходный файл для проверки:

struct S2 {        int w3;    };
struct S1 {        int v1, v2;      struct S2 v3; } s1;
int main(int argc, char *argv[]) {   return 0; }

Пример вывода:

  variable s1   type S1
Found a struct  s1
S1
  field s1.v1  typecode 8   type None
  field s1.v2  typecode 8   type None
  field s1.v3  typecode 3   type S2
Found sub level struct  s1.v3
S2
  field s1.v3.w3  typecode 8   type None

Сессия GDB для получения:   source/home/me/testpath/wzdfile.py   файл a.out   b основной   р   wzd s1   бросить курить

4b9b3361

Ответ 1

В соответствии с документами итерация через поля структуры C должна быть довольно тривиальной:

Если тип является структурой или типом класса или типом перечисления, поля этого типа могут быть доступны с использованием синтаксиса словаря Python. Например, если some_type является экземпляром gdb.Type, имеющим тип структуры, вы можете получить доступ к своему полю foo с помощью:

bar = some_type['foo']

bar будет gdb.Field объектом; см. ниже описание метода Type.fields для описания класса gdb.Field.

Вы также можете использовать Type.fields, чтобы явно получить поля struct, но (с 7.4) вы можете просто использовать обычный dict также, чтобы получить список имен / Field pairs:

for name, field in foo.type.iteritems():

Или, просто для имен:

for name, field in foo.type.iterkeys():

И так далее.

Это, похоже, не задокументировано на этой странице, но gdb.types подразумевает это довольно сильно, когда говорится, что deep_items:

Возвращает итератор Python, похожий на стандартный метод gdb.Type.iteritems.

Например, данный тип C:

struct S {
    int x;
    int y;
};

Вы можете сделать это:

(gdb) python struct_S = my_s.type # or gdb.lookup_type("struct S"), etc.
(gdb) python print struct_S.keys()
{['a', 'b']}
(gdb) python print my_s['a']
0

С быстрым взглядом на источник types.py посмотрите, как реализовано gdb.types.deep_item(type_), и, похоже, все, что ему нужно.


Перед gdb 7.4 вы не можете обращаться с типом непосредственно как dict. То есть, нет for name in instance_.type: или instance_.type.iteritems() и т.д. Вы должны были явно вызвать fields. В любом случае, все вместе, вот простой пример для итерации по всем полям структуры с помощью gdb 7.2:

for field in inst.fields:
    fname = field.name
    ftype = field.type
    fval = inst[fname]

За исключением того, что это не будет работать, если ваш struct имеет анонимный struct внутри него. Для этого вам понадобится deep_items (и, если этого нет в 7.2, вам нужно будет посмотреть на код и выяснить, как его реализовать самостоятельно).

Итак, не совсем тривиально в 7.2, но довольно просто. И, если вы хотите тривиально, просто обновите до 7.4.