1

I am wondering how GDB resolves opaque types for C executables for instance.

in a .so

// foo.h
struct bar;

// foo.c
#include "foo.h"
struct bar {
...
}

in my program

#include "foo.h"
struct bar *b; <-- GDB can print the structure.

Even when a second forward declaration is provided with the same name in a new CU also included by my program it seems that GDB is still able to find the correct definition.

I have looked at the dwarfdump for my program and for the .so and to me it seems that the variable DIE entry for b is unconnected with the structure definition of bar which is in a separate CU. There is a structure DIE associated with b but it has no member DIEs.

So for examples in the main program CU dwarf info I would see

< 2><0x00000148>    DW_TAG_variable
                    DW_AT_name                  b
                    DW_AT_decl_file             0x00000001
                    DW_AT_decl_line             0x00000011
                    DW_AT_decl_column           0x00000019
                    DW_AT_type                  <0x000000f2>
                    DW_AT_location              len 0x0003: 0x91b87f: 
                        DW_OP_fbreg -72

and when I chase the DW_AT_type (through a ptr type first) I get

< 1><0x000000db>  DW_TAG_structure_type
                  DW_AT_name                  bar
                  DW_AT_declaration           yes(1)

with no child DW_TAG_members.

However in the other CU there is the correct DW_TAG_structure type with DW_TAG_members. So the crux of the question is how does gdb go from the DW_TAG_variable to the correct DW_TAG_structure even if there are multiple possible definitions do to the same name being used in different CUs as an opaque type?

Thanks in advance.

Employed Russian
  • 199,314
  • 34
  • 295
  • 362
flansel
  • 35
  • 4
  • I presume you are linking `foo.so` into your program, right? It seems like you're about 10 minutes work away from making a [mre]. – pmacfarlane Jun 29 '23 at 23:03
  • GDB uses the debugging symbols that come from `foo.o`, not the declaration in `foo.h`. – Barmar Jun 29 '23 at 23:11
  • @Barmar yes I'm aware of that but atleast to my eyes looking at the actual dwarf data I don't see how the variable DIE entry in my program is related to the structure DIE entry. The variable DIE DW_AT_type points to a structure DIE without any members. – flansel Jun 29 '23 at 23:16

1 Answers1

1

GDB simply matches the types by name across all TUs. Consider the following example:

// main.c
struct bar;

extern struct bar* fn1();
extern struct bar* fn2();

int main()
{
  struct bar *b1 = fn1();
  struct bar *b2 = fn2();
  return 0;
}

// foo1.c
#include <stdlib.h>

struct bar {
  int x;
};

struct bar* fn1() {
  struct bar* b = malloc(sizeof(*b));
  b->x = 42;
  return b;
}

// foo2.c
#include <stdlib.h>

struct bar {
  double zzz;
};

struct bar* fn2() {
  struct bar* b = malloc(sizeof(*b));
  b->zzz = 1234.0;
  return b;
}

Compile this with gcc -g main.c foo1.c foo2.c and observe that GDB doesn't really know which struct bar is the correct one:

gdb -q ./a.out
(gdb) start
Temporary breakpoint 1, main () at main.c:8
8         struct bar *b1 = fn1();
(gdb) n
9         struct bar *b2 = fn2();
(gdb) n
10        return 0;
(gdb) p *b1
$1 = {zzz = 2.0750757125332355e-322}

(gdb) x/d b1
0x5555555592a0: 42

(gdb) p *b2
$2 = {zzz = 1234}
Employed Russian
  • 199,314
  • 34
  • 295
  • 362
  • Oh huh, I guess it just worked out that in my limited tests it was guessing correctly. Great that answers that then, tyvm! – flansel Jun 30 '23 at 06:13