public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug debug/103975] New: DWARF .debug_frame incorrect for ISRs on AVR; pushing SREG creates off-by-one error
@ 2022-01-11  7:53 kimballa at apache dot org
  2022-01-11  7:54 ` [Bug debug/103975] " kimballa at apache dot org
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: kimballa at apache dot org @ 2022-01-11  7:53 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103975

            Bug ID: 103975
           Summary: DWARF .debug_frame incorrect for ISRs on AVR; pushing
                    SREG creates off-by-one error
           Product: gcc
           Version: 7.3.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: debug
          Assignee: unassigned at gcc dot gnu.org
          Reporter: kimballa at apache dot org
  Target Milestone: ---

On the AVR platform, when generating ISRs/interrupts/signal handlers (without
using the `naked` attribute), the ISR prologue correctly emits standard code to
read the value of `SREG` from its register port 0x3f and save it to the stack.
However, this is ignored when generating the FDE for stack frame unwind
information in .debug_frame; the result is that for $PC values after that
point, the calculations for the CFA as well as the locations of all
subsequently-pushed registers are off-by-one on the stack. 

The test case (attached) is a minimal ISR:

```
volatile unsigned char x = 0;

ISR(TIMER1_COMPA_vect) {
  x++; // may set carry/overflow flags and affect SREG, forcing it to be
pushed.
}
```

which generates the following (correct) AVR assembly:

```
ISR(TIMER1_COMPA_vect) {
  ce:   1f 92           push    r1
  d0:   0f 92           push    r0
  d2:   0f b6           in      r0, 0x3f        ; 63 # read SREG to r0
  d4:   0f 92           push    r0                   # push SREG on stack
  d6:   11 24           eor     r1, r1
  d8:   8f 93           push    r24
  x++; // may set carry/overflow flags and affect SREG, forcing it to be
pushed.
  da:   80 91 00 01     lds     r24, 0x0100     ; 0x800100 <_edata>
  de:   8f 5f           subi    r24, 0xFF       ; 255
# (ISR continues; remainder elided)
```

A separate bug in binutils/objdump makes `objdump -Wframe` fail to decode the
unwind instructions, but pyelftools can parse the info correctly and shows as
follows:

```
* FDE for __vector_17() starting at $PC=0x00ce:

PC: 00ce {'cfa': CFARule(reg=32, offset=2, expr=None), 36: RegisterRule(OFFSET,
-1)}
PC: 00d0 {'cfa': CFARule(reg=32, offset=3, expr=None), 36: RegisterRule(OFFSET,
-1), 1: RegisterRule(OFFSET, -2)}
PC: 00d2 {'cfa': CFARule(reg=32, offset=4, expr=None), 36: RegisterRule(OFFSET,
-1), 1: RegisterRule(OFFSET, -2), 0: RegisterRule(OFFSET, -3)}

<-- we *should* see a RegisterRule for SREG here valid after $PC=00d4h.

PC: 00da {'cfa': CFARule(reg=32, offset=5, expr=None), 36: RegisterRule(OFFSET,
-1), 1: RegisterRule(OFFSET, -2), 0: RegisterRule(OFFSET, -3), 24:
RegisterRule(OFFSET, -4)}

^-- Even that notwithstanding, the 'push' at 0xd4 means the CFARule offset at
0xda is now 1 too few, and the subsequent RegisterRule offset for r24 makes it
look snug against r0, ignoring the intervening push; CFARule offset should = 6
and r24's rule should have OFFSET=-5.
```

(n.b., gcc refers to $SP as register 32 in the stack frame info, and the return
addr / virtual link register as register 36.)

I am by no means a gcc internals expert but I tried to satisfy myself that it
was a legitimate bug (and not my own goof) by reading the gcc source code. 

I believe the bug is in `gcc/config/avr/avr.c` at lines 1946--47:
```
1946           /* ??? There's no dwarf2 column reserved for SREG.  */
1947           emit_push_sfr (sreg_rtx, false, false /* clr */, AVR_TMP_REGNO);
```

The author's confused comment about lacking an unwind-tracking register for
SREG shows that something might be going wrong here.

I think the 2nd argument to emit_push_sfr() may need to be `true` to set
`frame_related_p=true` (which marks the instruction as
`RTX_FRAME_RELATED_P(insn)=1`). But I don't know what other knock-on effects
frame_related_p=true might have, so it's hard for me to say it's definitely
just a one-flag fix. 

Whether or not unwind info for SREG can be tracked, at minimum the remaining
unwind info needs to account for the extra push to the stack mid-prologue.

I have replicated this with avr-gcc 7.3.0-atmel3.6.1-arduino7 (Arduino's
official package) as well as gcc version 5.4.0 with target=avr, which is what
Ubuntu 20.04.3 installs as `apt install gcc-avr`. Although I couldn't bootstrap
a functioning cross-compiler with gcc 11.2 myself, the source code snippet
above is from the main branch of gcc.git, which makes me believe it's likely
still an issue.

The attached file was created with the 7.3.0 edition of gcc referenced above:
```
$ ./avr-g++ -v
Using built-in specs.
Reading specs from
/home/aaron/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/../lib/gcc/avr/7.3.0/device-specs/specs-avr2
COLLECT_GCC=./avr-g++
COLLECT_LTO_WRAPPER=/home/aaron/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/../libexec/gcc/avr/7.3.0/lto-wrapper
Target: avr
Configured with: ../gcc/configure --enable-fixed-point --enable-languages=c,c++
--prefix=/home/jenkins/workspace/avr-gcc-staging/label/debian7-x86_64/objdir
--disable-nls --disable-libssp --disable-libada --disable-shared
--with-avrlibc=yes --with-dwarf2 --disable-doc --target=avr
Thread model: single
gcc version 7.3.0 (GCC)
```

I'm compiling on Ubuntu 20.04.3 in a VM:
```
$ uname -a
Linux ubuntu 5.4.0-91-generic #102-Ubuntu SMP Fri Nov 5 16:31:28 UTC 2021
x86_64 x86_64 x86_64 GNU/Linux
```

My build target is an Atmel atmega32u4 (`-mmcu=atmega32u4`). 
The command line for my original test-case .c file is:
```
$ avr-gcc -Os -g -Wl,--relax,--gc-section -DARCH_AVR -mmcu=atmega32u4 \
    -DF_CPU=16000000 -fno-exceptions isr.c -o isr.elf
```

If compiled with the avr-gcc 5.4 from Ubuntu, you need to replace `-g` with
`-gdwarf-2` to force it to generate the dwarf sections. 

Thanks
- Aaron

PS Running the above command line with `avr-gcc -v -save-temps -Os -g...` gives
the following log; isr.i is attached:

```
Using built-in specs.
Reading specs from
/home/aaron/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/../lib/gcc/avr/7.3.0/device-specs/specs-atmega32u4
COLLECT_GCC=/home/aaron/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/avr-gcc
COLLECT_LTO_WRAPPER=/home/aaron/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/../libexec/gcc/avr/7.3.0/lto-wrapper
Target: avr
Configured with: ../gcc/configure --enable-fixed-point --enable-languages=c,c++
--prefix=/home/jenkins/workspace/avr-gcc-staging/label/debian7-x86_64/objdir
--disable-nls --disable-libssp --disable-libada --disable-shared
--with-avrlibc=yes --with-dwarf2 --disable-doc --target=avr
Thread model: single
gcc version 7.3.0 (GCC)
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Os' '-g' '-D' 'ARCH_AVR'  '-D'
'F_CPU=16000000' '-fno-exceptions' '-specs=device-specs/specs-atmega32u4'
'-mmcu=avr5'

/home/aaron/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/../libexec/gcc/avr/7.3.0/cc1
-E -quiet -v -imultilib avr5 -iprefix
/home/aaron/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/../lib/gcc/avr/7.3.0/
-D__AVR_ATmega32U4__ -D__AVR_DEVICE_NAME__=atmega32u4 -D ARCH_AVR -D
F_CPU=16000000 isr.c -mn-flash=1 -mno-skip-bug -mmcu=avr5 -fno-exceptions -g
-fworking-directory -Os -fpch-preprocess -o isr.i
ignoring nonexistent directory
"/home/aaron/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/../lib/gcc/avr/7.3.0/../../../../avr/sys-include"
ignoring duplicate directory
"/home/aaron/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/../lib/gcc/../../lib/gcc/avr/7.3.0/include"
ignoring duplicate directory
"/home/aaron/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/../lib/gcc/../../lib/gcc/avr/7.3.0/include-fixed"
ignoring nonexistent directory
"/home/aaron/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/../lib/gcc/../../lib/gcc/avr/7.3.0/../../../../avr/sys-include"
ignoring duplicate directory
"/home/aaron/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/../lib/gcc/../../lib/gcc/avr/7.3.0/../../../../avr/include"
#include "..." search starts here:
#include <...> search starts here:

/home/aaron/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/../lib/gcc/avr/7.3.0/include

/home/aaron/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/../lib/gcc/avr/7.3.0/include-fixed

/home/aaron/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/../lib/gcc/avr/7.3.0/../../../../avr/include
End of search list.
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Os' '-g' '-D' 'ARCH_AVR'  '-D'
'F_CPU=16000000' '-fno-exceptions' '-specs=device-specs/specs-atmega32u4'
'-mmcu=avr5'

/home/aaron/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/../libexec/gcc/avr/7.3.0/cc1
-fpreprocessed isr.i -mn-flash=1 -mno-skip-bug -quiet -dumpbase isr.c
-mmcu=avr5 -auxbase isr -g -Os -version -fno-exceptions -o isr.s
GNU C11 (GCC) version 7.3.0 (avr)
        compiled by GNU C version 4.7.2, GMP version 5.0.2, MPFR version 3.1.0,
MPC version 0.9, isl version none
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
GNU C11 (GCC) version 7.3.0 (avr)
        compiled by GNU C version 4.7.2, GMP version 5.0.2, MPFR version 3.1.0,
MPC version 0.9, isl version none
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: f1a5be5edc2698bbea3030b94defb7b4
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Os' '-g' '-D' 'ARCH_AVR'  '-D'
'F_CPU=16000000' '-fno-exceptions' '-specs=device-specs/specs-atmega32u4'
'-mmcu=avr5'

/home/aaron/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/../lib/gcc/avr/7.3.0/../../../../avr/bin/as
-mmcu=avr5 -mno-skip-bug -o isr.o isr.s
COMPILER_PATH=/home/aaron/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/../libexec/gcc/avr/7.3.0/:/home/aaron/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/../libexec/gcc/:/home/aaron/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/../lib/gcc/avr/7.3.0/../../../../avr/bin/
LIBRARY_PATH=/home/aaron/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/../lib/gcc/avr/7.3.0/avr5/:/home/aaron/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/:/home/aaron/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/../lib/gcc/avr/7.3.0/:/home/aaron/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/../lib/gcc/:/home/aaron/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Os' '-g' '-D' 'ARCH_AVR'  '-D'
'F_CPU=16000000' '-fno-exceptions' '-specs=device-specs/specs-atmega32u4'
'-mmcu=avr5'

/home/aaron/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/../libexec/gcc/avr/7.3.0/collect2
-plugin
/home/aaron/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/../libexec/gcc/avr/7.3.0/liblto_plugin.so
-plugin-opt=/home/aaron/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/../libexec/gcc/avr/7.3.0/lto-wrapper
-plugin-opt=-fresolution=isr.res -plugin-opt=-pass-through=-lgcc
-plugin-opt=-pass-through=-lm -plugin-opt=-pass-through=-lc
-plugin-opt=-pass-through=-latmega32u4 -mavr5 -Tdata 0x800100
/home/aaron/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/crtatmega32u4.o
-L/home/aaron/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/../lib/gcc/avr/7.3.0/avr5
-L/home/aaron/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5
-L/home/aaron/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/../lib/gcc/avr/7.3.0
-L/home/aaron/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/../lib/gcc
-L/home/aaron/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib
--relax --gc-section isr.o --start-group -lgcc -lm -lc -latmega32u4 --end-group
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Os' '-g' '-D' 'ARCH_AVR'  '-D'
'F_CPU=16000000' '-fno-exceptions' '-specs=device-specs/specs-atmega32u4'
'-mmcu=avr5'
```

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2022-10-26 20:35 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-01-11  7:53 [Bug debug/103975] New: DWARF .debug_frame incorrect for ISRs on AVR; pushing SREG creates off-by-one error kimballa at apache dot org
2022-01-11  7:54 ` [Bug debug/103975] " kimballa at apache dot org
2022-01-11  8:09 ` pinskia at gcc dot gnu.org
2022-01-11  9:15 ` [Bug target/103975] " kimballa at apache dot org
2022-01-11  9:16 ` kimballa at apache dot org
2022-10-26 20:35 ` gjl at gcc dot gnu.org

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).