diff --git a/arch/x86/include/asm/unwind_user.h b/arch/x86/include/asm/unwind_user.h
index f38f7c5ff1de..c96645c824d1 100644
--- a/arch/x86/include/asm/unwind_user.h
+++ b/arch/x86/include/asm/unwind_user.h
@@ -32,6 +32,7 @@ static inline int unwind_user_word_size(struct pt_regs *regs)
.rule = UNWIND_USER_RULE_CFA_OFFSET_DEREF,\
.offset = -2*(ws), \
}, \
+ .sp_off = 0, \
.outermost = false,
#define ARCH_INIT_USER_FP_ENTRY_FRAME(ws) \
@@ -46,6 +47,7 @@ static inline int unwind_user_word_size(struct pt_regs *regs)
.fp = { \
.rule = UNWIND_USER_RULE_RETAIN,\
}, \
+ .sp_off = 0, \
.outermost = false,
static inline bool unwind_user_at_function_start(struct pt_regs *regs)diff --git a/include/linux/unwind_user_types.h b/include/linux/unwind_user_types.h
index 670ac860ae76..4da058096259 100644
--- a/include/linux/unwind_user_types.h
+++ b/include/linux/unwind_user_types.h
@@ -67,6 +67,7 @@ struct unwind_user_frame {
struct unwind_user_cfa_rule_data cfa;
struct unwind_user_rule_data ra;
struct unwind_user_rule_data fp;
+ s32 sp_off;
bool outermost;
};
diff --git a/kernel/unwind/user.c b/kernel/unwind/user.c
index 9df5040df9b3..830c620fe453 100644
--- a/kernel/unwind/user.c
+++ b/kernel/unwind/user.c
@@ -43,7 +43,7 @@ get_user_word(unsigned long *word, unsigned long base, int off, unsigned int ws)
static int unwind_user_next_common(struct unwind_user_state *state,
const struct unwind_user_frame *frame)
{
- unsigned long cfa, fp, ra;
+ unsigned long cfa, sp, fp, ra;
/* Stop unwinding when reaching an outermost frame. */
if (frame->outermost) {@@ -77,16 +77,17 @@ static int unwind_user_next_common(struct unwind_user_state *state,
get_user_word(&cfa, cfa, 0, state->ws))
return -EINVAL;
+ /* Get the Stack Pointer (SP) */
+ sp = cfa + frame->sp_off;
/*
* Make sure that stack is not going in wrong direction. Allow SP
* to be unchanged for the topmost frame, by subtracting topmost,
* which is either 0 or 1.
*/
- if (cfa <= state->sp - state->topmost)
+ if (sp <= state->sp - state->topmost)
return -EINVAL;
-
/* Make sure that the address is word aligned */
- if (cfa & (state->ws - 1))
+ if (sp & (state->ws - 1))
return -EINVAL;
/* Get the Return Address (RA) */
@@ -149,7 +150,7 @@ static int unwind_user_next_common(struct unwind_user_state *state,
return -EINVAL;
state->ip = ra;
- state->sp = cfa;
+ state->sp = sp;
state->fp = fp;
state->topmost = false;
return 0;
--
2.53.0