Просмотр исходного кода

gcc: use the upstream form of the microblaze unwind patch for 15.3.0

The previous commit copied the 12.5.0 backport, which does not compile
against gcc 15's libgcc:

  ./md-unwind-support.h:84:22: error: 'struct <anonymous>' has no member
                                     named 'how'
  libgcc: unwind-dw2.o Error 1

libgcc moved that field out of the array element and into the structure
between 12 and 15:

  12.5.0   fs->regs.reg[i].how = REG_SAVED_OFFSET;
           fs->regs.reg[36].how = ...
  upstream fs->regs.how[i] = REG_SAVED_OFFSET;
           fs->regs.how[__LIBGCC_DWARF_ALT_FRAME_RETURN_COLUMN__] = ...

So take the version that went upstream as 4ef64ad1a, which is on
releases/gcc-15 and is therefore the one written for this gcc.  It also
uses the macro instead of a literal 36.  Applies with an offset of 2 lines
in libgcc/config.host, against 58 for the backport -- it belongs to this
tree.

Two things that hid this for a while, worth knowing:

"patch --dry-run" says only that the hunks locate, not that the result
compiles.  It reported success for the backport every time.

And "make v" is (echo; make all) 2>&1 | tee -a make.log -- the exit status
is tee's, so it is always 0.  It reported a finished build three times over
a gcc that had failed.  The error is in make.log; plain "make" propagates
the status correctly.

What came out of those builds was openadk's bootstrap gcc, which is
configured without --with-sysroot and is installed before libgcc is built.
It defines DWARF_ALT_FRAME_RETURN_COLUMN, because that half of the patch is
in microblaze.h and always compiles -- so the macro check passed while the
compiler could not find its own libc:

  ignoring nonexistent directory ".../microblaze-openadk-linux-uclibc/include"
  ... /microblaze-openadk-linux-uclibc/sys-include

which is why the CI failed with 'PATH_MAX' undeclared in a test that does
include <limits.h>.  A working toolchain has target_*/usr/include as the
last entry of its include search list, not sys-include.

Signed-off-by: Waldemar Brodkorb <wbx@openadk.org>
ramin 1 неделя назад
Родитель
Сommit
f336e60db9
1 измененных файлов с 58 добавлено и 23 удалено
  1. 58 23
      toolchain/gcc/patches/15.3.0/0012-microblaze-linux-signal-frame-unwind.patch

+ 58 - 23
toolchain/gcc/patches/15.3.0/0012-microblaze-linux-signal-frame-unwind.patch

@@ -1,5 +1,7 @@
-From: Ramin Moussavi <ramin.moussavi@yacoub.de>
-Subject: [PATCH] microblaze: add DWARF unwind support for Linux signal frames
+From 4ef64ad1aa9bbbe9471610e2de6ef0c8afed8b1f Mon Sep 17 00:00:00 2001
+From: Ramin Moussavi <lordrasmus@gmail.com>
+Date: Wed, 3 Jun 2026 00:00:00 +0200
+Subject: [PATCH] microblaze: add Linux signal frame unwinding support
 
 
 libgcc has no MD_FALLBACK_FRAME_STATE_FOR for microblaze*-linux*, so the
 libgcc has no MD_FALLBACK_FRAME_STATE_FOR for microblaze*-linux*, so the
 DWARF unwinder cannot step through signal frames at all.  Anything that
 DWARF unwinder cannot step through signal frames at all.  Anything that
@@ -7,7 +9,6 @@ unwinds out of a signal handler -- most prominently NPTL asynchronous
 pthread cancellation (SIGCANCEL) -- either stops early with
 pthread cancellation (SIGCANCEL) -- either stops early with
 _URC_END_OF_STACK (cleanup handlers below the signal frame never run) or
 _URC_END_OF_STACK (cleanup handlers below the signal frame never run) or
 misinterprets the on-stack signal trampoline and crashes with SIGSEGV.
 misinterprets the on-stack signal trampoline and crashes with SIGSEGV.
-On uClibc-ng this fails ~17 NPTL cancellation tests of the test suite.
 
 
 Add the standard fallback: recognize the two-instruction trampoline the
 Add the standard fallback: recognize the two-instruction trampoline the
 kernel writes into struct rt_sigframe on the stack
 kernel writes into struct rt_sigframe on the stack
@@ -15,37 +16,66 @@ kernel writes into struct rt_sigframe on the stack
 	addik r12, r0, __NR_rt_sigreturn
 	addik r12, r0, __NR_rt_sigreturn
 	brki  r14, 0x8
 	brki  r14, 0x8
 
 
