gdb doesn't find debug info for local static variables - c

I'm having trouble accessing debug information for local static variables with gdb. I created a very simple example that shows the behaviour:
int global = 0;
static int g_static = 1;
int main(void)
{
static int l_static = 2;
return global + g_static + l_static;
}
I compiled with arm-none-eabi-gcc (I'm compiling for an MCU target) using -O0 and -gdwarf-2 and I can see the debug information for all 3 variables in the output of objdump -g:
<1><29>: Abbrev Number: 2 (DW_TAG_variable)
<2a> DW_AT_name : (indirect string, offset: 0x9): global
<2e> DW_AT_decl_file : 1
<2f> DW_AT_decl_line : 1
<30> DW_AT_decl_column : 5
<31> DW_AT_type : <0x3c>
<35> DW_AT_external : 1
<36> DW_AT_location : 5 byte block: 3 0 0 0 0 (DW_OP_addr: 0)
<1><3c>: Abbrev Number: 3 (DW_TAG_base_type)
<3d> DW_AT_byte_size : 4
<3e> DW_AT_encoding : 5 (signed)
<3f> DW_AT_name : int
<1><43>: Abbrev Number: 4 (DW_TAG_variable)
<44> DW_AT_name : (indirect string, offset: 0xac): g_static
<48> DW_AT_decl_file : 1
<49> DW_AT_decl_line : 2
<4a> DW_AT_decl_column : 12
<4b> DW_AT_type : <0x3c>
<4f> DW_AT_location : 5 byte block: 3 0 0 0 0 (DW_OP_addr: 0)
<1><55>: Abbrev Number: 5 (DW_TAG_subprogram)
<56> DW_AT_external : 1
<57> DW_AT_name : (indirect string, offset: 0x17): main
<5b> DW_AT_decl_file : 1
<5c> DW_AT_decl_line : 4
<5d> DW_AT_decl_column : 5
<5e> DW_AT_prototyped : 1
<5f> DW_AT_type : <0x3c>
<63> DW_AT_low_pc : 0x0
<67> DW_AT_high_pc : 0x28
<6b> DW_AT_frame_base : 0x0 (location list)
<6f> DW_AT_GNU_all_call_sites: 1
<2><70>: Abbrev Number: 4 (DW_TAG_variable)
<71> DW_AT_name : (indirect string, offset: 0x0): l_static
<75> DW_AT_decl_file : 1
<76> DW_AT_decl_line : 6
<77> DW_AT_decl_column : 14
<78> DW_AT_type : <0x3c>
<7c> DW_AT_location : 5 byte block: 3 0 0 0 0 (DW_OP_addr: 0)
In the symbol table l_static is given a suffix to make it unique and prevent ambiguity. nm output:
00000000 b $d
00000000 d $d
00000000 d $d
0000001c t $d
00000000 t $t
00000000 d g_static
00000000 B global
00000000 d l_static.0
00000001 T main
Yet when I try to access it using gdb, I can only access debug info for global and g_static but not for l_static or even 'l_static.0'. It looks like gdb knows about the existence of l_static.0but can't find the related debug info.:
(gdb) ptype global
type = int
(gdb) ptype g_static
type = int
(gdb) ptype l_static
No symbol "l_static" in current context.
(gdb) ptype 'l_static.0'
type = <data variable, no debug info>
I have tried with gdb 7.6.1 and 11.2 with the same result. As far as I understand it the information is there, as shown by the output of objdump -g. But for some reason gdb can't find it.
My gut feeling is that this might be related to the way gcc appends the .0 to the local static's symbol name. Maybe this leads to a mismatch between the symbol name and the name related to the debug info?
Hoping for anyone who can shed some light on this. Thanks in advance!

You need to stop inside the main function to see that variable:

I found out how to do it without running the binary and setting a breakpoint.
(gdb) ptype main::l_static
type = int
Apparently gdb knows in which function the local static is defined and lets you access it in this c++ namespace-style way, even if the relevant stack frame has not been selected. This is documented in section 10.3 of the gdb manual.

Related

How to get the value of a variable in dwarf?

I am parsing dwarf files, and I want to get the value of a variable or a pointer.
For example,
#include<stdio.h>
int main(){
int *a=malloc(4*sizeof(int));
a[0]=1;
int *b=&a;
int c=a[0];
return 0;
}
I got the dwarf debug information like this:
<2><304>: Abbrev Number: 17 (DW_TAG_variable)
<305> DW_AT_name : a
<307> DW_AT_decl_file : 1
<308> DW_AT_decl_line : 4
<309> DW_AT_decl_column : 10
<30a> DW_AT_type : <0x341>
<30e> DW_AT_location : 2 byte block: 91 58 (DW_OP_fbreg: -40)
<2><311>: Abbrev Number: 18 (DW_TAG_subprogram)
<312> DW_AT_external : 1
<312> DW_AT_name : (indirect string, offset: 0x3f): malloc
<316> DW_AT_decl_file : 8
<317> DW_AT_decl_line : 0
<318> DW_AT_prototyped : 1
<318> DW_AT_type : <0x47>
<31c> DW_AT_declaration : 1
<31c> DW_AT_sibling : <0x326>
<3><320>: Abbrev Number: 19 (DW_TAG_formal_parameter)
<321> DW_AT_type : <0x39>
<3><325>: Abbrev Number: 0
<2><326>: Abbrev Number: 17 (DW_TAG_variable)
<327> DW_AT_name : b
<329> DW_AT_decl_file : 1
<32a> DW_AT_decl_line : 7
<32b> DW_AT_decl_column : 10
<32c> DW_AT_type : <0x341>
<330> DW_AT_location : 2 byte block: 91 60 (DW_OP_fbreg: -32) [without DW_AT_frame_base]
<2><333>: Abbrev Number: 17 (DW_TAG_variable)
<334> DW_AT_name : c
<336> DW_AT_decl_file : 1
<337> DW_AT_decl_line : 8
<338> DW_AT_decl_column : 9
<339> DW_AT_type : <0x65>
<33d> DW_AT_location : 2 byte block: 91 54 (DW_OP_fbreg: -44) [without DW_AT_frame_base]
I get the name,type,frame base offset of a,b and c, but could I know the value of int *b and int c ?

How does debugger know the local variables' name?

I begin to learn compiler.
I know that .symtab in ELF stores information about global variables and functions, but I don't find any valid information about local variables. For those local variables that are allocated on the stack, how could a debugger know their name? Are there any helpful information in ELF?
For example, here is a stupid C code:
void printLocal(){
char c1_loc='a';
int i_loc=1;
char c2_loc='b';
double d_loc=2;
char c3_loc='c';
float f_loc=3;
char c4_loc='d';
short s_loc=4;
printf("&c1_loc = %p\n",&c1_loc);
printf("&i_loc = %p\n",&i_loc);
printf("&c2_loc = %p\n",&c2_loc);
printf("&d_loc = %p\n",&d_loc);
printf("&c3_loc = %p\n",&c3_loc);
printf("&f_loc = %p\n",&f_loc);
printf("&c4_loc = %p\n",&c4_loc);
printf("&s_loc = %p\n",&s_loc);
}
And I get the .debug_info in ELF :
<1><490>: Abbrev Number: 19 (DW_TAG_subprogram)
<491> DW_AT_external : 1
<491> DW_AT_name : (indirect string, offset: 0x2b): printLocal
<495> DW_AT_decl_file : 1
<496> DW_AT_decl_line : 42
<497> DW_AT_decl_column : 6
<498> DW_AT_low_pc : 0x12ff
<4a0> DW_AT_high_pc : 0x129
<4a8> DW_AT_frame_base : 1 byte block: 9c (DW_OP_call_frame_cfa)
<4aa> DW_AT_GNU_all_tail_call_sites: 1
<4aa> DW_AT_sibling : <0x527>
<2><4ae>: Abbrev Number: 20 (DW_TAG_variable)
<4af> DW_AT_name : (indirect string, offset: 0x13d): c1_loc
<4b3> DW_AT_decl_file : 1
<4b4> DW_AT_decl_line : 43
<4b5> DW_AT_decl_column : 10
<4b6> DW_AT_type : <0x91>
<4ba> DW_AT_location : 2 byte block: 91 52 (DW_OP_fbreg: -46)
<2><4bd>: Abbrev Number: 20 (DW_TAG_variable)
<4be> DW_AT_name : (indirect string, offset: 0xc): i_loc
<4c2> DW_AT_decl_file : 1
<4c3> DW_AT_decl_line : 44
<4c4> DW_AT_decl_column : 9
<4c5> DW_AT_type : <0x65>
<4c9> DW_AT_location : 2 byte block: 91 58 (DW_OP_fbreg: -40)
<2><4cc>: Abbrev Number: 20 (DW_TAG_variable)
<4cd> DW_AT_name : (indirect string, offset: 0x126): c2_loc
<4d1> DW_AT_decl_file : 1
<4d2> DW_AT_decl_line : 45
<4d3> DW_AT_decl_column : 10
<4d4> DW_AT_type : <0x91>
<4d8> DW_AT_location : 2 byte block: 91 53 (DW_OP_fbreg: -45)
<2><4db>: Abbrev Number: 20 (DW_TAG_variable)
<4dc> DW_AT_name : (indirect string, offset: 0xce): d_loc
<4e0> DW_AT_decl_file : 1
<4e1> DW_AT_decl_line : 46
<4e2> DW_AT_decl_column : 12
<4e3> DW_AT_type : <0x334>
<4e7> DW_AT_location : 2 byte block: 91 60 (DW_OP_fbreg: -32)
<2><4ea>: Abbrev Number: 20 (DW_TAG_variable)
<4eb> DW_AT_name : (indirect string, offset: 0x333): c3_loc
<4ef> DW_AT_decl_file : 1
<4f0> DW_AT_decl_line : 47
<4f1> DW_AT_decl_column : 10
<4f2> DW_AT_type : <0x91>
<4f6> DW_AT_location : 2 byte block: 91 54 (DW_OP_fbreg: -44)
<2><4f9>: Abbrev Number: 20 (DW_TAG_variable)
<4fa> DW_AT_name : (indirect string, offset: 0x32d): f_loc
<4fe> DW_AT_decl_file : 1
<4ff> DW_AT_decl_line : 48
<500> DW_AT_decl_column : 11
<501> DW_AT_type : <0x364>
<505> DW_AT_location : 2 byte block: 91 5c (DW_OP_fbreg: -36)
<2><508>: Abbrev Number: 20 (DW_TAG_variable)
<509> DW_AT_name : (indirect string, offset: 0x159): c4_loc
<50d> DW_AT_decl_file : 1
<50e> DW_AT_decl_line : 49
<50f> DW_AT_decl_column : 10
<510> DW_AT_type : <0x91>
<514> DW_AT_location : 2 byte block: 91 55 (DW_OP_fbreg: -43)
<2><517>: Abbrev Number: 20 (DW_TAG_variable)
<518> DW_AT_name : (indirect string, offset: 0x1e): s_loc
<51c> DW_AT_decl_file : 1
<51d> DW_AT_decl_line : 50
<51e> DW_AT_decl_column : 11
<51f> DW_AT_type : <0x5e>
<523> DW_AT_location : 2 byte block: 91 56 (DW_OP_fbreg: -42)
when I use GDB to debug the program, I get:
(gdb) info locals
c1_loc = 97 'a'
i_loc = 1
c2_loc = 98 'b'
d_loc = 2
c3_loc = 99 'c'
f_loc = 3
c4_loc = 100 'd'
s_loc = 4
I don't know how GDB get the name of the local variables, hope someone could help me.

Information about Section Index field (st_shndx) in Section SHT_DYNSYM & SHT_SYMTAB

Toolchain:
Product: ARM Compiler 5.04
Component: ARM Compiler 5.04 update 1 (build 49)
From ELF Portable Formats Specification, Version 1.1,
Section Index field (st_shndx) contains:
Every symbol table entry is ‘‘defined’’ in relation to some section; this member holds the relevant section header table index.
I am compiling a simple object (exports one global data & routine) to understand various fields of ELF
Source code (test.c):
__declspec(dllexport) int x21 = 0x100;
__declspec(dllexport) void bar21(void)
{
x21++;
}
Build script used (build.bat)
armcc -c test.c
armlink --bpabi --dll -o test.dll test.o
fromelf -cdrsy -o test.txt test.dll
My query is about usage of st_shndx field of DYNSYM section & SYMTAB section.
Output file
(Removed few sections to keep it short)
** Section #1 'ER_RO' (SHT_PROGBITS) [SHF_ALLOC + SHF_EXECINSTR]
Size : 24 bytes (alignment 4)
Address: 0x00008000
$a
.text
bar21
0x00008000: e59f000c .... LDR r0,[pc,#12] ; [0x8014] = 0
0x00008004: e5901000 .... LDR r1,[r0,#0]
0x00008008: e2811001 .... ADD r1,r1,#1
0x0000800c: e5801000 .... STR r1,[r0,#0]
0x00008010: e12fff1e ../. BX lr
$d
0x00008014: 00000000 .... DCD 0
** Section #2 'ER_RW' (SHT_PROGBITS) [SHF_ALLOC + SHF_WRITE]
Size : 4 bytes (alignment 4)
Address: 0x00000000
0x000000: 00 01 00 00 ....
** Section #3 '.dynstr' (SHT_STRTAB)
Size : 32 bytes
** Section #4 '.dynsym' (SHT_DYNSYM)
Size : 80 bytes (alignment 4)
String table #3 '.dynstr'
Last local symbol no. 1
Symbol table .dynsym (4 symbols, 1 local)
# Symbol Name Value Bind Sec Type Vis Size
========================================================================
1 .data 0x00000000 Lc 1 Sect De 0x4
2 shared_2.dll 0x00000000 Gb Abs Data De
3 x21 0x00000000 Gb 1 Data Pr 0x4
4 bar21 0x00008000 Gb 2 Code Pr 0x14
** Section #5 '.hash' (SHT_HASH)
Size : 40 bytes (alignment 4)
Symbol table #4 '.dynsym'
<Section Truncated>
** Section #7 '.version' (SHT_GNU_versym)
Size : 10 bytes (alignment 4)
Symbol table #4 '.dynsym'
<Section Truncated>
** Section #8 '.version_d' (SHT_GNU_verdef)
Size : 56 bytes (alignment 4)
String table #3 '.dynstr'
<Section Truncated>
** Section #9 '.dynamic' (SHT_DYNAMIC)
Size : 120 bytes (alignment 4)
String table #3 '.dynstr'
<Section Truncated>
** Section #10 '.debug_frame' (SHT_PROGBITS)
Size : 68 bytes
** Section #11 '.symtab' (SHT_SYMTAB)
Size : 176 bytes (alignment 4)
String table #12 '.strtab'
Last local symbol no. 6
Symbol table .symtab (10 symbols, 6 local)
# Symbol Name Value Bind Sec Type Vis Size
========================================================================
1 $a 0x00008000 Lc 1 -- De
2 $d 0x00008014 Lc 1 -- De
3 $d.realdata 0x00000000 Lc 2 -- De
4 shared_2.c 0x00000000 Lc Abs File De
5 .text 0x00008000 Lc 1 Sect De
6 .data 0x00000000 Lc 2 Sect De 0x4
7 BuildAttributes$$ARM_ISAv4$S$PE$A:L22$X:L11$S22$IEEE1$~IW$USESV6$~STKCKD$USESV7$~SHL$OSPACE$EBA8$STANDARDLIB$REQ8$PRES8$EABIv2
0x00000000 Gb Abs -- Hi
8 shared_2.dll 0x00000000 Gb Abs Data De
9 x21 0x00000000 Gb 2 Data Pr 0x4
10 bar21 0x00008000 Gb 1 Code Pr 0x14
Section 1 is Code area (bar21 routine is present here)
Section 2 is RW area (x21 variable is present here)
Now, if we see st_shndx (section index -- marked as "Sec" in output above) field in DYNSYM section & SYMTAB section for these two variables is different.
For Example:
x21 in DYNSYM points to section 1 (code area) & in SYMTAB, it points to section 2 (RW area)
Can someone help me understand why? Or guide me to resource where I can get more information on this.
Regards,
Raju Udava

storage classes in C language [duplicate]

This question already has an answer here:
SIZE command in UNIX
(1 answer)
Closed 7 years ago.
In this program i am not declaring any variable still is showing data segment (BSS) size as 8 bytes.why ?
achul#achul:~/chennai/misclaneous$ vi memory.c
#include<stdio.h>
main()
{
}
achul#achul:~/chennai/misclaneous$ cc memory.c -o mem
achul#achul:~/chennai/misclaneous$ size mem
text data bss dec hex filename
1056 252 8 1316 524 mem
here i am not using any global variable as BSS is reserved for global variable only anyone plz ?
In a normal (hosted) environment, the .c files and compiled to object files, and this object files are linked with the standard clib. And the library contains a module (generally called crt0.o) that is natively loaded by the system, optionnaly decodes the command line and calls the function main passing argc, argv and environment, and also generally sets some global variables.
This crt0 module does contain global variables.
Here are couple of outputs
Below is a compiled object and not at all linked, purely the simple program above with no global content as indicated.
size t1.o
text data bss dec hex filename
62 0 0 62 3e t1.o
size --format=SysV t1.o
t1.o :
section size addr
.text 6 0
.data 0 0
.bss 0 0
.comment 42 0
.note.GNU-stack 0 0
.eh_frame 56 0
Total 104
And this Below is a complete executable likned with startup code and other supported stuff.
size a.out
text data bss dec hex filename
1115 552 8 1675 68b a.out
size --format=SysV a.out
a.out :
section size addr
.interp 28 4194872
.note.ABI-tag 32 4194900
.note.gnu.build-id 36 4194932
.gnu.hash 28 4194968
.dynsym 72 4195000
.dynstr 56 4195072
.gnu.version 6 4195128
.gnu.version_r 32 4195136
.rela.dyn 24 4195168
.rela.plt 48 4195192
.init 26 4195240
.plt 48 4195280
.text 370 4195328
.fini 9 4195700
.rodata 4 4195712
.eh_frame_hdr 52 4195716
.eh_frame 244 4195768
.init_array 8 6295056
.fini_array 8 6295064
.jcr 8 6295072
.dynamic 464 6295080
.got 8 6295544
.got.plt 40 6295552
.data 16 6295592
.bss 8 6295608
.comment 77 0
Total 1752

How the linker calculate the size of .bss section?

I want to know how the linker calculate the size of .bss section?
I have a test program with two variables, one is initialazed to zero, another is
initialzed to non-zero. I hope the size of .bss is is 4 and it is.
# cat test.c && gcc -o test.o -c test.c && ld -o test test.o && readelf -Ss test
int _start=0;
int a = 2;
......
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 1] .data PROGBITS 00000000006000b0 000000b0
0000000000000004 0000000000000000 WA 0 0 4
[ 2] .bss NOBITS 00000000006000b4 000000b4
0000000000000004 0000000000000000 WA 0 0 4
.....
Symbol table '.symtab' contains 11 entries:
Num: Value Size Type Bind Vis Ndx Name
6: 00000000006000b4 4 OBJECT GLOBAL DEFAULT 2 _start
10: 00000000006000b0 4 OBJECT GLOBAL DEFAULT 1 a
Then I add the second zero-initialazed variable. This time I hope the size of .bss is
is 8, but it is 12(0xc).
# cat test.c && gcc -o test.o -c test.c && ld -o test test.o && readelf -Ss test
int _start=0;
int a = 2;
int b = 0;
......
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 1] .data PROGBITS 00000000006000b0 000000b0
0000000000000004 0000000000000000 WA 0 0 4
[ 2] .bss NOBITS 00000000006000b4 000000b4
000000000000000c 0000000000000000 WA 0 0 4
......
Symbol table '.symtab' contains 12 entries:
Num: Value Size Type Bind Vis Ndx Name
6: 00000000006000b8 4 OBJECT GLOBAL DEFAULT 2 b
7: 00000000006000b4 4 OBJECT GLOBAL DEFAULT 2 _start
11: 00000000006000b0 4 OBJECT GLOBAL DEFAULT 1 a
I continue add the third zero-initialazed variable. This time I hope the size of .bss is
is 12 and it is.
# cat test.c && gcc -o test.o -c test.c && ld -o test test.o && readelf -Ss test
int _start=0;
int a = 2;
int b = 0;
int c = 0;
......
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .data PROGBITS 00000000006000b0 000000b0
0000000000000004 0000000000000000 WA 0 0 4
[ 2] .bss NOBITS 00000000006000b4 000000b4
000000000000000c 0000000000000000 WA 0 0 4
......
Symbol table '.symtab' contains 13 entries:
Num: Value Size Type Bind Vis Ndx Name
6: 00000000006000b8 4 OBJECT GLOBAL DEFAULT 2 b
7: 00000000006000b4 4 OBJECT GLOBAL DEFAULT 2 _start
8: 00000000006000bc 4 OBJECT GLOBAL DEFAULT 2 c
12: 00000000006000b0 4 OBJECT GLOBAL DEFAULT 1 a
I continue add the fourth zero-initialazed variable. This time I hope the size of .bss is
is 16, but it is 20(0x14).
# cat test.c && gcc -o test.o -c test.c && ld -o test test.o && readelf -Ss test
int _start=0;
int a = 2;
int b = 0;
int c = 0;
int d = 0;
......
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 1] .data PROGBITS 00000000006000b0 000000b0
0000000000000004 0000000000000000 WA 0 0 4
[ 2] .bss NOBITS 00000000006000b4 000000b4
0000000000000014 0000000000000000 WA 0 0 4
......
Symbol table '.symtab' contains 14 entries:
Num: Value Size Type Bind Vis Ndx Name
6: 00000000006000b8 4 OBJECT GLOBAL DEFAULT 2 b
7: 00000000006000b4 4 OBJECT GLOBAL DEFAULT 2 _start
8: 00000000006000bc 4 OBJECT GLOBAL DEFAULT 2 c
10: 00000000006000c0 4 OBJECT GLOBAL DEFAULT 2 d
13: 00000000006000b0 4 OBJECT GLOBAL DEFAULT 1 a
Sometimes the result matches my expectation, sometime not.
Is there any other factors influence the linker's output?
It is in fact alignment. The size of the bss in your example is not 8 byte aligned as you would expect, but that's because you have 4 bytes of data. If you add another initialized variable, you will see the sizes of the bss segment be 8 byte aligned.

Resources