Commit eef06cbf authored by Vasily Gorbik's avatar Vasily Gorbik
Browse files

s390/unwind: stop gracefully at user mode pt_regs in irq stack



Consider reaching user mode pt_regs at the bottom of irq stack graceful
unwinder termination. This is the case when irq/mcck/ext interrupt arrives
while in user mode.

Signed-off-by: default avatarVasily Gorbik <gor@linux.ibm.com>
parent c23587c9
Loading
Loading
Loading
Loading
+11 −4
Original line number Original line Diff line number Diff line
@@ -36,10 +36,17 @@ static bool update_stack_info(struct unwind_state *state, unsigned long sp)
	return true;
	return true;
}
}


static inline bool is_task_pt_regs(struct unwind_state *state,
static inline bool is_final_pt_regs(struct unwind_state *state,
				    struct pt_regs *regs)
				    struct pt_regs *regs)
{
{
	return task_pt_regs(state->task) == regs;
	/* user mode or kernel thread pt_regs at the bottom of task stack */
	if (task_pt_regs(state->task) == regs)
		return true;

	/* user mode pt_regs at the bottom of irq stack */
	return state->stack_info.type == STACK_TYPE_IRQ &&
	       state->stack_info.end - sizeof(struct pt_regs) == (unsigned long)regs &&
	       READ_ONCE_NOCHECK(regs->psw.mask) & PSW_MASK_PSTATE;
}
}


bool unwind_next_frame(struct unwind_state *state)
bool unwind_next_frame(struct unwind_state *state)
@@ -80,7 +87,7 @@ bool unwind_next_frame(struct unwind_state *state)
			if (!on_stack(info, sp, sizeof(struct pt_regs)))
			if (!on_stack(info, sp, sizeof(struct pt_regs)))
				goto out_err;
				goto out_err;
			regs = (struct pt_regs *) sp;
			regs = (struct pt_regs *) sp;
			if (is_task_pt_regs(state, regs))
			if (is_final_pt_regs(state, regs))
				goto out_stop;
				goto out_stop;
			ip = READ_ONCE_NOCHECK(regs->psw.addr);
			ip = READ_ONCE_NOCHECK(regs->psw.addr);
			sp = READ_ONCE_NOCHECK(regs->gprs[15]);
			sp = READ_ONCE_NOCHECK(regs->gprs[15]);