diff options
author | srikar <srikar> | 2007-10-25 13:54:41 +0000 |
---|---|---|
committer | srikar <srikar> | 2007-10-25 13:54:41 +0000 |
commit | eca23f3dbde340a85adbeb3ea4e81df5cbc10c0b (patch) | |
tree | 043efb940f4386e5122fc9949cbce5edfdc513b8 /runtime/uprobes/uprobes_ppc64.c | |
parent | aa1547b49b569064715d939d6a9dad4cd14e708c (diff) | |
download | systemtap-steved-eca23f3dbde340a85adbeb3ea4e81df5cbc10c0b.tar.gz systemtap-steved-eca23f3dbde340a85adbeb3ea4e81df5cbc10c0b.tar.xz systemtap-steved-eca23f3dbde340a85adbeb3ea4e81df5cbc10c0b.zip |
uprobes ppc64 ssol changes
Diffstat (limited to 'runtime/uprobes/uprobes_ppc64.c')
-rw-r--r-- | runtime/uprobes/uprobes_ppc64.c | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/runtime/uprobes/uprobes_ppc64.c b/runtime/uprobes/uprobes_ppc64.c index d80676e9..819ac73d 100644 --- a/runtime/uprobes/uprobes_ppc64.c +++ b/runtime/uprobes/uprobes_ppc64.c @@ -31,6 +31,117 @@ unsigned long arch_hijack_uret_addr(unsigned long trampoline_address, struct pt_regs *regs, struct uprobe_task *utask) { unsigned long orig_ret_addr = regs->link; + regs->link = trampoline_address; return orig_ret_addr; } + +/* + * Get an instruction slot from the process's SSOL area, containing the + * instruction at ppt's probepoint. Point the eip at that slot, in preparation + * for single-stepping out of line. + */ +static +void uprobe_pre_ssout(struct uprobe_task *utask, struct uprobe_probept *ppt, + struct pt_regs *regs) +{ + struct uprobe_ssol_slot *slot; + + slot = uprobe_get_insn_slot(ppt); + if (!slot) { + utask->doomed = 1; + return; + } + regs->nip = (long)slot->insn; +} + + +static inline void calc_offset(struct uprobe_probept *ppt, + struct pt_regs *regs) +{ + int offset = 0; + unsigned int opcode = 0; + unsigned int insn = *ppt->insn; + + opcode = insn >> 26; + switch (opcode) { + case 16: /* bc */ + if ((insn & 2) == 0) { + offset = (signed short)(insn & 0xfffc); + regs->nip = ppt->vaddr + offset; + } + if (insn & 1) + regs->link = ppt->vaddr + MAX_UINSN_BYTES; + break; + case 17: /* sc */ + /* Do we need to do anything */ + break; + case 18: /* b */ + if ((insn & 2) == 0) { + offset = insn & 0x03fffffc; + if (offset & 0x02000000) + offset -= 0x04000000; + regs->nip = ppt->vaddr + offset; + } + if (insn & 1) + regs->link = ppt->vaddr + MAX_UINSN_BYTES; + break; + } +#ifdef UPROBES_DEBUG + printk (KERN_ERR "ppt->vaddr=%p, regs->nip=%p, offset=%ld\n", + ppt->vaddr, regs->nip, offset); + if (insn & 1) + printk (KERN_ERR "regs->link=%p \n", regs->link); +#endif + return; +} + +/* + * Called after single-stepping. ppt->vaddr is the address of the + * instruction which was replaced by a breakpoint instruction. To avoid + * the SMP problems that can occur when we temporarily put back the + * original opcode to single-step, we single-stepped a copy of the + * instruction. + * + * This function prepares to return from the post-single-step + * interrupt. + * + * 1) Typically, the new nip is relative to the copied instruction. We + * need to make it relative to the original instruction. Exceptions are + * branch instructions. + * + * 2) For branch instructions, update the nip if the branch uses + * relative addressing. Update the link instruction to the instruction + * following the original instruction address. + */ + +static +void uprobe_post_ssout(struct uprobe_task *utask, struct uprobe_probept *ppt, + struct pt_regs *regs) +{ + unsigned long copy_nip; + + copy_nip = (unsigned long) ppt->slot->insn; + up_read(&ppt->slot->rwsem); + + /* + * If the single stepped instruction is non-branch instruction + * then update the IP to be relative to probepoint. + */ + if (regs->nip == copy_nip + MAX_UINSN_BYTES) + regs->nip = ppt->vaddr + MAX_UINSN_BYTES; + else + calc_offset(ppt,regs); +} + +static +int arch_validate_probed_insn(struct uprobe_probept *ppt, + struct task_struct *tsk) +{ + if ((unsigned long)ppt->vaddr & 0x03) { + printk(KERN_WARNING + "Attempt to register uprobe at an unaligned addr\n"); + return -EINVAL; + } + return 0; +} |