From: Jens Remus <jremus@linux.ibm.com>
To: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org,
linux-s390@vger.kernel.org, x86@kernel.org,
Steven Rostedt <rostedt@kernel.org>,
Josh Poimboeuf <jpoimboe@kernel.org>,
Peter Zijlstra <peterz@infradead.org>,
Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Jens Remus <jremus@linux.ibm.com>,
Heiko Carstens <hca@linux.ibm.com>,
Vasily Gorbik <gor@linux.ibm.com>,
Alexander Gordeev <agordeev@linux.ibm.com>,
Ilya Leoshkevich <iii@linux.ibm.com>,
Indu Bhagat <ibhagatgnu@gmail.com>,
Thomas Gleixner <tglx@kernel.org>, Ingo Molnar <mingo@redhat.com>,
Borislav Petkov <bp@alien8.de>,
Dave Hansen <dave.hansen@linux.intel.com>,
"H. Peter Anvin" <hpa@zytor.com>,
Namhyung Kim <namhyung@kernel.org>,
Andrii Nakryiko <andrii@kernel.org>, Kees Cook <kees@kernel.org>,
Sam James <sam@gentoo.org>, Fangrui Song <i@maskray.me>
Subject: [RFC PATCH v2 20/24] unwind_user/eh_frame/x86: Handle PLT expressions
Date: Fri, 21 Aug 2026 21:52:55 +0200 [thread overview]
Message-ID: <20260821195259.2688377-21-jremus@linux.ibm.com> (raw)
In-Reply-To: <20260821195259.2688377-1-jremus@linux.ibm.com>
Add x86-specific support for handling the CFA expression found in GNU
linker generated .eh_frame for PLT.
This enables unwinding through GNU linker generated PLT entries on i386
and x86-64, unless linker option --no-ld-generated-unwind-info is used.
Signed-off-by: Jens Remus <jremus@linux.ibm.com>
---
arch/x86/include/asm/unwind_user_eh_frame.h | 68 ++++++++++++++++++++-
kernel/unwind/eh_frame.c | 3 +-
kernel/unwind/eh_frame.h | 14 +++++
3 files changed, 83 insertions(+), 2 deletions(-)
diff --git a/arch/x86/include/asm/unwind_user_eh_frame.h b/arch/x86/include/asm/unwind_user_eh_frame.h
index fdccbda2fe4b..8268eb1a0ff5 100644
--- a/arch/x86/include/asm/unwind_user_eh_frame.h
+++ b/arch/x86/include/asm/unwind_user_eh_frame.h
@@ -2,6 +2,8 @@
#ifndef _ASM_X86_UNWIND_USER_EH_FRAME_H
#define _ASM_X86_UNWIND_USER_EH_FRAME_H
+#include <linux/unwind_user_eh_frame_types.h>
+
#ifdef CONFIG_X86_64
#define EH_FRAME_REG_SP 7 /* designated stack pointer register */
@@ -15,7 +17,71 @@
#define EH_FRAME_MIN_DATA_ALIGN -8
#define EH_FRAME_MAX_DATA_ALIGN -1
-#endif
+#endif /* CONFIG_X86_64 */
+
+static inline int memcmp_masked(const void *s1, const void *s2,
+ const void *mask, size_t n)
+{
+ const unsigned char *p1 = s1, *p2 = s2, *m = mask;
+ int res = 0;
+
+ while (n--)
+ if ((res = (*p1++ ^ *p2++) & *m++))
+ break;
+
+ return res;
+}
+
+static inline int eh_frame_do_def_cfa_expression(const char *expr,
+ int size,
+ unsigned long ip,
+ struct eh_frame_reg_state *reg_state)
+{
+ /*
+ * PLT CFA expression:
+ *
+ * DW_OP_breg<SP> + <SP_offset> // 4 (ESP) + 4 or 7 (RSP) + 8
+ * DW_OP_breg<IP> + 0 // 8 (EIP) or 16 (RIP)
+ * DW_OP_lit15
+ * DW_OP_and
+ * DW_OP_lit<N>
+ * DW_OP_ge
+ * DW_OP_lit<shift> // 2 or 3
+ * DW_OP_shl
+ * DW_OP_plus
+ *
+ * CFA = (SP + offset) + (((IP & 0xf) >= N) << shift)
+ */
+ static const char plt_expr[] = {0x00,0x00,0x00,0x00,0x3f,0x1a,0x30,0x2a,0x30,0x24,0x22};
+ static const char plt_mask[] = {0x00,0xf0,0x00,0xff,0xff,0xff,0xf0,0xff,0xf0,0xff,0xff};
+
+ if (size == sizeof(plt_expr) &&
+ !memcmp_masked(expr, plt_expr, plt_mask, sizeof(plt_expr))) {
+ unsigned char sp_op = expr[0];
+ unsigned char sp_offset = expr[1] & 0x0f;
+ unsigned char ip_op = expr[2];
+ unsigned char n = DW_OP_lit_value(expr[6]);
+ unsigned char shift = DW_OP_lit_value(expr[8]);
+ unsigned char sp_reg, ip_reg;
+
+ if (!DW_OP_is_breg(sp_op) || !DW_OP_is_breg(ip_op))
+ return -EOPNOTSUPP;
+
+ sp_reg = DW_OP_breg_register(sp_op);
+ ip_reg = DW_OP_breg_register(ip_op);
+ if (sp_reg != EH_FRAME_REG_SP || ip_reg != EH_FRAME_REG_RA)
+ return -EOPNOTSUPP;
+
+ /* CFA = (SP + SP_offset) + (((IP & 0xf) >= N) << shift) */
+ reg_state->cfa_rule = CFA_REG_OFFSET;
+ reg_state->cfa_regnum = EH_FRAME_REG_SP;
+ reg_state->cfa_offset = sp_offset + (((ip & 15) >= n) << shift);
+ return 0;
+ }
+
+ return -EOPNOTSUPP;
+}
+#define eh_frame_do_def_cfa_expression eh_frame_do_def_cfa_expression
#include <asm-generic/unwind_user_eh_frame.h>
diff --git a/kernel/unwind/eh_frame.c b/kernel/unwind/eh_frame.c
index a98804dbe588..0a81ba1a0377 100644
--- a/kernel/unwind/eh_frame.c
+++ b/kernel/unwind/eh_frame.c
@@ -15,11 +15,12 @@
#include <linux/types.h>
#include <linux/unwind_user_types.h>
#include <linux/unwind_user_eh_frame_types.h>
-#include <asm/unwind_user_eh_frame.h>
#include "eh_frame.h"
#include "eh_frame_debug.h"
+#include <asm/unwind_user_eh_frame.h>
+
struct eh_frame_cfi_context {
struct eh_frame_reg_state state;
struct eh_frame_reg_state stack[EH_FRAME_MAX_STATE_STACK];
diff --git a/kernel/unwind/eh_frame.h b/kernel/unwind/eh_frame.h
index a43560486283..2f87d1b32bbc 100644
--- a/kernel/unwind/eh_frame.h
+++ b/kernel/unwind/eh_frame.h
@@ -60,6 +60,20 @@
#define DW_EH_PE_format(encoding) ((encoding) & 0x0f)
#define DW_EH_PE_application(encoding) ((encoding) & 0x70)
+/* DWARF expression operations */
+#define DW_OP_lit0 0x30
+/* ... */
+#define DW_OP_lit31 0x4f
+#define DW_OP_breg0 0x70
+/* ... */
+#define DW_OP_breg31 0x8f
+
+/* Helpers for DWARF expression operations */
+#define DW_OP_is_lit(op) ((op) >= DW_OP_lit0 && (op) <= DW_OP_lit31)
+#define DW_OP_is_breg(op) ((op) >= DW_OP_breg0 && (op) <= DW_OP_breg31)
+#define DW_OP_lit_value(op) ((op) - DW_OP_lit0)
+#define DW_OP_breg_register(op) ((op) - DW_OP_breg0)
+
/* CIE/FDE constants */
#define EH_FRAME_CIE_ID 0
#define EH_FRAME_DWARF64_LENGTH 0xffffffff
--
2.53.0
next prev parent reply other threads:[~2026-08-21 19:53 UTC|newest]
Thread overview: 48+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-21 19:52 [RFC PATCH v2 00/24] unwind_user: Implement .eh_frame handling Jens Remus
2026-08-21 19:52 ` [RFC PATCH v2 01/24] unwind_user: Add generic and arch-specific headers to MAINTAINERS Jens Remus
2026-08-21 19:52 ` [RFC PATCH v2 02/24] unwind_user: Stop when reaching an outermost frame Jens Remus
2026-08-21 20:00 ` sashiko-bot
2026-08-21 19:52 ` [RFC PATCH v2 03/24] unwind_user: Enable archs that pass RA in a register Jens Remus
2026-08-21 20:02 ` sashiko-bot
2026-08-21 19:52 ` [RFC PATCH v2 04/24] unwind_user: Flexible FP/RA recovery rules Jens Remus
2026-08-21 20:03 ` sashiko-bot
2026-08-21 19:52 ` [RFC PATCH v2 05/24] unwind_user: Flexible CFA " Jens Remus
2026-08-21 20:03 ` sashiko-bot
2026-08-21 19:52 ` [RFC PATCH v2 06/24] unwind_user: Enable archs that define CFA = SP_callsite + offset Jens Remus
2026-08-21 20:03 ` sashiko-bot
2026-08-21 19:52 ` [RFC PATCH v2 07/24] unwind_user/eh_frame: Add support for reading .eh_frame_hdr section Jens Remus
2026-08-21 20:06 ` sashiko-bot
2026-08-21 19:52 ` [RFC PATCH v2 08/24] unwind_user/eh_frame: Store .eh_frame_hdr section data in per-mm maple tree Jens Remus
2026-08-21 20:13 ` sashiko-bot
2026-08-21 19:52 ` [RFC PATCH v2 09/24] unwind_user/eh_frame: Add support for reading .eh_frame section Jens Remus
2026-08-21 20:16 ` sashiko-bot
2026-08-21 19:52 ` [RFC PATCH v2 10/24] unwind_user/eh_frame: Detect .eh_frame_hdr sections in executables Jens Remus
2026-08-21 20:10 ` sashiko-bot
2026-08-21 19:52 ` [RFC PATCH v2 11/24] unwind_user/eh_frame: Wire up unwind_user to eh_frame Jens Remus
2026-08-21 20:07 ` sashiko-bot
2026-08-21 19:52 ` [RFC PATCH v2 12/24] unwind_user/eh_frame: Remove .eh_frame[_hdr] section on detected corruption Jens Remus
2026-08-21 20:18 ` sashiko-bot
2026-08-21 19:52 ` [RFC PATCH v2 13/24] unwind_user/eh_frame: Show file name in debug output Jens Remus
2026-08-21 20:06 ` sashiko-bot
2026-08-21 19:52 ` [RFC PATCH v2 14/24] unwind_user/eh_frame: Add .eh_frame[_hdr] validation option Jens Remus
2026-08-21 20:10 ` sashiko-bot
2026-08-21 19:52 ` [RFC PATCH v2 15/24] unwind_user/eh_frame: Duplicate registered .eh_frame[_hdr] section data on clone/fork Jens Remus
2026-08-21 20:09 ` sashiko-bot
2026-08-21 19:52 ` [RFC PATCH v2 16/24] unwind_user/eh_frame: Ignore DW_CFA_GNU_args_size Jens Remus
2026-08-21 20:03 ` sashiko-bot
2026-08-21 19:52 ` [RFC PATCH v2 17/24] unwind_user/eh_frame: Add support for DWARF expressions Jens Remus
2026-08-21 20:18 ` sashiko-bot
2026-08-21 19:52 ` [RFC PATCH v2 18/24] x86/uaccess: Add unsafe_copy_from_user() implementation Jens Remus
2026-08-21 20:11 ` sashiko-bot
2026-08-21 19:52 ` [RFC PATCH v2 19/24] unwind_user/eh_frame/x86: Enable eh_frame unwinding on x86 Jens Remus
2026-08-21 20:16 ` sashiko-bot
2026-08-21 19:52 ` Jens Remus [this message]
2026-08-21 20:17 ` [RFC PATCH v2 20/24] unwind_user/eh_frame/x86: Handle PLT expressions sashiko-bot
2026-08-21 19:52 ` [RFC PATCH v2 21/24] unwind_user/eh_frame/x86: Handle DRAP expressions Jens Remus
2026-08-21 20:15 ` sashiko-bot
2026-08-21 19:52 ` [RFC PATCH v2 22/24] s390/ptrace: Provide frame_pointer() Jens Remus
2026-08-21 20:07 ` sashiko-bot
2026-08-21 19:52 ` [RFC PATCH v2 23/24] unwind_user/eh_frame/s390: Enable eh_frame unwinding on s390 Jens Remus
2026-08-21 20:15 ` sashiko-bot
2026-08-21 19:52 ` [RFC PATCH v2 24/24] unwind_user/eh_frame: Add prctl() interface for (un)registering .eh_frame_hdr sections Jens Remus
2026-08-21 20:22 ` sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260821195259.2688377-21-jremus@linux.ibm.com \
--to=jremus@linux.ibm.com \
--cc=agordeev@linux.ibm.com \
--cc=andrii@kernel.org \
--cc=bp@alien8.de \
--cc=dave.hansen@linux.intel.com \
--cc=gor@linux.ibm.com \
--cc=hca@linux.ibm.com \
--cc=hpa@zytor.com \
--cc=i@maskray.me \
--cc=ibhagatgnu@gmail.com \
--cc=iii@linux.ibm.com \
--cc=jpoimboe@kernel.org \
--cc=kees@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-s390@vger.kernel.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=mathieu.desnoyers@efficios.com \
--cc=mingo@redhat.com \
--cc=namhyung@kernel.org \
--cc=peterz@infradead.org \
--cc=rostedt@kernel.org \
--cc=sam@gentoo.org \
--cc=tglx@kernel.org \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.