[PATCH 1/4] mips: Fix issues in backtraces
From: Corey MinyardI 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
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