Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 227229
b: refs/heads/master
c: fc0a1fe
h: refs/heads/master
i:
  227227: 7ff6732
v: v3
  • Loading branch information
Martin Schwidefsky authored and Martin Schwidefsky committed Jan 5, 2011
1 parent 802ce84 commit 7839b09
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 45 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 35f2aaa79a2d484c8449f34461464a1e84e36e2b
refs/heads/master: fc0a1fea6b81095b6c0e01ec3407d04c8341974c
3 changes: 0 additions & 3 deletions trunk/arch/s390/include/asm/kprobes.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,6 @@ struct ins_replace_args {
struct prev_kprobe {
struct kprobe *kp;
unsigned long status;
unsigned long saved_psw;
unsigned long kprobe_saved_imask;
unsigned long kprobe_saved_ctl[3];
};

/* per-cpu kprobe control block */
Expand Down
77 changes: 36 additions & 41 deletions trunk/arch/s390/kernel/kprobes.c
Original file line number Diff line number Diff line change
Expand Up @@ -198,51 +198,58 @@ void __kprobes arch_remove_kprobe(struct kprobe *p)
}
}

static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
static void __kprobes enable_singlestep(struct kprobe_ctlblk *kcb,
struct pt_regs *regs,
unsigned long ip)
{
per_cr_bits kprobe_per_regs[1];

memset(kprobe_per_regs, 0, sizeof(per_cr_bits));
regs->psw.addr = (unsigned long)p->ainsn.insn | PSW_ADDR_AMODE;

/* Set up the per control reg info, will pass to lctl */
memset(kprobe_per_regs, 0, sizeof(per_cr_bits));
kprobe_per_regs[0].em_instruction_fetch = 1;
kprobe_per_regs[0].starting_addr = (unsigned long)p->ainsn.insn;
kprobe_per_regs[0].ending_addr = (unsigned long)p->ainsn.insn + 1;
kprobe_per_regs[0].starting_addr = ip;
kprobe_per_regs[0].ending_addr = ip;

/* Set the PER control regs, turns on single step for this address */
/* Save control regs and psw mask */
__ctl_store(kcb->kprobe_saved_ctl, 9, 11);
kcb->kprobe_saved_imask = regs->psw.mask &
(PSW_MASK_PER | PSW_MASK_IO | PSW_MASK_EXT);

/* Set PER control regs, turns on single step for the given address */
__ctl_load(kprobe_per_regs, 9, 11);
regs->psw.mask |= PSW_MASK_PER;
regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT);
regs->psw.addr = ip | PSW_ADDR_AMODE;
}

static void __kprobes disable_singlestep(struct kprobe_ctlblk *kcb,
struct pt_regs *regs,
unsigned long ip)
{
/* Restore control regs and psw mask, set new psw address */
__ctl_load(kcb->kprobe_saved_ctl, 9, 11);
regs->psw.mask &= ~PSW_MASK_PER;
regs->psw.mask |= kcb->kprobe_saved_imask;
regs->psw.addr = ip | PSW_ADDR_AMODE;
}


static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb)
{
kcb->prev_kprobe.kp = kprobe_running();
kcb->prev_kprobe.status = kcb->kprobe_status;
kcb->prev_kprobe.kprobe_saved_imask = kcb->kprobe_saved_imask;
memcpy(kcb->prev_kprobe.kprobe_saved_ctl, kcb->kprobe_saved_ctl,
sizeof(kcb->kprobe_saved_ctl));
}

static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb)
{
__get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp;
kcb->kprobe_status = kcb->prev_kprobe.status;
kcb->kprobe_saved_imask = kcb->prev_kprobe.kprobe_saved_imask;
memcpy(kcb->kprobe_saved_ctl, kcb->prev_kprobe.kprobe_saved_ctl,
sizeof(kcb->kprobe_saved_ctl));
}

static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs,
struct kprobe_ctlblk *kcb)
{
__get_cpu_var(current_kprobe) = p;
/* Save the interrupt and per flags */
kcb->kprobe_saved_imask = regs->psw.mask &
(PSW_MASK_PER | PSW_MASK_IO | PSW_MASK_EXT);
/* Save the control regs that govern PER */
__ctl_store(kcb->kprobe_saved_ctl, 9, 11);
}

void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
Expand Down Expand Up @@ -282,7 +289,8 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
save_previous_kprobe(kcb);
set_current_kprobe(p, regs, kcb);
kprobes_inc_nmissed_count(p);
prepare_singlestep(p, regs);
enable_singlestep(kcb, regs,
(unsigned long) p->ainsn.insn);
kcb->kprobe_status = KPROBE_REENTER;
return 1;
} else {
Expand Down Expand Up @@ -311,7 +319,7 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
return 1;

ss_probe:
prepare_singlestep(p, regs);
enable_singlestep(kcb, regs, (unsigned long) p->ainsn.insn);
kcb->kprobe_status = KPROBE_HIT_SS;
return 1;

Expand Down Expand Up @@ -433,31 +441,20 @@ static int __kprobes trampoline_probe_handler(struct kprobe *p,
static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
{
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();

regs->psw.addr &= PSW_ADDR_INSN;
unsigned long ip = regs->psw.addr & PSW_ADDR_INSN;

if (p->ainsn.fixup & FIXUP_PSW_NORMAL)
regs->psw.addr = (unsigned long)p->addr +
((unsigned long)regs->psw.addr -
(unsigned long)p->ainsn.insn);
ip += (unsigned long) p->addr - (unsigned long) p->ainsn.insn;

if (p->ainsn.fixup & FIXUP_BRANCH_NOT_TAKEN)
if ((unsigned long)regs->psw.addr -
(unsigned long)p->ainsn.insn == p->ainsn.ilen)
regs->psw.addr = (unsigned long)p->addr + p->ainsn.ilen;
if (ip - (unsigned long) p->ainsn.insn == p->ainsn.ilen)
ip = (unsigned long) p->addr + p->ainsn.ilen;

if (p->ainsn.fixup & FIXUP_RETURN_REGISTER)
regs->gprs[p->ainsn.reg] = ((unsigned long)p->addr +
(regs->gprs[p->ainsn.reg] -
(unsigned long)p->ainsn.insn))
| PSW_ADDR_AMODE;
regs->gprs[p->ainsn.reg] += (unsigned long) p->addr -
(unsigned long) p->ainsn.insn;

regs->psw.addr |= PSW_ADDR_AMODE;
/* turn off PER mode */
regs->psw.mask &= ~PSW_MASK_PER;
/* Restore the original per control regs */
__ctl_load(kcb->kprobe_saved_ctl, 9, 11);
regs->psw.mask |= kcb->kprobe_saved_imask;
disable_singlestep(kcb, regs, ip);
}

static int __kprobes post_kprobe_handler(struct pt_regs *regs)
Expand Down Expand Up @@ -515,9 +512,7 @@ static int __kprobes kprobe_trap_handler(struct pt_regs *regs, int trapnr)
* and allow the page fault handler to continue as a
* normal page fault.
*/
regs->psw.addr = (unsigned long)cur->addr | PSW_ADDR_AMODE;
regs->psw.mask &= ~PSW_MASK_PER;
regs->psw.mask |= kcb->kprobe_saved_imask;
disable_singlestep(kcb, regs, (unsigned long) cur->addr);
if (kcb->kprobe_status == KPROBE_REENTER)
restore_previous_kprobe(kcb);
else {
Expand Down

0 comments on commit 7839b09

Please sign in to comment.