-and rebuild the frame state from the sigcontext's pt_regs.
+and rebuild the frame state from the sigcontext's pt_regs.  The ucontext
+is anchored relative to the trampoline (its last member) rather than to
+the CFA, so the layout of the frame head does not matter.
 
 
-The interrupted PC is recorded in DWARF column 36 (one past the hard
-registers): column 15 must keep the interrupted r15, which is unrelated
-to the resume address of a signal frame.  Declaring it as
+The interrupted PC is recorded in DWARF column 36, one past the hard
+registers, because column 15 must keep the interrupted r15 (unrelated to
+the resume address of a signal frame).  Declaring it as
 DWARF_ALT_FRAME_RETURN_COLUMN makes init_dwarf_reg_size_table size the
 DWARF_ALT_FRAME_RETURN_COLUMN makes init_dwarf_reg_size_table size the
-column; without that _Unwind_GetGR reads a zero size and aborts (same
-issue the C-SKY port had).
+column; without that _Unwind_GetGR reads a zero size and aborts.
+
+Tested with a microblazeel-linux-uclibc cross compiler against uClibc-ng
+git, running its NPTL test suite under qemu-system-microblazeel -M
+petalogix-s3adsp1800.  Without the fix 17 tests fail (tst-cancel{1..5,7,
+9,16,20,x4,x7}, tst-cleanup{1..3}, tst-cond{16,17}) by SIGSEGV or by
+hanging in the unwinder; with it all 17 pass and the rest of the suite
+is unchanged.  The implementation follows the mips/aarch64
+linux-unwind.h pattern.
+
+gcc/ChangeLog:
+
+	* config/microblaze/microblaze.h (DWARF_ALT_FRAME_RETURN_COLUMN):
+	Define.
+
+libgcc/ChangeLog:
+
+	* config.host (microblaze*-linux*): Set md_unwind_header.
+	* config/microblaze/linux-unwind.h: New file.
 
 
 Signed-off-by: Ramin Moussavi <ramin.moussavi@yacoub.de>
 Signed-off-by: Ramin Moussavi <ramin.moussavi@yacoub.de>
+---
+ gcc/config/microblaze/microblaze.h      |   8 ++
+ libgcc/config.host                      |   1 +
+ libgcc/config/microblaze/linux-unwind.h | 102 ++++++++++++++++++++++++
+ 3 files changed, 111 insertions(+)
+ create mode 100644 libgcc/config/microblaze/linux-unwind.h
 
 
+diff --git a/gcc/config/microblaze/microblaze.h b/gcc/config/microblaze/microblaze.h
+index 2b5bd52040f7f..fc8c4b8717545 100644
 --- a/gcc/config/microblaze/microblaze.h
 --- a/gcc/config/microblaze/microblaze.h
 +++ b/gcc/config/microblaze/microblaze.h
 +++ b/gcc/config/microblaze/microblaze.h
-@@ -176,6 +176,14 @@
+@@ -176,6 +176,14 @@ extern enum pipeline_type microblaze_pipe;
  #define DWARF_FRAME_RETURN_COLUMN \
  #define DWARF_FRAME_RETURN_COLUMN \
  	(GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM)
  	(GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM)
