powerpc: Add emulation for the addpcis instruction
authorPaul Mackerras <paulus@ozlabs.org>
Wed, 30 Aug 2017 04:12:31 +0000 (14:12 +1000)
committerMichael Ellerman <mpe@ellerman.id.au>
Fri, 1 Sep 2017 06:39:51 +0000 (16:39 +1000)
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>
arch/powerpc/lib/sstep.c

index 10eabd9a255dfee97b937ddc079a9d07dcf0a569..96283499664bd83bc400f2e51cfe38809d7dbd32 100644 (file)
@@ -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;