| From 941b84c7899ea6f0365372609e5ea74bf4904d93 Mon Sep 17 00:00:00 2001 |
| From: Paul Burton <paul.burton@imgtec.com> |
| Date: Mon, 7 Nov 2016 15:07:04 +0000 |
| Subject: [PATCH] MIPS: Fix get_frame_info() handling of microMIPS function |
| size |
| |
| commit b6c7a324df37bf05ef7a2c1580683cf10d082d97 upstream. |
| |
| get_frame_info() is meant to iterate over up to the first 128 |
| instructions within a function, but for microMIPS kernels it will not |
| reach that many instructions unless the function is 512 bytes long since |
| we calculate the maximum number of instructions to check by dividing the |
| function length by the 4 byte size of a union mips_instruction. In |
| microMIPS kernels this won't do since instructions are variable length. |
| |
| Fix this by instead checking whether the pointer to the current |
| instruction has reached the end of the function, and use max_insns as a |
| simple constant to check the number of iterations against. |
| |
| Signed-off-by: Paul Burton <paul.burton@imgtec.com> |
| Fixes: 34c2f668d0f6 ("MIPS: microMIPS: Add unaligned access support.") |
| Cc: Leonid Yegoshin <leonid.yegoshin@imgtec.com> |
| Cc: linux-mips@linux-mips.org |
| Cc: <stable@vger.kernel.org> # v3.10+ |
| Patchwork: https://patchwork.linux-mips.org/patch/14530/ |
| Signed-off-by: Ralf Baechle <ralf@linux-mips.org> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c |
| index 77c3debc322f..a8673ec4e7f4 100644 |
| --- a/arch/mips/kernel/process.c |
| +++ b/arch/mips/kernel/process.c |
| @@ -293,9 +293,9 @@ static inline int is_sp_move_ins(union mips_instruction *ip) |
| static int get_frame_info(struct mips_frame_info *info) |
| { |
| bool is_mmips = IS_ENABLED(CONFIG_CPU_MICROMIPS); |
| - union mips_instruction insn, *ip; |
| - unsigned max_insns = info->func_size / sizeof(union mips_instruction); |
| - unsigned i; |
| + union mips_instruction insn, *ip, *ip_end; |
| + const unsigned int max_insns = 128; |
| + unsigned int i; |
| |
| info->pc_offset = -1; |
| info->frame_size = 0; |
| @@ -304,11 +304,9 @@ static int get_frame_info(struct mips_frame_info *info) |
| if (!ip) |
| goto err; |
| |
| - if (max_insns == 0) |
| - max_insns = 128U; /* unknown function size */ |
| - max_insns = min(128U, max_insns); |
| + ip_end = (void *)ip + info->func_size; |
| |
| - for (i = 0; i < max_insns; i++, ip++) { |
| + for (i = 0; i < max_insns && ip < ip_end; i++, ip++) { |
| if (is_mmips && mm_insn_16bit(ip->halfword[0])) { |
| insn.halfword[0] = 0; |
| insn.halfword[1] = ip->halfword[0]; |
| -- |
| 2.12.0 |
| |