Montag, Januar 27, 2020

GDB-Python-scripting: alle Proben Durchlaufen C/C++ – struct-Felder

Den neuen GDB-Python-scripting-API sieht Recht mächtig und sollte sehr nützlich sein. Jedoch schreiben ein nützliches script zum Durchlaufen der Felder in einem struct in C oder C++ ist nicht trivial. Hat jemand wissen, einige Feste Proben, was genau das macht?

Vielen Dank im Voraus.


Update die endgültige Stichprobe: Ersetzen Sie die _print_fields() im frühen Probe.

    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

Und die Ausgabe:

  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

Update mit der ersten Probe: haben Sie das folgende Beispiel-code funktioniert. Dies ist nicht das optimale, wie es ist ein look-up auf jedes Feld nach dem verfassen des string-Feld name. abarnert zeigt eine vielversprechende und eleganten Ansatz, den funktionierenden code aktualisiert wird, der oben in der letzten update-Abschnitt.

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()

Der source-Datei zu testen mit:

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

Beispiel-Ausgabe:

  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-Sitzung zu bekommen:
Quelle /home/me/testpath/wzdfile.py
Datei ein.aus
b main
r
wzd s1
beenden Sie

  • Haben Sie versucht, Suche durch die Python-Quelltext für die pretty-printers, die mit gcc und gdb? Es müssen gute Beispiele gibt.
  • Sind Sie mit Python 2.x, oder 3.x? Was ich sagen kann, gdb kann nun entweder. Und die gdb-docs bedeuten, dass die Arten sind effektiv ausgesetzt, wie python dict Objekte. Und die API für dict Objekte ist der Unterschied zwischen den beiden Versionen. (Zum Beispiel in 2.x, iteritems() gibt eine lazy iterator über die Schlüssel-Wert-Paare, während items() gibt eine Liste von Schlüssel-Wert-Paare; in 3.x, items() gibt eine lazy-iterator, und es gibt keine iteritems().)
  • python 2.6.6, gdb-7.2, x86_64
InformationsquelleAutor minghua | 2013-02-05

