|
|
@@ -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
|
|
|
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
|
|
|
_URC_END_OF_STACK (cleanup handlers below the signal frame never run) or
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
-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>
|
|
|
+---
|
|
|
+ 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 @@
|
|
|
+@@ -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 (e.g. pthread cancellation). */
|
|
|
++ 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
|
|
|
-@@ -994,6 +994,7 @@
|
|
|
+@@ -1050,6 +1050,7 @@ mcore-*-elf)
|
|
|
;;
|
|
|
microblaze*-linux*)
|
|
|
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)
|
|
|
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,100 @@
|
|
|
+@@ -0,0 +1,102 @@
|
|
|
+/* DWARF2 EH unwinding support for MicroBlaze Linux.
|
|
|
+ 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
|
|
|
+ (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 *) ((char *) pc - sizeof (ucontext_t));
|
|
|
++ ucontext_t *uc = (ucontext_t *) ((_Unwind_Ptr) pc - sizeof (ucontext_t));
|
|
|
+
|
|
|
+ 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. */
|
|
|
+ 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
|
|
|
+ = (_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;
|
|
|
+
|
|
|
+ return _URC_NO_REASON;
|
|
|
+}
|
|
|
+
|
|
|
-+#endif /* ifdef inhibit_libc */
|
|
|
++#endif
|