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 <pau...@ozlabs.org>
---
 arch/powerpc/lib/sstep.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c
index 7921b2a..d9b3b63 100644
--- a/arch/powerpc/lib/sstep.c
+++ b/arch/powerpc/lib/sstep.c
@@ -1024,9 +1024,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:
@@ -1126,6 +1123,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;
-- 
2.7.4

Reply via email to