1 Kommentar

  1. 8

    Laut die docs, Durchlaufen die Felder eines C-struct sollte ziemlich trivial:

    Wenn der Typ einer Struktur oder Klasse geben, oder einen enum-Typ, der die Felder dieses Typs zugegriffen werden kann mit Hilfe der Python-dictionary syntax. Zum Beispiel, wenn some_type ist ein gdb.Type Instanz holding eine Struktur geben, können Sie auf dessen foo Feld mit:

    bar = some_type['foo']

    bar wird ein gdb.Field Objekt; siehe unten bei der Beschreibung der Type.fields Methode für eine Beschreibung der gdb.Field Klasse.

    Können Sie auch Type.fields um die Felder einer struct explizit, aber (ab 7.4), können Sie einfach die normalen dict Methoden als gut, so dass man eine Liste von Namen/Field Paare:

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

    Oder, um nur die Namen:

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

    Und so weiter.

    Scheint dies nicht direkt dokumentiert auf dieser Seite, aber gdb.Typen deutet es ziemlich stark, wenn es sagt, dass deep_items:

    Gibt eine Python-iterator ist ähnlich dem der standard-gdb.Typ.iteritems-Methode.

    Beispielsweise diese C-Typ:

    struct S {
        int x;
        int y;
    };

    Können Sie dies tun:

    (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

    Von einem schnellen Blick auf die types.py Quelle, schauen Sie, wie gdb.types.deep_item(type_) implementiert ist, und das scheint tatsächlich so zu sein, alles dort ist zu ihm.


    Bevor gdb 7.4, man konnte nicht behandeln, ein Typ direkt als dict. Das heißt, keine for name in instance_.type: oder instance_.type.iteritems() usw. Sie hatte explizit nennen fields. Trotzdem, setzen Sie alle zusammen, hier ist ein einfaches Beispiel für die Iteration über alle Felder einer Struktur mit gdb 7.2:

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

    Außer, dass das nicht funktionieren, wenn Ihr struct hat eine anonyme struct drin. Für diese, müssen Sie deep_items (und wenn, dass gibt es nicht in 7.2, müssen Sie Blick auf den code werfen und herausfinden, wie man es selbst implementieren).

    So, nicht ganz trivial in 7.2, aber ziemlich einfach. Und, wenn Sie möchten, trivial, einfach ein upgrade auf 7.4.

    • Ich bin auf der Suche nach etwas „für x in Felder(N): { print x.name, x.type; }“, ohne zu wissen, ‚a‘, ‚b‘ up-front. Danke für die schnelle Antwort, aber! Tatsächlich habe versucht, sowohl Ihrem Beispiel. Für eine bekam eine fehlende „dict“ – oder ähnliche Fehler, die andere sagt gdb.Art-Objekt hat kein Attribut iteritems. Ich bin nicht vertraut mit python.
    • Ok, ich sehe, Ihr aktualisiertes Beispiel kann das sein, was ich Suche.
    • Naja, die Python, die keine Anweisungen in geschweiften Klammern, so dass Ihr code nicht funktionieren wird… aber ich nehme an, du hast Vergangenheit, oder Sie konnte nicht bekommen haben die Fehler, die Sie berichtet.
    • Wie auch immer, ich bin mir nicht 100% sicher, welche bits du bist unter Bezugnahme auf, wie meine zwei Beispiele, aber wenn iteritems ist das auslösen einer AttributeError während keys ist arbeiten, meine erste Vermutung ist, dass Sie mit Python 3.x, und ich habe Ihnen eine 2.x Antwort. Wenn ja, lassen Sie mich wissen, und ich kann es ändern.
    • meine python 2.6.6, gdb-7.2 auf x86_64. anyway, ich habe ein Beispiel der Arbeit, werde nach oben. haben nicht die _deep_items funktioniert noch, werde später versuchen, wie es später schöner aussieht. wie Sie sehen können ich bin ein C-Programmierer, daher meine obigen Beispiel ist nur zur Veranschaulichung der Logik.
    • Hallo, ich habe versucht es wieder: „name-Feld in foo.Typ.iteritems():“, „Namen-Feld in foo.Typ.iterkeys():“, und „keys()“. Sie alle heben ein „AttributeError“.
    • Dieses code-Stück: print str(instance_) zeigt {v1 = 0, v2 = 0, v3 = {w3 = 0}}. Wahrscheinlich ist es trivial, aber wie kann man Sie durchqueren es? Sobald das geschehen ist, denke ich, noch brauchen, um den Typ der einzelnen Elemente. Das sollte alles, was benötigt wird. Ich sah dieser Frage ALSO über den Zugriff auf GDB-python Wert Schlüssel und Werte, dass ist in der Nähe, aber nicht genau das was ich brauche.
    • Erstens, der Grund Sie können nicht auf die Art direkt als dict ist, dass Sie 7.2. Wenn Sie ein upgrade auf eine neuere 7.x der code in meiner Antwort funktioniert. Ansonsten müssen Sie ausdrücklich nennen fields().
    • Zweitens: Man kann nicht Durchlaufen direkt über instance_; Sie haben zu Durchlaufen instance_.type oder instance_.type.fields() um die Namen und Typen; dann können Sie instance_[name] für jeden Namen. Lassen Sie mich aktualisieren meine Antwort zu gehören 7.2 Beispiele (obwohl ich eigentlich gar nicht haben, 7.2, so wird dies nicht getestet).
    • Ich habe auch ein paar links. Wenn Sie nicht sicher sind, wie Sie sich mit dictionaries in Python, siehe docs.python.org/2/tutorial/datastructures.html#dictionaries. Auch, weil Sie wahrscheinlich nicht zu erraten, Dinge wie iteritems auf Ihre eigenen, Feuer einen regelmäßigen Python-interpreter und verwenden Sie die integrierte Hilfe. Sie können, z.B., schreiben d={'key': 'value'}, dann help(d) zu sehen, alle die Dinge, die Sie tun können, mit einem dict.
    • Alles funktioniert! Ich danke Ihnen sehr! Die endgültige Stichprobe aktualisiert, um die Frage Abschnitt.

Kostenlose Online-Tests