diff options
author | Paul Mackerras <paulus@ozlabs.org> | 2017-08-30 07:12:31 +0300 |
---|---|---|
committer | Michael Ellerman <mpe@ellerman.id.au> | 2017-09-01 09:39:51 +0300 |
commit | 958465ee5407dc1b25ba6eb33f0e8bb6179960ee (patch) | |
tree | 6f4712b6150519bb4830a3fe206be77301d8590f /arch | |
parent | 5762e08344bd7c5bfc41030f74c4ab6ce6e461d0 (diff) | |
download | linux-958465ee5407dc1b25ba6eb33f0e8bb6179960ee.tar.xz |
powerpc: Add emulation for the addpcis instruction
The addpcis instruction puts the sum of the next instruction address
plus a constant into a register. Since the result depends on the
address of the instruction, it will give an incorrect result if it
is single-stepped out of line, which is what the *probes subsystem
will currently do if a probe is placed on an addpcis instruction.
This fixes the problem by adding emulation of it to analyse_instr().
Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/lib/sstep.c | 14 |
1 files changed, 11 insertions, 3 deletions
diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c index 10eabd9a255d..96283499664b 100644 --- a/arch/powerpc/lib/sstep.c +++ b/arch/powerpc/lib/sstep.c @@ -1021,9 +1021,6 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs, op->ccval = (regs->ccr & ~(1UL << (31 - rd))) | (val << (31 - rd)); return 1; - default: - op->type = UNKNOWN; - return 0; } break; case 31: @@ -1123,6 +1120,17 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs, op->val = imm; goto compute_done; + case 19: + if (((instr >> 1) & 0x1f) == 2) { + /* addpcis */ + imm = (short) (instr & 0xffc1); /* d0 + d2 fields */ + imm |= (instr >> 15) & 0x3e; /* d1 field */ + op->val = regs->nip + (imm << 16) + 4; + goto compute_done; + } + op->type = UNKNOWN; + return 0; + case 20: /* rlwimi */ mb = (instr >> 6) & 0x1f; me = (instr >> 1) & 0x1f; |