new file mode 100644
@@ -0,0 +1,196 @@
+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
+DWARF unwinder cannot step through signal frames at all. Anything that
+unwinds out of a signal handler -- most prominently NPTL asynchronous
+pthread cancellation (SIGCANCEL) -- either stops early with
+_URC_END_OF_STACK (cleanup handlers below the signal frame never run) or
+misinterprets the on-stack signal trampoline and crashes with SIGSEGV.
+
+Add the standard fallback: recognize the two-instruction trampoline the
+kernel writes into struct rt_sigframe on the stack
+
+ addik r12, r0, __NR_rt_sigreturn
+ brki r14, 0x8
+
+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, 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
+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.
+
+Upstream: https://gcc.gnu.org/cgit/gcc/commit/?id=4ef64ad1aa9bbbe9471610e2de6ef0c8afed8b1f
+
+Signed-off-by: Ramin Moussavi <ramin.moussavi@yacoub.de>
+Signed-off-by: Neal Frager <neal.frager@amd.com>
+---
+ 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
++++ b/gcc/config/microblaze/microblaze.h
+@@ -176,6 +176,14 @@ extern enum pipeline_type microblaze_pipe;
+ #define DWARF_FRAME_RETURN_COLUMN \
+ (GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM)
+
++/* Signal frames (config/microblaze/linux-unwind.h) record the
++ interrupted PC in DWARF column 36, one past the hard registers,
++ because column 15 must keep the interrupted r15. Declaring it as
++ the alternate return column makes init_dwarf_reg_size_table size
++ it; otherwise _Unwind_GetGR aborts when unwinding through a signal
++ frame, such as during pthread cancellation. */
++#define DWARF_ALT_FRAME_RETURN_COLUMN 36
++
+ /* Initial state of return address on entry to func = R15.
+ Actually, the RA is at R15+8, but gcc doesn't know how
+ to generate this.
+diff --git a/libgcc/config.host b/libgcc/config.host
+index 046156fa5e786..a685d5da7a107 100644
+--- a/libgcc/config.host
++++ b/libgcc/config.host
+@@ -1050,6 +1050,7 @@ mcore-*-elf)
+ ;;
+ microblaze*-linux*)
+ tmake_file="${tmake_file} microblaze/t-microblaze t-fdpbit t-slibgcc-libgcc"
++ md_unwind_header=microblaze/linux-unwind.h
+ ;;
+ microblaze*-*-elf)
+ 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
++++ b/libgcc/config/microblaze/linux-unwind.h
+@@ -0,0 +1,102 @@
++/* DWARF2 EH unwinding support for MicroBlaze Linux.
++ Copyright (C) 2026 Free Software Foundation, Inc.
++
++ This file is part of GCC.
++
++ GCC is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 3, or (at your option)
++ any later version.
++
++ GCC is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ Under Section 7 of GPL version 3, you are granted additional
++ permissions described in the GCC Runtime Library Exception, version
++ 3.1, as published by the Free Software Foundation.
++
++ You should have received a copy of the GNU General Public License and
++ a copy of the GCC Runtime Library Exception along with this program;
++ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
++ <http://www.gnu.org/licenses/>. */
++
++#ifndef inhibit_libc
++
++/* Do code reading to identify a signal frame, and set the frame state
++ data appropriately. See unwind-dw2.c for the structs. */
++
++#include <signal.h>
++#include <sys/ucontext.h>
++#include <asm/unistd.h>
++
++#define MD_FALLBACK_FRAME_STATE_FOR microblaze_fallback_frame_state
++
++static _Unwind_Reason_Code
++microblaze_fallback_frame_state (struct _Unwind_Context *context,
++ _Unwind_FrameState *fs)
++{
++ const unsigned int *pc = (const unsigned int *) context->ra;
++ struct sigcontext *sc;
++ _Unwind_Ptr new_cfa;
++ int i;
++
++ /* The outermost frame of a thread may leave a null or near-null
++ return address; do not dereference it looking for the
++ trampoline. */
++ if ((unsigned long) pc < 4096)
++ return _URC_END_OF_STACK;
++
++ /* The kernel writes the signal trampoline onto the stack
++ (struct rt_sigframe.tramp):
++
++ addik r12, r0, __NR_rt_sigreturn
++ brki r14, 0x8
++
++ and sets the saved r15 to the trampoline address minus 8 (the
++ handler returns with "rtsd r15, 8"), so the unwound return
++ address points 8 bytes before the trampoline. */
++ if (pc[0] == (0x31800000 | __NR_rt_sigreturn) && pc[1] == 0xb9cc0008)
++ ;
++ else if (pc[2] == (0x31800000 | __NR_rt_sigreturn) && pc[3] == 0xb9cc0008)
++ pc += 2;
++ else
++ return _URC_END_OF_STACK;
++
++ /* The trampoline is the last member of the kernel's rt_sigframe and
++ the ucontext sits directly in front of it. Anchor there rather
++ 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).
++ uClibc's ucontext_t matches the kernel's struct ucontext. */
++ ucontext_t *uc = (ucontext_t *) ((_Unwind_Ptr) pc - sizeof (ucontext_t));
++
++ sc = (struct sigcontext *) &uc->uc_mcontext;
++
++ new_cfa = sc->regs.r1;
++ fs->regs.cfa_how = CFA_REG_OFFSET;
++ fs->regs.cfa_reg = 1; /* r1, the stack pointer. */
++ fs->regs.cfa_offset = new_cfa - (_Unwind_Ptr) context->cfa;
++
++ /* pt_regs holds r0..r31 consecutively. */
++ for (i = 0; i < 32; i++)
++ {
++ fs->regs.how[i] = REG_SAVED_OFFSET;
++ fs->regs.reg[i].loc.offset
++ = (_Unwind_Ptr) &sc->regs.r0 + i * sizeof (unsigned long) - new_cfa;
++ }
++
++ /* 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;
++
++ return _URC_NO_REASON;
++}
++
++#endif
new file mode 100644
@@ -0,0 +1,196 @@
+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
+DWARF unwinder cannot step through signal frames at all. Anything that
+unwinds out of a signal handler -- most prominently NPTL asynchronous
+pthread cancellation (SIGCANCEL) -- either stops early with
+_URC_END_OF_STACK (cleanup handlers below the signal frame never run) or
+misinterprets the on-stack signal trampoline and crashes with SIGSEGV.
+
+Add the standard fallback: recognize the two-instruction trampoline the
+kernel writes into struct rt_sigframe on the stack
+
+ addik r12, r0, __NR_rt_sigreturn
+ brki r14, 0x8
+
+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, 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
+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.
+
+Upstream: https://gcc.gnu.org/cgit/gcc/commit/?id=4ef64ad1aa9bbbe9471610e2de6ef0c8afed8b1f
+
+Signed-off-by: Ramin Moussavi <ramin.moussavi@yacoub.de>
+Signed-off-by: Neal Frager <neal.frager@amd.com>
+---
+ 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
++++ b/gcc/config/microblaze/microblaze.h
+@@ -176,6 +176,14 @@ extern enum pipeline_type microblaze_pipe;
+ #define DWARF_FRAME_RETURN_COLUMN \
+ (GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM)
+
++/* Signal frames (config/microblaze/linux-unwind.h) record the
++ interrupted PC in DWARF column 36, one past the hard registers,
++ because column 15 must keep the interrupted r15. Declaring it as
++ the alternate return column makes init_dwarf_reg_size_table size
++ it; otherwise _Unwind_GetGR aborts when unwinding through a signal
++ frame, such as during pthread cancellation. */
++#define DWARF_ALT_FRAME_RETURN_COLUMN 36
++
+ /* Initial state of return address on entry to func = R15.
+ Actually, the RA is at R15+8, but gcc doesn't know how
+ to generate this.
+diff --git a/libgcc/config.host b/libgcc/config.host
+index 046156fa5e786..a685d5da7a107 100644
+--- a/libgcc/config.host
++++ b/libgcc/config.host
+@@ -1050,6 +1050,7 @@ mcore-*-elf)
+ ;;
+ microblaze*-linux*)
+ tmake_file="${tmake_file} microblaze/t-microblaze t-fdpbit t-slibgcc-libgcc"
++ md_unwind_header=microblaze/linux-unwind.h
+ ;;
+ microblaze*-*-elf)
+ 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
++++ b/libgcc/config/microblaze/linux-unwind.h
+@@ -0,0 +1,102 @@
++/* DWARF2 EH unwinding support for MicroBlaze Linux.
++ Copyright (C) 2026 Free Software Foundation, Inc.
++
++ This file is part of GCC.
++
++ GCC is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 3, or (at your option)
++ any later version.
++
++ GCC is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ Under Section 7 of GPL version 3, you are granted additional
++ permissions described in the GCC Runtime Library Exception, version
++ 3.1, as published by the Free Software Foundation.
++
++ You should have received a copy of the GNU General Public License and
++ a copy of the GCC Runtime Library Exception along with this program;
++ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
++ <http://www.gnu.org/licenses/>. */
++
++#ifndef inhibit_libc
++
++/* Do code reading to identify a signal frame, and set the frame state
++ data appropriately. See unwind-dw2.c for the structs. */
++
++#include <signal.h>
++#include <sys/ucontext.h>
++#include <asm/unistd.h>
++
++#define MD_FALLBACK_FRAME_STATE_FOR microblaze_fallback_frame_state
++
++static _Unwind_Reason_Code
++microblaze_fallback_frame_state (struct _Unwind_Context *context,
++ _Unwind_FrameState *fs)
++{
++ const unsigned int *pc = (const unsigned int *) context->ra;
++ struct sigcontext *sc;
++ _Unwind_Ptr new_cfa;
++ int i;
++
++ /* The outermost frame of a thread may leave a null or near-null
++ return address; do not dereference it looking for the
++ trampoline. */
++ if ((unsigned long) pc < 4096)
++ return _URC_END_OF_STACK;
++
++ /* The kernel writes the signal trampoline onto the stack
++ (struct rt_sigframe.tramp):
++
++ addik r12, r0, __NR_rt_sigreturn
++ brki r14, 0x8
++
++ and sets the saved r15 to the trampoline address minus 8 (the
++ handler returns with "rtsd r15, 8"), so the unwound return
++ address points 8 bytes before the trampoline. */
++ if (pc[0] == (0x31800000 | __NR_rt_sigreturn) && pc[1] == 0xb9cc0008)
++ ;
++ else if (pc[2] == (0x31800000 | __NR_rt_sigreturn) && pc[3] == 0xb9cc0008)
++ pc += 2;
++ else
++ return _URC_END_OF_STACK;
++
++ /* The trampoline is the last member of the kernel's rt_sigframe and
++ the ucontext sits directly in front of it. Anchor there rather
++ 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).
++ uClibc's ucontext_t matches the kernel's struct ucontext. */
++ ucontext_t *uc = (ucontext_t *) ((_Unwind_Ptr) pc - sizeof (ucontext_t));
++
++ sc = (struct sigcontext *) &uc->uc_mcontext;
++
++ new_cfa = sc->regs.r1;
++ fs->regs.cfa_how = CFA_REG_OFFSET;
++ fs->regs.cfa_reg = 1; /* r1, the stack pointer. */
++ fs->regs.cfa_offset = new_cfa - (_Unwind_Ptr) context->cfa;
++
++ /* pt_regs holds r0..r31 consecutively. */
++ for (i = 0; i < 32; i++)
++ {
++ fs->regs.how[i] = REG_SAVED_OFFSET;
++ fs->regs.reg[i].loc.offset
++ = (_Unwind_Ptr) &sc->regs.r0 + i * sizeof (unsigned long) - new_cfa;
++ }
++
++ /* 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;
++
++ return _URC_NO_REASON;
++}
++
++#endif
Add microblaze signal-frame unwinding fix back port to gcc 15.3.0 and 16.2.0. Upstream: https://gcc.gnu.org/cgit/gcc/commit/?id=4ef64ad1aa9bbbe9471610e2de6ef0c8afed8b1f Signed-off-by: Neal Frager <neal.frager@amd.com> --- V1->V2: - Added upstream link and sob message to patches --- ...Linux-signal-frame-unwinding-support.patch | 196 ++++++++++++++++++ ...Linux-signal-frame-unwinding-support.patch | 196 ++++++++++++++++++ 2 files changed, 392 insertions(+) create mode 100644 package/gcc/15.3.0/0004-microblaze-add-Linux-signal-frame-unwinding-support.patch create mode 100644 package/gcc/16.2.0/0003-microblaze-add-Linux-signal-frame-unwinding-support.patch