Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to define offsetof() macro in GDB

Tags:

c

debugging

gdb

I want to define some auxiliary marcos in GDB for convenience, one of them is the offsetof() macro.

I tried

define offsetof
    if $argc == 2
        (int)(&((($arg0 *)0)->$arg1))
    end
end

It doesn't work because:

  1. A type such as struct node will be splitted into Struct and node, so $arg0 = Struct, $arg1 = node.
  2. I am not sure if gdb's command can return a value.

Can anyone give me a hand?

like image 320
Douglas Su Avatar asked Sep 21 '16 04:09

Douglas Su


People also ask

Is offsetof a macro?

The offsetof() macro is an ANSI -required macro that should be found in stddef. h. Simply put, the offsetof() macro returns the number of bytes of offset before a particular element of a struct or union. The declaration of the macro varies from vendor to vendor and depends upon the processor architecture.

How do I use macros in GDB?

If there is a current stack frame, GDB uses the macros in scope at that frame's source code line. Otherwise, GDB uses the macros in scope at the current listing location; see List. Whenever GDB evaluates an expression, it always expands any macro invocations present in the expression.

How can I determine the byte offset of a field within a structure?

Use offsetof() to find the offset from the start of z or from the start of x . #include <stddef. h> size_t offsetof(type, member); offsetof() returns the offset of the field member from the start of the structure type.

How do you find the offset of a structure member?

C library macro - offsetof() The C library macro offsetof(type, member-designator) results in a constant integer of type size_t which is the offset in bytes of a structure member from the beginning of the structure. The member is given by member-designator, and the name of the structure is given in type.


2 Answers

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.

like image 81
Tom Tromey Avatar answered Nov 12 '22 08:11

Tom Tromey


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.

like image 23
Eirik Fuller Avatar answered Nov 12 '22 09:11

Eirik Fuller