The new GDB-Python scripting API looks quite powerful and should be very useful. However writing a useful script to iterate through the fields in a struct of C or C++ is not trivial. Does any one know some solid samples that does exactly that?
Thanks in advance.
Update the final sample: Replace the _print_fields()
in early sample.
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
And the output:
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 with the first sample: Got the following sample code working. This is not the optimal as it does a look-up on every field after composing the string field name. abarnert is showing a promising and elegant approach, the working code is updated in the above final update section.
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()
The source file to test with:
struct S2 { int w3; };
struct S1 { int v1, v2; struct S2 v3; } s1;
int main(int argc, char *argv[]) { return 0; }
Example output:
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 session to get the: source /home/me/testpath/wzdfile.py file a.out b main r wzd s1 quit
According to the docs, iterating through the fields of a C struct should be pretty trivial:
If the type is a structure or class type, or an enum type, the fields of that type can be accessed using the Python dictionary syntax. For example, if
some_type
is agdb.Type
instance holding a structure type, you can access its foo field with:bar = some_type['foo']
bar
will be agdb.Field
object; see below under the description of theType.fields
method for a description of thegdb.Field
class.
You can also use Type.fields
to get the fields of a struct
explicitly, but (as of 7.4) you can just use the normal dict
methods as well, so to get a list of name/Field
pairs:
for name, field in foo.type.iteritems():
Or, for just the names:
for name, field in foo.type.iterkeys():
And so on.
This doesn't seem to be directly documented on that page, but gdb.types implies it pretty strongly when it says that deep_items
:
Returns a Python iterator similar to the standard gdb.Type.iteritems method.
For example, given this C type:
struct S {
int x;
int y;
};
You can do this:
(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
From a quick glance at the types.py
source, look at how gdb.types.deep_item(type_)
is implemented, and that does seem to be all there is to it.
Before gdb 7.4, you could not treat a type directly as a dict
. That is, no for name in instance_.type:
or instance_.type.iteritems()
, etc. You had to explicitly call fields
. Anyway, putting it all together, here's a simple example for iterating over all of the fields of a structure with gdb 7.2:
for field in inst.fields:
fname = field.name
ftype = field.type
fval = inst[fname]
Except that this won't work if your struct
has an anonymous struct
inside it. For that, you'll need deep_items
(and, if that isn't there in 7.2, you'll need to look at the code and figure out how to implement it yourself).
So, not quite trivial in 7.2, but pretty simple. And, if you want trivial, just upgrade to 7.4.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With