Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1589571 > unrolled thread
| Started by | Matt Redfearn <matt.redfearn@imgtec.com> |
|---|---|
| First post | 2017-02-28 16:40 +0100 |
| Last post | 2017-03-01 08:40 +0100 |
| Articles | 9 — 2 participants |
Back to article view | Back to linux.kernel
[PATCH 0/4] MIPS: Further microMIPS stack unwinding fixes Matt Redfearn <matt.redfearn@imgtec.com> - 2017-02-28 16:40 +0100
Re: [PATCH 1/4] MIPS: Handle non word sized instructions when examining frame "Maciej W. Rozycki" <macro@imgtec.com> - 2017-02-28 22:00 +0100
Re: [PATCH 1/4] MIPS: Handle non word sized instructions when examining frame Matt Redfearn <matt.redfearn@imgtec.com> - 2017-03-01 15:10 +0100
Re: [PATCH 2/4] MIPS: microMIPS: Fix decoding of addiusp instruction "Maciej W. Rozycki" <macro@imgtec.com> - 2017-03-01 03:00 +0100
Re: [PATCH 2/4] MIPS: microMIPS: Fix decoding of addiusp instruction Matt Redfearn <matt.redfearn@imgtec.com> - 2017-03-01 16:50 +0100
[PATCH 4/4] MIPS: microMIPS: Fix decoding of swsp16 instruction Matt Redfearn <matt.redfearn@imgtec.com> - 2017-03-01 08:40 +0100
[PATCH 2/4] MIPS: microMIPS: Fix decoding of addiusp instruction Matt Redfearn <matt.redfearn@imgtec.com> - 2017-03-01 08:40 +0100
[PATCH 1/4] MIPS: Handle non word sized instructions when examining frame Matt Redfearn <matt.redfearn@imgtec.com> - 2017-03-01 08:40 +0100
[PATCH 3/4] MIPS: Stacktrace: Fix __usermode() of uninitialised regs Matt Redfearn <matt.redfearn@imgtec.com> - 2017-03-01 08:40 +0100
| From | Matt Redfearn <matt.redfearn@imgtec.com> |
|---|---|
| Date | 2017-02-28 16:40 +0100 |
| Subject | [PATCH 0/4] MIPS: Further microMIPS stack unwinding fixes |
| Message-ID | <tfS2C-6kf-25@gated-at.bofh.it> |
4.11 includes a bunch of stack unwinding fixes for microMIPS, but some of those fixes require additional fixup, provided by this series. These patches have been tested on qemu M14Kc micromips and tested for regression on ci40, Boston, Octeon III & malta. This series is based on mips-for-linux-next Matt Redfearn (4): MIPS: Handle non word sized instructions when examining frame MIPS: microMIPS: Fix decoding of addiusp instruction MIPS: Stacktrace: Fix __usermode() of uninitialised regs MIPS: microMIPS: Fix decoding of swsp16 instruction arch/mips/include/asm/stacktrace.h | 3 +++ arch/mips/include/uapi/asm/inst.h | 2 +- arch/mips/kernel/process.c | 14 ++++++++++---- 3 files changed, 14 insertions(+), 5 deletions(-) -- 2.7.4
[toc] | [next] | [standalone]
| From | "Maciej W. Rozycki" <macro@imgtec.com> |
|---|---|
| Date | 2017-02-28 22:00 +0100 |
| Subject | Re: [PATCH 1/4] MIPS: Handle non word sized instructions when examining frame |
| Message-ID | <tfX2h-15p-3@gated-at.bofh.it> |
| In reply to | #1589571 |
On Tue, 28 Feb 2017, Matt Redfearn wrote: > Since the instruction modifying the stack pointer is usually the first > in the function, that one is ususally handled correctly. But the s/ususally/usually/ > diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c > index 803e255b6fc3..5b1e932ae973 100644 > --- a/arch/mips/kernel/process.c > +++ b/arch/mips/kernel/process.c > @@ -347,6 +347,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; > + unsigned int last_insn_size = 0; Please keep declarations in the reverse Christmas tree order, i.e. swap the last two. Maciej
[toc] | [prev] | [next] | [standalone]
| From | Matt Redfearn <matt.redfearn@imgtec.com> |
|---|---|
| Date | 2017-03-01 15:10 +0100 |
| Subject | Re: [PATCH 1/4] MIPS: Handle non word sized instructions when examining frame |
| Message-ID | <tgd73-47I-9@gated-at.bofh.it> |
| In reply to | #1589765 |
Hi Maciej On 28/02/17 20:54, Maciej W. Rozycki wrote: > On Tue, 28 Feb 2017, Matt Redfearn wrote: > >> Since the instruction modifying the stack pointer is usually the first >> in the function, that one is ususally handled correctly. But the > s/ususally/usually/ oops > >> diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c >> index 803e255b6fc3..5b1e932ae973 100644 >> --- a/arch/mips/kernel/process.c >> +++ b/arch/mips/kernel/process.c >> @@ -347,6 +347,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; >> + unsigned int last_insn_size = 0; > Please keep declarations in the reverse Christmas tree order, i.e. swap > the last two. > > Maciej OK, no problem. Thanks, Matt
[toc] | [prev] | [next] | [standalone]
| From | "Maciej W. Rozycki" <macro@imgtec.com> |
|---|---|
| Date | 2017-03-01 03:00 +0100 |
| Subject | Re: [PATCH 2/4] MIPS: microMIPS: Fix decoding of addiusp instruction |
| Message-ID | <tg1IB-48Z-5@gated-at.bofh.it> |
| In reply to | #1589571 |
On Tue, 28 Feb 2017, Matt Redfearn wrote:
> diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
> index 5b1e932ae973..6ba5b775579c 100644
> --- a/arch/mips/kernel/process.c
> +++ b/arch/mips/kernel/process.c
> @@ -386,8 +386,9 @@ static int get_frame_info(struct mips_frame_info *info)
>
> if (ip->halfword[0] & mm_addiusp_func)
> {
> - tmp = (((ip->halfword[0] >> 1) & 0x1ff) << 2);
> - info->frame_size = -(signed short)(tmp | ((tmp & 0x100) ? 0xfe00 : 0));
> + tmp = (ip->halfword[0] >> 1) & 0x1ff;
> + tmp = tmp | ((tmp & 0x100) ? 0xfe00 : 0);
> + info->frame_size = -(signed short)(tmp << 2);
Ugh, this is unreadable -- can you please figure out a way to fit it in
79 columns? Perhaps by factoring this piece out?
Also this:
tmp = (ip->halfword[0] >> 1) & 0x1ff;
tmp = tmp | ((tmp & 0x100) ? 0xfe00 : 0);
will likely result in better code without the conditional, e.g.:
tmp = (((ip->halfword[0] >> 1) & 0x1ff) ^ 0x100) - 0x100;
(the usual way to sign-extend).
Maciej
[toc] | [prev] | [next] | [standalone]
| From | Matt Redfearn <matt.redfearn@imgtec.com> |
|---|---|
| Date | 2017-03-01 16:50 +0100 |
| Subject | Re: [PATCH 2/4] MIPS: microMIPS: Fix decoding of addiusp instruction |
| Message-ID | <tgeFP-55d-1@gated-at.bofh.it> |
| In reply to | #1589940 |
Hi Maciej,
On 28/02/17 22:04, Maciej W. Rozycki wrote:
> On Tue, 28 Feb 2017, Matt Redfearn wrote:
>
>> diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
>> index 5b1e932ae973..6ba5b775579c 100644
>> --- a/arch/mips/kernel/process.c
>> +++ b/arch/mips/kernel/process.c
>> @@ -386,8 +386,9 @@ static int get_frame_info(struct mips_frame_info *info)
>>
>> if (ip->halfword[0] & mm_addiusp_func)
>> {
>> - tmp = (((ip->halfword[0] >> 1) & 0x1ff) << 2);
>> - info->frame_size = -(signed short)(tmp | ((tmp & 0x100) ? 0xfe00 : 0));
>> + tmp = (ip->halfword[0] >> 1) & 0x1ff;
>> + tmp = tmp | ((tmp & 0x100) ? 0xfe00 : 0);
>> + info->frame_size = -(signed short)(tmp << 2);
> Ugh, this is unreadable -- can you please figure out a way to fit it in
> 79 columns? Perhaps by factoring this piece out?
Yeah, it's not pretty. I've got a v2 which refactors this into
is_sp_move_ins, which makes it work the same way as is_ra_save_ins and
perform the immediate interpretation there, instead.
But I've kept that as a separate patch so as to keep the functional fix
and refactor separate.
>
> Also this:
>
> tmp = (ip->halfword[0] >> 1) & 0x1ff;
> tmp = tmp | ((tmp & 0x100) ? 0xfe00 : 0);
>
> will likely result in better code without the conditional, e.g.:
>
> tmp = (((ip->halfword[0] >> 1) & 0x1ff) ^ 0x100) - 0x100;
>
> (the usual way to sign-extend).
>
> Maciej
Yes, that looks nicer.
Thanks,
Matt
[toc] | [prev] | [next] | [standalone]
| From | Matt Redfearn <matt.redfearn@imgtec.com> |
|---|---|
| Date | 2017-03-01 08:40 +0100 |
| Subject | [PATCH 4/4] MIPS: microMIPS: Fix decoding of swsp16 instruction |
| Message-ID | <tg71D-894-1@gated-at.bofh.it> |
| In reply to | #1589571 |
When the immediate encoded in the instruction is accessed, it is sign
extended due to being a signed value being assigned to a signed integer.
The ISA specifies that this operation is an unsigned operation.
The sign extension leads us to incorrectly decode:
801e9c8e: cbf1 sw ra,68(sp)
As having an immediate of 1073741809.
Since the instruction format does not specify signed/unsigned, and this
is currently the only location to use this instuction format, change it
to an unsigned immediate.
Fixes: bb9bc4689b9c ("MIPS: Calculate microMIPS ra properly when unwinding the stack")
Suggested-by: Paul Burton <paul.burton@imgtec.com>
Signed-off-by: Matt Redfearn <matt.redfearn@imgtec.com>
---
arch/mips/include/uapi/asm/inst.h | 2 +-
arch/mips/kernel/process.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/mips/include/uapi/asm/inst.h b/arch/mips/include/uapi/asm/inst.h
index 77429d1622b3..711d9b8465b8 100644
--- a/arch/mips/include/uapi/asm/inst.h
+++ b/arch/mips/include/uapi/asm/inst.h
@@ -964,7 +964,7 @@ struct mm16_r3_format { /* Load from global pointer format */
struct mm16_r5_format { /* Load/store from stack pointer format */
__BITFIELD_FIELD(unsigned int opcode : 6,
__BITFIELD_FIELD(unsigned int rt : 5,
- __BITFIELD_FIELD(signed int simmediate : 5,
+ __BITFIELD_FIELD(unsigned int imm : 5,
__BITFIELD_FIELD(unsigned int : 16, /* Ignored */
;))))
};
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 6ba5b775579c..67182baaf719 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -212,7 +212,7 @@ static inline int is_ra_save_ins(union mips_instruction *ip, int *poff)
if (ip->mm16_r5_format.rt != 31)
return 0;
- *poff = ip->mm16_r5_format.simmediate;
+ *poff = ip->mm16_r5_format.imm;
*poff = (*poff << 2) / sizeof(ulong);
return 1;
--
2.7.4
[toc] | [prev] | [next] | [standalone]
| From | Matt Redfearn <matt.redfearn@imgtec.com> |
|---|---|
| Date | 2017-03-01 08:40 +0100 |
| Subject | [PATCH 2/4] MIPS: microMIPS: Fix decoding of addiusp instruction |
| Message-ID | <tg1IB-48Z-7@gated-at.bofh.it> |
| In reply to | #1589571 |
Commit 34c2f668d0f6 ("MIPS: microMIPS: Add unaligned access support.")
added handling of microMIPS instructions to manipulate the stack
pointer. Unfortunately the decoding of the addiusp instruction was
incorrect, and performed a left shift by 2 bits to the raw immediate,
rather than decoding the immediate and then performing the shift, as
documented in the ISA.
This led to incomplete stack traces, due to incorrect frame sizes being
calculated. For example the instruction:
801faee0 <do_sys_poll>:
801faee0: 4e25 addiu sp,sp,-952
As decoded by objdump, would be interpreted by the existing code as
having manipulated the stack pointer by +1096.
Fix this by changing the order of decoding the immediate and applying
the left shift.
Fixes: 34c2f668d0f6 ("MIPS: microMIPS: Add unaligned access support.")
Signed-off-by: Matt Redfearn <matt.redfearn@imgtec.com>
---
arch/mips/kernel/process.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 5b1e932ae973..6ba5b775579c 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -386,8 +386,9 @@ static int get_frame_info(struct mips_frame_info *info)
if (ip->halfword[0] & mm_addiusp_func)
{
- tmp = (((ip->halfword[0] >> 1) & 0x1ff) << 2);
- info->frame_size = -(signed short)(tmp | ((tmp & 0x100) ? 0xfe00 : 0));
+ tmp = (ip->halfword[0] >> 1) & 0x1ff;
+ tmp = tmp | ((tmp & 0x100) ? 0xfe00 : 0);
+ info->frame_size = -(signed short)(tmp << 2);
} else {
tmp = (ip->halfword[0] >> 1);
info->frame_size = -(signed short)(tmp & 0xf);
--
2.7.4
[toc] | [prev] | [next] | [standalone]
| From | Matt Redfearn <matt.redfearn@imgtec.com> |
|---|---|
| Date | 2017-03-01 08:40 +0100 |
| Subject | [PATCH 1/4] MIPS: Handle non word sized instructions when examining frame |
| Message-ID | <tfX2h-15p-5@gated-at.bofh.it> |
| In reply to | #1589571 |
Commit b6c7a324df37 ("MIPS: Fix get_frame_info() handling of microMIPS
function size") goes some way to fixing get_frame_info() to iterate over
microMIPS instuctions, but increments the instruction pointer using a
postincrement of the instruction pointer, which is of union
mips_instruction type. Since the union is sized to the largest member (a
word), but microMIPS instructions are a mix of halfword and word sizes,
the function does not always iterate correctly, ending up misaligned
with the instruction stream and interpreting it incorrectly.
Since the instruction modifying the stack pointer is usually the first
in the function, that one is ususally handled correctly. But the
instruction which saves the return address to the sp is some variable
number of instructions into the frame and is frequently missed due to
not being on a word boundary, leading to incomplete walking of the
stack.
Fix this by incrementing the instruction pointer based on the size of
the previously decoded instruction.
Fixes: b6c7a324df37 ("MIPS: Fix get_frame_info() handling of microMIPS function size")
Signed-off-by: Matt Redfearn <matt.redfearn@imgtec.com>
---
arch/mips/kernel/process.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 803e255b6fc3..5b1e932ae973 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -347,6 +347,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;
+ unsigned int last_insn_size = 0;
info->pc_offset = -1;
info->frame_size = 0;
@@ -357,15 +358,19 @@ static int get_frame_info(struct mips_frame_info *info)
ip_end = (void *)ip + info->func_size;
- for (i = 0; i < max_insns && ip < ip_end; i++, ip++) {
+ for (i = 0; i < max_insns && ip < ip_end; i++) {
+ ip = (void *)ip + last_insn_size;
if (is_mmips && mm_insn_16bit(ip->halfword[0])) {
insn.halfword[0] = 0;
insn.halfword[1] = ip->halfword[0];
+ last_insn_size = sizeof(unsigned short);
} else if (is_mmips) {
insn.halfword[0] = ip->halfword[1];
insn.halfword[1] = ip->halfword[0];
+ last_insn_size = sizeof(unsigned int);
} else {
insn.word = ip->word;
+ last_insn_size = sizeof(unsigned int);
}
if (is_jump_ins(&insn))
--
2.7.4
[toc] | [prev] | [next] | [standalone]
| From | Matt Redfearn <matt.redfearn@imgtec.com> |
|---|---|
| Date | 2017-03-01 08:40 +0100 |
| Subject | [PATCH 3/4] MIPS: Stacktrace: Fix __usermode() of uninitialised regs |
| Message-ID | <tg71D-894-13@gated-at.bofh.it> |
| In reply to | #1589571 |
Commit 81a76d7119f6 ("MIPS: Avoid using unwind_stack() with usermode")
added a check if the passed regs are from user mode, and perform a raw
backtrace if so.
When WARN() is invoked, __dump_stack calls show_stack()
with NULL task and stack pointers. This leads show_stack to create a
pt_regs struct on the stack, and initialise it via prepare_frametrace().
When show_backtrace() examines the regs, the value of the status
register checked by user_mode() is unpredictable, depending on the
uninitialised content of the stack. This leads to show_backtrace()
sometimes showing raw backtraces instead of correctly walking the kernel
stack.
Fix this by initialising the contents of the saved status register in
prepare_frametrace().
Fixes: 81a76d7119f6 ("MIPS: Avoid using unwind_stack() with usermode")
Signed-off-by: Matt Redfearn <matt.redfearn@imgtec.com>
---
arch/mips/include/asm/stacktrace.h | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/mips/include/asm/stacktrace.h b/arch/mips/include/asm/stacktrace.h
index 780ee2c2a2ac..4845945d02a5 100644
--- a/arch/mips/include/asm/stacktrace.h
+++ b/arch/mips/include/asm/stacktrace.h
@@ -1,6 +1,7 @@
#ifndef _ASM_STACKTRACE_H
#define _ASM_STACKTRACE_H
+#include <asm/asm.h>
#include <asm/ptrace.h>
#ifdef CONFIG_KALLSYMS
@@ -47,6 +48,8 @@ static __always_inline void prepare_frametrace(struct pt_regs *regs)
: "=m" (regs->cp0_epc),
"=m" (regs->regs[29]), "=m" (regs->regs[31])
: : "memory");
+ /* show_backtrace behaviour depends on user_mode(regs) */
+ regs->cp0_status = read_c0_status();
}
#endif /* _ASM_STACKTRACE_H */
--
2.7.4
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web