summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--runtime/uprobes/uprobes_ppc64.c36
-rw-r--r--runtime/uprobes/uprobes_ppc64.h70
-rw-r--r--runtime/uprobes/uprobes_s390.c208
-rw-r--r--runtime/uprobes/uprobes_s390.h85
5 files changed, 404 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index 4c1801d6..77883fc6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2007-10-10 Jim Keniston <jkenisto@us.ibm.com>
+
+ * runtime/uprobes/uprobes_ppc64.[ch]: Added
+ * runtime/uprobes/uprobes_s390.[ch]: Added
+
2007-10-09 Jim Keniston <jkenisto@us.ibm.com>
PR 5083
diff --git a/runtime/uprobes/uprobes_ppc64.c b/runtime/uprobes/uprobes_ppc64.c
new file mode 100644
index 00000000..d80676e9
--- /dev/null
+++ b/runtime/uprobes/uprobes_ppc64.c
@@ -0,0 +1,36 @@
+/*
+ * Userspace Probes (UProbes) for PowerPC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright IBM Corporation, 2007
+ */
+/*
+ * In versions of uprobes built in the SystemTap runtime, this file
+ * is #included at the end of uprobes.c.
+ */
+
+/*
+ * Replace the return address with the trampoline address. Returns
+ * the original return address.
+ */
+static
+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;
+}
diff --git a/runtime/uprobes/uprobes_ppc64.h b/runtime/uprobes/uprobes_ppc64.h
new file mode 100644
index 00000000..619ba324
--- /dev/null
+++ b/runtime/uprobes/uprobes_ppc64.h
@@ -0,0 +1,70 @@
+#ifndef _ASM_UPROBES_H
+#define _ASM_UPROBES_H
+/*
+ * Userspace Probes (UProbes) for PowerPC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright IBM Corporation, 2007
+ */
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/signal.h>
+
+#define BREAKPOINT_SIGNAL SIGTRAP
+#define SSTEP_SIGNAL SIGTRAP
+
+/* Normally defined in Kconfig */
+#undef CONFIG_UPROBES_SSOL
+#define CONFIG_URETPROBES 1
+
+typedef unsigned int uprobe_opcode_t;
+#define BREAKPOINT_INSTRUCTION 0x7fe00008 /* trap */
+#define BP_INSN_SIZE 4
+#define MAX_UINSN_BYTES 4
+#define SLOT_IP 32 /* instruction pointer slot from include/asm/elf.h */
+
+/* Architecture specific switch for where the IP points after a bp hit */
+#define ARCH_BP_INST_PTR(inst_ptr) (inst_ptr)
+
+struct uprobe_probept;
+struct uprobe_task;
+
+static inline int arch_validate_probed_insn(struct uprobe_probept *ppt)
+{
+ return 0;
+}
+
+/* On powerpc, nip points to the trap. */
+static inline unsigned long arch_get_probept(struct pt_regs *regs)
+{
+ return (unsigned long)(regs->nip);
+}
+
+static inline void arch_reset_ip_for_sstep(struct pt_regs *regs)
+{
+}
+
+#ifdef CONFIG_URETPROBES
+static inline void arch_restore_uret_addr(unsigned long ret_addr,
+ struct pt_regs *regs)
+{
+ regs->nip = ret_addr;
+}
+#endif /* CONFIG_URETPROBES */
+
+static unsigned long arch_hijack_uret_addr(unsigned long trampoline_addr,
+ struct pt_regs *regs, struct uprobe_task *utask);
+#endif /* _ASM_UPROBES_H */
diff --git a/runtime/uprobes/uprobes_s390.c b/runtime/uprobes/uprobes_s390.c
new file mode 100644
index 00000000..f97dd408
--- /dev/null
+++ b/runtime/uprobes/uprobes_s390.c
@@ -0,0 +1,208 @@
+/*
+ * Userspace Probes (UProbes)
+ * arch/s390/uprobes/uprobes_s390.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) IBM Corporation, 2006
+ */
+/*
+ * In versions of uprobes built in the SystemTap runtime, this file
+ * is #included at the end of uprobes.c.
+ */
+#include <linux/uaccess.h>
+
+/* adapted from s390/kernel/kprobes.c is_prohibited_opcode() */
+/* TODO More instructions?? Should floating point inst be added?? */
+static int prohibited_opcode(uprobe_opcode_t *instruction)
+{
+ switch (*(__u8 *) instruction) {
+ case 0x0c: /* bassm */
+ case 0x0b: /* bsm */
+ case 0x83: /* diag */
+ case 0x44: /* ex */
+ return -EINVAL;
+ }
+ switch (*(__u16 *) instruction) {
+ case 0x0101: /* pr */
+ case 0xb25a: /* bsa */
+ case 0xb240: /* bakr */
+ case 0xb258: /* bsg */
+ case 0xb218: /* pc */
+ case 0xb228: /* pt */
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static
+int arch_validate_probed_insn(struct uprobe_probept *ppt)
+{
+ if (ppt->vaddr & 0x01) {
+ printk("Attempt to register uprobe at an unaligned address\n");
+ return -EPERM;
+ }
+
+ /* Make sure the probe isn't going on a difficult instruction */
+ if (prohibited_opcode((uprobe_opcode_t *) ppt->insn))
+ return -EPERM;
+
+ return 0;
+}
+
+/*
+ * Get an instruction slot from the process's SSOL area, containing the
+ * instruction at ppt's probepoint. Point the psw.addr 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->psw.addr = (long)slot->insn;
+ utask->singlestep_addr = regs->psw.addr;
+}
+
+static
+void uprobe_post_ssout(struct uprobe_task *utask, struct uprobe_probept *ppt,
+ struct pt_regs *regs)
+{
+ int ilen, fixup, reg;
+ unsigned long copy_ins_addr = utask->singlestep_addr;
+ unsigned long orig_ins_addr = ppt->vaddr;
+
+ up_read(&ppt->slot->rwsem);
+
+ /* default fixup method */
+ fixup = FIXUP_PSW_NORMAL;;
+
+ /* get r1 operand */
+ reg = (*ppt->insn & 0xf0) >> 4;
+
+ /* save the instruction length (pop 5-5) in bytes */
+ switch (*(__u8 *) (ppt->insn) >> 6) {
+ case 0:
+ ilen = 2;
+ break;
+ case 1:
+ case 2:
+ ilen = 4;
+ break;
+ case 3:
+ ilen = 6;
+ break;
+ default:
+ ilen = 0;
+ BUG();
+ }
+
+
+ switch (*(__u8 *) ppt->insn) {
+ case 0x05: /* balr */
+ case 0x0d: /* basr */
+ fixup = FIXUP_RETURN_REGISTER;
+ /* if r2 = 0, no branch will be taken */
+ if ((*ppt->insn & 0x0f) == 0)
+ fixup |= FIXUP_BRANCH_NOT_TAKEN;
+ break;
+ case 0x06: /* bctr */
+ case 0x07: /* bcr */
+ fixup = FIXUP_BRANCH_NOT_TAKEN;
+ break;
+ case 0x45: /* bal */
+ case 0x4d: /* bas */
+ fixup = FIXUP_RETURN_REGISTER;
+ break;
+ case 0x47: /* bc */
+ case 0x46: /* bct */
+ case 0x86: /* bxh */
+ case 0x87: /* bxle */
+ fixup = FIXUP_BRANCH_NOT_TAKEN;
+ break;
+ case 0x82: /* lpsw */
+ fixup = FIXUP_NOT_REQUIRED;
+ break;
+ case 0xb2: /* lpswe */
+ if (*(((__u8 *) ppt->insn) + 1) == 0xb2) {
+ fixup = FIXUP_NOT_REQUIRED;
+ }
+ break;
+ case 0xa7: /* bras */
+ if ((*ppt->insn & 0x0f) == 0x05) {
+ fixup |= FIXUP_RETURN_REGISTER;
+ }
+ break;
+ case 0xc0:
+ if ((*ppt->insn & 0x0f) == 0x00 /* larl */
+ || (*ppt->insn & 0x0f) == 0x05) /* brasl */
+ fixup |= FIXUP_RETURN_REGISTER;
+ break;
+ case 0xeb:
+ if (*(((__u8 *) ppt->insn) + 5 ) == 0x44 || /* bxhg */
+ *(((__u8 *) ppt->insn) + 5) == 0x45) {/* bxleg */
+ fixup = FIXUP_BRANCH_NOT_TAKEN;
+ }
+ break;
+ case 0xe3: /* bctg */
+ if (*(((__u8 *) ppt->insn) + 5) == 0x46) {
+ fixup = FIXUP_BRANCH_NOT_TAKEN;
+ }
+ break;
+ }
+
+ /* do the fixup and adjust psw as needed */
+ regs->psw.addr &= PSW_ADDR_INSN;
+
+ if (fixup & FIXUP_PSW_NORMAL)
+ regs->psw.addr = orig_ins_addr + regs->psw.addr -
+ copy_ins_addr;
+
+ if (fixup & FIXUP_BRANCH_NOT_TAKEN)
+ if (regs->psw.addr - copy_ins_addr == ilen)
+ regs->psw.addr = orig_ins_addr + ilen;
+
+ if (fixup & FIXUP_RETURN_REGISTER)
+ regs->gprs[reg] = (orig_ins_addr + (regs->gprs[reg] -
+ copy_ins_addr)) | PSW_ADDR_AMODE;
+
+ regs->psw.addr |= PSW_ADDR_AMODE;
+}
+
+
+/*
+ * Replace the return address with the trampoline address. Returns
+ * the original return address.
+ */
+static
+unsigned long arch_hijack_uret_addr(unsigned long trampoline_address,
+ struct pt_regs *regs, struct uprobe_task *utask)
+{
+ unsigned long orig_ret_addr;
+#ifdef CONFIG_COMPAT
+ if (test_tsk_thread_flag(utask->tsk, TIF_31BIT))
+ orig_ret_addr = regs->gprs[14]&0x7FFFFFFFUL;
+ else
+#endif
+ orig_ret_addr = regs->gprs[14];
+ regs->gprs[14] = trampoline_address;
+ return orig_ret_addr;
+}
diff --git a/runtime/uprobes/uprobes_s390.h b/runtime/uprobes/uprobes_s390.h
new file mode 100644
index 00000000..4f3a8187
--- /dev/null
+++ b/runtime/uprobes/uprobes_s390.h
@@ -0,0 +1,85 @@
+#ifndef _ASM_UPROBES_H
+#define _ASM_UPROBES_H
+/*
+ * Userspace Probes (UProbes)
+ * include/asm-s390/uprobes.h
+ *
+ * Adapted from include/asm-i386/uprobes.h by:
+ * David Wilder <dwilder.us.ibm.com> 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) IBM Corporation, 2006
+ */
+#include <linux/types.h>
+#include <linux/ptrace.h>
+
+/* Normally defined in Kconfig */
+#define CONFIG_URETPROBES 1
+#define CONFIG_UPROBES_SSOL 1
+
+typedef u16 uprobe_opcode_t;
+
+#define BREAKPOINT_INSTRUCTION 0x0002
+#define BP_INSN_SIZE 2
+#define MAX_UINSN_BYTES 6
+
+#define BREAKPOINT_SIGNAL SIGILL
+#define SSTEP_SIGNAL SIGTRAP
+
+#ifdef CONFIG_COMPAT
+#define SLOT_IP (test_tsk_thread_flag(current, TIF_31BIT) ? 0x04 : 0x08)
+#else
+#define SLOT_IP 0x08
+#endif
+
+#define FIXUP_PSW_NORMAL 0x08
+#define FIXUP_BRANCH_NOT_TAKEN 0x04
+#define FIXUP_RETURN_REGISTER 0x02
+#define FIXUP_NOT_REQUIRED 0x01
+
+/* Architecture specific switch for where the IP points after a bp hit */
+#define ARCH_BP_INST_PTR(inst_ptr) (inst_ptr - BP_INSN_SIZE)
+
+struct uprobe_probept;
+struct uprobe_task;
+static int arch_validate_probed_insn(struct uprobe_probept *ppt);
+
+/*
+ * On s390, a trap leaves the instruction pointer pointing past the
+ * trap instruction.
+ */
+static inline unsigned long arch_get_probept(struct pt_regs *regs)
+{
+ return (unsigned long) (regs->psw.addr - BP_INSN_SIZE);
+}
+
+static inline void arch_reset_ip_for_sstep(struct pt_regs *regs)
+{
+ regs->psw.addr -= BP_INSN_SIZE;
+}
+
+#ifdef CONFIG_URETPROBES
+static inline void arch_restore_uret_addr(unsigned long ret_addr,
+ struct pt_regs *regs)
+{
+ regs->psw.addr = ret_addr;
+}
+
+static unsigned long arch_hijack_uret_addr(unsigned long trampoline_addr,
+ struct pt_regs *regs, struct uprobe_task *utask);
+
+#endif /* CONFIG_URETPROBES */
+#endif /* _ASM_UPROBES_H */