I'm writing a tool that uses the dwarf debug data from gcc (or tries
to), and I just can't seem to understand how some of the location info
works. Most of it works, but
Here is a minimal test file, just 5 lines:
void delay(int num)
{
volatile int i;
for(i=0;i<num;i++);
}
I want to figure out where the loop variable "i" is located in memory.
Here are the relevant parts of the debug data:
<2><4b>: Abbrev Number: 4 (DW_TAG_variable)
<4c> DW_AT_name : i
<4e> DW_AT_decl_file : 1
<4f> DW_AT_decl_line : 3
<50> DW_AT_type : <60>
<54> DW_AT_location : 0x1f (location list)
Offset Begin End Expression
0000001f 0000000c 00000018 (DW_OP_breg13: 0)
0000001f 00000018 00000020 (DW_OP_fbreg: -12)
0000001f 00000020 00000028 (DW_OP_reg3)
0000001f 00000028 00000038 (DW_OP_fbreg: -12)
0000001f <End of list>
It is the 2 entries with "(DW_OP_fbreg: -12)" that I just can't seem to
understand. As nearly as I can tell from the dwarf specification, I'm
supposed to find the frame base and subtract 12.
Here is the relevant debug info for the function:
<1><25>: Abbrev Number: 2 (DW_TAG_subprogram)
<26> DW_AT_external : 1
<27> DW_AT_name : (indirect string, offset: 0x44): delay
<2b> DW_AT_decl_file : 1
<2c> DW_AT_decl_line : 2
<2d> DW_AT_prototyped : 1
<2e> DW_AT_low_pc : 0
<32> DW_AT_high_pc : 0x38
<36> DW_AT_frame_base : 0 (location list)
<3a> DW_AT_sibling : <59>
Offset Begin End Expression
00000000 00000000 00000004 (DW_OP_reg13)
00000000 00000004 00000038 (DW_OP_breg13: 4)
00000000 <End of list>
So from address 4 to 38, the frame base should be r13 + 4, according to
what I can understand?
When "i" is at "(DW_OP_fbreg: -12)", I should take r13 + 4 and subtract
12, or so it seems?
But from the generated code, clearly "i" is actually being loaded and
stored using r13 as a pointer, not 8 bytes away. Here's the code:
00000000 <delay>:
0: e24dd004 sub r13, r13, #4 ; 0x4
4: e3a03000 mov r3, #0 ; 0x0
8: e58d3000 str r3, [r13]
c: e59d3000 ldr r3, [r13]
10: e1500003 cmp r0, r3
14: da000005 ble 30 <delay+0x30>
18: e59d3000 ldr r3, [r13]
1c: e2833001 add r3, r3, #1 ; 0x1
20: e58d3000 str r3, [r13]
24: e59d3000 ldr r3, [r13]
28: e1530000 cmp r3, r0
2c: bafffff9 blt 18 <delay+0x18>
30: e28dd004 add r13, r13, #4 ; 0x4
34: e12fff1e bx r14
Maybe I've misunderstood how to use "(DW_OP_fbreg: -12)", or maybe I'm
not using "(DW_OP_breg13: 4)" correctly. In the cases from 0 to 17 and
22 to 27, I can find the correct value of "i", but for the two
"(DW_OP_fbreg: -12)" I end up 8 bytes off, and I have no idea why?
Please help!
I've placed a copy of the code and output files here:
http://www.pjrc.com/tmp/debug_test_23sep2008.tar.gz
Also, I'm using gcc 4.3.2, compiled from source using gcc 4.2.3
"4.2.3-2ubuntu7".
> arm-elf-gcc -v
Using built-in specs.
Target: arm-elf
Configured with: ../gcc-4.3.2/configure --target=arm-elf
--prefix=/home/paul/arm/tools/build
--with-build-time-tools=/home/paul/arm/tools/build --enable-interwork
--enable-multilib --enable-languages=c --with-newlib
--with-headers=../newlib-1.14.0/newlib/libc/include
--with-gmp=/home/paul/arm/tools/build/tmplibs
--with-mpfr=/home/paul/arm/tools/build/tmplibs --disable-libssp
--disable-nls
Thread model: single
gcc version 4.3.2 (GCC)
I should also mention this is compiled with -O1. I get similar
"(DW_OP_fbreg: -12)" with -O2 or -Os. Without any optimization, it
doesn't using these at all and I can always find the variable "i", at
least in such simple code.
I know there are lots of issues with mixing debugging and optimization,
but in this case gcc is trying to tell me where "i" is located and I'm
just not able to understand how to use "(DW_OP_fbreg: -12)".
Thanks,
-Paul