Reputation: 29
I am wondering how the location information of a variable is presented in a dwarf-file (a file with debug symbols), when the variable is declared as extern. A very simple example to illustrate my question:
simple.c:
#include <stdio.h>
extern int itest;
void main() {
printf("val: %d and addr: %p\n", itest, (void*) &itest);
}
simple_int.c:
int itest = 4;
compile:
gcc -g simple.c simple_int.c -o simple
When I inspect the executable simple using
dwarfdump simple | less
I get information for the variable itest like this:
< 1><0x00000072> DW_TAG_variable
DW_AT_name itest
DW_AT_decl_file 0x00000001 /<censored>/simple.c
DW_AT_decl_line 0x00000003
DW_AT_decl_column 0x0000000c
DW_AT_type <0x00000058>
DW_AT_external yes(1)
DW_AT_declaration yes(1)
There is no entry from which I could derive the location.
Usually I know entries like
DW_AT_location len 0x0009: 0x031440000000000000:
DW_OP_addr 0x00004014
or
DW_AT_location len 0x0002: 0x9164:
DW_OP_fbreg -28
So in which format is the location information stored for this variable declared as extern? Where can I read something about the location?
Thank you for your help
Upvotes: 0
Views: 485
Reputation: 3203
With some compilers, declaring variables as "extern" produces two DW_TAG_variable
entries, one with variable name and type, and a second one with location. You need to parse both entries to associate the name and the location.
Here's an example from GCC10:
test.c:
extern unsigned char test_var;
unsigned char test_var;
test.dwarf:
<1><29e2>: Abbrev Number: 7 (DW_TAG_variable)
<29e3> DW_AT_name : test_var
<29ec> DW_AT_decl_file : 2
<29ed> DW_AT_decl_line : 5
<29ee> DW_AT_decl_column : 22
<29ef> DW_AT_type : <0x29d1>
<29f3> DW_AT_external : 1
<29f3> DW_AT_declaration : 1
<1><29f3>: Abbrev Number: 8 (DW_TAG_variable)
<29f4> DW_AT_specification: <0x29e2>
<29f8> DW_AT_decl_line : 6
<29f9> DW_AT_decl_column : 15
<29fa> DW_AT_location : 9 byte block: 3 40 d0 0 40 1 0 0 0 (DW_OP_addr: 14000d040)
Upvotes: 0
Reputation: 213526
When I execute your repro commands, I observe (using readelf -wi simple
):
Compilation Unit @ offset 0:
...
<0><c>: Abbrev Number: 2 (DW_TAG_compile_unit)
<d> DW_AT_producer : (indirect string, offset: 0x2f): GNU C17 12.2.0 -mtune=generic -march=x86-64 -g -fasynchronous-unwind-tables
<11> DW_AT_language : 29 (C11)
<12> DW_AT_name : (indirect line string, offset: 0): simple.c
<16> DW_AT_comp_dir : (indirect line string, offset: 0x9): /tmp
<1a> DW_AT_low_pc : 0x1139
<22> DW_AT_high_pc : 0x2a
<2a> DW_AT_stmt_list : 0
...
Compilation Unit @ offset 0xb7:
...
<1><72>: Abbrev Number: 5 (DW_TAG_variable)
<73> DW_AT_name : (indirect string, offset: 0x92): itest
<77> DW_AT_decl_file : 1
<78> DW_AT_decl_line : 3
<79> DW_AT_decl_column : 12
<7a> DW_AT_type : <0x58>
<7e> DW_AT_external : 1
<7e> DW_AT_declaration : 1
...
<0><c3>: Abbrev Number: 1 (DW_TAG_compile_unit)
<c4> DW_AT_producer : (indirect string, offset: 0x2f): GNU C17 12.2.0 -mtune=generic -march=x86-64 -g -fasynchronous-unwind-tables
<c8> DW_AT_language : 29 (C11)
<c9> DW_AT_name : (indirect line string, offset: 0x23): simple_int.c
<cd> DW_AT_comp_dir : (indirect line string, offset: 0x9): /tmp
<d1> DW_AT_stmt_list : 0x5a
<1><d5>: Abbrev Number: 2 (DW_TAG_variable)
<d6> DW_AT_name : (indirect string, offset: 0x92): itest
<da> DW_AT_decl_file : 1
<db> DW_AT_decl_line : 1
<dc> DW_AT_decl_column : 5
<dd> DW_AT_type : <0xeb>
<e1> DW_AT_external : 1
<e1> DW_AT_location : 9 byte block: 3 18 40 0 0 0 0 0 0 (DW_OP_addr: 4018)
Just installed dwarfdump
and confirmed that it also sees the definition:
...
COMPILE_UNIT<header overall offset = 0x000000b7>:
< 0><0x0000000c> DW_TAG_compile_unit
DW_AT_producer GNU C17 12.2.0 -mtune=generic -march=x86-64 -g -fasynchronous-unwind-tables
DW_AT_language DW_LANG_C11
DW_AT_name simple_int.c
DW_AT_comp_dir /tmp
DW_AT_stmt_list 0x0000005a
LOCAL_SYMBOLS:
< 1><0x0000001e> DW_TAG_variable
DW_AT_name itest
DW_AT_decl_file 0x00000001 /tmp/simple_int.c
DW_AT_decl_line 0x00000001
DW_AT_decl_column 0x00000005
DW_AT_type <0x00000034>
DW_AT_external yes(1)
DW_AT_location len 0x0009: 0x031840000000000000:
DW_OP_addr 0x00004018
It seems that you are either not looking far enough for the definition of the variable, or the file with the definition is compiled without -g
, or you have over-reduced the test case if the DW_AT_location
is really not present.
Upvotes: 2
Reputation: 105
This might be worth a shot because compiler optimizations can cause certain debugging information to be lost, you could try recompiling with lower optimization levels or even omitting entirely with the '-O0' flag.
gcc -g -O0 simple.c simple_int.c -o simple
Upvotes: -1