How to define offsetof() macro in GDB
Rather than define offsetof
as a command, I think it's better to define it as a function. That way you can use it in expressions; and if you just want to see the offset you can always just use print
.
There are two ways to define offsetof
as a function.
If you are debugging C or C++, you can simply define it as a macro:
(gdb) macro define offsetof(t, f) &((t *) 0)->f
So given:
struct x {
int a;
long b;
};
On my machine I get:
(gdb) p offsetof(struct x, a)
$1 = (int *) 0x0
(gdb) p offsetof(struct x, b)
$2 = (long *) 0x8
The reason for the "C or C++" restriction above is that other languages don't run their expressions through gdb's built-in preprocessor.
If you want it to work in other languages, then the answer is to write a new convenience function in Python. This is a bit more involved, but see the gdb documentation for gdb.Function
.
If you use python to define offsetof
, you might begin with something like this:
import gdb
class offsetof(gdb.Command):
def invoke(self, args, from_tty):
value, name = args.split()
struct = gdb.parse_and_eval(value)
fields = { field.name: field for field in struct.type.fields() }
gdb.write("{} offset: {} bits\n".format(name, fields[name].bitpos))
offsetof("offsetof", gdb.COMMAND_USER)
If you save that to a file, and insure that the directory where you save it is in sys.path
, you can import it. For example, if you save it to your home directory, you might do something along these lines:
(gdb) pi
>>> import os
>>> sys.path.insert(0, os.getenv('HOME'))
>>> import offsetof
>>>
(gdb)
If your gdb has no pi
command you can prepend python
to each command following a >>>
prompt.
If gdb imports offsetof
with no complaint, you should then be able to invoke offsetof
as a gdb command. As written it expects two arguments (space separated), a value, and a name. If the value is a struct with a field having the provided name, it will report the offset in bits (not bytes, because the underlying python code can handle bitfields).
The code here can be improved. It has no real error handling beyond what it inherits from the code it calls, and as written it doesn't handle pointers.
This page describes some of the underlying code used in that example; the target
method it mentions might provide the beginnings of handling pointers (or you can just dereference pointers in the values you pass in, i.e. you might specify *this
rather than this
as the first parameter). The section on Type.fields()
mentions other attributes besides bitpos
which might also be of interest if you want to report other details about struct layout.