[PATCH 1/4] mips: Fix issues in backtraces

2017-08-10 Thread minyard
From: Corey Minyard 

I saw two problems when doing backtraces:

The compiler was putting a "fast return" at the top of some
functions, before it set up the frame.  The backtrace code
would stop when it saw a jump instruction, so it would never
get to the stack frame setup and would thus misinterpret it.
To fix this, don't look for jump instructions until the
frame setup has been seen.

The assembly code here is:

80b885a0 :
80b885a0:   c8a3bbit0   a1,0x0,80b885b0 

80b885a4:   102dmovev0,zero
80b885a8:   03e8jr  ra
80b885ac:   nop
80b885b0:   67bdffd0daddiu  sp,sp,-48
80b885b4:   ffb8sd  s0,8(sp)

The second problem was the compiler was putting the last
instruction of the frame save in the delay slot of the
jump instruction.  If it saved the RA in there, the
backtrace could would miss it and misinterpret the frame.
To fix this, make sure to process the instruction after
the first jump seen.

The assembly code for this is:

80806fd0 :
80806fd0:   67bdffd0daddiu  sp,sp,-48
80806fd4:   ffb30020sd  s3,32(sp)
80806fd8:   24130018li  s3,24
80806fdc:   ffb20018sd  s2,24(sp)
80806fe0:   3c12811clui s2,0x811c
80806fe4:   ffb10010sd  s1,16(sp)
80806fe8:   3c11811clui s1,0x811c
80806fec:   ffb8sd  s0,8(sp)
80806ff0:   3c10811clui s0,0x811c
80806ff4:   08201c03j   8080700c 
80806ff8:   ffbf0028sd  ra,40(sp)

Signed-off-by: Corey Minyard 
---
 arch/mips/kernel/process.c | 22 +++---
 1 file changed, 19 insertions(+), 3 deletions(-)

diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 5351e1f..a1d930a 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())
-   break;
-
if (!info->frame_size) {
if (is_sp_move_ins())
{
@@ -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(, >pc_offset))
break;
+   if (saw_jump)
+   break;
}
if (info->frame_size && info->pc_offset >= 0) /* nested */
return 0;
-- 
2.7.4



[PATCH 1/4] mips: Fix issues in backtraces

2017-08-10 Thread minyard
From: Corey Minyard 

I saw two problems when doing backtraces:

The compiler was putting a "fast return" at the top of some
functions, before it set up the frame.  The backtrace code
would stop when it saw a jump instruction, so it would never
get to the stack frame setup and would thus misinterpret it.
To fix this, don't look for jump instructions until the
frame setup has been seen.

The assembly code here is:

80b885a0 :
80b885a0:   c8a3bbit0   a1,0x0,80b885b0 

80b885a4:   102dmovev0,zero
80b885a8:   03e8jr  ra
80b885ac:   nop
80b885b0:   67bdffd0daddiu  sp,sp,-48
80b885b4:   ffb8sd  s0,8(sp)

The second problem was the compiler was putting the last
instruction of the frame save in the delay slot of the
jump instruction.  If it saved the RA in there, the
backtrace could would miss it and misinterpret the frame.
To fix this, make sure to process the instruction after
the first jump seen.

The assembly code for this is:

80806fd0 :
80806fd0:   67bdffd0daddiu  sp,sp,-48
80806fd4:   ffb30020sd  s3,32(sp)
80806fd8:   24130018li  s3,24
80806fdc:   ffb20018sd  s2,24(sp)
80806fe0:   3c12811clui s2,0x811c
80806fe4:   ffb10010sd  s1,16(sp)
80806fe8:   3c11811clui s1,0x811c
80806fec:   ffb8sd  s0,8(sp)
80806ff0:   3c10811clui s0,0x811c
80806ff4:   08201c03j   8080700c 
80806ff8:   ffbf0028sd  ra,40(sp)

Signed-off-by: Corey Minyard 
---
 arch/mips/kernel/process.c | 22 +++---
 1 file changed, 19 insertions(+), 3 deletions(-)

diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 5351e1f..a1d930a 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())
-   break;
-
if (!info->frame_size) {
if (is_sp_move_ins())
{
@@ -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(, >pc_offset))
break;
+   if (saw_jump)
+   break;
}
if (info->frame_size && info->pc_offset >= 0) /* nested */
return 0;
-- 
2.7.4