Issue
Consider the following AVR program:
#define F_CPU 500000ul
#include <avr/io.h>
#include <util/delay.h>
// Not used, but it has significance. I suspect its presence is causing some undesired behaviour in debug info
void do_nothing() {
_delay_ms(300);
_delay_ms(300);
}
int main(void) {
DDRD = 0xFF; // Line 13
PORTD = 0x00; // Line 14
PORTD = 0x01; // Line 15
PORTD = 0x00; // Line 16
while (1) {
}
}
Pretty straight forward. If we compile with optimisations disabled and debug info (-ggdb) enabled, and have GDB disassemble the opcodes, we get the following instructions for main()
:
0x000002dc <main+0>: push r28
0x000002de <main+2>: push r29
0x000002e0 <main+4>: in r28, 0x3d
0x000002e2 <main+6>: in r29, 0x3e
0x000002e4 <main+8>: ldi r24, 0x2A
0x000002e6 <main+10>: ldi r25, 0x00
0x000002e8 <main+12>: ldi r18, 0xFF ; 255
0x000002ea <main+14>: movw r30, r24
0x000002ec <main+16>: st Z, r18
0x000002ee <main+18>: ldi r24, 0x2B
0x000002f0 <main+20>: ldi r25, 0x00
0x000002f2 <main+22>: movw r30, r24
0x000002f4 <main+24>: st Z, r1
0x000002f6 <main+26>: ldi r24, 0x2B
0x000002f8 <main+28>: ldi r25, 0x00
0x000002fa <main+30>: ldi r18, 0x01 ; 1
0x000002fc <main+32>: movw r30, r24
0x000002fe <main+34>: st Z, r18
0x00000300 <main+36>: ldi r24, 0x2B
0x00000302 <main+38>: ldi r25, 0x00
0x00000304 <main+40>: movw r30, r24
0x00000306 <main+42>: st Z, r1
0x00000308 <main+44>: rjmp .-2 ; 0x308 <main+44> (offset in GDB is byte offset, not word offset, so RJMP .-2 is actually RJMP .-1 (infinite loop))
Now, let's focus on line 13. Unless I'm mistaken, the PC (byte address) range for that line should be 0x0000002e4 (inclusive) to 0x000002ee (exclusive). In other words, I believe that line 13 consists of the following subset of instructions:
0x000002e4 <main+8>: ldi r24, 0x2A
0x000002e6 <main+10>: ldi r25, 0x00
0x000002e8 <main+12>: ldi r18, 0xFF ; 255
0x000002ea <main+14>: movw r30, r24
0x000002ec <main+16>: st Z, r18
We load the address of the DDR for port D in r24 and r25, then load 0xFF into r18, then copy the DDR address to the Z register, then write the value of r18 to that DDR. All of this is for line 13, unless I'm mistaken.
The problem is that the DWARF data doesn't agree with me. Dumping the DWARF data (with dwarfdump) from the ELF, we get the following line number info:
0x000002c8 [ 10, 1] NS uri: "main.c"
0x000002de [ 12,18] NS
0x000002e6 [ 13, 5] NS <-- This seems wrong...
0x000002ea [ 13,10] NS
0x000002f0 [ 14, 5] NS <-- and this...and so on
0x000002f4 [ 14,11] NS
0x000002f8 [ 15, 5] NS
0x000002fc [ 15,11] NS
0x00000302 [ 16, 5] NS
0x00000306 [ 16,11] NS
0x0000030a [ 18,11] NS DI=0x1
0x0000030c [ 18,11] NS ET
So according to the DWARF data, line 13 of main.c starts at 0x0000002e6, and line 14 starts at 0x0000002f0, but that doesn't seem right. It should be 0x0000002e4 and 0x0000002ee respectively.
What's more odd, is that the unused do_nothing()
function seems to be playing a part in this. If I remove that function all together, the DWARF data is correct:
0x00000082 <main+0>: push r28
0x00000084 <main+2>: push r29
0x00000086 <main+4>: in r28, 0x3d
0x00000088 <main+6>: in r29, 0x3e
0x0000008a <main+8>: ldi r24, 0x2A
0x0000008c <main+10>: ldi r25, 0x00
0x0000008e <main+12>: ldi r18, 0xFF ; 255
0x00000090 <main+14>: movw r30, r24
0x00000092 <main+16>: st Z, r18
0x00000094 <main+18>: ldi r24, 0x2B
...
0x00000082 [ 12,18] NS uri: "main.c"
0x0000008a [ 13, 5] NS
0x0000008e [ 13,10] NS
0x00000094 [ 14, 5] NS
0x00000098 [ 14,11] NS
0x0000009c [ 15, 5] NS
0x000000a0 [ 15,11] NS
0x000000a6 [ 16, 5] NS
0x000000aa [ 16,11] NS
0x000000ae [ 18,11] NS DI=0x1
0x000000b0 [ 18,11] NS ET
There, line 13 starts at 0x0000008a (the first LDI
instruction, to load DDRD into r24 and r25), and line 14 at 0x00000094, which is correct.
The same applies if I remove one of the _delay_ms()
calls from the unused function body:
void do_nothing() {
_delay_ms(300);
// By removing the other _delay_ms() call, the debug info is no longer incorrect.
}
Any idea what's going wrong here?
I'm using GCC 11.1.0, for the AVR architecture.
Solution
This seems to have been a regression in GCC 11.1.0. It has since been fixed. I upgraded to GCC 13.2.0 and cannot reproduce the issue, so all good.
Answered By - navnav Answer Checked By - Mildred Charles (WPSolving Admin)