Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 98 additions & 0 deletions build_scripts/elfutils-0.195-aarch64-signal-frame.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
diff --git a/backends/aarch64_unwind.c b/backends/aarch64_unwind.c
index e0a7e96..d276d92 100644
--- a/backends/aarch64_unwind.c
+++ b/backends/aarch64_unwind.c
@@ -40,16 +40,91 @@

#include "libebl_CPU.h"

+/* Linux AArch64 rt_sigreturn ABI. See kernel/vdso/sigreturn.S,
+ kernel/signal.c and include/uapi/asm/{ucontext,sigcontext}.h under:
+ https://github.com/torvalds/linux/tree/v6.6/arch/arm64
+
+ mov x8, #139 (0xd2801168) followed by svc #0 (0xd4000001) forms
+ RT_SIGRETURN_WORD on little-endian systems. The frame offsets are:
+
+ mcontext = 128 + 8 + 8 + 24 + 128 + 8 = 0x130
+ regs = 8, sp = 8 + 31 * 8 = 0x100, pc = sp + 8 = 0x108.
+ */
+#define RT_SIGRETURN_WORD UINT64_C (0xd4000001d2801168)
+#define RT_SIGFRAME_SIGCONTEXT_OFFSET 0x130
+#define SIGCONTEXT_REGS_OFFSET 0x8
+#define SIGCONTEXT_SP_OFFSET 0x100
+#define SIGCONTEXT_PC_OFFSET 0x108
+
+static bool
+unwind_signal_frame (Ebl *ebl, Dwarf_Addr pc,
+ ebl_tid_registers_t *setfunc,
+ ebl_tid_registers_get_t *getfunc,
+ ebl_pid_memory_read_t *readfunc, void *arg,
+ bool *signal_framep)
+{
+ /* Do not guess at the Linux AArch64 big-endian signal ABI here. */
+ if (ebl->data != ELFDATA2LSB)
+ return false;
+
+ /* frame_unwind.c normally passes PC - 1 for a non-activation frame. */
+ if ((pc & 3) == 3)
+ ++pc;
+ else if ((pc & 3) != 0)
+ return false;
+
+ Dwarf_Word instructions;
+ if (!readfunc (pc, &instructions, arg)
+ || instructions != RT_SIGRETURN_WORD)
+ return false;
+
+ Dwarf_Word signal_sp;
+ if (!getfunc (SP_REG, 1, &signal_sp, arg))
+ return false;
+
+ const Dwarf_Addr sigcontext
+ = signal_sp + RT_SIGFRAME_SIGCONTEXT_OFFSET;
+ Dwarf_Word registers[31];
+ Dwarf_Word saved_sp;
+ Dwarf_Word saved_pc;
+
+ /* Read the whole context before changing the tentative caller state. */
+ for (unsigned int regno = 0; regno < 31; ++regno)
+ if (!readfunc (sigcontext + SIGCONTEXT_REGS_OFFSET
+ + regno * sizeof (Dwarf_Word),
+ &registers[regno], arg))
+ return false;
+
+ if (!readfunc (sigcontext + SIGCONTEXT_SP_OFFSET, &saved_sp, arg)
+ || !readfunc (sigcontext + SIGCONTEXT_PC_OFFSET, &saved_pc, arg)
+ || saved_pc == 0
+ || saved_sp == 0
+ || (saved_sp & 15) != 0)
+ return false;
+
+ if (!setfunc (0, 31, registers, arg)
+ || !setfunc (SP_REG, 1, &saved_sp, arg)
+ || !setfunc (-1, 1, &saved_pc, arg))
+ return false;
+
+ *signal_framep = true;
+ return true;
+}
+
/* There was no CFI. Maybe we happen to have a frame pointer and can unwind from that? */

bool
-EBLHOOK(unwind) (Ebl *ebl __attribute__ ((unused)), Dwarf_Addr pc __attribute__ ((unused)),
+EBLHOOK(unwind) (Ebl *ebl, Dwarf_Addr pc,
ebl_tid_registers_t *setfunc, ebl_tid_registers_get_t *getfunc,
ebl_pid_memory_read_t *readfunc, void *arg,
- bool *signal_framep __attribute__ ((unused)))
+ bool *signal_framep)
{
Dwarf_Word fp, lr, sp;

+ if (unwind_signal_frame (ebl, pc, setfunc, getfunc, readfunc, arg,
+ signal_framep))
+ return true;
+
if (!getfunc(LR_REG, 1, &lr, arg))
return false;

11 changes: 8 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,10 @@ wheel.exclude = ["pystack/_pystack/**"]
wheel.py-api = "cp312"
metadata.version.provider = "scikit_build_core.metadata.regex"
metadata.version.input = "src/pystack/_version.py"
sdist.include = ["src/pystack/_version.py"]
sdist.include = [
"build_scripts/elfutils-0.195-aarch64-signal-frame.patch",
"src/pystack/_version.py",
]
sdist.exclude = [
".devcontainer/**",
".github/**",
Expand Down Expand Up @@ -133,13 +136,14 @@ skip = "*-musllinux_aarch64"

[tool.cibuildwheel.linux]
before-all = [
"yum install -y libzstd-devel cmake",
"yum install -y libzstd-devel cmake patch",
"yum install -y devtoolset-10-make || true", # Install a new enough GNU make on manylinux2014
"cd /",
"VERS=0.195",
"curl https://sourceware.org/elfutils/ftp/$VERS/elfutils-$VERS.tar.bz2 > ./elfutils.tar.bz2",
"tar -xf elfutils.tar.bz2",
"cd elfutils-$VERS",
"patch --batch --forward --fuzz=0 -p1 -i {package}/build_scripts/elfutils-0.195-aarch64-signal-frame.patch",
"CFLAGS='-Wno-error -g -O3' CXXFLAGS='-Wno-error -g -O3' ./configure --disable-nls --enable-libdebuginfod=dummy --disable-debuginfod --with-zstd",
'PATH="/opt/rh/devtoolset-10/root/usr/bin/:$PATH" make install', # Ensure we pick up gnu make 4.x on manylinux2014
]
Expand All @@ -157,11 +161,12 @@ before-all = [
# set the FNM_EXTMATCH macro to get the build to succeed is seen here:
# https://git.alpinelinux.org/aports/tree/main/elfutils/musl-macros.patch
"cd /",
"apk add --update argp-standalone bison bsd-compat-headers bzip2-dev flex-dev libtool linux-headers musl-fts-dev musl-libintl musl-obstack-dev xz-dev zlib-dev zstd-dev cmake",
"apk add --update argp-standalone bison bsd-compat-headers bzip2-dev flex-dev libtool linux-headers musl-fts-dev musl-libintl musl-obstack-dev patch xz-dev zlib-dev zstd-dev cmake",
"VERS=0.195",
"curl https://sourceware.org/elfutils/ftp/$VERS/elfutils-$VERS.tar.bz2 > ./elfutils.tar.bz2",
"tar -xf elfutils.tar.bz2",
"cd elfutils-$VERS",
"patch --batch --forward --fuzz=0 -p1 -i {package}/build_scripts/elfutils-0.195-aarch64-signal-frame.patch",
"CFLAGS='-Wno-error -DFNM_EXTMATCH=0 -g -O3' CXXFLAGS='-Wno-error -g -O3' ./configure --disable-nls --enable-libdebuginfod=dummy --disable-debuginfod --with-zstd",
"make install",

Expand Down