From nobody Sat Feb 7 09:59:11 2026 Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BE08B35EDAD; Tue, 27 Jan 2026 15:06:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.163.156.1 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769526420; cv=none; b=R+vOOuKb9Bco7Vs7ES9dIDbJ/cQc0cZBX+UhCNEjtw7EvjqcKGpOmS2JsX6CTeAokd9BdfEY67T3o0CFoIuT94qME/cpuq0HdyAwt6YxemAFQPfyiYeurNGLuD6YVYG6HRpyW496kM8jwIlfoAO4Z0JzdZz/gJv+4MBFHtcRTf4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769526420; c=relaxed/simple; bh=rxY8xGBZ5yJit2+YWuz47hZhT0yoaeRIGpacQau1RRc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Q1HuMiTRZuHKpZkKZkmq8gwveqwiRJ6eaVvO77zHXCObq83iWWPfRa0Z9ercVG9D+YNxt5SGJsuZLVIYfuQ6VgYOd6oCAbdZz4pySFkmQccMKjDj1qRtpr801vBqcqu5tMgNhHau3o+cHBOb1aaD+60C/2+/KVLhn6ahTRoHRys= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.ibm.com; spf=pass smtp.mailfrom=linux.ibm.com; dkim=pass (2048-bit key) header.d=ibm.com header.i=@ibm.com header.b=KuUi5gcZ; arc=none smtp.client-ip=148.163.156.1 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.ibm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.ibm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=ibm.com header.i=@ibm.com header.b="KuUi5gcZ" Received: from pps.filterd (m0360083.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 60R8VC3L019081; Tue, 27 Jan 2026 15:06:08 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=cc :content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=pp1; bh=/3PfnVmrJ4bjdUuPi bRsWkINJ7RY5gnKqjYR9SGs8lk=; b=KuUi5gcZFeyz0ICxuIdUgcsT6tsE+VaSA uo3WH0cH0I8rNElydSgIcawC0FaTGu/8Jrgh+x/3o227fX91aYQ67QA7Xp2Kf2rz 95gzrKpweL9wCDo7y26ra6n9DHfqYU9TeBikOq4vHO0g6PFVOh1LsU0rNNhM4d/+ dOs+MIpGiJBQtO+74pYyzEsVyvb4nwXG++X4odtSctKFT+ZTjc0tC/RpDWJyyOfz qfed6SEkR3xFgJvVIQIMHU/4ZQ+KtQ6BuLWFKuCAfa6tHyk8elIpRLN9XlOQVjtG 0vtRSFyZfaPL6/8YCRvA3zYpZFlcry//toK0gRJdzsHGk8Sr98nzA== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4bvnk6x32y-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 27 Jan 2026 15:06:07 +0000 (GMT) Received: from m0360083.ppops.net (m0360083.ppops.net [127.0.0.1]) by pps.reinject (8.18.1.12/8.18.0.8) with ESMTP id 60RF67I1017499; Tue, 27 Jan 2026 15:06:07 GMT Received: from ppma12.dal12v.mail.ibm.com (dc.9e.1632.ip4.static.sl-reverse.com [50.22.158.220]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4bvnk6x32t-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 27 Jan 2026 15:06:07 +0000 (GMT) Received: from pps.filterd (ppma12.dal12v.mail.ibm.com [127.0.0.1]) by ppma12.dal12v.mail.ibm.com (8.18.1.2/8.18.1.2) with ESMTP id 60RD4EJN031030; Tue, 27 Jan 2026 15:06:05 GMT Received: from smtprelay07.fra02v.mail.ibm.com ([9.218.2.229]) by ppma12.dal12v.mail.ibm.com (PPS) with ESMTPS id 4bw8dsh6cp-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 27 Jan 2026 15:06:05 +0000 Received: from smtpav06.fra02v.mail.ibm.com (smtpav06.fra02v.mail.ibm.com [10.20.54.105]) by smtprelay07.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 60RF62VW50659822 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 27 Jan 2026 15:06:02 GMT Received: from smtpav06.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 2575B20040; Tue, 27 Jan 2026 15:06:02 +0000 (GMT) Received: from smtpav06.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id B9B6320049; Tue, 27 Jan 2026 15:06:01 +0000 (GMT) Received: from tuxmaker.boeblingen.de.ibm.com (unknown [9.87.85.9]) by smtpav06.fra02v.mail.ibm.com (Postfix) with ESMTP; Tue, 27 Jan 2026 15:06:01 +0000 (GMT) From: Jens Remus To: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, bpf@vger.kernel.org, x86@kernel.org, linux-mm@kvack.org, Steven Rostedt Cc: Jens Remus , Josh Poimboeuf , Masami Hiramatsu , Mathieu Desnoyers , Peter Zijlstra , Ingo Molnar , Jiri Olsa , Arnaldo Carvalho de Melo , Namhyung Kim , Thomas Gleixner , Andrii Nakryiko , Indu Bhagat , "Jose E. Marchesi" , Beau Belgrave , Linus Torvalds , Andrew Morton , Florian Weimer , Kees Cook , "Carlos O'Donell" , Sam James , Dylan Hatch , Borislav Petkov , Dave Hansen , David Hildenbrand , "H. Peter Anvin" , "Liam R. Howlett" , Lorenzo Stoakes , Michal Hocko , Mike Rapoport , Suren Baghdasaryan , Vlastimil Babka , Heiko Carstens , Vasily Gorbik Subject: [PATCH v13 13/18] unwind_user: Flexible FP/RA recovery rules Date: Tue, 27 Jan 2026 16:05:48 +0100 Message-ID: <20260127150554.2760964-14-jremus@linux.ibm.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260127150554.2760964-1-jremus@linux.ibm.com> References: <20260127150554.2760964-1-jremus@linux.ibm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-TM-AS-GCONF: 00 X-Proofpoint-GUID: XE0RzFmCVQb5zWyHjwUBrwMS-vJMXWBs X-Proofpoint-ORIG-GUID: KAkSN1-K_xFuumNvJggSiF3ey7msAwbx X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMTI3MDEyMSBTYWx0ZWRfX3BM4sLcNzZgq 6z/lYcuuColZwrV7LGol9MsOo0DjdLJJIgEql10Fo9L9tt1I6lfIUhB+TCwnuQxr41SzWdbkg2X t4NrzOWrR+mfZRm/iZ5sLT3uWmLX0pTPn/KPXrZ2a7xwvcYjSnbaXOpKCquqzz2npupcP/8UPoS 8lKSKtMwJHB7zrvWRFZEj82suALaNdBWVRX6q9pF1/eOwF0MxTKN6n4XSccM6oMEidAnw5nQRYO daYo6gM3yZJ/lr9tLXX5lwQUszkwJmdc103D9T9pFByrVymMYzHD4lukJNSBkq8qDgo742uTywe ULCAXsnj9Wkzti4oTyFQIRVHJi3hrCA+T4wXYfZnrIdNZM0Pi++bNlx8iYOF4IM4SwYLJGd8FdF dDx+yh92q2tuixN1g16+Hes7lSMhERL3sDatdRrtwPp0WbtNoLbKJaPWXo3Qs+B/h9UuA/BSJ5y zvQsKiWJNgyIUVbWDrQ== X-Authority-Analysis: v=2.4 cv=AMiVTGgp c=1 sm=1 tr=0 ts=6978d45f cx=c_pps a=bLidbwmWQ0KltjZqbj+ezA==:117 a=bLidbwmWQ0KltjZqbj+ezA==:17 a=vUbySO9Y5rIA:10 a=VkNPw1HP01LnGYTKEx00:22 a=VwQbUJbxAAAA:8 a=VnNF1IyMAAAA:8 a=7d_E57ReAAAA:8 a=JfrnYn6hAAAA:8 a=yPCof4ZbAAAA:8 a=mDV3o1hIAAAA:8 a=yMhMjlubAAAA:8 a=Z4Rwk6OoAAAA:8 a=20KFwNOVAAAA:8 a=7mOBRU54AAAA:8 a=-jr7Rsxdtpxs5_a9E3IA:9 a=jhqOcbufqs7Y1TYCrUUU:22 a=1CNFftbPRP8L7MoqJWF3:22 a=HkZW87K1Qel5hWWM3VKY:22 a=wa9RWnbW_A1YIeRBVszw:22 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-01-27_03,2026-01-27_02,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 malwarescore=0 spamscore=0 phishscore=0 bulkscore=0 suspectscore=0 adultscore=0 clxscore=1015 priorityscore=1501 lowpriorityscore=0 impostorscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2601150000 definitions=main-2601270121 Content-Type: text/plain; charset="utf-8" To enable support for SFrame V3 flexible FDEs with a subsequent patch, add support for the following flexible frame pointer (FP) and return address (RA) recovery rules: FP/RA =3D *(CFA + offset) FP/RA =3D register + offset FP/RA =3D *(register + offset) Note that FP/RA recovery rules that use arbitrary register contents are only valid when in the topmost frame, as their contents are otherwise unknown. This also enables unwinding of user space for architectures, such as s390, that may save the frame pointer (FP) and/or return address (RA) in other registers, for instance when in a leaf function. Cc: Steven Rostedt Cc: Josh Poimboeuf Cc: Masami Hiramatsu Cc: Mathieu Desnoyers Cc: Peter Zijlstra Cc: Ingo Molnar Cc: Jiri Olsa Cc: Arnaldo Carvalho de Melo Cc: Namhyung Kim Cc: Thomas Gleixner Cc: Andrii Nakryiko Cc: Indu Bhagat Cc: "Jose E. Marchesi" Cc: Beau Belgrave Cc: Jens Remus Cc: Linus Torvalds Cc: Andrew Morton Cc: Florian Weimer Cc: Sam James Cc: Kees Cook Cc: "Carlos O'Donell" Signed-off-by: Jens Remus --- Notes (jremus): Changes in v13: - New patch. Based on my s390 sframe support series patch "unwind_user: Enable archs that save RA/FP in other registers": https://lore.kernel.org/all/20251208171559.2029709-12-jremus@linux.ib= m.com/ arch/x86/include/asm/unwind_user.h | 21 ++++++++++--- include/linux/unwind_user.h | 9 ++++++ include/linux/unwind_user_types.h | 23 +++++++++++++-- kernel/unwind/sframe.c | 16 ++++++++-- kernel/unwind/user.c | 47 +++++++++++++++++++++++++----- 5 files changed, 101 insertions(+), 15 deletions(-) diff --git a/arch/x86/include/asm/unwind_user.h b/arch/x86/include/asm/unwi= nd_user.h index 2dfb5ef11e36..9c3417be4283 100644 --- a/arch/x86/include/asm/unwind_user.h +++ b/arch/x86/include/asm/unwind_user.h @@ -21,15 +21,26 @@ static inline int unwind_user_word_size(struct pt_regs = *regs) =20 #define ARCH_INIT_USER_FP_FRAME(ws) \ .cfa_off =3D 2*(ws), \ - .ra_off =3D -1*(ws), \ - .fp_off =3D -2*(ws), \ + .ra =3D { \ + .rule =3D UNWIND_USER_RULE_CFA_OFFSET_DEREF,\ + .offset =3D -1*(ws), \ + }, \ + .fp =3D { \ + .rule =3D UNWIND_USER_RULE_CFA_OFFSET_DEREF,\ + .offset =3D -2*(ws), \ + }, \ .use_fp =3D true, \ .outermost =3D false, =20 #define ARCH_INIT_USER_FP_ENTRY_FRAME(ws) \ .cfa_off =3D 1*(ws), \ - .ra_off =3D -1*(ws), \ - .fp_off =3D 0, \ + .ra =3D { \ + .rule =3D UNWIND_USER_RULE_CFA_OFFSET_DEREF,\ + .offset =3D -1*(ws), \ + }, \ + .fp =3D { \ + .rule =3D UNWIND_USER_RULE_RETAIN,\ + }, \ .use_fp =3D false, \ .outermost =3D false, =20 @@ -41,4 +52,6 @@ static inline bool unwind_user_at_function_start(struct p= t_regs *regs) =20 #endif /* CONFIG_HAVE_UNWIND_USER_FP */ =20 +#include + #endif /* _ASM_X86_UNWIND_USER_H */ diff --git a/include/linux/unwind_user.h b/include/linux/unwind_user.h index bc2edae39955..92cdf38c8ade 100644 --- a/include/linux/unwind_user.h +++ b/include/linux/unwind_user.h @@ -32,6 +32,15 @@ static inline int unwind_user_get_ra_reg(unsigned long *= val) #define unwind_user_get_ra_reg unwind_user_get_ra_reg #endif =20 +#ifndef unwind_user_get_reg +static inline int unwind_user_get_reg(unsigned long *val, unsigned int reg= num) +{ + WARN_ON_ONCE(1); + return -EINVAL; +} +#define unwind_user_get_reg unwind_user_get_reg +#endif + int unwind_user(struct unwind_stacktrace *trace, unsigned int max_entries); =20 #endif /* _LINUX_UNWIND_USER_H */ diff --git a/include/linux/unwind_user_types.h b/include/linux/unwind_user_= types.h index 616cc5ee4586..0d02714a1b5d 100644 --- a/include/linux/unwind_user_types.h +++ b/include/linux/unwind_user_types.h @@ -27,10 +27,29 @@ struct unwind_stacktrace { unsigned long *entries; }; =20 +#define UNWIND_USER_RULE_DEREF BIT(31) + +enum unwind_user_rule { + UNWIND_USER_RULE_RETAIN, /* entity =3D entity */ + UNWIND_USER_RULE_CFA_OFFSET, /* entity =3D CFA + offset */ + UNWIND_USER_RULE_REG_OFFSET, /* entity =3D register + offset */ + /* DEREF variants */ + UNWIND_USER_RULE_CFA_OFFSET_DEREF =3D /* entity =3D *(CFA + offset) */ + UNWIND_USER_RULE_CFA_OFFSET | UNWIND_USER_RULE_DEREF, + UNWIND_USER_RULE_REG_OFFSET_DEREF =3D /* entity =3D *(register + offset) = */ + UNWIND_USER_RULE_REG_OFFSET | UNWIND_USER_RULE_DEREF, +}; + +struct unwind_user_rule_data { + enum unwind_user_rule rule; + s32 offset; + unsigned int regnum; +}; + struct unwind_user_frame { s32 cfa_off; - s32 ra_off; - s32 fp_off; + struct unwind_user_rule_data ra; + struct unwind_user_rule_data fp; bool use_fp; bool outermost; }; diff --git a/kernel/unwind/sframe.c b/kernel/unwind/sframe.c index fc905504ddde..b5301fa9dbc8 100644 --- a/kernel/unwind/sframe.c +++ b/kernel/unwind/sframe.c @@ -271,6 +271,18 @@ static __always_inline int __read_fre(struct sframe_se= ction *sec, return -EFAULT; } =20 +static __always_inline void +sframe_init_rule_data(struct unwind_user_rule_data *rule_data, + s32 offset) +{ + if (offset) { + rule_data->rule =3D UNWIND_USER_RULE_CFA_OFFSET_DEREF; + rule_data->offset =3D offset; + } else { + rule_data->rule =3D UNWIND_USER_RULE_RETAIN; + } +} + static __always_inline int __find_fre(struct sframe_section *sec, struct sframe_fde_internal *fde, unsigned long ip, @@ -321,8 +333,8 @@ static __always_inline int __find_fre(struct sframe_sec= tion *sec, fre =3D prev_fre; =20 frame->cfa_off =3D fre->cfa_off; - frame->ra_off =3D fre->ra_off; - frame->fp_off =3D fre->fp_off; + sframe_init_rule_data(&frame->ra, fre->ra_off); + sframe_init_rule_data(&frame->fp, fre->fp_off); frame->use_fp =3D SFRAME_V3_FRE_CFA_BASE_REG_ID(fre->info) =3D=3D SFRAME= _BASE_REG_FP; frame->outermost =3D SFRAME_V3_FRE_RA_UNDEFINED_P(fre->info); =20 diff --git a/kernel/unwind/user.c b/kernel/unwind/user.c index 9ceef9b2b8db..0405922c5c0d 100644 --- a/kernel/unwind/user.c +++ b/kernel/unwind/user.c @@ -61,22 +61,55 @@ static int unwind_user_next_common(struct unwind_user_s= tate *state, return -EINVAL; =20 /* Get the Return Address (RA) */ - if (frame->ra_off) { - if (get_user_word(&ra, cfa, frame->ra_off, state->ws)) - return -EINVAL; - } else { + switch (frame->ra.rule) { + case UNWIND_USER_RULE_RETAIN: if (!state->topmost || unwind_user_get_ra_reg(&ra)) return -EINVAL; + break; + /* UNWIND_USER_RULE_CFA_OFFSET not implemented on purpose */ + case UNWIND_USER_RULE_CFA_OFFSET_DEREF: + ra =3D cfa + frame->ra.offset; + break; + case UNWIND_USER_RULE_REG_OFFSET: + case UNWIND_USER_RULE_REG_OFFSET_DEREF: + if (!state->topmost || unwind_user_get_reg(&ra, frame->ra.regnum)) + return -EINVAL; + ra +=3D frame->ra.offset; + break; + default: + WARN_ON_ONCE(1); + return -EINVAL; } + if (frame->ra.rule & UNWIND_USER_RULE_DEREF && + get_user_word(&ra, ra, 0, state->ws)) + return -EINVAL; =20 /* Get the Frame Pointer (FP) */ - if (frame->fp_off && get_user_word(&fp, cfa, frame->fp_off, state->ws)) + switch (frame->fp.rule) { + case UNWIND_USER_RULE_RETAIN: + fp =3D state->fp; + break; + /* UNWIND_USER_RULE_CFA_OFFSET not implemented on purpose */ + case UNWIND_USER_RULE_CFA_OFFSET_DEREF: + fp =3D cfa + frame->fp.offset; + break; + case UNWIND_USER_RULE_REG_OFFSET: + case UNWIND_USER_RULE_REG_OFFSET_DEREF: + if (!state->topmost || unwind_user_get_reg(&fp, frame->fp.regnum)) + return -EINVAL; + fp +=3D frame->fp.offset; + break; + default: + WARN_ON_ONCE(1); + return -EINVAL; + } + if (frame->fp.rule & UNWIND_USER_RULE_DEREF && + get_user_word(&fp, fp, 0, state->ws)) return -EINVAL; =20 state->ip =3D ra; state->sp =3D cfa; - if (frame->fp_off) - state->fp =3D fp; + state->fp =3D fp; state->topmost =3D false; return 0; } --=20 2.51.0