summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/mips/kernel/process.c22
1 files changed, 19 insertions, 3 deletions
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 5351e1f3950d..a1d930a8705b 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -349,6 +349,7 @@ static int get_frame_info(struct mips_frame_info *info)
union mips_instruction insn, *ip, *ip_end;
const unsigned int max_insns = 128;
unsigned int i;
+ bool saw_jump = false;
info->pc_offset = -1;
info->frame_size = 0;
@@ -370,9 +371,6 @@ static int get_frame_info(struct mips_frame_info *info)
insn.word = ip->word;
}
- if (is_jump_ins(&insn))
- break;
-
if (!info->frame_size) {
if (is_sp_move_ins(&insn))
{
@@ -396,10 +394,28 @@ static int get_frame_info(struct mips_frame_info *info)
info->frame_size = - ip->i_format.simmediate;
}
continue;
+ } else if (!saw_jump && is_jump_ins(ip)) {
+ /*
+ * If we see a jump instruction, we are finished
+ * with the frame save.
+ *
+ * Some functions can have a shortcut return at
+ * the beginning of the function, so don't start
+ * looking for jump instruction until we see the
+ * frame setup.
+ *
+ * The RA save instruction can get put into the
+ * delay slot of the jump instruction, so look
+ * at the next instruction, too.
+ */
+ saw_jump = true;
+ continue;
}
if (info->pc_offset == -1 &&
is_ra_save_ins(&insn, &info->pc_offset))
break;
+ if (saw_jump)
+ break;
}
if (info->frame_size && info->pc_offset >= 0) /* nested */
return 0;