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.

Tags:

C

Debugging

Gdb