s390/uprobes: common library for kprobes and uprobes
authorJan Willeke <willeke@de.ibm.com>
Mon, 22 Sep 2014 14:37:27 +0000 (16:37 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Thu, 25 Sep 2014 08:52:14 +0000 (10:52 +0200)
This patch moves common functions from kprobes.c to probes.c.
Thus its possible for uprobes to use them without enabling kprobes.

Signed-off-by: Jan Willeke <willeke@de.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
arch/s390/include/asm/kprobes.h
arch/s390/kernel/kprobes.c
arch/s390/lib/Makefile
arch/s390/lib/probes.c [new file with mode: 0644]

index 4176dfe..9862917 100644 (file)
@@ -84,6 +84,10 @@ int kprobe_fault_handler(struct pt_regs *regs, int trapnr);
 int kprobe_exceptions_notify(struct notifier_block *self,
        unsigned long val, void *data);
 
+int probe_is_prohibited_opcode(u16 *insn);
+int probe_get_fixup_type(u16 *insn);
+int probe_is_insn_relative_long(u16 *insn);
+
 #define flush_insn_slot(p)     do { } while (0)
 
 #endif /* _ASM_S390_KPROBES_H */
index c48a00c..27ae543 100644 (file)
@@ -58,161 +58,13 @@ struct kprobe_insn_cache kprobe_dmainsn_slots = {
        .insn_size = MAX_INSN_SIZE,
 };
 
-static int __kprobes is_prohibited_opcode(kprobe_opcode_t *insn)
-{
-       if (!is_known_insn((unsigned char *)insn))
-               return -EINVAL;
-       switch (insn[0] >> 8) {
-       case 0x0c:      /* bassm */
-       case 0x0b:      /* bsm   */
-       case 0x83:      /* diag  */
-       case 0x44:      /* ex    */
-       case 0xac:      /* stnsm */
-       case 0xad:      /* stosm */
-               return -EINVAL;
-       case 0xc6:
-               switch (insn[0] & 0x0f) {
-               case 0x00: /* exrl   */
-                       return -EINVAL;
-               }
-       }
-       switch (insn[0]) {
-       case 0x0101:    /* pr    */
-       case 0xb25a:    /* bsa   */
-       case 0xb240:    /* bakr  */
-       case 0xb258:    /* bsg   */
-       case 0xb218:    /* pc    */
-       case 0xb228:    /* pt    */
-       case 0xb98d:    /* epsw  */
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static int __kprobes get_fixup_type(kprobe_opcode_t *insn)
-{
-       /* default fixup method */
-       int fixup = FIXUP_PSW_NORMAL;
-
-       switch (insn[0] >> 8) {
-       case 0x05:      /* balr */
-       case 0x0d:      /* basr */
-               fixup = FIXUP_RETURN_REGISTER;
-               /* if r2 = 0, no branch will be taken */
-               if ((insn[0] & 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 ((insn[0] & 0xff) == 0xb2)
-                       fixup = FIXUP_NOT_REQUIRED;
-               break;
-       case 0xa7:      /* bras */
-               if ((insn[0] & 0x0f) == 0x05)
-                       fixup |= FIXUP_RETURN_REGISTER;
-               break;
-       case 0xc0:
-               if ((insn[0] & 0x0f) == 0x05)   /* brasl */
-                       fixup |= FIXUP_RETURN_REGISTER;
-               break;
-       case 0xeb:
-               switch (insn[2] & 0xff) {
-               case 0x44: /* bxhg  */
-               case 0x45: /* bxleg */
-                       fixup = FIXUP_BRANCH_NOT_TAKEN;
-                       break;
-               }
-               break;
-       case 0xe3:      /* bctg */
-               if ((insn[2] & 0xff) == 0x46)
-                       fixup = FIXUP_BRANCH_NOT_TAKEN;
-               break;
-       case 0xec:
-               switch (insn[2] & 0xff) {
-               case 0xe5: /* clgrb */
-               case 0xe6: /* cgrb  */
-               case 0xf6: /* crb   */
-               case 0xf7: /* clrb  */
-               case 0xfc: /* cgib  */
-               case 0xfd: /* cglib */
-               case 0xfe: /* cib   */
-               case 0xff: /* clib  */
-                       fixup = FIXUP_BRANCH_NOT_TAKEN;
-                       break;
-               }
-               break;
-       }
-       return fixup;
-}
-
-static int __kprobes is_insn_relative_long(kprobe_opcode_t *insn)
-{
-       /* Check if we have a RIL-b or RIL-c format instruction which
-        * we need to modify in order to avoid instruction emulation. */
-       switch (insn[0] >> 8) {
-       case 0xc0:
-               if ((insn[0] & 0x0f) == 0x00) /* larl */
-                       return true;
-               break;
-       case 0xc4:
-               switch (insn[0] & 0x0f) {
-               case 0x02: /* llhrl  */
-               case 0x04: /* lghrl  */
-               case 0x05: /* lhrl   */
-               case 0x06: /* llghrl */
-               case 0x07: /* sthrl  */
-               case 0x08: /* lgrl   */
-               case 0x0b: /* stgrl  */
-               case 0x0c: /* lgfrl  */
-               case 0x0d: /* lrl    */
-               case 0x0e: /* llgfrl */
-               case 0x0f: /* strl   */
-                       return true;
-               }
-               break;
-       case 0xc6:
-               switch (insn[0] & 0x0f) {
-               case 0x02: /* pfdrl  */
-               case 0x04: /* cghrl  */
-               case 0x05: /* chrl   */
-               case 0x06: /* clghrl */
-               case 0x07: /* clhrl  */
-               case 0x08: /* cgrl   */
-               case 0x0a: /* clgrl  */
-               case 0x0c: /* cgfrl  */
-               case 0x0d: /* crl    */
-               case 0x0e: /* clgfrl */
-               case 0x0f: /* clrl   */
-                       return true;
-               }
-               break;
-       }
-       return false;
-}
-
 static void __kprobes copy_instruction(struct kprobe *p)
 {
        s64 disp, new_disp;
        u64 addr, new_addr;
 
        memcpy(p->ainsn.insn, p->addr, insn_length(p->opcode >> 8));
-       if (!is_insn_relative_long(p->ainsn.insn))
+       if (!probe_is_insn_relative_long(p->ainsn.insn))
                return;
        /*
         * For pc-relative instructions in RIL-b or RIL-c format patch the
@@ -276,7 +128,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
        if ((unsigned long) p->addr & 0x01)
                return -EINVAL;
        /* Make sure the probe isn't going on a difficult instruction */
-       if (is_prohibited_opcode(p->addr))
+       if (probe_is_prohibited_opcode(p->addr))
                return -EINVAL;
        if (s390_get_insn_slot(p))
                return -ENOMEM;
@@ -605,7 +457,7 @@ static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
 {
        struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
        unsigned long ip = regs->psw.addr & PSW_ADDR_INSN;
-       int fixup = get_fixup_type(p->ainsn.insn);
+       int fixup = probe_get_fixup_type(p->ainsn.insn);
 
        if (fixup & FIXUP_PSW_NORMAL)
                ip += (unsigned long) p->addr - (unsigned long) p->ainsn.insn;
index c6d752e..a01df23 100644 (file)
@@ -6,3 +6,5 @@ lib-y += delay.o string.o uaccess.o find.o
 obj-$(CONFIG_32BIT) += div64.o qrnnd.o ucmpdi2.o mem32.o
 obj-$(CONFIG_64BIT) += mem64.o
 lib-$(CONFIG_SMP) += spinlock.o
+lib-$(CONFIG_KPROBES) += probes.o
+lib-$(CONFIG_UPROBES) += probes.o
diff --git a/arch/s390/lib/probes.c b/arch/s390/lib/probes.c
new file mode 100644 (file)
index 0000000..c5d64a0
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ *    Common helper functions for kprobes and uprobes
+ *
+ *    Copyright IBM Corp. 2014
+ */
+
+#include <linux/kprobes.h>
+#include <asm/dis.h>
+
+int probe_is_prohibited_opcode(u16 *insn)
+{
+       if (!is_known_insn((unsigned char *)insn))
+               return -EINVAL;
+       switch (insn[0] >> 8) {
+       case 0x0c:      /* bassm */
+       case 0x0b:      /* bsm   */
+       case 0x83:      /* diag  */
+       case 0x44:      /* ex    */
+       case 0xac:      /* stnsm */
+       case 0xad:      /* stosm */
+               return -EINVAL;
+       case 0xc6:
+               switch (insn[0] & 0x0f) {
+               case 0x00: /* exrl   */
+                       return -EINVAL;
+               }
+       }
+       switch (insn[0]) {
+       case 0x0101:    /* pr    */
+       case 0xb25a:    /* bsa   */
+       case 0xb240:    /* bakr  */
+       case 0xb258:    /* bsg   */
+       case 0xb218:    /* pc    */
+       case 0xb228:    /* pt    */
+       case 0xb98d:    /* epsw  */
+       case 0xe560:    /* tbegin */
+       case 0xe561:    /* tbeginc */
+       case 0xb2f8:    /* tend  */
+               return -EINVAL;
+       }
+       return 0;
+}
+
+int probe_get_fixup_type(u16 *insn)
+{
+       /* default fixup method */
+       int fixup = FIXUP_PSW_NORMAL;
+
+       switch (insn[0] >> 8) {
+       case 0x05:      /* balr */
+       case 0x0d:      /* basr */
+               fixup = FIXUP_RETURN_REGISTER;
+               /* if r2 = 0, no branch will be taken */
+               if ((insn[0] & 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 ((insn[0] & 0xff) == 0xb2)
+                       fixup = FIXUP_NOT_REQUIRED;
+               break;
+       case 0xa7:      /* bras */
+               if ((insn[0] & 0x0f) == 0x05)
+                       fixup |= FIXUP_RETURN_REGISTER;
+               break;
+       case 0xc0:
+               if ((insn[0] & 0x0f) == 0x05)   /* brasl */
+                       fixup |= FIXUP_RETURN_REGISTER;
+               break;
+       case 0xeb:
+               switch (insn[2] & 0xff) {
+               case 0x44: /* bxhg  */
+               case 0x45: /* bxleg */
+                       fixup = FIXUP_BRANCH_NOT_TAKEN;
+                       break;
+               }
+               break;
+       case 0xe3:      /* bctg */
+               if ((insn[2] & 0xff) == 0x46)
+                       fixup = FIXUP_BRANCH_NOT_TAKEN;
+               break;
+       case 0xec:
+               switch (insn[2] & 0xff) {
+               case 0xe5: /* clgrb */
+               case 0xe6: /* cgrb  */
+               case 0xf6: /* crb   */
+               case 0xf7: /* clrb  */
+               case 0xfc: /* cgib  */
+               case 0xfd: /* cglib */
+               case 0xfe: /* cib   */
+               case 0xff: /* clib  */
+                       fixup = FIXUP_BRANCH_NOT_TAKEN;
+                       break;
+               }
+               break;
+       }
+       return fixup;
+}
+
+int probe_is_insn_relative_long(u16 *insn)
+{
+       /* Check if we have a RIL-b or RIL-c format instruction which
+        * we need to modify in order to avoid instruction emulation. */
+       switch (insn[0] >> 8) {
+       case 0xc0:
+               if ((insn[0] & 0x0f) == 0x00) /* larl */
+                       return true;
+               break;
+       case 0xc4:
+               switch (insn[0] & 0x0f) {
+               case 0x02: /* llhrl  */
+               case 0x04: /* lghrl  */
+               case 0x05: /* lhrl   */
+               case 0x06: /* llghrl */
+               case 0x07: /* sthrl  */
+               case 0x08: /* lgrl   */
+               case 0x0b: /* stgrl  */
+               case 0x0c: /* lgfrl  */
+               case 0x0d: /* lrl    */
+               case 0x0e: /* llgfrl */
+               case 0x0f: /* strl   */
+                       return true;
+               }
+               break;
+       case 0xc6:
+               switch (insn[0] & 0x0f) {
+               case 0x02: /* pfdrl  */
+               case 0x04: /* cghrl  */
+               case 0x05: /* chrl   */
+               case 0x06: /* clghrl */
+               case 0x07: /* clhrl  */
+               case 0x08: /* cgrl   */
+               case 0x0a: /* clgrl  */
+               case 0x0c: /* cgfrl  */
+               case 0x0d: /* crl    */
+               case 0x0e: /* clgfrl */
+               case 0x0f: /* clrl   */
+                       return true;
+               }
+               break;
+       }
+       return false;
+}