Merge branch 'master' into gfs2
[pandora-kernel.git] / arch / ia64 / kernel / kprobes.c
index f9039f8..169ec3a 100644 (file)
@@ -23,7 +23,6 @@
  *              <anil.s.keshavamurthy@intel.com> adapted from i386
  */
 
-#include <linux/config.h>
 #include <linux/kprobes.h>
 #include <linux/ptrace.h>
 #include <linux/string.h>
@@ -137,10 +136,8 @@ static void __kprobes update_kprobe_inst_flag(uint template, uint  slot,
 static int __kprobes unsupported_inst(uint template, uint  slot,
                                      uint major_opcode,
                                      unsigned long kprobe_inst,
-                                     struct kprobe *p)
+                                     unsigned long addr)
 {
-       unsigned long addr = (unsigned long)p->addr;
-
        if (bundle_encoding[template][slot] == I) {
                switch (major_opcode) {
                        case 0x0: //I_UNIT_MISC_OPCODE:
@@ -218,7 +215,7 @@ static void __kprobes prepare_break_inst(uint template, uint  slot,
                                         struct kprobe *p)
 {
        unsigned long break_inst = BREAK_INST;
-       bundle_t *bundle = &p->ainsn.insn.bundle;
+       bundle_t *bundle = &p->opcode.bundle;
 
        /*
         * Copy the original kprobe_inst qualifying predicate(qp)
@@ -424,11 +421,9 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
        unsigned long *kprobe_addr = (unsigned long *)(addr & ~0xFULL);
        unsigned long kprobe_inst=0;
        unsigned int slot = addr & 0xf, template, major_opcode = 0;
-       bundle_t *bundle = &p->ainsn.insn.bundle;
-
-       memcpy(&p->opcode.bundle, kprobe_addr, sizeof(bundle_t));
-       memcpy(&p->ainsn.insn.bundle, kprobe_addr, sizeof(bundle_t));
+       bundle_t *bundle;
 
+       bundle = &((kprobe_opcode_t *)kprobe_addr)->bundle;
        template = bundle->quad0.template;
 
        if(valid_kprobe_addr(template, slot, addr))
@@ -441,9 +436,16 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
        /* Get kprobe_inst and major_opcode from the bundle */
        get_kprobe_inst(bundle, slot, &kprobe_inst, &major_opcode);
 
-       if (unsupported_inst(template, slot, major_opcode, kprobe_inst, p))
+       if (unsupported_inst(template, slot, major_opcode, kprobe_inst, addr))
                        return -EINVAL;
 
+
+       p->ainsn.insn = get_insn_slot();
+       if (!p->ainsn.insn)
+               return -ENOMEM;
+       memcpy(&p->opcode, kprobe_addr, sizeof(kprobe_opcode_t));
+       memcpy(p->ainsn.insn, kprobe_addr, sizeof(kprobe_opcode_t));
+
        prepare_break_inst(template, slot, major_opcode, kprobe_inst, p);
 
        return 0;
@@ -454,8 +456,10 @@ void __kprobes arch_arm_kprobe(struct kprobe *p)
        unsigned long addr = (unsigned long)p->addr;
        unsigned long arm_addr = addr & ~0xFULL;
 
-       memcpy((char *)arm_addr, &p->ainsn.insn.bundle, sizeof(bundle_t));
-       flush_icache_range(arm_addr, arm_addr + sizeof(bundle_t));
+       flush_icache_range((unsigned long)p->ainsn.insn,
+                       (unsigned long)p->ainsn.insn + sizeof(kprobe_opcode_t));
+       memcpy((char *)arm_addr, &p->opcode, sizeof(kprobe_opcode_t));
+       flush_icache_range(arm_addr, arm_addr + sizeof(kprobe_opcode_t));
 }
 
 void __kprobes arch_disarm_kprobe(struct kprobe *p)
@@ -463,11 +467,18 @@ void __kprobes arch_disarm_kprobe(struct kprobe *p)
        unsigned long addr = (unsigned long)p->addr;
        unsigned long arm_addr = addr & ~0xFULL;
 
-       /* p->opcode contains the original unaltered bundle */
-       memcpy((char *) arm_addr, (char *) &p->opcode.bundle, sizeof(bundle_t));
-       flush_icache_range(arm_addr, arm_addr + sizeof(bundle_t));
+       /* p->ainsn.insn contains the original unaltered kprobe_opcode_t */
+       memcpy((char *) arm_addr, (char *) p->ainsn.insn,
+                                        sizeof(kprobe_opcode_t));
+       flush_icache_range(arm_addr, arm_addr + sizeof(kprobe_opcode_t));
 }
 
+void __kprobes arch_remove_kprobe(struct kprobe *p)
+{
+       mutex_lock(&kprobe_mutex);
+       free_insn_slot(p->ainsn.insn);
+       mutex_unlock(&kprobe_mutex);
+}
 /*
  * We are resuming execution after a single step fault, so the pt_regs
  * structure reflects the register state after we executed the instruction
@@ -478,12 +489,12 @@ void __kprobes arch_disarm_kprobe(struct kprobe *p)
  */
 static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
 {
-       unsigned long bundle_addr = ((unsigned long) (&p->opcode.bundle)) & ~0xFULL;
+       unsigned long bundle_addr = (unsigned long) (&p->ainsn.insn->bundle);
        unsigned long resume_addr = (unsigned long)p->addr & ~0xFULL;
        unsigned long template;
        int slot = ((unsigned long)p->addr & 0xf);
 
-       template = p->opcode.bundle.quad0.template;
+       template = p->ainsn.insn->bundle.quad0.template;
 
        if (slot == 1 && bundle_encoding[template][1] == L)
                slot = 2;
@@ -545,7 +556,7 @@ turn_ss_off:
 
 static void __kprobes prepare_ss(struct kprobe *p, struct pt_regs *regs)
 {
-       unsigned long bundle_addr = (unsigned long) &p->opcode.bundle;
+       unsigned long bundle_addr = (unsigned long) &p->ainsn.insn->bundle;
        unsigned long slot = (unsigned long)p->addr & 0xf;
 
        /* single step inline if break instruction */
@@ -760,6 +771,12 @@ static int __kprobes kprobes_fault_handler(struct pt_regs *regs, int trapnr)
                 */
                if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
                        return 1;
+               /*
+                * In case the user-specified fault handler returned
+                * zero, try to fix up.
+                */
+               if (ia64_done_with_exception(regs))
+                       return 1;
 
                /*
                 * Let ia64_do_page_fault() fix it.