WedX - журнал о программировании и компьютерных науках

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

Новый API сценариев GDB-Python выглядит довольно мощным и должен быть очень полезным. Однако написание полезного скрипта для перебора полей в структуре C или 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 main r wzd s1 quit

05.02.2013

  • Пробовали ли вы просматривать исходный код Python в поисках симпатичных принтеров, поставляемых с gcc и gdb? Там должны быть хорошие примеры. 05.02.2013
  • Вы используете Python 2.x или 3.x? Насколько я могу судить, теперь gdb может использовать и то, и другое. И документы gdb подразумевают, что типы эффективно отображаются как объекты dict python. И API для dict объектов различается между двумя версиями. (Например, в версии 2.x iteritems() возвращает отложенный итератор для пар ключ-значение, а items() возвращает список пар ключ-значение; в версии 3.x items() возвращает отложенный итератор, а iteritems() отсутствует.) 05.02.2013
  • питон 2.6.6, gdb 7.2, на x86_64 05.02.2013

Ответы:


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:

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 source, посмотрите, как реализован 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.

05.02.2013
  • Я ищу что-то для x в полях (S): { print x.name, x.type; }, не зная заранее 'a', 'b'. Но спасибо за быстрый ответ! На самом деле попробовал оба ваших примера. В одном из них отсутствует dict или аналогичная ошибка, в другом говорится, что объект gdb.Type не имеет атрибутов iteritems. Я не знаком с питоном. 05.02.2013
  • @minghua: Ну, Python не заключает операторы в фигурные скобки, поэтому ваш код не будет работать… но я предполагаю, что вы преодолели это, иначе вы не могли получить те ошибки, о которых сообщали. 05.02.2013
  • В любом случае, я не уверен на 100%, какие биты вы имеете в виду в двух моих примерах, но если iteritems вызывает AttributeError, пока keys работает, мое первое предположение состоит в том, что вы используете Python 3.x, а я мы дали вам ответ 2.x. Если да, дайте мне знать, и я могу изменить его. 05.02.2013
  • мой питон 2.6.6, gdb 7.2 на x86_64. в любом случае, у меня есть рабочий пример, опубликую выше. _deep_items еще не работает, попробую позже, так как он выглядит лучше. как вы можете видеть, я программист на C, поэтому мой предыдущий пример просто иллюстрирует логику. 05.02.2013
  • Привет, я попробовал еще раз: для имени поле в foo.type.iteritems():, для имени поле в foo.type.iterkeys(): и keys(). Все они вызывают AttributeError. 05.02.2013
  • @abarnet: этот фрагмент кода: print str(instance_) показывает {v1 = 0, v2 = 0, v3 = {w3 = 0}}. Вероятно, это тривиально, но как вы проходите через это? Как только это будет сделано, я думаю, мне все еще нужно получить тип каждого элемента. Это должно быть все необходимое. Я видел этот вопрос SO о доступе к GDB python Value ключи и значения, которые близки, но не совсем то, что мне нужно. 05.02.2013
  • @minghua: Во-первых, причина, по которой вы не можете получить доступ к типу напрямую как dict, заключается в том, что вы используете 7.2. Если вы обновитесь до более поздней версии 7.x, код в моем ответе будет работать. В противном случае вы должны явно вызвать fields(). 05.02.2013
  • @minghua: Во-вторых: вы не можете напрямую перебирать instance_; вам нужно перебрать instance_.type или instance_.type.fields(), чтобы получить имена и типы; то вы можете сделать instance_[name] для каждого имени. Позвольте мне обновить мой ответ, включив в него примеры 7.2 (хотя на самом деле у меня нет 7.2, поэтому это не будет проверено). 05.02.2013
  • @minghua: я также добавил несколько ссылок. Если вы не знаете, как обращаться со словарями в Python, см. docs.python. .org/2/tutorial/datastructures.html#dictionaries. Кроме того, поскольку вы вряд ли сами догадаетесь о таких вещах, как iteritems, запустите обычный интерпретатор Python и воспользуйтесь встроенной справкой. Вы можете, например, написать d={'key': 'value'}, а затем help(d), чтобы увидеть все, что вы можете сделать с помощью dict. 05.02.2013
  • Все работает! Большое спасибо! Окончательный образец обновляется до раздела вопросов. 06.02.2013
  • Новые материалы

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

    Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
    Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

    Учебные заметки: создание моего первого пакета Node.js
    Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

    Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
    Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..

    ИИ в аэрокосмической отрасли
    Каждый полет – это шаг вперед к великой мечте. Чтобы это происходило в их собственном темпе, необходима команда астронавтов для погони за космосом и команда технического обслуживания..


    Для любых предложений по сайту: [email protected]