Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
---
include/linux/unwind_user_types.h | 1 +
kernel/unwind/user.c | 24 ++++++++++++++++++++----
2 files changed, 21 insertions(+), 4 deletions(-)
--- a/include/linux/unwind_user_types.h
+++ b/include/linux/unwind_user_types.h
@@ -36,6 +36,7 @@ struct unwind_user_state {
unsigned long ip;
unsigned long sp;
unsigned long fp;
+ unsigned int ws;
enum unwind_user_type current_type;
unsigned int available_types;
bool done;
--- a/kernel/unwind/user.c
+++ b/kernel/unwind/user.c
@@ -15,6 +15,21 @@ static const struct unwind_user_frame fp
#define for_each_user_frame(state) \
for (unwind_user_start(state); !(state)->done; unwind_user_next(state))
+static inline int
+get_user_word(unsigned long *word, unsigned long base, int off, int size)
+{
+ unsigned long __user *addr = (void __user *)base + (off * size);
+#ifdef CONFIG_COMPAT
+ if (size == sizeof(int)) {
+ unsigned int data;
+ int ret = get_user(data, (unsigned int __user *)addr);
+ *word = data;
+ return ret;
+ }
+#endif
+ return get_user(*word, addr);
+}
+
static int unwind_user_next_fp(struct unwind_user_state *state)
{
const struct unwind_user_frame *frame = &fp_frame;
@@ -29,21 +44,21 @@ static int unwind_user_next_fp(struct un
}
/* Get the Canonical Frame Address (CFA) */
- cfa += frame->cfa_off;
+ cfa += state->ws * frame->cfa_off;
/* stack going in wrong direction? */
if (cfa <= state->sp)
return -EINVAL;
/* Make sure that the address is word aligned */
- if (cfa & (sizeof(long) - 1))
+ if (cfa & (state->ws - 1))
return -EINVAL;
/* Find the Return Address (RA) */
- if (get_user(ra, (unsigned long *)(cfa + frame->ra_off)))
+ if (get_user_word(&ra, cfa, frame->ra_off, state->ws))
return -EINVAL;
- if (frame->fp_off && get_user(fp, (unsigned long __user *)(cfa + frame->fp_off)))
+ if (frame->fp_off && get_user_word(&fp, cfa, frame->fp_off, state->ws))
return -EINVAL;
state->ip = ra;
@@ -100,6 +115,7 @@ static int unwind_user_start(struct unwi
state->ip = instruction_pointer(regs);
state->sp = user_stack_pointer(regs);
state->fp = frame_pointer(regs);
+ state->ws = compat_user_mode(regs) ? sizeof(int) : sizeof(long);
return 0;
}
On Wed, 24 Sep 2025 09:59:59 +0200
Peter Zijlstra <peterz@infradead.org> wrote:
> @@ -100,6 +115,7 @@ static int unwind_user_start(struct unwi
> state->ip = instruction_pointer(regs);
> state->sp = user_stack_pointer(regs);
> state->fp = frame_pointer(regs);
> + state->ws = compat_user_mode(regs) ? sizeof(int) : sizeof(long);
compat_user_mode() is an architecture function (only defined in arm64 and now x86).
s390 doesn't implement it and regs can't be used to tell if it's compat or
not (although Jens tells me the task_struct can).
To do this properly in generic code, we should add a a:
unwind_compat_mode(struct pt_regs *regs);
call in include/linux/unwind_user.h:
#ifndef unwind_compat_mode
static inline bool unwind_compat_mode(struct pt_regs *regs)
{
return false;
}
#endif
And then in the x86 and arm64 asm/unwind_user.h:
static inline bool unwind_compat_mode(struct pt_regs *regs)
{
return compat_user_mode(regs);
}
#define unwind_compat_mode unwind_compat_mode
-- Steve
>
> return 0;
> }
>
On Wed, Oct 22, 2025 at 02:31:40PM -0400, Steven Rostedt wrote:
> On Wed, 24 Sep 2025 09:59:59 +0200
> Peter Zijlstra <peterz@infradead.org> wrote:
>
> > @@ -100,6 +115,7 @@ static int unwind_user_start(struct unwi
> > state->ip = instruction_pointer(regs);
> > state->sp = user_stack_pointer(regs);
> > state->fp = frame_pointer(regs);
> > + state->ws = compat_user_mode(regs) ? sizeof(int) : sizeof(long);
>
> compat_user_mode() is an architecture function (only defined in arm64 and now x86).
>
> s390 doesn't implement it and regs can't be used to tell if it's compat or
> not (although Jens tells me the task_struct can).
I've made this:
state->ws = unwind_user_word_size(regs);
And then every arch will need to implement this. The x86 implementations
is:
static inline int unwind_user_word_size(struct pt_regs *regs)
{
#ifdef CONFIG_X86_64
if (!user_64bit_mode(regs))
return sizeof(int);
#endif
return sizeof(long);
}
On Fri, Oct 24, 2025 at 04:10:56PM +0200, Peter Zijlstra wrote:
> On Wed, Oct 22, 2025 at 02:31:40PM -0400, Steven Rostedt wrote:
> > On Wed, 24 Sep 2025 09:59:59 +0200
> > Peter Zijlstra <peterz@infradead.org> wrote:
> >
> > > @@ -100,6 +115,7 @@ static int unwind_user_start(struct unwi
> > > state->ip = instruction_pointer(regs);
> > > state->sp = user_stack_pointer(regs);
> > > state->fp = frame_pointer(regs);
> > > + state->ws = compat_user_mode(regs) ? sizeof(int) : sizeof(long);
> >
> > compat_user_mode() is an architecture function (only defined in arm64 and now x86).
> >
> > s390 doesn't implement it and regs can't be used to tell if it's compat or
> > not (although Jens tells me the task_struct can).
>
> I've made this:
>
> state->ws = unwind_user_word_size(regs);
Ooh, how about I do:
if (!state->ws) {
state->done = true;
return -EINVAL; // nobody cares about this return value
}
>
> And then every arch will need to implement this. The x86 implementations
> is:
>
> static inline int unwind_user_word_size(struct pt_regs *regs)
> {
if (regs->flags & X86_VM_MASK)
return 0;
> #ifdef CONFIG_X86_64
> if (!user_64bit_mode(regs))
> return sizeof(int);
> #endif
> return sizeof(long);
> }
Then we flat out refuse to unwind VM86, which is slightly different from
the current code (which would still record regs->ip), but meh.
Hello Peter, Steve, Josh, and Indu,
while rebasing the unwind user sframe series on top of this series and
https://lore.kernel.org/linux-trace-kernel/20251007214008.080852573@kernel.org/
I ran into the following issue:
On 9/24/2025 9:59 AM, Peter Zijlstra wrote:
> --- a/include/linux/unwind_user_types.h
> +++ b/include/linux/unwind_user_types.h
> @@ -36,6 +36,7 @@ struct unwind_user_state {
> unsigned long ip;
> unsigned long sp;
> unsigned long fp;
> + unsigned int ws;
Factoring out the word size (ws) from the CFA, FP, and RA offsets is
clever. Wondering though whether that would be an issue for unwind user
sframe. Do all architectures guarantee that those offsets are aligned
to the native word size?
> enum unwind_user_type current_type;
> unsigned int available_types;
> bool done;
> --- a/kernel/unwind/user.c
> +++ b/kernel/unwind/user.c
> @@ -29,21 +44,21 @@ static int unwind_user_next_fp(struct un
> }
>
> /* Get the Canonical Frame Address (CFA) */
> - cfa += frame->cfa_off;
> + cfa += state->ws * frame->cfa_off;
In SFrame the CFA, FP, and RA offsets are unscaled. Would it be ok, if
unwind user sframe would factor state->ws from those offset values? What
if they were not aligned? unwind user sframe would then have to fail.
@Indu: Thought from a SFrame perspective?
>
> /* stack going in wrong direction? */
> if (cfa <= state->sp)
> return -EINVAL;
>
> /* Make sure that the address is word aligned */
> - if (cfa & (sizeof(long) - 1))
> + if (cfa & (state->ws - 1))
> return -EINVAL;
Alternatively using a state->ws of 1 in uwind user sframe would defeat
this alignment check.
>
> /* Find the Return Address (RA) */
> - if (get_user(ra, (unsigned long *)(cfa + frame->ra_off)))
> + if (get_user_word(&ra, cfa, frame->ra_off, state->ws))
> return -EINVAL;
>
> - if (frame->fp_off && get_user(fp, (unsigned long __user *)(cfa + frame->fp_off)))
> + if (frame->fp_off && get_user_word(&fp, cfa, frame->fp_off, state->ws))
> return -EINVAL;
>
> state->ip = ra;
> @@ -100,6 +115,7 @@ static int unwind_user_start(struct unwi
> state->ip = instruction_pointer(regs);
> state->sp = user_stack_pointer(regs);
> state->fp = frame_pointer(regs);
> + state->ws = compat_user_mode(regs) ? sizeof(int) : sizeof(long);
>
> return 0;
> }
Thanks and 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/
On Fri, Oct 17, 2025 at 05:47:26PM +0200, Jens Remus wrote:
> On 9/24/2025 9:59 AM, Peter Zijlstra wrote:
>
> > --- a/include/linux/unwind_user_types.h
> > +++ b/include/linux/unwind_user_types.h
> > @@ -36,6 +36,7 @@ struct unwind_user_state {
> > unsigned long ip;
> > unsigned long sp;
> > unsigned long fp;
> > + unsigned int ws;
>
> Factoring out the word size (ws) from the CFA, FP, and RA offsets is
> clever. Wondering though whether that would be an issue for unwind user
> sframe. Do all architectures guarantee that those offsets are aligned
> to the native word size?
I would hope so, but this is all opt-in, I'm sure the first architecture
with an unaligned stack trying to support this will let us know ;-)
> > /* Make sure that the address is word aligned */
> > - if (cfa & (sizeof(long) - 1))
> > + if (cfa & (state->ws - 1))
> > return -EINVAL;
>
> Alternatively using a state->ws of 1 in uwind user sframe would defeat
> this alignment check.
Indeed. Or rather, with a words size of 1, everything is aligned :-)
Hello Peter!
On 10/17/2025 5:47 PM, Jens Remus wrote:
> while rebasing the unwind user sframe series on top of this series and
> https://lore.kernel.org/linux-trace-kernel/20251007214008.080852573@kernel.org/
> I ran into the following issue:
>
> On 9/24/2025 9:59 AM, Peter Zijlstra wrote:
>
>> --- a/include/linux/unwind_user_types.h
>> +++ b/include/linux/unwind_user_types.h
>> @@ -36,6 +36,7 @@ struct unwind_user_state {
>> unsigned long ip;
>> unsigned long sp;
>> unsigned long fp;
>> + unsigned int ws;
>
> Factoring out the word size (ws) from the CFA, FP, and RA offsets is
> clever. Wondering though whether that would be an issue for unwind user
> sframe. Do all architectures guarantee that those offsets are aligned
> to the native word size?
>
>> enum unwind_user_type current_type;
>> unsigned int available_types;
>> bool done;
>
>> --- a/kernel/unwind/user.c
>> +++ b/kernel/unwind/user.c
>
>> @@ -29,21 +44,21 @@ static int unwind_user_next_fp(struct un
>> }
>>
>> /* Get the Canonical Frame Address (CFA) */
>> - cfa += frame->cfa_off;
>> + cfa += state->ws * frame->cfa_off;
>
> In SFrame the CFA, FP, and RA offsets are unscaled. Would it be ok, if
> unwind user sframe would factor state->ws from those offset values? What
> if they were not aligned? unwind user sframe would then have to fail.
Sorry that I did not immediately think about the most obvious solution
tho above issues: to not factor out the word size from the frame CFA,
FP, and RA offsets. What do you think about making the following
changes to this and giyour subsequent patch? That would work nicely
with unwind user sframe.
diff --git a/kernel/unwind/user.c b/kernel/unwind/user.c
--- a/kernel/unwind/user.c
+++ b/kernel/unwind/user.c
@@ -8,19 +8,15 @@
#include <linux/unwind_user.h>
#include <linux/uaccess.h>
-static const struct unwind_user_frame fp_frame = {
- ARCH_INIT_USER_FP_FRAME
-};
-
#define for_each_user_frame(state) \
for (unwind_user_start(state); !(state)->done; unwind_user_next(state))
static inline int
-get_user_word(unsigned long *word, unsigned long base, int off, int size)
+get_user_word(unsigned long *word, unsigned long base, int off, unsigned int ws)
{
- unsigned long __user *addr = (void __user *)base + (off * size);
+ unsigned long __user *addr = (void __user *)base + off;
#ifdef CONFIG_COMPAT
- if (size == sizeof(int)) {
+ if (ws == sizeof(int)) {
unsigned int data;
int ret = get_user(data, (unsigned int __user *)addr);
*word = data;
@@ -32,6 +28,9 @@ get_user_word(unsigned long *word, unsigned long base, int off, int size)
static int unwind_user_next_fp(struct unwind_user_state *state)
{
+ const struct unwind_user_frame fp_frame = {
+ ARCH_INIT_USER_FP_FRAME(state->ws)
+ };
const struct unwind_user_frame *frame = &fp_frame;
unsigned long cfa, fp, ra;
@@ -44,7 +43,7 @@ static int unwind_user_next_fp(struct unwind_user_state *state)
}
/* Get the Canonical Frame Address (CFA) */
- cfa += state->ws * frame->cfa_off;
+ cfa += frame->cfa_off;
/* stack going in wrong direction? */
if (cfa <= state->sp)
diff --git a/arch/x86/include/asm/unwind_user.h b/arch/x86/include/asm/unwind_user.h
--- a/arch/x86/include/asm/unwind_user.h
+++ b/arch/x86/include/asm/unwind_user.h
@@ -2,10 +2,10 @@
#ifndef _ASM_X86_UNWIND_USER_H
#define _ASM_X86_UNWIND_USER_H
-#define ARCH_INIT_USER_FP_FRAME \
- .cfa_off = 2, \
- .ra_off = -1, \
- .fp_off = -2, \
+#define ARCH_INIT_USER_FP_FRAME(ws) \
+ .cfa_off = 2*(ws), \
+ .ra_off = -1*(ws), \
+ .fp_off = -2*(ws), \
.use_fp = true,
#endif /* _ASM_X86_UNWIND_USER_H */
Thanks and 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/
On Mon, Oct 20, 2025 at 11:16:45AM +0200, Jens Remus wrote:
> Hello Peter!
>
> On 10/17/2025 5:47 PM, Jens Remus wrote:
> > while rebasing the unwind user sframe series on top of this series and
> > https://lore.kernel.org/linux-trace-kernel/20251007214008.080852573@kernel.org/
> > I ran into the following issue:
> >
> > On 9/24/2025 9:59 AM, Peter Zijlstra wrote:
> >
> >> --- a/include/linux/unwind_user_types.h
> >> +++ b/include/linux/unwind_user_types.h
> >> @@ -36,6 +36,7 @@ struct unwind_user_state {
> >> unsigned long ip;
> >> unsigned long sp;
> >> unsigned long fp;
> >> + unsigned int ws;
> >
> > Factoring out the word size (ws) from the CFA, FP, and RA offsets is
> > clever. Wondering though whether that would be an issue for unwind user
> > sframe. Do all architectures guarantee that those offsets are aligned
> > to the native word size?
> >
> >> enum unwind_user_type current_type;
> >> unsigned int available_types;
> >> bool done;
> >
> >> --- a/kernel/unwind/user.c
> >> +++ b/kernel/unwind/user.c
> >
> >> @@ -29,21 +44,21 @@ static int unwind_user_next_fp(struct un
> >> }
> >>
> >> /* Get the Canonical Frame Address (CFA) */
> >> - cfa += frame->cfa_off;
> >> + cfa += state->ws * frame->cfa_off;
> >
> > In SFrame the CFA, FP, and RA offsets are unscaled. Would it be ok, if
> > unwind user sframe would factor state->ws from those offset values? What
> > if they were not aligned? unwind user sframe would then have to fail.
>
> Sorry that I did not immediately think about the most obvious solution
> tho above issues: to not factor out the word size from the frame CFA,
> FP, and RA offsets. What do you think about making the following
> changes to this and giyour subsequent patch? That would work nicely
> with unwind user sframe.
Yes, this should do nicely. I've made the changes, I'll do a test build
and then push out to the robots.
Thanks!
Hello Peter! On 10/20/2025 12:39 PM, Peter Zijlstra wrote: > On Mon, Oct 20, 2025 at 11:16:45AM +0200, Jens Remus wrote: >> On 10/17/2025 5:47 PM, Jens Remus wrote: >>> In SFrame the CFA, FP, and RA offsets are unscaled. Would it be ok, if >>> unwind user sframe would factor state->ws from those offset values? What >>> if they were not aligned? unwind user sframe would then have to fail. >> >> Sorry that I did not immediately think about the most obvious solution >> tho above issues: to not factor out the word size from the frame CFA, >> FP, and RA offsets. What do you think about making the following >> changes to this and giyour subsequent patch? That would work nicely >> with unwind user sframe. > > > Yes, this should do nicely. I've made the changes, I'll do a test build > and then push out to the robots. Thanks! Looking at your following updated patch I found that your change from "pointer to const struct unwind_user_frame" to "const struct unwind_user_frame" (done for obvious reasons) will require unwind user sframe to undo this when refactoring unwind_user_next_fp() into unwind_user_next_common(). Would that be the usual procedure or could you leave it as "pointer to const struct unwind_user_frame" for now? https://git.kernel.org/pub/scm/linux/kernel/git/peterz/queue.git/commit/?h=unwind/cleanup&id=f3624d64ba4862067b620fbd5bfbc0bfaf5368ae Thanks and 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/
On Wed, Oct 22, 2025 at 04:55:01PM +0200, Jens Remus wrote: > Hello Peter! > > On 10/20/2025 12:39 PM, Peter Zijlstra wrote: > > On Mon, Oct 20, 2025 at 11:16:45AM +0200, Jens Remus wrote: > >> On 10/17/2025 5:47 PM, Jens Remus wrote: > > >>> In SFrame the CFA, FP, and RA offsets are unscaled. Would it be ok, if > >>> unwind user sframe would factor state->ws from those offset values? What > >>> if they were not aligned? unwind user sframe would then have to fail. > >> > >> Sorry that I did not immediately think about the most obvious solution > >> tho above issues: to not factor out the word size from the frame CFA, > >> FP, and RA offsets. What do you think about making the following > >> changes to this and giyour subsequent patch? That would work nicely > >> with unwind user sframe. > > > > > > Yes, this should do nicely. I've made the changes, I'll do a test build > > and then push out to the robots. > > Thanks! Looking at your following updated patch I found that your > change from "pointer to const struct unwind_user_frame" to > "const struct unwind_user_frame" (done for obvious reasons) will require > unwind user sframe to undo this when refactoring unwind_user_next_fp() > into unwind_user_next_common(). Would that be the usual procedure or > could you leave it as "pointer to const struct unwind_user_frame" for > now? Ah, I see, that is here: https://lkml.kernel.org/r/20251022144326.4082059-9-jremus@linux.ibm.com Yeah, just change it there. It is a bit weird to have this indirection at this point.
On Mon, Oct 20, 2025 at 12:39:40PM +0200, Peter Zijlstra wrote: > Yes, this should do nicely. I've made the changes, I'll do a test build > and then push out to the robots. Ok, this now lives here: git://git.kernel.org/pub/scm/linux/kernel/git/peterz/queue.git unwind/cleanup Suppose this all comes back clean from the robots, where shall I merge it? tip/perf/core, tip/x86/core ?
On Mon, 20 Oct 2025 12:48:07 +0200 Peter Zijlstra <peterz@infradead.org> wrote: > On Mon, Oct 20, 2025 at 12:39:40PM +0200, Peter Zijlstra wrote: > > > Yes, this should do nicely. I've made the changes, I'll do a test build > > and then push out to the robots. > > Ok, this now lives here: > > git://git.kernel.org/pub/scm/linux/kernel/git/peterz/queue.git unwind/cleanup > > Suppose this all comes back clean from the robots, where shall I merge > it? tip/perf/core, tip/x86/core ? I've been basing all my perf work off of tip/perf/core, so perhaps use that branch? Thanks! -- Steve
On Wed, Oct 22, 2025 at 11:23:44AM -0400, Steven Rostedt wrote: > On Mon, 20 Oct 2025 12:48:07 +0200 > Peter Zijlstra <peterz@infradead.org> wrote: > > > On Mon, Oct 20, 2025 at 12:39:40PM +0200, Peter Zijlstra wrote: > > > > > Yes, this should do nicely. I've made the changes, I'll do a test build > > > and then push out to the robots. > > > > Ok, this now lives here: > > > > git://git.kernel.org/pub/scm/linux/kernel/git/peterz/queue.git unwind/cleanup > > > > Suppose this all comes back clean from the robots, where shall I merge > > it? tip/perf/core, tip/x86/core ? > > I've been basing all my perf work off of tip/perf/core, so perhaps use that branch? Right, I'll move the pile over to queue/perf/core and once blessed by the robots shove it into -tip.
The following commit has been merged into the perf/core branch of tip:
Commit-ID: c79dd946e370af3537edb854f210cba3a94b4516
Gitweb: https://git.kernel.org/tip/c79dd946e370af3537edb854f210cba3a94b4516
Author: Peter Zijlstra <peterz@infradead.org>
AuthorDate: Tue, 23 Sep 2025 13:27:34 +02:00
Committer: Peter Zijlstra <peterz@infradead.org>
CommitterDate: Wed, 29 Oct 2025 10:29:57 +01:00
unwind: Implement compat fp unwind
It is important to be able to unwind compat tasks too.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://patch.msgid.link/20250924080119.613695709@infradead.org
---
include/linux/unwind_user_types.h | 1 +-
kernel/unwind/user.c | 40 +++++++++++++++++++++---------
2 files changed, 30 insertions(+), 11 deletions(-)
diff --git a/include/linux/unwind_user_types.h b/include/linux/unwind_user_types.h
index a449f15..938f7e6 100644
--- a/include/linux/unwind_user_types.h
+++ b/include/linux/unwind_user_types.h
@@ -36,6 +36,7 @@ struct unwind_user_state {
unsigned long ip;
unsigned long sp;
unsigned long fp;
+ unsigned int ws;
enum unwind_user_type current_type;
unsigned int available_types;
bool done;
diff --git a/kernel/unwind/user.c b/kernel/unwind/user.c
index 9dcde79..6428715 100644
--- a/kernel/unwind/user.c
+++ b/kernel/unwind/user.c
@@ -8,19 +8,32 @@
#include <linux/unwind_user.h>
#include <linux/uaccess.h>
-static const struct unwind_user_frame fp_frame = {
- ARCH_INIT_USER_FP_FRAME
-};
-
#define for_each_user_frame(state) \
for (unwind_user_start(state); !(state)->done; unwind_user_next(state))
+static inline int
+get_user_word(unsigned long *word, unsigned long base, int off, unsigned int ws)
+{
+ unsigned long __user *addr = (void __user *)base + off;
+#ifdef CONFIG_COMPAT
+ if (ws == sizeof(int)) {
+ unsigned int data;
+ int ret = get_user(data, (unsigned int __user *)addr);
+ *word = data;
+ return ret;
+ }
+#endif
+ return get_user(*word, addr);
+}
+
static int unwind_user_next_fp(struct unwind_user_state *state)
{
- const struct unwind_user_frame *frame = &fp_frame;
+ const struct unwind_user_frame frame = {
+ ARCH_INIT_USER_FP_FRAME(state->ws)
+ };
unsigned long cfa, fp, ra;
- if (frame->use_fp) {
+ if (frame.use_fp) {
if (state->fp < state->sp)
return -EINVAL;
cfa = state->fp;
@@ -29,26 +42,26 @@ static int unwind_user_next_fp(struct unwind_user_state *state)
}
/* Get the Canonical Frame Address (CFA) */
- cfa += frame->cfa_off;
+ cfa += frame.cfa_off;
/* stack going in wrong direction? */
if (cfa <= state->sp)
return -EINVAL;
/* Make sure that the address is word aligned */
- if (cfa & (sizeof(long) - 1))
+ if (cfa & (state->ws - 1))
return -EINVAL;
/* Find the Return Address (RA) */
- if (get_user(ra, (unsigned long *)(cfa + frame->ra_off)))
+ if (get_user_word(&ra, cfa, frame.ra_off, state->ws))
return -EINVAL;
- if (frame->fp_off && get_user(fp, (unsigned long __user *)(cfa + frame->fp_off)))
+ if (frame.fp_off && get_user_word(&fp, cfa, frame.fp_off, state->ws))
return -EINVAL;
state->ip = ra;
state->sp = cfa;
- if (frame->fp_off)
+ if (frame.fp_off)
state->fp = fp;
return 0;
}
@@ -100,6 +113,11 @@ static int unwind_user_start(struct unwind_user_state *state)
state->ip = instruction_pointer(regs);
state->sp = user_stack_pointer(regs);
state->fp = frame_pointer(regs);
+ state->ws = unwind_user_word_size(regs);
+ if (!state->ws) {
+ state->done = true;
+ return -EINVAL;
+ }
return 0;
}
© 2016 - 2026 Red Hat, Inc.