-
+ 
 +/* Signal frames (config/microblaze/linux-unwind.h) record the
 +/* Signal frames (config/microblaze/linux-unwind.h) record the
 +   interrupted PC in DWARF column 36, one past the hard registers,
 +   interrupted PC in DWARF column 36, one past the hard registers,
 +   because column 15 must keep the interrupted r15.  Declaring it as
 +   because column 15 must keep the interrupted r15.  Declaring it as
 +   the alternate return column makes init_dwarf_reg_size_table size
 +   the alternate return column makes init_dwarf_reg_size_table size
 +   it; otherwise _Unwind_GetGR aborts when unwinding through a signal
 +   it; otherwise _Unwind_GetGR aborts when unwinding through a signal
-+   frame (e.g. pthread cancellation).  */
++   frame, such as during pthread cancellation.  */
 +#define DWARF_ALT_FRAME_RETURN_COLUMN 36
 +#define DWARF_ALT_FRAME_RETURN_COLUMN 36
 +
 +
  /* Initial state of return address on entry to func = R15.
  /* Initial state of return address on entry to func = R15.
     Actually, the RA is at R15+8, but gcc doesn't know how
     Actually, the RA is at R15+8, but gcc doesn't know how
     to generate this.
     to generate this.
+diff --git a/libgcc/config.host b/libgcc/config.host
+index 046156fa5e786..a685d5da7a107 100644
 --- a/libgcc/config.host
 --- a/libgcc/config.host
 +++ b/libgcc/config.host
 +++ b/libgcc/config.host
-@@ -994,6 +994,7 @@
+@@ -1050,6 +1050,7 @@ mcore-*-elf)
  	;;
  	;;
  microblaze*-linux*)
  microblaze*-linux*)
  	tmake_file="${tmake_file} microblaze/t-microblaze t-fdpbit t-slibgcc-libgcc"
  	tmake_file="${tmake_file} microblaze/t-microblaze t-fdpbit t-slibgcc-libgcc"
@@ -53,9 +83,12 @@ Signed-off-by: Ramin Moussavi <ramin.moussavi@yacoub.de>
  	;;
  	;;
  microblaze*-*-elf)
  microblaze*-*-elf)
  	tmake_file="${tmake_file} microblaze/t-microblaze t-fdpbit"
  	tmake_file="${tmake_file} microblaze/t-microblaze t-fdpbit"
+diff --git a/libgcc/config/microblaze/linux-unwind.h b/libgcc/config/microblaze/linux-unwind.h
+new file mode 100644
+index 0000000000000..b54704a065198
 --- /dev/null
 --- /dev/null
 +++ b/libgcc/config/microblaze/linux-unwind.h
 +++ b/libgcc/config/microblaze/linux-unwind.h
-@@ -0,0 +1,100 @@
+@@ -0,0 +1,102 @@
 +/* DWARF2 EH unwinding support for MicroBlaze Linux.
 +/* DWARF2 EH unwinding support for MicroBlaze Linux.
 +   Copyright (C) 2026 Free Software Foundation, Inc.
 +   Copyright (C) 2026 Free Software Foundation, Inc.
 +
 +
@@ -127,7 +160,7 @@ Signed-off-by: Ramin Moussavi <ramin.moussavi@yacoub.de>
 +     than at the CFA so the layout of the frame head does not matter
 +     than at the CFA so the layout of the frame head does not matter
 +     (the kernel may insert an ABI argument-home gap at the front).
 +     (the kernel may insert an ABI argument-home gap at the front).
 +     uClibc's ucontext_t matches the kernel's struct ucontext.  */
 +     uClibc's ucontext_t matches the kernel's struct ucontext.  */
-+  ucontext_t *uc = (ucontext_t *) ((char *) pc - sizeof (ucontext_t));
++  ucontext_t *uc = (ucontext_t *) ((_Unwind_Ptr) pc - sizeof (ucontext_t));
 +
 +
 +  sc = (struct sigcontext *) &uc->uc_mcontext;
 +  sc = (struct sigcontext *) &uc->uc_mcontext;
 +
 +
@@ -139,20 +172,22 @@ Signed-off-by: Ramin Moussavi <ramin.moussavi@yacoub.de>
 +  /* pt_regs holds r0..r31 consecutively.  */
 +  /* pt_regs holds r0..r31 consecutively.  */
 +  for (i = 0; i < 32; i++)
 +  for (i = 0; i < 32; i++)
 +    {
 +    {
-+      fs->regs.reg[i].how = REG_SAVED_OFFSET;
++      fs->regs.how[i] = REG_SAVED_OFFSET;
 +      fs->regs.reg[i].loc.offset
 +      fs->regs.reg[i].loc.offset
 +	= (_Unwind_Ptr) &sc->regs.r0 + i * sizeof (unsigned long) - new_cfa;
 +	= (_Unwind_Ptr) &sc->regs.r0 + i * sizeof (unsigned long) - new_cfa;
 +    }
 +    }
 +
 +
-+  /* The interrupted PC goes into column 36, the alternate return
-+     column (DWARF_ALT_FRAME_RETURN_COLUMN in gcc proper); column 15
-+     above keeps the interrupted r15.  */
-+  fs->regs.reg[36].how = REG_SAVED_OFFSET;
-+  fs->regs.reg[36].loc.offset = (_Unwind_Ptr) &sc->regs.pc - new_cfa;
-+  fs->retaddr_column = 36;
++  /* The interrupted PC goes into the alternate return column
++     (DWARF_ALT_FRAME_RETURN_COLUMN, defined as 36 in
++     gcc/config/microblaze/microblaze.h), one past the hard registers;
++     column 15 above keeps the interrupted r15.  */
++  fs->regs.how[__LIBGCC_DWARF_ALT_FRAME_RETURN_COLUMN__] = REG_SAVED_OFFSET;
++  fs->regs.reg[__LIBGCC_DWARF_ALT_FRAME_RETURN_COLUMN__].loc.offset
++    = (_Unwind_Ptr) &sc->regs.pc - new_cfa;
++  fs->retaddr_column = __LIBGCC_DWARF_ALT_FRAME_RETURN_COLUMN__;
 +  fs->signal_frame = 1;
 +  fs->signal_frame = 1;
 +
 +
 +  return _URC_NO_REASON;
 +  return _URC_NO_REASON;
 +}
 +}
 +
 +
-+#endif /* ifdef inhibit_libc  */
++#endif