diff options
Diffstat (limited to 'arch/powerpc/lib/sstep.c')
-rw-r--r-- | arch/powerpc/lib/sstep.c | 36 |
1 files changed, 34 insertions, 2 deletions
diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c index 9a52349874ee..e15c521846ca 100644 --- a/arch/powerpc/lib/sstep.c +++ b/arch/powerpc/lib/sstep.c | |||
@@ -566,7 +566,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) | |||
566 | unsigned long int ea; | 566 | unsigned long int ea; |
567 | unsigned int cr, mb, me, sh; | 567 | unsigned int cr, mb, me, sh; |
568 | int err; | 568 | int err; |
569 | unsigned long old_ra; | 569 | unsigned long old_ra, val3; |
570 | long ival; | 570 | long ival; |
571 | 571 | ||
572 | opcode = instr >> 26; | 572 | opcode = instr >> 26; |
@@ -1486,11 +1486,43 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) | |||
1486 | goto ldst_done; | 1486 | goto ldst_done; |
1487 | 1487 | ||
1488 | case 36: /* stw */ | 1488 | case 36: /* stw */ |
1489 | case 37: /* stwu */ | ||
1490 | val = regs->gpr[rd]; | 1489 | val = regs->gpr[rd]; |
1491 | err = write_mem(val, dform_ea(instr, regs), 4, regs); | 1490 | err = write_mem(val, dform_ea(instr, regs), 4, regs); |
1492 | goto ldst_done; | 1491 | goto ldst_done; |
1493 | 1492 | ||
1493 | case 37: /* stwu */ | ||
1494 | val = regs->gpr[rd]; | ||
1495 | val3 = dform_ea(instr, regs); | ||
1496 | /* | ||
1497 | * For PPC32 we always use stwu to change stack point with r1. So | ||
1498 | * this emulated store may corrupt the exception frame, now we | ||
1499 | * have to provide the exception frame trampoline, which is pushed | ||
1500 | * below the kprobed function stack. So we only update gpr[1] but | ||
1501 | * don't emulate the real store operation. We will do real store | ||
1502 | * operation safely in exception return code by checking this flag. | ||
1503 | */ | ||
1504 | if ((ra == 1) && !(regs->msr & MSR_PR) \ | ||
1505 | && (val3 >= (regs->gpr[1] - STACK_INT_FRAME_SIZE))) { | ||
1506 | /* | ||
1507 | * Check if we will touch kernel sack overflow | ||
1508 | */ | ||
1509 | if (val3 - STACK_INT_FRAME_SIZE <= current->thread.ksp_limit) { | ||
1510 | printk(KERN_CRIT "Can't kprobe this since Kernel stack overflow.\n"); | ||
1511 | err = -EINVAL; | ||
1512 | break; | ||
1513 | } | ||
1514 | |||
1515 | /* | ||
1516 | * Check if we already set since that means we'll | ||
1517 | * lose the previous value. | ||
1518 | */ | ||
1519 | WARN_ON(test_thread_flag(TIF_EMULATE_STACK_STORE)); | ||
1520 | set_thread_flag(TIF_EMULATE_STACK_STORE); | ||
1521 | err = 0; | ||
1522 | } else | ||
1523 | err = write_mem(val, val3, 4, regs); | ||
1524 | goto ldst_done; | ||
1525 | |||
1494 | case 38: /* stb */ | 1526 | case 38: /* stb */ |
1495 | case 39: /* stbu */ | 1527 | case 39: /* stbu */ |
1496 | val = regs->gpr[rd]; | 1528 | val = regs->gpr[rd]; |