Re: [RFC PATCH v3 17/17] s390/unwind_user/fp: Enable back chain unwinding of user space

Jens Remus
2025-12-12T09:22:06Z

On 12/8/2025 6:15 PM, Jens Remus wrote:

...

> Leverage the unwind user fp infrastructure to enable unwinding of user
> space using back chain. Enable HAVE_UNWIND_USER_FP and provide a s390-
> specific implementation of unwind_user_fp_get_frame(), which uses the
> back chain.

> diff --git a/arch/s390/include/asm/unwind_user.h b/arch/s390/include/asm/unwind_user.h

> +static inline int unwind_user_fp_get_frame(struct unwind_user_state *state,
> + struct unwind_user_frame *frame)
> +{
> + struct stack_frame_user __user *sf;
> + unsigned long __user *ra_addr;
> + unsigned long sp;
> +
> + sf = (void __user *)state->sp;
> +
> + /*
> + * In topmost frame check whether IP in early prologue, RA and SP
> + * registers saved, and no new stack frame allocated.
> + */
> + if (state->topmost) {
> + unsigned long ra, ra_reg;
> +
> + ra_addr = (unsigned long __user *)&sf->gprs[8];
> + if (__get_user(ra, ra_addr))
> + return -EINVAL;
> + if (__get_user(sp, (unsigned long __user *)&sf->gprs[9]))
> + return -EINVAL;
> + if (unwind_user_get_ra_reg(&ra_reg))
> + return -EINVAL;
> + if (ra == ra_reg && sp == state->sp)
> + goto done;
> + }

I realized that this additional heuristic is flawed:

The topmost function may be past prologue, have allocated a new stack
frame, and called a function. The callee may have saved its RA and SP
registers in the current stack frame, so that after the return from
function call, the heuristic would erroneously assume that the topmost
function is in early prologue and use the callee's RA and SP.

Instead of erroneously skipping the caller it might erroneously insert
a callee as caller. I'll remove it again in the next version.

> +
> + if (__get_user(sp, (unsigned long __user *)&sf->back_chain))
> + return -EINVAL;
> + if (!sp && ip_within_vdso(state->ip)) {
> + /*
> + * Assume non-standard vDSO user wrapper stack frame.
> + * See vDSO user wrapper code for details.
> + */
> + struct stack_frame_vdso_wrapper *sf_vdso = (void __user *)sf;
> +
> + ra_addr = (unsigned long __user *)&sf_vdso->return_address;
> + sf = (void __user *)((unsigned long)sf + STACK_FRAME_VDSO_OVERHEAD);
> + if (__get_user(sp, (unsigned long __user *)&sf->back_chain))
> + return -EINVAL;
> + } else if (!sp) {
> + /*
> + * Assume outermost frame reached. unwind_user_next_common()
> + * disregards all other fields in outermost frame.
> + */
> + frame->outermost = false;

frame->outermost = true;

> + return 0;
> + } else {
> + /*
> + * Assume IP past prologue and new stack frame allocated.
> + * Follow back chain, which then equals the SP at entry.
> + * Skips caller if wrong in topmost frame.
> + */
> + sf = (void __user *)sp;
> + ra_addr = (unsigned long __user *)&sf->gprs[8];
> + }
> +
> +done:
> + frame->cfa_off = sp - state->sp + 160;
> + frame->sp_off = -160;
> + frame->fp.loc = UNWIND_USER_LOC_UNKNOWN; /* Cannot unwind FP. */
> + frame->use_fp = false;
> + frame->ra.loc = UNWIND_USER_LOC_STACK;
> + frame->ra.offset = (unsigned long)ra_addr - (state->sp + frame->cfa_off);
> + frame->outermost = false;
> +
> + return 0;
> +}
> +#define unwind_user_fp_get_frame unwind_user_fp_get_frame
Regards,
Jens
--
Jens Remus
Linux on Z Development (D3303)
+49-7031-16-1128 Office
jremus@de.ibm.com

IBM

IBM Deutschland Research & Development GmbH; Vorsitzender des Aufsichtsrats: Wolfgang Wendt; Geschäftsführung: David Faller; Sitz der Gesellschaft: Böblingen; Registergericht: Amtsgericht Stuttgart, HRB 243294
IBM Data Privacy Statement: https://www.ibm.com/privacy/