]> sourceware.org Git - systemtap-htdocs.git/commitdiff
*** empty log message ***
authorfche <fche>
Mon, 7 Feb 2005 15:54:19 +0000 (15:54 +0000)
committerfche <fche>
Mon, 7 Feb 2005 15:54:19 +0000 (15:54 +0000)
18 files changed:
kprobes/releases/kprobes-2.6.7-rc2.tar.gz [new file with mode: 0644]
kprobes/releases/kprobes-2.6.8-rc1.tar.gz [new file with mode: 0644]
kprobes/releases/kprobes-2.6.9-final.tar.gz [new file with mode: 0644]
kprobes/releases/kprobes-2421-base.tar.gz [new file with mode: 0644]
kprobes/releases/kprobes-2600-test1.tar.gz [new file with mode: 0644]
kprobes/releases/kprobes-2600-test11.tar.gz [new file with mode: 0644]
kprobes/releases/kprobes-2600-test7.tar.gz [new file with mode: 0644]
kprobes/releases/kprobes-2600-test9.tar.gz [new file with mode: 0644]
kprobes/releases/kprobes-261.tar.gz [new file with mode: 0644]
kprobes/releases/kprobes-262.tar.gz [new file with mode: 0644]
kprobes/releases/kprobes-dprobes-2.6.1-full-20040209.patch.bz2 [new file with mode: 0644]
kprobes/releases/kprobes-dprobes-2.6.2-full-20040210.patch.bz2 [new file with mode: 0644]
kprobes/releases/kprobes-dprobes-2.6.5-rc2-full-03312004.patch.bz2 [new file with mode: 0644]
kprobes/releases/kprobes-dprobes-2.6.7-rc2-full.patch.bz2 [new file with mode: 0644]
kprobes/releases/kprobes-dprobes-2.6.8-rc1-full.patch.bz2 [new file with mode: 0644]
kprobes/releases/kprobes-dprobes-2.6.9-final-full.patch.bz2 [new file with mode: 0644]
kprobes/releases/kprobes-full-20031124.patch [new file with mode: 0644]
kprobes/releases/kprobes-full-20031215.patch [new file with mode: 0644]

diff --git a/kprobes/releases/kprobes-2.6.7-rc2.tar.gz b/kprobes/releases/kprobes-2.6.7-rc2.tar.gz
new file mode 100644 (file)
index 0000000..96fcf90
Binary files /dev/null and b/kprobes/releases/kprobes-2.6.7-rc2.tar.gz differ
diff --git a/kprobes/releases/kprobes-2.6.8-rc1.tar.gz b/kprobes/releases/kprobes-2.6.8-rc1.tar.gz
new file mode 100644 (file)
index 0000000..b16933e
Binary files /dev/null and b/kprobes/releases/kprobes-2.6.8-rc1.tar.gz differ
diff --git a/kprobes/releases/kprobes-2.6.9-final.tar.gz b/kprobes/releases/kprobes-2.6.9-final.tar.gz
new file mode 100644 (file)
index 0000000..3e08f78
Binary files /dev/null and b/kprobes/releases/kprobes-2.6.9-final.tar.gz differ
diff --git a/kprobes/releases/kprobes-2421-base.tar.gz b/kprobes/releases/kprobes-2421-base.tar.gz
new file mode 100644 (file)
index 0000000..32459f0
Binary files /dev/null and b/kprobes/releases/kprobes-2421-base.tar.gz differ
diff --git a/kprobes/releases/kprobes-2600-test1.tar.gz b/kprobes/releases/kprobes-2600-test1.tar.gz
new file mode 100644 (file)
index 0000000..e826d74
Binary files /dev/null and b/kprobes/releases/kprobes-2600-test1.tar.gz differ
diff --git a/kprobes/releases/kprobes-2600-test11.tar.gz b/kprobes/releases/kprobes-2600-test11.tar.gz
new file mode 100644 (file)
index 0000000..8e2ea5a
Binary files /dev/null and b/kprobes/releases/kprobes-2600-test11.tar.gz differ
diff --git a/kprobes/releases/kprobes-2600-test7.tar.gz b/kprobes/releases/kprobes-2600-test7.tar.gz
new file mode 100644 (file)
index 0000000..7e32ef0
Binary files /dev/null and b/kprobes/releases/kprobes-2600-test7.tar.gz differ
diff --git a/kprobes/releases/kprobes-2600-test9.tar.gz b/kprobes/releases/kprobes-2600-test9.tar.gz
new file mode 100644 (file)
index 0000000..b4dfd3c
Binary files /dev/null and b/kprobes/releases/kprobes-2600-test9.tar.gz differ
diff --git a/kprobes/releases/kprobes-261.tar.gz b/kprobes/releases/kprobes-261.tar.gz
new file mode 100644 (file)
index 0000000..0d82a66
Binary files /dev/null and b/kprobes/releases/kprobes-261.tar.gz differ
diff --git a/kprobes/releases/kprobes-262.tar.gz b/kprobes/releases/kprobes-262.tar.gz
new file mode 100644 (file)
index 0000000..deaecf3
Binary files /dev/null and b/kprobes/releases/kprobes-262.tar.gz differ
diff --git a/kprobes/releases/kprobes-dprobes-2.6.1-full-20040209.patch.bz2 b/kprobes/releases/kprobes-dprobes-2.6.1-full-20040209.patch.bz2
new file mode 100644 (file)
index 0000000..edf83a7
Binary files /dev/null and b/kprobes/releases/kprobes-dprobes-2.6.1-full-20040209.patch.bz2 differ
diff --git a/kprobes/releases/kprobes-dprobes-2.6.2-full-20040210.patch.bz2 b/kprobes/releases/kprobes-dprobes-2.6.2-full-20040210.patch.bz2
new file mode 100644 (file)
index 0000000..730ca92
Binary files /dev/null and b/kprobes/releases/kprobes-dprobes-2.6.2-full-20040210.patch.bz2 differ
diff --git a/kprobes/releases/kprobes-dprobes-2.6.5-rc2-full-03312004.patch.bz2 b/kprobes/releases/kprobes-dprobes-2.6.5-rc2-full-03312004.patch.bz2
new file mode 100644 (file)
index 0000000..1c2870c
Binary files /dev/null and b/kprobes/releases/kprobes-dprobes-2.6.5-rc2-full-03312004.patch.bz2 differ
diff --git a/kprobes/releases/kprobes-dprobes-2.6.7-rc2-full.patch.bz2 b/kprobes/releases/kprobes-dprobes-2.6.7-rc2-full.patch.bz2
new file mode 100644 (file)
index 0000000..493b745
Binary files /dev/null and b/kprobes/releases/kprobes-dprobes-2.6.7-rc2-full.patch.bz2 differ
diff --git a/kprobes/releases/kprobes-dprobes-2.6.8-rc1-full.patch.bz2 b/kprobes/releases/kprobes-dprobes-2.6.8-rc1-full.patch.bz2
new file mode 100644 (file)
index 0000000..ef6f776
Binary files /dev/null and b/kprobes/releases/kprobes-dprobes-2.6.8-rc1-full.patch.bz2 differ
diff --git a/kprobes/releases/kprobes-dprobes-2.6.9-final-full.patch.bz2 b/kprobes/releases/kprobes-dprobes-2.6.9-final-full.patch.bz2
new file mode 100644 (file)
index 0000000..85210c7
Binary files /dev/null and b/kprobes/releases/kprobes-dprobes-2.6.9-final-full.patch.bz2 differ
diff --git a/kprobes/releases/kprobes-full-20031124.patch b/kprobes/releases/kprobes-full-20031124.patch
new file mode 100644 (file)
index 0000000..29c0682
--- /dev/null
@@ -0,0 +1,8197 @@
+diff -urNp linux-2.6.0-test9/arch/i386/Kconfig linux-2.6.0-test9+kp/arch/i386/Kconfig
+--- linux-2.6.0-test9/arch/i386/Kconfig        2003-10-26 00:13:01.000000000 +0530
++++ linux-2.6.0-test9+kp/arch/i386/Kconfig     2003-11-18 07:29:47.000000000 +0530
+@@ -1133,6 +1133,37 @@ config DEBUG_KERNEL
+         Say Y here if you are developing drivers or trying to debug and
+         identify kernel problems.
++config KPROBES
++      bool "Kprobes"
++      depends on DEBUG_KERNEL
++      help
++        Kprobes allows you to trap at almost any kernel address, using
++        register_kprobe(), and providing a callback function.  This is useful
++        for kernel debugging, non-intrusive instrumentation and testing.  If
++        in doubt, say "N".
++
++config DEBUGREG
++      bool "Global Debug Registers"
++      depends on DEBUG_KERNEL
++      help
++        Global debug register settings will be honoured if this is turned on.
++        If in doubt, say "N".
++
++config KWATCH
++      bool "Kwatch points"
++      depends on DEBUG_KERNEL && DEBUGREG
++      help
++        This enables kernel-space watchpoints using processor's debug
++        registers. If in doubt, say "N".
++
++config DPROBES
++      tristate "Dynamic Probes"
++      depends on DEBUG_KERNEL && KPROBES
++      help
++        DProbes provides a higher level interface to kprobes. DProbes
++        enables you to write probe programs in a RPN language. If
++        in doubt, say "N".
++
+ config DEBUG_STACKOVERFLOW
+       bool "Check for stack overflows"
+       depends on DEBUG_KERNEL
+diff -urNp linux-2.6.0-test9/arch/i386/kernel/debugreg.c linux-2.6.0-test9+kp/arch/i386/kernel/debugreg.c
+--- linux-2.6.0-test9/arch/i386/kernel/debugreg.c      1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.0-test9+kp/arch/i386/kernel/debugreg.c   2003-11-18 07:29:47.000000000 +0530
+@@ -0,0 +1,178 @@
++/*
++ * This provides a debug register allocation mechanism, to be 
++ * used by all debuggers, which need debug registers.
++ *
++ * Author: vamsi_krishna@in.ibm.com
++ *       bharata@in.ibm.com
++ */
++#include <linux/kernel.h>
++#include <linux/spinlock.h>
++#include <linux/module.h>
++#include <asm/system.h>
++#include <asm/debugreg.h>
++
++struct debugreg dr_list[DR_MAX];
++unsigned long dr7_global_mask = 0;
++static spinlock_t dr_lock = SPIN_LOCK_UNLOCKED;
++
++static inline void set_dr7_global_mask(int regnum) 
++{
++      switch (regnum) {
++              case 0: dr7_global_mask |= DR7_DR0_BITS; break;
++              case 1: dr7_global_mask |= DR7_DR1_BITS; break;
++              case 2: dr7_global_mask |= DR7_DR2_BITS; break;
++              case 3: dr7_global_mask |= DR7_DR3_BITS; break;
++      }
++      return;
++}
++
++static inline void clear_dr7_global_mask(int regnum) 
++{
++      switch (regnum) {
++              case 0: dr7_global_mask &= ~DR7_DR0_BITS; break;
++              case 1: dr7_global_mask &= ~DR7_DR1_BITS; break;
++              case 2: dr7_global_mask &= ~DR7_DR2_BITS; break;
++              case 3: dr7_global_mask &= ~DR7_DR3_BITS; break;
++      }
++      return;
++}
++
++static int get_dr(int regnum, int flag)
++{
++      if ((flag == DR_ALLOC_GLOBAL) && (dr_list[regnum].flag == DR_UNUSED)) {
++              dr_list[regnum].flag = DR_GLOBAL;
++              set_dr7_global_mask(regnum);
++              return regnum;
++      }
++      else if ((dr_list[regnum].flag == DR_UNUSED) || (dr_list[regnum].flag == DR_LOCAL)) {
++              dr_list[regnum].use_count++;
++              dr_list[regnum].flag = DR_LOCAL;
++              return regnum;
++      }
++      return -1;
++}
++      
++static int get_any_dr(int flag)
++{
++      int i;
++      if (flag == DR_ALLOC_LOCAL) {
++              for (i = 0; i < DR_MAX; i++) {
++                      if (dr_list[i].flag == DR_LOCAL) {
++                              dr_list[i].use_count++;
++                              return i;
++                      } else if (dr_list[i].flag == DR_UNUSED) {
++                              dr_list[i].flag = DR_LOCAL;
++                              dr_list[i].use_count = 1;
++                              return i;
++                      }
++              }
++      } else {
++              for (i = DR_MAX-1; i >= 0; i--) {
++                      if (dr_list[i].flag == DR_UNUSED) {
++                              dr_list[i].flag = DR_GLOBAL;
++                              set_dr7_global_mask(i);
++                              return i;
++                      }
++              }
++      }
++      return -1;
++}
++
++static inline void dr_free_local(int regnum)
++{
++      if (! (--dr_list[regnum].use_count)) 
++              dr_list[regnum].flag = DR_UNUSED;
++      return;
++}
++
++static inline void dr_free_global(int regnum) 
++{
++      dr_list[regnum].flag = DR_UNUSED;
++      dr_list[regnum].use_count = 0;
++      clear_dr7_global_mask(regnum);
++      return;
++}
++              
++int dr_alloc(int regnum, int flag)
++{
++      int ret;
++      
++      spin_lock(&dr_lock);
++      if (regnum == DR_ANY) 
++              ret = get_any_dr(flag);
++      else if (regnum >= DR_MAX)
++              ret = -1;
++      else
++              ret = get_dr(regnum, flag);
++      spin_unlock(&dr_lock);
++      return ret;
++}
++
++int dr_free(int regnum)
++{
++      spin_lock(&dr_lock);
++      if (regnum >= DR_MAX || dr_list[regnum].flag == DR_UNUSED) {
++              spin_unlock(&dr_lock);
++              return -1;
++      }
++      if (dr_list[regnum].flag == DR_LOCAL)
++              dr_free_local(regnum);
++      else 
++              dr_free_global(regnum);
++      spin_unlock(&dr_lock);
++      return 0;
++}
++
++void dr_inc_use_count(unsigned long mask)
++{
++      int i;
++      
++      spin_lock(&dr_lock);
++      for (i =0; i < DR_MAX; i++) {
++              if (DR_IS_LOCAL(mask, i))
++                      dr_list[i].use_count++;
++      }
++      spin_unlock(&dr_lock);
++}
++
++void dr_dec_use_count(unsigned long mask)
++{
++      int i;
++      
++      spin_lock(&dr_lock);
++      for (i =0; i < DR_MAX; i++) {
++              if (DR_IS_LOCAL(mask, i))
++                      dr_free_local(i);
++      }
++      spin_unlock(&dr_lock);
++}
++
++/*
++ * This routine decides if the ptrace request is for enabling or disabling 
++ * a debug reg, and accordingly calls dr_alloc() or dr_free().
++ *
++ * gdb uses ptrace to write to debug registers. It assumes that writing to
++ * debug register always succeds and it doesn't check the return value of 
++ * ptrace. Now with this new global debug register allocation/freeing,
++ * ptrace request for a local debug register can fail, if the required debug
++ * register is already globally allocated. Since gdb fails to notice this 
++ * failure, it sometimes tries to free a debug register, which is not 
++ * allocated for it.
++ */
++int enable_debugreg(unsigned long old_dr7, unsigned long new_dr7)
++{
++      int i, dr_shift = 1UL;
++      for (i = 0; i < DR_MAX; i++, dr_shift <<= 2) {
++              if ((old_dr7 ^ new_dr7) & dr_shift) {
++                      if (new_dr7 & dr_shift)
++                              dr_alloc(i, DR_ALLOC_LOCAL);
++                      else
++                              dr_free(i);
++                      return 0;
++              }
++      }
++      return -1;
++}
++
++EXPORT_SYMBOL(dr_alloc);
++EXPORT_SYMBOL(dr_free);
+diff -urNp linux-2.6.0-test9/arch/i386/kernel/entry.S linux-2.6.0-test9+kp/arch/i386/kernel/entry.S
+--- linux-2.6.0-test9/arch/i386/kernel/entry.S 2003-10-26 00:13:14.000000000 +0530
++++ linux-2.6.0-test9+kp/arch/i386/kernel/entry.S      2003-11-18 07:29:47.000000000 +0530
+@@ -493,10 +493,17 @@ ENTRY(debug)
+       jne debug_stack_correct
+       FIX_STACK(12, debug_stack_correct, debug_esp_fix_insn)
+ debug_stack_correct:
+-      pushl $0
+-      pushl $do_debug
+-      jmp error_code
+-
++      pushl $-1                       # mark this as an int
++      SAVE_ALL
++      movl %esp,%edx
++      pushl $0
++      pushl %edx
++      call do_debug
++      addl $8,%esp
++      testl %eax,%eax 
++      jnz restore_all
++      jmp ret_from_exception
++  
+ /*
+  * NMI is doubly nasty. It can happen _while_ we're handling
+  * a debug fault, and the debug fault hasn't yet been able to
+@@ -544,9 +551,16 @@ nmi_debug_stack_fixup:
+       jmp nmi_stack_correct
+ ENTRY(int3)
++      pushl $-1                       # mark this as an int
++      SAVE_ALL
++      movl %esp,%edx
+       pushl $0
+-      pushl $do_int3
+-      jmp error_code
++      pushl %edx
++      call do_int3
++      addl $8,%esp
++      testl %eax,%eax 
++      jnz restore_all
++      jmp ret_from_exception
+ ENTRY(overflow)
+       pushl $0
+diff -urNp linux-2.6.0-test9/arch/i386/kernel/kprobes.c linux-2.6.0-test9+kp/arch/i386/kernel/kprobes.c
+--- linux-2.6.0-test9/arch/i386/kernel/kprobes.c       1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.0-test9+kp/arch/i386/kernel/kprobes.c    2003-11-18 07:30:12.000000000 +0530
+@@ -0,0 +1,249 @@
++/* 
++ * Support for kernel probes.
++ * (C) 2002 Vamsi Krishna S <vamsi_krishna@in.ibm.com>.
++ */
++
++#include <linux/config.h>
++#include <linux/kprobes.h>
++#include <linux/ptrace.h>
++#include <linux/spinlock.h>
++#include <linux/preempt.h>
++
++/* kprobe_status settings */
++#define KPROBE_HIT_ACTIVE     0x00000001
++#define KPROBE_HIT_SS         0x00000002
++
++static struct kprobe *current_kprobe;
++static unsigned long kprobe_status, kprobe_old_eflags, kprobe_saved_eflags;
++
++void kprobes_asm_code_start(void){}
++/*
++ * returns non-zero if opcode modifies the interrupt flag.
++ */
++static inline int is_IF_modifier(kprobe_opcode_t opcode)
++{
++      switch(opcode) {
++              case 0xfa:      /* cli */
++              case 0xfb:      /* sti */
++              case 0xcf:      /* iret/iretd */
++              case 0x9d:      /* popf/popfd */
++                      return 1;
++      }
++      return 0;
++}
++
++void arch_prepare_kprobe(struct kprobe *p)
++{
++      memcpy(p->insn, p->addr, MAX_INSN_SIZE);
++}
++
++static inline void disarm_kprobe(struct kprobe *p, struct pt_regs *regs)
++{
++      set_opcode(p, p->opcode);
++      regs->eip = (unsigned long)p->addr;
++}
++
++static void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
++{
++      regs->eflags |= TF_MASK;
++      regs->eflags &= ~IF_MASK;
++
++      if (!(p->user)) {
++              regs->eip = (unsigned long)&p->insn;
++      } else {
++              set_opcode(p, p->opcode);
++              regs->eip = (unsigned long)p->addr;
++              }
++}
++
++/*
++ * Interrupts are disabled on entry as trap3 is an interrupt gate and they
++ * remain disabled thorough out this function.
++ */
++int kprobe_handler(struct pt_regs *regs)
++{
++      struct kprobe *p;
++      int ret = 0;
++      kprobe_opcode_t *addr = (kprobe_opcode_t *)(regs->eip - sizeof(kprobe_opcode_t));
++
++      /* We're in an interrupt, but this is clear and BUG()-safe. */
++      preempt_disable();
++
++      /* Check we're not actually recursing */
++      if (kprobe_running()) {
++              /* We *are* holding lock here, so this is safe.
++                   Disarm the probe we just hit, and ignore it. */
++              p = get_kprobe(addr);
++              if (p) {
++                      disarm_kprobe(p, regs);
++                      put_kprobe(p);
++                      ret = 1;
++              }
++              /* If it's not ours, can't be delete race, (we hold lock). */
++              goto no_kprobe;
++      }
++
++      lock_kprobes();
++      p = get_kprobe(addr); 
++      if (!p) {
++              unlock_kprobes();
++              /* Unregistered (on another cpu) after this hit?  Ignore */
++              if (*addr != BREAKPOINT_INSTRUCTION)
++                      ret = 1;
++              /* Not one of ours: let kernel handle it */
++              goto no_kprobe;
++      }
++      /* If p->opcode == BREAKPOINT_INSTRUCTION, means we haven't yet inserted
++       * breakpoint corresponding to this probe.No need to handle this probe.
++       */ 
++      if (p->user && p->opcode == BREAKPOINT_INSTRUCTION) {
++              unlock_kprobes();
++              ret = 1;
++              goto no_kprobe;
++      }
++              
++      kprobe_status = KPROBE_HIT_ACTIVE;
++      current_kprobe = p;
++      kprobe_saved_eflags = kprobe_old_eflags 
++              = (regs->eflags & (TF_MASK|IF_MASK));
++      if (is_IF_modifier(p->opcode))
++              kprobe_saved_eflags &= ~IF_MASK;
++
++      /* If the pre_handler returns 1, means probes are marked for emergency
++       *  removal. Restore back the original opcode.
++       */
++      if (p->pre_handler(p, regs)) {
++              if (!p->user)
++                      disarm_kprobe(p, regs);
++              else {
++                      set_opcode(p, p->opcode);
++                      regs->eip = (unsigned long)p->addr;
++              }
++              ret = 1;
++              unlock_kprobes();
++              goto no_kprobe;
++      }
++
++      prepare_singlestep(p, regs);
++      //disarm_kprobe(p, regs);
++      kprobe_status = KPROBE_HIT_SS;
++      return 1;
++
++      if (p->post_handler)
++              p->post_handler(p, regs, 0);
++      unlock_kprobes();
++      preempt_enable_no_resched();
++      return 1;
++
++no_kprobe:
++      preempt_enable_no_resched();
++      return ret;
++}
++
++static void resume_execution(struct kprobe *p, struct pt_regs *regs)
++{
++      unsigned long *tos = &regs->esp;
++      unsigned long next_eip = 0;
++      unsigned long copy_eip = (unsigned long)&p->insn;
++      unsigned long orig_eip = (unsigned long)p->addr;
++
++      /*
++       * We singlestepped with interrupts disabled. So, the result on
++       * the stack would be incorrect for "pushfl" instruction.
++       * Note that regs->esp is actually the top of the stack when the
++       * trap occurs in kernel space.
++       */
++      switch(p->insn[0]) {
++              case 0x9c:      /* pushfl */
++                      if (regs->eip < PAGE_OFFSET)
++                              tos = (unsigned long *)regs->esp;
++                      *tos &= ~(TF_MASK | IF_MASK);
++                      *tos |= kprobe_old_eflags;
++                      break;
++              case 0xe8:      /* call relative */
++                      *tos = orig_eip + (*tos - copy_eip);
++                      break;
++              case 0xff:      
++                      if ((p->insn[1] & 0x30) == 0x10) { /* call absolute, indirect */
++                              next_eip = regs->eip;
++                              *tos = orig_eip + (*tos - copy_eip);
++                      } else if (((p->insn[1] & 0x31) == 0x20) || /* jmp near, absolute indirect */
++                                 ((p->insn[1] & 0x31) == 0x21)) { /* jmp far, absolute indirect */
++                              next_eip = regs->eip;
++                      }
++                      break;
++              case 0xea:      /* jmp absolute */
++                      next_eip = regs->eip;
++                      break;
++              default:
++                      break;
++      }
++      
++      regs->eflags &= ~TF_MASK;
++      if (next_eip) {
++              regs->eip = next_eip;
++      } else {
++              regs->eip = orig_eip + (regs->eip - copy_eip);
++      }
++}
++
++static void resume_execution_user(struct kprobe *p, struct pt_regs *regs)
++{
++      regs->eflags &= ~TF_MASK;
++      set_opcode(p, BREAKPOINT_INSTRUCTION);
++}
++
++/*
++ * Interrupts are disabled on entry as trap1 is an interrupt gate and they
++ * remain disabled thorough out this function.  And we hold kprobe lock.
++ */
++int post_kprobe_handler(struct pt_regs *regs)
++{
++      if (!kprobe_running())
++              return 0;
++
++      if (current_kprobe->post_handler)
++              current_kprobe->post_handler(current_kprobe, regs, 0);
++
++      if (!(current_kprobe->user))
++              resume_execution(current_kprobe, regs);
++      else
++              resume_execution_user(current_kprobe, regs);
++      regs->eflags |= kprobe_saved_eflags;
++
++      put_kprobe(current_kprobe);
++      unlock_kprobes();
++      preempt_enable_no_resched();
++
++        /*
++       * if somebody else is singlestepping across a probe point, eflags
++       * will have TF set, in which case, continue the remaining processing
++       * of do_debug, as if this is not a probe hit.
++       */
++      if (regs->eflags & TF_MASK)
++              return 0;
++
++      return 1;
++}
++
++/* Interrupts disabled, kprobe_lock held. */
++int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
++{
++      if (current_kprobe->fault_handler
++          && current_kprobe->fault_handler(current_kprobe, regs, trapnr))
++              return 1;
++
++      if (kprobe_status & KPROBE_HIT_SS) {
++              if (!(current_kprobe->user))
++                      resume_execution(current_kprobe, regs);
++              else
++                      resume_execution_user(current_kprobe, regs);
++
++              regs->eflags |= kprobe_old_eflags;
++              put_kprobe(current_kprobe);
++              unlock_kprobes();
++              preempt_enable_no_resched();
++      }
++      return 0;
++}
++void kprobes_asm_code_end(void) {}
+diff -urNp linux-2.6.0-test9/arch/i386/kernel/kwatch.c linux-2.6.0-test9+kp/arch/i386/kernel/kwatch.c
+--- linux-2.6.0-test9/arch/i386/kernel/kwatch.c        1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.0-test9+kp/arch/i386/kernel/kwatch.c     2003-11-18 07:30:12.000000000 +0530
+@@ -0,0 +1,142 @@
++/* 
++ * Support for kernel watchpoints.
++ * (C) 2002 Vamsi Krishna S <vamsi_krishna@in.ibm.com>.
++ */
++#include <linux/config.h>
++#include <linux/kprobes.h>
++#include <linux/ptrace.h>
++#include <linux/spinlock.h>
++#include <linux/module.h>
++#include <asm/kwatch.h>
++#include <asm/debugreg.h>
++#include <asm/bitops.h>
++
++static struct kwatch kwatch_list[DR_MAX];
++static spinlock_t kwatch_lock = SPIN_LOCK_UNLOCKED;
++static unsigned long kwatch_in_progress; /* currently being handled */
++
++struct dr_info {
++      int debugreg;
++      unsigned long addr;
++      int type;
++};
++
++void kwatch_asm_start(void) {}
++static inline void write_smp_dr(void *info)
++{
++      struct dr_info *dr = (struct dr_info *)info;
++
++      if (cpu_has_de && dr->type == DR_TYPE_IO)
++              set_in_cr4(X86_CR4_DE);
++      write_dr(dr->debugreg, dr->addr);
++}
++
++/* Update the debug register on all CPUs */
++static void sync_dr(int debugreg, unsigned long addr, int type)
++{
++      struct dr_info dr;
++      dr.debugreg = debugreg;
++      dr.addr = addr;
++      dr.type = type;
++      smp_call_function(write_smp_dr, &dr, 0, 0);
++}
++
++/*
++ * Interrupts are disabled on entry as trap1 is an interrupt gate and they
++ * remain disabled thorough out this function.
++ */
++int kwatch_handler(unsigned long condition, struct pt_regs *regs)
++{
++      int debugreg = dr_trap(condition);
++      unsigned long addr = dr_trap_addr(condition);
++      int retval = 0;
++
++      if (!(condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3))) {
++              return 0;
++      }
++      
++      /* We're in an interrupt, but this is clear and BUG()-safe. */
++      preempt_disable();
++
++      /* If we are recursing, we already hold the lock. */
++      if (kwatch_in_progress) {
++              goto recursed;
++      }
++      set_bit(debugreg, &kwatch_in_progress);
++      
++      spin_lock(&kwatch_lock);
++      if (kwatch_list[debugreg].addr != addr)
++              goto out;
++
++      if (kwatch_list[debugreg].handler) {
++              kwatch_list[debugreg].handler(&kwatch_list[debugreg], regs, debugreg);
++      }
++      
++      if (kwatch_list[debugreg].type == DR_TYPE_EXECUTE)
++              regs->eflags |= RF_MASK;
++out:
++      clear_bit(debugreg, &kwatch_in_progress);
++      spin_unlock(&kwatch_lock);
++      preempt_enable_no_resched();
++      return retval;
++
++recursed:
++      if (kwatch_list[debugreg].type == DR_TYPE_EXECUTE)
++              regs->eflags |= RF_MASK;
++      preempt_enable_no_resched();
++      return 1;
++}
++
++int register_kwatch(unsigned long addr, u8 length, u8 type, 
++              kwatch_handler_t handler)
++{
++      int debugreg;
++      unsigned long dr7, flags;
++
++      debugreg = dr_alloc(DR_ANY, DR_ALLOC_GLOBAL);
++      if (debugreg < 0) {
++              return -1;
++      }
++
++      spin_lock_irqsave(&kwatch_lock, flags);
++      kwatch_list[debugreg].addr = addr;
++      kwatch_list[debugreg].length = length;
++      kwatch_list[debugreg].type = type;
++      kwatch_list[debugreg].handler = handler;
++      spin_unlock_irqrestore(&kwatch_lock, flags);
++
++      write_dr(debugreg, (unsigned long)addr);
++      sync_dr(debugreg, (unsigned long)addr, type);
++      if (cpu_has_de && type == DR_TYPE_IO)
++              set_in_cr4(X86_CR4_DE);
++      
++      dr7 = read_dr(7);
++      SET_DR7(dr7, debugreg, type, length);
++      write_dr(7, dr7);
++      sync_dr(7, dr7, 0);
++      return debugreg;
++}
++
++void unregister_kwatch(int debugreg)
++{
++      unsigned long flags;
++      unsigned long dr7 = read_dr(7);
++
++      RESET_DR7(dr7, debugreg);
++      write_dr(7, dr7);
++      sync_dr(7, dr7, 0);
++      dr_free(debugreg);
++
++      spin_lock_irqsave(&kwatch_lock, flags);
++      kwatch_list[debugreg].addr = 0;
++      kwatch_list[debugreg].handler = NULL;
++      spin_unlock_irqrestore(&kwatch_lock, flags);
++}
++
++void kwatch_asm_end(void) {}
++
++EXPORT_SYMBOL_GPL(register_kwatch);
++EXPORT_SYMBOL_GPL(unregister_kwatch);
++EXPORT_SYMBOL_GPL(kwatch_asm_start);
++EXPORT_SYMBOL_GPL(kwatch_asm_end);
++
+diff -urNp linux-2.6.0-test9/arch/i386/kernel/Makefile linux-2.6.0-test9+kp/arch/i386/kernel/Makefile
+--- linux-2.6.0-test9/arch/i386/kernel/Makefile        2003-10-26 00:13:03.000000000 +0530
++++ linux-2.6.0-test9+kp/arch/i386/kernel/Makefile     2003-11-18 07:29:47.000000000 +0530
+@@ -26,10 +26,13 @@ obj-$(CONFIG_X86_IO_APIC)  += io_apic.o
+ obj-$(CONFIG_X86_NUMAQ)               += numaq.o
+ obj-$(CONFIG_X86_SUMMIT)      += summit.o
+ obj-$(CONFIG_EDD)                     += edd.o
++obj-$(CONFIG_KPROBES)         += kprobes.o
+ obj-$(CONFIG_MODULES)         += module.o
+ obj-y                         += sysenter.o vsyscall.o
+ obj-$(CONFIG_ACPI_SRAT)       += srat.o
+ obj-$(CONFIG_HPET_TIMER)      += time_hpet.o
++obj-$(CONFIG_DEBUGREG)                += debugreg.o
++obj-$(CONFIG_KWATCH)          += kwatch.o
+ EXTRA_AFLAGS   := -traditional
+diff -urNp linux-2.6.0-test9/arch/i386/kernel/process.c linux-2.6.0-test9+kp/arch/i386/kernel/process.c
+--- linux-2.6.0-test9/arch/i386/kernel/process.c       2003-10-26 00:12:40.000000000 +0530
++++ linux-2.6.0-test9+kp/arch/i386/kernel/process.c    2003-11-18 07:29:47.000000000 +0530
+@@ -50,6 +50,7 @@
+ #ifdef CONFIG_MATH_EMULATION
+ #include <asm/math_emu.h>
+ #endif
++#include <asm/debugreg.h>
+ #include <linux/irq.h>
+ #include <linux/err.h>
+@@ -295,12 +296,16 @@ void exit_thread(void)
+               kfree(tsk->thread.io_bitmap_ptr);
+               tsk->thread.io_bitmap_ptr = NULL;
+       }
++      if (tsk->thread.debugreg[7])
++              dr_dec_use_count(tsk->thread.debugreg[7]);
+ }
+ void flush_thread(void)
+ {
+       struct task_struct *tsk = current;
++      if (tsk->thread.debugreg[7])
++              dr_dec_use_count(tsk->thread.debugreg[7]); 
+       memset(tsk->thread.debugreg, 0, sizeof(unsigned long)*8);
+       memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array));        
+       /*
+@@ -390,6 +395,9 @@ int copy_thread(int nr, unsigned long cl
+               desc->b = LDT_entry_b(&info);
+       }
++      if (tsk->thread.debugreg[7])
++              dr_inc_use_count(tsk->thread.debugreg[7]);
++
+       err = 0;
+  out:
+       if (err && p->thread.io_bitmap_ptr)
+@@ -532,6 +540,24 @@ struct task_struct * __switch_to(struct 
+       /*
+        * Now maybe reload the debug registers
+        */
++#ifdef CONFIG_DEBUGREG
++{
++      /*
++       * Don't reload global debug registers. Don't touch the global debug
++       * register settings in dr7.
++       */
++      unsigned long next_dr7 = next->debugreg[7];
++      if (unlikely(next_dr7)) {
++              if (DR7_L0(next_dr7)) loaddebug(next, 0);
++              if (DR7_L1(next_dr7)) loaddebug(next, 1);
++              if (DR7_L2(next_dr7)) loaddebug(next, 2);
++              if (DR7_L3(next_dr7)) loaddebug(next, 3);
++              /* no 4 and 5 */
++              loaddebug(next, 6);
++              load_process_dr7(next_dr7);
++      }
++}
++#else
+       if (unlikely(next->debugreg[7])) {
+               loaddebug(next, 0);
+               loaddebug(next, 1);
+@@ -541,7 +567,7 @@ struct task_struct * __switch_to(struct 
+               loaddebug(next, 6);
+               loaddebug(next, 7);
+       }
+-
++#endif
+       if (unlikely(prev->io_bitmap_ptr || next->io_bitmap_ptr)) {
+               if (next->io_bitmap_ptr) {
+                       /*
+diff -urNp linux-2.6.0-test9/arch/i386/kernel/ptrace.c linux-2.6.0-test9+kp/arch/i386/kernel/ptrace.c
+--- linux-2.6.0-test9/arch/i386/kernel/ptrace.c        2003-10-26 00:13:15.000000000 +0530
++++ linux-2.6.0-test9+kp/arch/i386/kernel/ptrace.c     2003-11-18 07:29:47.000000000 +0530
+@@ -350,6 +350,11 @@ asmlinkage int sys_ptrace(long request, 
+                         addr -= (long) &dummy->u_debugreg;
+                         addr = addr >> 2;
++
++                        if (addr == 7 && (enable_debugreg(child->thread.debugreg[addr], data)) < 0) {
++                                ret = -EBUSY;
++                                break;
++                        }
+                         child->thread.debugreg[addr] = data;
+                         ret = 0;
+                 }
+diff -urNp linux-2.6.0-test9/arch/i386/kernel/signal.c linux-2.6.0-test9+kp/arch/i386/kernel/signal.c
+--- linux-2.6.0-test9/arch/i386/kernel/signal.c        2003-10-26 00:13:33.000000000 +0530
++++ linux-2.6.0-test9+kp/arch/i386/kernel/signal.c     2003-11-18 07:29:47.000000000 +0530
+@@ -23,6 +23,7 @@
+ #include <asm/ucontext.h>
+ #include <asm/uaccess.h>
+ #include <asm/i387.h>
++#include <asm/debugreg.h>
+ #include "sigframe.h"
+ #define DEBUG_SIG 0
+@@ -578,7 +579,7 @@ int do_signal(struct pt_regs *regs, sigs
+                * have been cleared if the watchpoint triggered
+                * inside the kernel.
+                */
+-              __asm__("movl %0,%%db7" : : "r" (current->thread.debugreg[7]));
++              load_process_dr7(current->thread.debugreg[7]);
+               /* Whee!  Actually deliver the signal.  */
+               handle_signal(signr, &info, oldset, regs);
+diff -urNp linux-2.6.0-test9/arch/i386/kernel/traps.c linux-2.6.0-test9+kp/arch/i386/kernel/traps.c
+--- linux-2.6.0-test9/arch/i386/kernel/traps.c 2003-10-26 00:13:02.000000000 +0530
++++ linux-2.6.0-test9+kp/arch/i386/kernel/traps.c      2003-11-18 07:29:47.000000000 +0530
+@@ -25,6 +25,7 @@
+ #include <linux/highmem.h>
+ #include <linux/kallsyms.h>
+ #include <linux/ptrace.h>
++#include <linux/kprobes.h>
+ #ifdef CONFIG_EISA
+ #include <linux/ioport.h>
+@@ -41,6 +42,7 @@
+ #include <asm/io.h>
+ #include <asm/atomic.h>
+ #include <asm/debugreg.h>
++#include <asm/kwatch.h>
+ #include <asm/desc.h>
+ #include <asm/i387.h>
+ #include <asm/nmi.h>
+@@ -362,7 +364,6 @@ asmlinkage void do_##name(struct pt_regs
+ }
+ DO_VM86_ERROR_INFO( 0, SIGFPE,  "divide error", divide_error, FPE_INTDIV, regs->eip)
+-DO_VM86_ERROR( 3, SIGTRAP, "int3", int3)
+ DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow)
+ DO_VM86_ERROR( 5, SIGSEGV, "bounds", bounds)
+ DO_ERROR_INFO( 6, SIGILL,  "invalid operand", invalid_op, ILL_ILLOPN, regs->eip)
+@@ -379,6 +380,9 @@ asmlinkage void do_general_protection(st
+  
+       if (regs->eflags & VM_MASK)
+               goto gp_in_vm86;
++      
++      if (kprobe_running() && kprobe_fault_handler(regs, 13))
++              return;
+       if (!(regs->xcs & 3))
+               goto gp_in_kernel;
+@@ -500,6 +504,17 @@ void unset_nmi_callback(void)
+       nmi_callback = dummy_nmi_callback;
+ }
++asmlinkage int do_int3(struct pt_regs *regs, long error_code)
++{
++      if (kprobe_handler(regs))
++              return 1;
++      /* This is an interrupt gate, because kprobes wants interrupts
++           disabled.  Normal trap handlers don't. */
++      restore_interrupts(regs);
++      do_trap(3, SIGTRAP, "int3", 1, regs, error_code, NULL);
++      return 0;
++}
++
+ /*
+  * Our handling of the processor debug registers is non-trivial.
+  * We do not clear them on entry and exit from the kernel. Therefore
+@@ -522,14 +537,20 @@ void unset_nmi_callback(void)
+  * find every occurrence of the TF bit that could be saved away even
+  * by user code)
+  */
+-asmlinkage void do_debug(struct pt_regs * regs, long error_code)
++asmlinkage int do_debug(struct pt_regs * regs, long error_code)
+ {
+       unsigned int condition;
+       struct task_struct *tsk = current;
+       siginfo_t info;
++      if (post_kprobe_handler(regs))
++              return 1;
++
+       __asm__ __volatile__("movl %%db6,%0" : "=r" (condition));
++      if (kwatch_handler(condition, regs))
++              return 1;
++
+       /* It's safe to allow irq's after DR6 has been saved */
+       if (regs->eflags & X86_EFLAGS_IF)
+               local_irq_enable();
+@@ -581,20 +602,18 @@ asmlinkage void do_debug(struct pt_regs 
+        * the signal is delivered.
+        */
+ clear_dr7:
+-      __asm__("movl %0,%%db7"
+-              : /* no output */
+-              : "r" (0));
+-      return;
++      load_process_dr7(0);
++      return 0;
+ debug_vm86:
+       handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
+-      return;
++      return 0;
+ clear_TF_reenable:
+       set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
+ clear_TF:
+       regs->eflags &= ~TF_MASK;
+-      return;
++      return 0;
+ }
+ /*
+@@ -760,6 +779,8 @@ asmlinkage void math_state_restore(struc
+       struct thread_info *thread = current_thread_info();
+       struct task_struct *tsk = thread->task;
++      if (kprobe_running() && kprobe_fault_handler(&regs, 7))
++              return;
+       clts();         /* Allow maths ops (or we recurse) */
+       if (!tsk->used_math)
+               init_fpu(tsk);
+@@ -854,7 +875,7 @@ void __init trap_init(void)
+       set_trap_gate(0,&divide_error);
+       set_intr_gate(1,&debug);
+       set_intr_gate(2,&nmi);
+-      set_system_gate(3,&int3);       /* int3-5 can be called from all */
++      _set_gate(idt_table+3,14,3,&int3,__KERNEL_CS); /* int3-5 can be called from all */
+       set_system_gate(4,&overflow);
+       set_system_gate(5,&bounds);
+       set_trap_gate(6,&invalid_op);
+diff -urNp linux-2.6.0-test9/arch/i386/mm/fault.c linux-2.6.0-test9+kp/arch/i386/mm/fault.c
+--- linux-2.6.0-test9/arch/i386/mm/fault.c     2003-10-26 00:12:43.000000000 +0530
++++ linux-2.6.0-test9+kp/arch/i386/mm/fault.c  2003-11-18 07:29:47.000000000 +0530
+@@ -21,6 +21,7 @@
+ #include <linux/vt_kern.h>            /* For unblank_screen() */
+ #include <linux/highmem.h>
+ #include <linux/module.h>
++#include <linux/kprobes.h>
+ #include <asm/system.h>
+ #include <asm/uaccess.h>
+@@ -222,6 +223,9 @@ asmlinkage void do_page_fault(struct pt_
+       /* get the address */
+       __asm__("movl %%cr2,%0":"=r" (address));
++      if (kprobe_running() && kprobe_fault_handler(regs, 14))
++              return;
++
+       /* It's safe to allow irq's after cr2 has been saved */
+       if (regs->eflags & (X86_EFLAGS_IF|VM_MASK))
+               local_irq_enable();
+diff -urNp linux-2.6.0-test9/drivers/dprobes/dprobes.c linux-2.6.0-test9+kp/drivers/dprobes/dprobes.c
+--- linux-2.6.0-test9/drivers/dprobes/dprobes.c        1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.0-test9+kp/drivers/dprobes/dprobes.c     2003-11-18 07:30:12.000000000 +0530
+@@ -0,0 +1,1589 @@
++/*
++ * IBM Dynamic Probes
++ * Copyright (c) International Business Machines Corp., 2000
++ *
++ * 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.  
++ */
++
++#include <linux/dprobes.h>
++#include <linux/dcache.h>
++#include <linux/pagemap.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/vmalloc.h>
++#include <linux/swap.h>
++#include <linux/smp.h>
++#ifdef CONFIG_MAGIC_SYSRQ
++#include <linux/sysrq.h>
++#endif
++
++#include <asm/semaphore.h>
++#include <asm/uaccess.h>
++#include <asm/errno.h>
++#ifdef CONFIG_DEBUGREG
++#include <asm/debugreg.h>
++#endif
++
++#ifdef CONFIG_SMP
++struct dprobes_struct dprobes_set[NR_CPUS];
++#else
++struct dprobes_struct dprobes;
++#endif
++
++struct dp_module_struct *dp_module_list = NULL;
++DECLARE_RWSEM(dp_modlist_sem);
++
++byte_t *dp_heap = NULL;
++unsigned long dp_num_heap = 0;
++rwlock_t dp_heap_lock = RW_LOCK_UNLOCKED;
++
++unsigned long *dp_gv = NULL;
++unsigned long dp_num_gv = 0;
++rwlock_t dp_gv_lock = RW_LOCK_UNLOCKED;
++
++
++#ifdef CONFIG_MAGIC_SYSRQ
++static struct work_struct dprobes_work;
++static struct workqueue_struct *dprobes_wq;
++static void dprobes_sysrq( int , struct pt_regs *, struct tty_struct *);
++static struct sysrq_key_op key_op = {
++      .handler = &dprobes_sysrq,
++      .help_msg = "remoVe_dynamic_probes",
++      .action_msg = "Deactivating all probepoints",
++};
++unsigned long emergency_remove = 0; /*Flag to disable active dprobes*/
++#endif
++
++
++void dprobes_code_start(void) { }
++
++static void init_trace_hdr(struct dp_module_struct *m)
++{
++      unsigned long log_flags = m->pgm.flags & DP_LOG_MASK;
++      unsigned long mask = 0;
++      unsigned short len = sizeof(m->hdr);
++
++      mask |= DP_HDR_MAJOR | DP_HDR_MINOR;
++#ifdef CONFIG_SMP
++      mask |= DP_HDR_CPU;
++      len += sizeof(int);
++#endif        
++      if (log_flags & DP_LOG_PID) {
++              mask |= DP_HDR_PID;
++              len += sizeof(pid_t);
++      }
++      if (log_flags & DP_LOG_UID) {
++              mask |= DP_HDR_UID;
++              len += sizeof(uid_t);
++      }
++      if (log_flags & DP_LOG_CS_EIP) {
++              mask |= DP_HDR_CS | DP_HDR_EIP;
++              len += (sizeof(unsigned short) + sizeof(unsigned long));
++      }
++      if (log_flags & DP_LOG_SS_ESP) {
++              mask |= DP_HDR_SS | DP_HDR_ESP;
++              len += (sizeof(unsigned short) + sizeof(unsigned long));
++      }
++      if (log_flags & DP_LOG_TSC) {
++              mask |= DP_HDR_TSC;
++              len += sizeof(struct timeval);
++      }
++      if (log_flags & DP_LOG_PROCNAME) {
++              mask |= DP_HDR_PROCNAME;
++              len += 16; /* size of task_struct.comm */
++      }
++      m->hdr.facility_id = DP_TRACE_HDR_ID;
++      m->hdr.mask = mask;
++      m->hdr.len = len;
++      /* Adjust the logmax to take care of log header bytes */
++      m->pgm.logmax += len;
++      return;
++}
++
++#if defined(CONFIG_TRACE) || defined(CONFIG_TRACE_MODULE)
++#include <linux/trace.h>
++static inline void get_trace_id(struct dp_module_struct *m)
++{
++      m->trace_id = trace_create_event(m->pgm.name, NULL, CUSTOM_EVENT_FORMAT_TYPE_HEX, NULL);
++}     
++static inline void free_trace_id(struct dp_module_struct *m)
++{
++      trace_destroy_event(m->trace_id);
++}
++#else
++#define get_trace_id(m)
++#define free_trace_id(m)
++#endif
++
++static inline struct dp_module_struct * find_mod_by_inode(struct inode *inode)
++{
++      struct dp_module_struct *m;
++      for (m = dp_module_list; m; m = m->next) {
++              if (m->inode == inode)
++                      break;
++      }
++      return m;
++}
++
++static inline struct dp_module_struct * find_mod_by_name(const char * name)
++{
++      struct dp_module_struct *m;
++      for (m = dp_module_list; m ; m = m->next) {
++              if (!strcmp(m->pgm.name, name))
++                      break;
++      }
++      return m;
++}
++
++static inline void link_module(struct dp_module_struct *m)
++{
++      m->next = dp_module_list;
++      dp_module_list = m;
++      return;
++}
++
++static inline void unlink_module(struct dp_module_struct *m)
++{
++      struct dp_module_struct *prev;
++
++      if (m == dp_module_list) {
++              dp_module_list = m->next;
++              return;
++      }
++      prev = dp_module_list;
++      while (prev->next && prev->next != m)
++              prev = prev->next;
++      if (prev->next)
++              prev->next = prev->next->next;
++      return;
++}
++
++/*
++ * copied from kernel/module.c find_module().
++ */
++static struct module * find_kmodule(const char *name)
++{
++      struct module *kmod = NULL;
++#if 0
++      extern struct list_head *modules;
++      list_for_each_entry(kmod, modules, list) {
++              if (!strcmp(kmod->name, name))
++                      break;
++      }
++#endif
++      return kmod;
++}
++
++/*
++ * Returns the index of the last dp_record that lies in the same page as the
++ * dp_record at start index.
++ */
++static inline unsigned short
++find_last(struct dp_module_struct *m, unsigned short start)
++{
++      int i;
++      struct dp_record_struct * rec = &m->rec[start];
++      unsigned short num_recs = m->pgm.num_points;
++      unsigned long end_offset = (rec->point.offset & PAGE_MASK) + PAGE_SIZE;
++
++      for (i = start; i < num_recs && rec->point.offset < end_offset; i++, rec++)
++              ;
++
++      return i;
++}
++
++/*
++ * Unlinks the given module from dp_module_list and frees all the memory
++ * taken by it.
++ */
++static int free_dp_module(struct dp_module_struct *m)
++{
++      /* unlink mod */
++      unlink_module(m);
++
++      if (m->flags & DP_MOD_FLAGS_LARGE_REC)
++              vfree(m->rec);
++      else
++              kfree(m->rec);
++      kfree(m->lv);
++      kfree(m->pgm.rpn_code);
++      putname(m->pgm.name);
++      kfree(m);
++      return 0;
++}
++
++/*
++ * Allocates dp_record_structs, copies dp_point_structs from user space into
++ * the dp_record_structs in the kernel space.
++ */
++static int
++copy_point_from_user (struct dp_module_struct *m, struct dp_pgm_struct *pgm)
++{
++      unsigned short count = m->pgm.num_points, i;
++      struct dp_record_struct *rec;
++      unsigned long rec_size;
++
++      if (!count)
++              return 0;
++
++      rec_size = count * sizeof(*rec);
++      if (rec_size > PAGE_SIZE) {
++              rec = vmalloc(rec_size);
++              m->flags |= DP_MOD_FLAGS_LARGE_REC;
++      } else {
++              rec = kmalloc(rec_size, GFP_KERNEL);
++      }
++      if (!rec)
++              return -ENOMEM;
++      memset(rec, 0, rec_size);
++      m->rec = rec;
++
++      for (i = 0; i < count; i++, rec++) {
++              if (copy_from_user (&rec->point, &pgm->point[i],
++                              sizeof (struct dp_point_struct))) {
++                      if (m->flags & DP_MOD_FLAGS_LARGE_REC)
++                              vfree(m->rec);
++                      else
++                              kfree(m->rec);
++                      m->rec = NULL;
++                      return -EFAULT;
++              }
++              rec->status = DP_REC_STATUS_COMPILED;
++              rec->lock = SPIN_LOCK_UNLOCKED;
++              rec->mod = m;
++              rec->count = -rec->point.passcount;
++              if (!rec->point.maxhits) rec->point.maxhits =DEFAULT_MAXHITS;
++      }
++      return 0;
++}
++
++/* 
++ * We may have to realloc global variables area.
++ */
++static int check_gv_space(unsigned short num_gv)
++{
++      unsigned long *tmp, *tmp1;      
++      unsigned long eflags;
++
++      if (num_gv <= dp_num_gv)
++              return 0;
++
++      tmp = kmalloc(num_gv * sizeof(*tmp), GFP_KERNEL);
++      if (!tmp) 
++              return -ENOMEM;
++      memset(tmp, 0, num_gv * sizeof(*tmp));
++
++      write_lock_irqsave(&dp_gv_lock, eflags);
++      if (dp_num_gv) {
++              memcpy((void *)tmp, (void *)dp_gv, 
++                      sizeof(unsigned long)*dp_num_gv);
++      }
++      tmp1 = dp_gv;
++      dp_gv = tmp;
++      dp_num_gv = num_gv;
++      write_unlock_irqrestore(&dp_gv_lock, eflags);
++
++      kfree(tmp1);
++      return 0;
++} 
++
++static int check_heap_space(unsigned short num_heap)
++{
++      byte_t *tmp, *tmp1;     
++      unsigned long eflags;
++
++      if (num_heap * num_online_cpus() <= dp_num_heap)
++              return 0;
++
++      tmp = kmalloc(num_heap * sizeof(*tmp) * num_online_cpus(), GFP_KERNEL);
++      if (!tmp) 
++              return -ENOMEM;
++
++      write_lock_irqsave(&dp_heap_lock, eflags);
++      tmp1 = dp_heap;
++      dp_heap = tmp;
++      dp_num_heap = num_heap * num_online_cpus();
++      write_unlock_irqrestore(&dp_heap_lock, eflags);
++      kfree(tmp1);
++
++      return 0;
++} 
++
++/*
++ * Allocates a dp_module_struct and copies the dp_pgm_struct from user space
++ * into it, in kernel space.
++ */
++static int
++copy_pgm_from_user(struct dp_module_struct **mod, struct dp_pgm_struct *pgm)
++{
++      int  retval = 0;
++      struct dp_module_struct *m;
++
++      pgm->name = getname(pgm->name);
++      if (IS_ERR(pgm->name)) {
++              retval = PTR_ERR(pgm->name);
++              goto error;
++      }
++
++      m = find_mod_by_name(pgm->name);
++      if (m) {
++              retval = -EEXIST;
++              goto err1;
++      }
++
++      m = kmalloc(sizeof(*m), GFP_KERNEL);
++      if (!m) {
++              retval = -ENOMEM;
++              goto err1;
++      }
++      memset(m, 0, sizeof(*m));
++
++      m->pgm = *pgm;
++
++      if (m->pgm.logmax > LOG_SIZE) m->pgm.logmax = DEFAULT_LOGMAX;
++      if (m->pgm.jmpmax > JMP_MAX) m->pgm.jmpmax = DEFAULT_JMPMAX;
++      if (m->pgm.ex_logmax > EX_LOG_SIZE) m->pgm.ex_logmax = DEFAULT_EX_LOG_MAX;
++      if (m->pgm.heapmax > HEAPMAX)
++              m->pgm.heapmax = DEFAULT_HEAPMAX;
++
++      if (pgm->num_lv != 0) {
++              m->lv = kmalloc(pgm->num_lv * sizeof(*m->lv), GFP_KERNEL);
++              if (!m->lv) {
++                      retval = -ENOMEM;
++                      goto err2;
++              }
++              memset(m->lv, 0, pgm->num_lv * sizeof(*m->lv));
++      }
++
++      if (pgm->num_gv != 0) {
++              retval = check_gv_space(pgm->num_gv);
++              if (retval < 0)
++                      goto err3;
++      }
++
++      if (pgm->heapmax != 0) {
++              retval = check_heap_space(pgm->heapmax);
++              if (retval < 0)
++                      goto err3;
++      }
++
++      m->pgm.rpn_code = kmalloc(pgm->rpn_length, GFP_KERNEL);
++      if (!m->pgm.rpn_code) {
++              retval = -ENOMEM;
++              goto err3;
++      }
++      if (copy_from_user(m->pgm.rpn_code, pgm->rpn_code, pgm->rpn_length)) {
++              retval = -EFAULT;
++              goto err4;
++      }
++
++      retval = copy_point_from_user(m, pgm);
++      if (retval)
++              goto err4;
++      *mod = m;
++      return 0;
++
++err4:         kfree(m->pgm.rpn_code);
++err3:         kfree(m->lv);
++err2:         kfree(m);
++err1: putname(pgm->name);
++error:        return retval;
++
++}
++
++/*
++ * Fills up the base and end fields of the given dp_module_struct with the
++ * starting and end addresses of the given kernel module, accounting for
++ * correct alignment of the code segment.
++ */
++static inline int get_kmod_bounds(struct dp_module_struct *m, struct module *kmod)
++{
++      m->base = (unsigned long)kmod->module_core;
++      m->end = kmod->core_size;
++      return 1;
++}
++
++/*
++ * Fills up the base and end fields of the dp_module_struct with the details
++ * of where the corresponding kernel module is loaded.
++ */
++static inline int get_mod_load_addr(struct dp_module_struct *m)
++{
++      struct module * kmod;
++      kmod = find_kmodule(m->pgm.name);
++      if (!kmod)
++              return 0; // module not yet loaded.
++      return get_kmod_bounds(m, kmod);
++}
++
++/*
++ * Fills up the base and end fields of dp_module_struct if this module is
++ * for a kernel or a kernel module.
++ */
++static int get_load_addr(struct dp_module_struct *m)
++{
++      if (m->pgm.flags & DP_MODTYPE_KMOD)
++              return get_mod_load_addr(m);
++      m->base = PAGE_OFFSET;
++      m->end = init_mm.end_code - PAGE_OFFSET;
++      return 1;
++}
++
++/* last thing we do should be to remove the breakpoint setting. */
++static int insert_probe(byte_t *addr, struct dp_record_struct *rec, 
++      struct dp_module_struct *m, struct page * page, 
++      struct vm_area_struct *vma)
++{
++      /* 
++       * remove residual status bits, applicable only to probes in kernel
++       * modules when they are being reinserted. 
++       */
++      rec->status &= ~(DP_REC_STATUS_REMOVED | DP_REC_STATUS_DISABLED);
++      if(!(m->pgm.flags & DP_MODTYPE_USER))
++              return __insert_probe(addr, rec, m, page);
++      else
++              return insert_probe_userspace(addr, rec, page, vma);
++}
++
++/* first thing we do should be to remove the breakpoint setting. */
++static int remove_probe(byte_t * addr, struct dp_record_struct *rec,
++      struct dp_module_struct *m, struct page * page, 
++      struct vm_area_struct *vma)
++{
++      unsigned long eflags;
++      spin_lock_irqsave(&rec->lock, eflags);
++      if(!(m->pgm.flags & DP_MODTYPE_USER))
++              __remove_probe(addr, rec);
++      else 
++              remove_probe_userspace(addr, rec, page, vma);
++      rec->status &= ~(DP_REC_STATUS_ACTIVE | DP_REC_STATUS_MISMATCH);
++      rec->status |= DP_REC_STATUS_REMOVED;
++      spin_unlock_irqrestore(&rec->lock, eflags);
++      return 0;
++}
++
++/*
++ * Creates hash table links and inserts all records in kernel / kmodule.
++ */
++static int insert_all_recs_k(struct dp_module_struct *m)
++{
++      struct dp_record_struct * rec;
++      byte_t * addr;
++      int i;
++      unsigned short num_recs = m->pgm.num_points;
++
++      for (i = 0, rec = m->rec; i < num_recs; i++, rec++) {
++              if (!(rec->point.address_flag & DP_ADDRESS_ABSOLUTE)) { 
++                      rec->point.offset += m->base;
++              }
++              addr = (byte_t *)((unsigned long)rec->point.offset);
++              insert_probe(addr, rec, m, NULL, NULL);
++      }
++      return 0;
++}                             
++
++/*
++ * Removes probes in kernel / kmodules: all _will_ be in memory.
++ * Note that rec->point.offset is now the linear address itself.
++ */
++static int remove_all_recs_k(struct dp_module_struct *m)
++{
++      struct dp_record_struct * rec;
++      int i;
++      byte_t * addr;
++      unsigned short num_recs = m->pgm.num_points;
++
++      for (i = 0, rec = m->rec; i < num_recs; i++, rec++) {
++              addr = (byte_t *) ((unsigned long)rec->point.offset);
++              if (rec->status & DP_REC_STATUS_ACTIVE) {
++                      remove_probe(addr, rec, m, NULL, NULL);
++              }
++              if (!(rec->point.address_flag & DP_ADDRESS_ABSOLUTE))
++                      rec->point.offset -= m->base;
++
++      }
++      m->base = m->end = 0;
++      return 0;
++}
++
++/*
++ * mod->pgm.name is already in kernel space.
++ */
++static int insert_k (struct dp_module_struct * m)
++{
++      if (!get_load_addr(m))
++              return 0;
++      return insert_all_recs_k(m);
++}
++
++static int remove_k(struct dp_module_struct *m)
++{
++      return remove_all_recs_k(m);
++}
++
++/*
++ * Inserts user probes into the page. Insert probes that lie in the same page 
++ * after waiting for the page to be unlocked, if it was locked.
++ */
++static unsigned short insert_recs_in_page (struct dp_module_struct *m,
++      struct page * page, unsigned short start, unsigned short end, 
++              struct vm_area_struct *vma)
++{
++      unsigned long alias;
++      byte_t * addr;
++      unsigned short i;
++      struct dp_record_struct * rec = &m->rec[start];
++
++      if (!page) {
++              return 1;
++      }
++      wait_on_page_locked(page);
++      if (!PageUptodate(page)) { /* we could probably retry readpage here. */
++              return 1;
++      }
++
++      alias = (unsigned long)kmap(page);
++      for (i = start; i < end; i++, rec++) {
++              addr = (byte_t *) (alias +
++                      (unsigned long)(rec->point.offset & ~PAGE_MASK));
++              insert_probe(addr, rec, m, page, vma);
++      }
++      kunmap(page);
++      return 1;
++}
++
++/*
++ * Removes user probes that lie in the same page after waiting for the page to
++ * be unlocked, if it was locked. Make sure the page does not get swapped out.
++ */
++static unsigned short remove_recs_from_page (struct dp_module_struct *m,
++      struct page * page, unsigned short start, unsigned short end, 
++              struct vm_area_struct *vma)
++{
++      struct dp_record_struct * rec = &m->rec[start];
++      unsigned long alias;
++      byte_t * addr;
++      unsigned short i;
++
++      if (!page)
++              return 1;
++      wait_on_page_locked(page);
++      lock_page(page);
++      alias = (unsigned long)kmap(page); 
++      for (i = start; i < end; i++, rec++) {
++              addr = (byte_t *) (alias +
++                      (unsigned long)(rec->point.offset & ~PAGE_MASK)); 
++              remove_probe(addr, rec, m, page, vma);
++      }
++      kunmap(page);
++      unlock_page(page);
++
++      return 1;
++}
++
++typedef unsigned short
++(*process_recs_func_t)(struct dp_module_struct *m, struct page *page,
++              unsigned short start, unsigned short end, struct vm_area_struct *);
++
++static inline pte_t *get_one_pte(struct mm_struct *mm, unsigned long addr)
++{
++      pgd_t * pgd;
++      pmd_t * pmd;
++      pte_t * pte = NULL;
++
++      pgd = pgd_offset(mm, addr);
++      if (pgd_none(*pgd))
++              goto end;
++      if (pgd_bad(*pgd)) {
++              pgd_ERROR(*pgd);
++              pgd_clear(pgd);
++              goto end;
++      }
++
++      pmd = pmd_offset(pgd, addr);
++      if (pmd_none(*pmd))
++              goto end;
++      if (pmd_bad(*pmd)) {
++              pmd_ERROR(*pmd);
++              pmd_clear(pmd);
++              goto end;
++      }
++
++      pte = pte_offset_kernel(pmd, addr);
++      if (pte_none(*pte))
++              pte = NULL;
++end:
++      return pte;
++}
++
++struct dp_page_locator_struct {
++      struct list_head list;
++      struct mm_struct *mm;
++      unsigned long addr;
++};
++
++/*
++ * Get the page corresponding to a given virtual addr, marking it as needing
++ * to be brought in later and checked, if it has been swapped out. 
++ * It doesn't bring in discarded pages as a_ops->readpage
++ * takes care of that.
++ */
++struct page * dp_vaddr_to_page(struct vm_area_struct *vma, unsigned long addr,
++struct list_head  *swapped_list_head)
++{
++      struct mm_struct *mm = vma->vm_mm;
++      pte_t *pte = get_one_pte(mm, addr);
++      struct page *page;
++      struct dp_page_locator_struct *pageloc;
++
++      if (!pte) {
++              return NULL;
++      }
++      /*
++       * If the page has been swapped out, we want to bring it in.
++       * We can't do it right away since we are holding spin locks.
++       * So just queue it up on the swapped pages list.
++       */
++      if (!pte_present(*pte)) {
++              if (swapped_list_head == NULL) return NULL;     
++              pageloc = kmalloc(sizeof(*pageloc), GFP_ATOMIC);
++              if (!pageloc) return NULL;
++              pageloc->mm = mm;
++              pageloc->addr = addr;
++              atomic_inc(&mm->mm_users); /* so that mm won't go away */
++              list_add(&pageloc->list, swapped_list_head);
++              return NULL;
++      }
++
++      page = pte_page(*pte);
++      page_cache_get(page); /* TODO: Check if we need the page_cache_lock */
++
++      /*
++       * If this is a COW page, then we want to make sure that any changes
++       * made to the page get written back when swapped out. We need to do
++       * the following explicitly because dprobes will write via an alias.
++       */
++      if (IS_COW_PAGE(page, vma->vm_file->f_dentry->d_inode)) {
++              if (PageSwapCache(page))
++                      delete_from_swap_cache(page);
++              set_pte(pte, pte_mkdirty(*pte));
++      }
++
++      return page;
++}
++
++/*
++ * Tracks all COW pages for the page containing the specified probe point
++ * and inserts/removes all the probe points for that page.
++ * Avoid the inserts/removes if the page's inode matches the module's inode.
++ * since that means that it is the original page and not a copied page.
++ */
++static int process_recs_in_cow_pages (struct dp_module_struct *m,
++              unsigned short start, unsigned short end,
++              process_recs_func_t process_recs_in_page)
++{
++      unsigned long offset = m->rec[start].point.offset;
++      struct vm_area_struct *vma;
++      struct page *page;
++      unsigned long addr;
++      struct mm_struct *mm;
++      struct address_space *mapping = m->inode->i_mapping;
++      struct list_head *head = &mapping->i_mmap;
++      struct list_head swapped_pages_list, *ptr;
++      struct dp_page_locator_struct *pageloc;
++
++      INIT_LIST_HEAD(&swapped_pages_list);
++      down(&mapping->i_shared_sem);
++
++      list_for_each_entry(vma, head, shared) {
++              mm = vma->vm_mm;
++              spin_lock(&mm->page_table_lock);        
++                                                      
++              /* Locate the page in this vma */
++              addr = vma->vm_start - (vma->vm_pgoff << PAGE_SHIFT) + offset;
++              /*
++               * The following routine would also bring in the page if it is
++               * swapped out
++               */
++              page = dp_vaddr_to_page (vma, addr, &swapped_pages_list);
++              spin_unlock(&mm->page_table_lock);
++              if (!page)
++                      continue;
++              if (IS_COW_PAGE(page, m->inode)) {      
++                      (*process_recs_in_page)(m, page, start, end, vma);
++              }
++              page_cache_release(page); /* TODO: Do we need a lock ? */
++      }
++      up(&mapping->i_shared_sem);
++
++      while (!list_empty(&swapped_pages_list)) { 
++              ptr = swapped_pages_list.next;
++              pageloc = list_entry(ptr, struct dp_page_locator_struct, list);
++              mm = pageloc->mm;      
++              addr = pageloc->addr;      
++              down_read(&mm->mmap_sem); 
++              /* first make sure that the vma didn't go away  */
++              vma = find_vma(mm, addr);
++              /* and that this is the same one we had */
++              if (vma && vma->vm_file && 
++              (vma->vm_file->f_dentry->d_inode == m->inode) &&
++              (vma->vm_start - (vma->vm_pgoff << PAGE_SHIFT) + offset 
++              == addr)) {
++                      if (handle_mm_fault(mm, vma, addr, 0) <= 0) {
++                              goto next;
++                      }
++                      page = dp_vaddr_to_page(vma, addr, NULL); 
++                      if (!page) /* could this ever happen ? */ {
++                              goto next;
++                      }
++                      if (IS_COW_PAGE(page, m->inode)) {
++                              (*process_recs_in_page)(m, page, start, end, vma);
++                      }
++                      page_cache_release(page); /*TODO: Do we need a lock ?*/
++              }
++next:         
++              up_read(&mm->mmap_sem); 
++              mmput(mm);
++              list_del(ptr);
++              kfree(pageloc);
++      }
++      return 1;
++}
++/* 
++ * find_get_vma walks through the list of process private mappings and
++ * returns the pointer to vma containing the offset if found.
++ */
++static struct vm_area_struct * find_get_vma(unsigned long offset, 
++      struct address_space *mapping)
++{
++      struct vm_area_struct *vma = NULL;
++      struct list_head *head = &mapping->i_mmap;
++      struct mm_struct *mm;
++      unsigned long start, end;
++
++      down(&mapping->i_shared_sem);
++        list_for_each_entry(vma, head, shared) {
++              mm = vma->vm_mm;
++              spin_lock(&mm->page_table_lock);
++              start = vma->vm_start - (vma->vm_pgoff << PAGE_SHIFT);
++              end = vma->vm_end - (vma->vm_pgoff << PAGE_SHIFT);
++              spin_unlock(&mm->page_table_lock);
++              if ((start + offset) < end) {
++                      up(&mapping->i_shared_sem);
++                      return vma;
++              }
++      }
++      up(&mapping->i_shared_sem);
++      return NULL;
++}
++/*
++ * physical insertion/removal of probes in the actual pages of the module.
++ * Register user space probes before actually instering probes in the page for 
++ * a given pair of inode and offset.
++ * 
++ */
++static int process_recs(struct dp_module_struct *m,
++              process_recs_func_t process_recs_in_page)
++{
++      struct address_space * mapping = m->inode->i_mapping;
++      struct page *page;
++      unsigned short i = 0, j;
++      unsigned short num_recs = m->pgm.num_points;
++      unsigned short start, end;
++      struct vm_area_struct *vma = NULL;
++
++      while (i < num_recs) {
++              start = i;
++              i = end = find_last(m, start);
++              vma = find_get_vma(m->rec[start].point.offset, mapping);
++              page = find_get_page(mapping, 
++                              m->rec[start].point.offset >> PAGE_CACHE_SHIFT);
++              
++              for (j = start; j < end; j++) {
++                      if (process_recs_in_page == insert_recs_in_page)
++                              register_userspace_probes(&m->rec[j]);
++              }
++                              
++              (*process_recs_in_page)(m, page, start, end, vma);
++              if (page) 
++                      page_cache_release(page); /* TODO: Lock needed ? */
++              process_recs_in_cow_pages(m, start, end, process_recs_in_page);
++
++              for (j = start; j < end; j++) {
++                      if (process_recs_in_page == remove_recs_from_page)
++                              unregister_userspace_probes(&m->rec[j]);
++              }
++      }
++      return 1;
++}
++
++static inline int insert_recs(struct dp_module_struct *m)
++{
++      return process_recs(m, insert_recs_in_page);
++}
++
++static inline int remove_recs(struct dp_module_struct *m)
++{
++      return process_recs(m, remove_recs_from_page);
++}
++
++/*
++ * Gets exclusive write access to the given inode to ensure that the file
++ * on which probes are currently applied does not change. Use the function,
++ * deny_write_access_to_inode() we added in fs/namei.c.
++ */
++extern int deny_write_access_to_inode(struct inode * inode);
++static inline int ex_write_lock(struct inode * inode)
++{
++      return deny_write_access_to_inode(inode);
++}
++
++/*
++ * Called when removing user space probes to release the write lock on the
++ * inode.
++ */
++static inline int ex_write_unlock(struct inode * inode)
++{
++      atomic_inc(&inode->i_writecount);
++      return 0;
++}
++
++/*
++ * Inserts user space probes.
++ *
++ * mod->pgm.name is already in user space. This function leaves with the
++ * dentry held and taking with the inode writelock held to ensure that the
++ * file on which probes are currently active does not change from under us.
++ */
++static int insert_u (struct dp_module_struct * m)
++{
++      struct address_space *as;
++      int error;
++
++      error = user_path_walk(m->pgm.name, &m->nd);
++      if (error)
++              return error;
++
++      m->inode = m->nd.dentry->d_inode;
++      as = m->inode->i_mapping;
++
++      error = ex_write_lock(m->inode);
++      if (error) {
++              path_release(&m->nd);
++              return error;
++      }
++
++      /* switch i_op to hook into readpage */
++      m->ori_a_ops = as->a_ops;
++      m->dp_a_ops = *as->a_ops;
++      m->dp_a_ops.readpage = dp_readpage;
++      as->a_ops = &m->dp_a_ops;
++
++      /* physically insert the probes in existing pages */
++      insert_recs(m);
++
++      return 0;
++}
++
++/*
++ * Removes user space probes.
++ */
++static int remove_u(struct dp_module_struct *m)
++{
++      m->inode->i_mapping->a_ops = m->ori_a_ops; /* unhook readpage */
++      remove_recs(m); /* remove the probes */
++      ex_write_unlock(m->inode);
++      path_release(&m->nd); /* release path */
++      return 0;
++}
++
++/*
++ * Entry routine for the insert command. It checks for existing probes in this
++ * module to avoid any duplications, creates the necessary data structures
++ * calls insert_k() or insert_u() depending on whether it is a kernel space or
++ * user space probe.
++ */
++static int do_insert(struct dp_pgm_struct *upgm)
++{
++      struct dp_module_struct *m;
++      struct dp_pgm_struct *pgm;
++      char *uname, *kname;
++      int retval;
++
++      if (!upgm)
++              return -EINVAL;
++
++      pgm = kmalloc (sizeof(*pgm), GFP_KERNEL);
++      if (!pgm)
++              return -ENOMEM;
++
++      if (copy_from_user(pgm, upgm, sizeof(*pgm))) {
++              retval = -EFAULT;
++              goto done;
++      }
++
++      if (!pgm->name || !pgm->num_points) {
++              retval = -EINVAL;
++              goto done;
++      }
++      uname = pgm->name;
++      retval = copy_pgm_from_user(&m, pgm);
++      if (retval)
++              goto done;
++
++      try_module_get(THIS_MODULE);
++      down_write(&dp_modlist_sem);
++      link_module(m);
++      if (pgm->flags & DP_MODTYPE_USER) {
++              /* kludge: needed to use user_path_walk. */
++              kname = m->pgm.name;
++              m->pgm.name = uname;
++              retval = insert_u(m);
++              m->pgm.name = kname;
++      } else {
++              retval = insert_k(m);
++      }
++      
++      if (retval) {
++              free_dp_module(m);
++              module_put(THIS_MODULE);
++      } else {
++              init_trace_hdr(m);
++              get_trace_id(m);
++      }
++      up_write(&dp_modlist_sem);
++
++done: kfree(pgm);
++      return retval;
++}
++
++static int remove_module(struct dp_module_struct *m)
++{
++      /* remove probes */
++      if (m->pgm.flags & DP_MODTYPE_USER) {
++              remove_u(m);
++      } else {
++              remove_k(m);
++      }
++      free_trace_id(m);
++
++      /* free module and all its contents */
++      free_dp_module(m);
++      return 0;
++}
++
++/*
++ * Entry routine for removing probes.
++ */
++static int do_remove (unsigned long cmd, char * uname)
++{
++      struct dp_module_struct *m, *tmp;
++      char *name;
++
++      if (cmd & DP_ALL) {
++              down_write(&dp_modlist_sem);
++              m = dp_module_list;
++              while (m) {
++                      tmp = m->next;
++                      remove_module (m);
++                      m = tmp;
++                      module_put(THIS_MODULE);
++              }
++              up_write(&dp_modlist_sem);
++      } else {
++              if (!uname)
++                      return -EINVAL;
++              name = getname(uname);
++              if (IS_ERR(name))
++                      return (PTR_ERR(name));
++
++              down_write(&dp_modlist_sem);
++              m = find_mod_by_name (name);
++              putname(name);
++              if (!m) {
++                      up_write(&dp_modlist_sem);
++                      return -EINVAL;
++              }
++              remove_module (m);
++              module_put(THIS_MODULE);
++              up_write(&dp_modlist_sem);
++      }
++      return 0;
++}
++
++static int 
++dp_get_globalvars(unsigned long cmd, struct dp_getvars_in_struct * req, 
++              byte_t * result)
++{
++      unsigned long num_vars;
++      unsigned long *tmp_gv = NULL;
++      unsigned long eflags;
++      unsigned short orig_to = req->to;
++      int retval = 0;
++
++      read_lock_irqsave(&dp_gv_lock, eflags);
++      if (!(cmd & DP_GETVARS_INDEX)) {
++              req->from = 0;
++              req->to = dp_num_gv - 1;
++              num_vars = dp_num_gv;
++      } else if (req->from >= dp_num_gv) {
++              num_vars = 0;
++      } else if (req->to >= dp_num_gv) {
++              req->to = dp_num_gv - 1;
++              num_vars = req->to - req->from + 1;
++      } else {
++              num_vars = req->to - req->from + 1;
++      }
++
++      if (cmd & DP_GETVARS_RESET) {
++              memset(dp_gv + req->from, 0, num_vars*sizeof(unsigned long));
++              read_unlock_irqrestore(&dp_gv_lock, eflags);
++              goto done;
++      }
++
++      read_unlock_irqrestore(&dp_gv_lock, eflags);
++
++      if (num_vars) {
++              tmp_gv = kmalloc(num_vars * sizeof(*tmp_gv), GFP_KERNEL);
++              if (!tmp_gv) {
++                      retval = -ENOMEM;
++                      goto done;
++              }
++
++              read_lock_irqsave(&dp_gv_lock, eflags);
++
++              /*
++               * dp_num_gv can change(only increase) during kmalloc. In such
++               * a case, only copy the previously determined number
++               * of global vars.
++               */
++              memcpy((void *)tmp_gv, (void *)(dp_gv + req->from), 
++                      sizeof(unsigned long) * num_vars);
++              read_unlock_irqrestore(&dp_gv_lock, eflags);
++      }
++      
++      req->returned +=  (num_vars + 1) * sizeof(unsigned long); 
++              if (req->returned < req->allocated) {
++              if (copy_to_user(result, &num_vars, sizeof(unsigned long)))
++                      retval = -EFAULT;
++              else if (num_vars) {
++                      if (copy_to_user(result + sizeof(unsigned long), 
++                              tmp_gv, sizeof(unsigned long) * num_vars))
++                      retval = -EFAULT;
++                      kfree(tmp_gv);
++              }
++      }
++      else
++              retval = -ENOMEM;
++done:
++      req->to = orig_to;
++      return retval;
++}
++
++static int
++cp_lvars_for_mod(struct dp_module_struct *m, struct dp_getvars_in_struct * req,
++              byte_t * result, unsigned long var_bytes)
++{
++      unsigned long len = 0;
++      unsigned long offset = 0;
++      unsigned long num_vars = req->to - req->from + 1;
++
++              len = sizeof(struct dp_getvars_local_out_struct) +
++                      var_bytes + strlen(m->pgm.name) + 1;
++      req->returned += len;
++
++              if (req->returned < req->allocated) {
++              if (copy_to_user(result, &len, sizeof(unsigned long)))
++                      return -EFAULT;
++              else
++                      offset = sizeof(unsigned long);
++
++              if (copy_to_user(result+offset, &num_vars,
++                              sizeof(unsigned long)))
++                      return -EFAULT;
++              else
++                      offset += sizeof(unsigned long);
++
++              if (copy_to_user(result+offset, m->lv + req->from, var_bytes))
++                      return -EFAULT;
++              else
++                      offset += var_bytes;
++
++              if (copy_to_user(result+offset, m->pgm.name,
++                              strlen(m->pgm.name)+1))
++                      return -EFAULT;
++      }
++      else
++              return -ENOMEM;
++
++      return 0;
++}
++
++static int
++getvars_m(struct dp_module_struct *m, unsigned long cmd,
++              struct dp_getvars_in_struct *req, byte_t *result)
++{
++      int retval = 0;
++      unsigned long var_bytes;
++      unsigned short orig_to = req->to;
++
++      if (cmd & DP_GETVARS_INDEX) {
++              if (req->from >= m->pgm.num_lv)
++                      return 0;
++              if(req->to >= m->pgm.num_lv)
++                      req->to = m->pgm.num_lv - 1;
++      }
++      else {
++              req->from = 0;
++              req->to = m->pgm.num_lv - 1;
++      }
++      var_bytes = (req->to - req->from + 1) * sizeof(unsigned long);
++
++      if (cmd & DP_GETVARS_RESET)
++              memset(m->lv + req->from, 0, var_bytes);
++      else
++              retval = cp_lvars_for_mod(m, req, result, var_bytes);
++      req->to = orig_to;
++      return retval;
++}
++
++static int
++do_getvars(unsigned long cmd, struct dp_getvars_in_struct * ureq,
++              byte_t * result)
++{
++      struct dp_module_struct *m;
++      struct dp_getvars_in_struct req;
++      int retval = 0;
++
++      if (!ureq)
++              return -EINVAL;
++
++      if (copy_from_user(&req, ureq, sizeof(req))) {
++              retval = -EFAULT;
++              goto failed;
++      }
++      if (req.name) {
++              req.name = getname(req.name);
++              if (IS_ERR(req.name)) {
++                      retval = PTR_ERR(req.name);
++                      goto failed;
++              }
++      }
++      else
++              req.name = NULL;
++
++              req.returned = 0;
++      if (cmd & DP_GETVARS_GLOBAL) {
++              retval = dp_get_globalvars(cmd, &req, result);
++              if (retval) 
++                      goto done;
++      }
++
++      if (cmd & DP_GETVARS_LOCAL) {
++              down_read(&dp_modlist_sem);
++              if (cmd & DP_ALL) {
++                      for (m = dp_module_list; m; m = m->next) {
++                              if (!m->lv) 
++                                      continue;
++                              retval = getvars_m(m, cmd, &req, result + req.returned);
++                              if (retval && (retval != -ENOMEM))
++                                      break;
++                      }
++              } else if (req.name) {
++                      m = find_mod_by_name(req.name);
++                      if (m && m->lv)
++                              retval = getvars_m(m, cmd, &req, result + req.returned);
++                      else 
++                              retval = -EINVAL;
++              }
++              up_read(&dp_modlist_sem);
++      }
++done:
++      if (copy_to_user(&ureq->returned, &req.returned,
++                      sizeof(unsigned long)))
++              retval = -EFAULT;
++
++      if (req.name)
++              putname(req.name);
++failed:
++      return retval;
++}
++
++#define dp_copy_to_user(destination, source, length) \
++do { \
++      if (copy_to_user(destination, source, length)) \
++              return -EFAULT; \
++      destination += length; \
++} while(0)
++
++static int query_r(struct dp_module_struct *m, byte_t **result)
++{
++      struct dp_outrec_struct outrec;
++      struct dp_record_struct * rec;
++      unsigned short i;
++      unsigned short num_recs = m->pgm.num_points;
++      byte_t * offset = *result;
++      unsigned long eflags;
++
++      for (i = 0, rec = m->rec; i < num_recs; i++, rec++) {
++              spin_lock_irqsave(&rec->lock, eflags);
++              outrec.status = rec->status;
++              outrec.count = rec->count;
++              outrec.dbregno = rec->dbregno;
++              outrec.point = rec->point;
++              spin_unlock_irqrestore(&rec->lock, eflags);
++              dp_copy_to_user(offset, &outrec, sizeof(outrec));
++      }
++      *result = offset;
++      return 0;
++}
++
++static int
++query_m(struct dp_module_struct *m, struct dp_query_in_struct *req,
++              byte_t * result)
++{
++      unsigned long len = 0;
++      byte_t * offset = result;
++      struct dp_outmod_struct outmod;
++      int retval;
++      unsigned long rec_bytes = m->pgm.num_points *
++                                sizeof(struct dp_outrec_struct);
++      unsigned long var_bytes = m->pgm.num_lv * sizeof(m->lv);
++      unsigned long rpn_bytes = m->pgm.rpn_length;
++      unsigned long mod_name_len = strlen(m->pgm.name) + 1;
++
++      len = sizeof(struct dp_outmod_struct) + var_bytes + rec_bytes
++              + rpn_bytes + mod_name_len;
++
++      req->returned += len;
++      if (req->returned <= req->allocated) {
++              outmod.pgm = m->pgm;
++              outmod.flags = m->flags;
++              outmod.base = m->base;
++              outmod.end = m->end;
++
++              offset += sizeof(outmod);
++
++              outmod.rec = (struct dp_outrec_struct *) offset ;
++              retval = query_r(m, &offset);
++              if (retval)
++                      return retval;
++
++              if (var_bytes) {
++                      outmod.lv = (unsigned long *) offset;
++                      dp_copy_to_user(offset, m->lv, var_bytes);
++              } else
++                      outmod.lv = NULL;
++
++              outmod.pgm.rpn_code = offset;
++              dp_copy_to_user(offset, m->pgm.rpn_code, rpn_bytes);
++
++              outmod.pgm.name = (char *) offset;
++              dp_copy_to_user(offset, m->pgm.name, mod_name_len);
++              if (m->next && !(req->name))
++                      outmod.next = (struct dp_outmod_struct *) offset;
++              else
++                      outmod.next = NULL;
++              offset = result;
++              dp_copy_to_user(offset, &outmod, sizeof(outmod));
++      }
++      else
++              return -ENOMEM;
++      return 0;
++}
++
++static int
++do_query(unsigned long cmd, struct dp_query_in_struct * ureq, byte_t * result)
++{
++      struct dp_query_in_struct req;
++      struct dp_module_struct *m;
++      int retval = 0;
++
++      if (!ureq)
++              return -EINVAL;
++      if (copy_from_user(&req, ureq, sizeof(req))) {
++              retval = -EFAULT;
++              goto failed;
++      }
++      if (req.name) {
++              req.name = getname(req.name);
++              if (IS_ERR(req.name)) {
++                      retval = PTR_ERR(req.name);
++                      goto failed;
++              }
++      }
++      else
++              req.name = NULL;
++      req.returned = 0;
++
++      down_read(&dp_modlist_sem);
++      if (cmd & DP_ALL) {
++              for (m = dp_module_list; m; m = m->next) {
++                      retval = query_m(m, &req, result + req.returned);
++                      if (retval && (retval != -ENOMEM))
++                              break;
++              }
++      }
++      else if (req.name) {
++              m = find_mod_by_name(req.name);
++              if (m) 
++                      retval = query_m(m, &req, result + req.returned);
++              else 
++                      retval = -EINVAL;
++      }
++      up_read(&dp_modlist_sem);
++
++      if (copy_to_user(&ureq->returned, &req.returned,
++                      sizeof(unsigned long)))
++              retval = -EFAULT;
++      if (req.name)
++              putname(req.name);
++failed:
++      return retval;
++}
++
++/*
++ * Returns the index of the first probe record that lies in the page
++ * starting with given offset.
++ */
++static inline int
++find_first_in_page(struct dp_module_struct * m, unsigned long offset)
++{
++      int i;
++      unsigned short num_recs = m->pgm.num_points;
++      struct dp_record_struct * rec;
++      unsigned long end = offset + PAGE_SIZE;
++
++      for (i = 0, rec = m->rec; i < num_recs; i++, rec++) {
++              if (rec->point.offset >=offset && rec->point.offset < end)
++                      return i;
++      }
++      return -1;
++}
++
++/*
++ * This routine does the post processing for all pages that are brought
++ * in from a user module which has active probes in it.
++ */
++static int fixup_page (struct dp_module_struct *m, struct page *page)
++{
++      int start;
++      unsigned short end;
++      struct vm_area_struct *vma = NULL;
++
++      /* find and insert all probes in this page */
++      start = find_first_in_page(m, (page->index << PAGE_CACHE_SHIFT));
++      if (start < 0)
++              return -1;
++      end = find_last(m, start);
++
++      return insert_recs_in_page (m, page, start, end, vma);
++}
++
++/*
++ * This function handles the readpage of all modules that have active probes
++ * in them. Here, we first call the original readpage() of this
++ * inode / address_space to actually read the page into memory. Then, we will
++ * insert all the probes that are specified in this page before returning.
++ */
++int dp_readpage(struct file *file, struct page *page)
++{
++      int retval = 0;
++      struct dp_module_struct *m;
++
++      down_read(&dp_modlist_sem);
++      m = find_mod_by_inode(file->f_dentry->d_inode);
++      if (!m) {
++              printk("dp_readpage: major problem. we don't have mod for this !!!\n");
++              up_read(&dp_modlist_sem);
++              return -EINVAL;
++      }
++
++      /* call original readpage() */
++      retval = m->ori_a_ops->readpage(file, page);
++      if (retval >= 0)
++              fixup_page (m, page);
++
++      up_read(&dp_modlist_sem);
++      return retval;
++}
++
++/*
++ * This is called from kernel/module.c,sys_init_module() after a kernel module
++ * is loaded before it is initialized to give us a chance to insert any probes
++ * in it.
++ */
++int dp_insmod(struct module *kmod)
++{
++      struct dp_module_struct *m;
++      int retval;
++
++      down_read(&dp_modlist_sem);
++      m = find_mod_by_name(kmod->name);
++      if (!m) {
++              retval = -1;
++      } else {
++              get_kmod_bounds(m, kmod);
++              retval = insert_all_recs_k(m);
++      }
++      up_read(&dp_modlist_sem);
++      return retval;
++}
++
++/*
++ * This is called from kernel/module.c, free_module() before freeing a kernel
++ * module and from sys_init_module() when a kernel module initialization fails
++ * to give us a chance to remove any probes in it.
++ */
++int dp_remmod(struct module *kmod)
++{
++      struct dp_module_struct *m;
++      int retval;
++
++      down_read(&dp_modlist_sem);
++      m = find_mod_by_name(kmod->name);
++      if (!m)
++              retval = -1;
++      else
++              retval = remove_all_recs_k(m);
++      up_read(&dp_modlist_sem);
++      return retval;
++}
++
++/* 
++ * ioctl function for dprobes driver.
++ */
++static int dp_ioctl (struct inode *in, struct file *fp, unsigned int ioctl_cmd,
++             unsigned long arg)
++{
++      struct dp_ioctl_arg dp_arg;
++      int retval = 0;
++
++      if (current->euid) {
++              return -EACCES;
++      }
++
++      if (copy_from_user((void *)&dp_arg, (void *)arg, sizeof(dp_arg))) {
++              module_put(THIS_MODULE);
++              return -EFAULT;
++      }
++
++      switch (dp_arg.cmd & DP_CMD_MASK) {
++      case DP_INSERT:
++              retval = do_insert(dp_arg.input); 
++              break;
++      case DP_REMOVE:
++              retval = do_remove(dp_arg.cmd, dp_arg.input); 
++              break; 
++      case DP_GETVARS:
++              retval = do_getvars(dp_arg.cmd, dp_arg.input, dp_arg.output); 
++              break;
++      case DP_QUERY:
++              retval = do_query(dp_arg.cmd, dp_arg.input, dp_arg.output); 
++              break;
++      default:
++              retval = -EINVAL;
++              break;
++      }
++      return retval;  
++}
++
++static struct file_operations dprobes_ops = {
++      owner:  THIS_MODULE,
++      ioctl:  dp_ioctl
++};
++
++static int dprobes_major;
++
++#ifdef CONFIG_MAGIC_SYSRQ
++
++/* SysRq handler - emergency removal of all probes via Alt-SysRq-V */
++
++static void do_remove_sysrq(struct dprobes_struct *dp) 
++{
++      int retval;
++      if ((retval = do_remove(DP_ALL, NULL)))
++              printk("<1>Probe removal failed rc %i\n", retval);
++      else
++              printk("<1> All probes removed\n");
++      test_and_clear_bit(0, &emergency_remove);
++      return;
++}
++
++static void dprobes_sysrq( int key, struct pt_regs *ptr, struct tty_struct *tty) 
++{
++
++      int retval;
++      retval = test_and_set_bit(0,&emergency_remove);
++      if (!retval) 
++              queue_work(dprobes_wq, &dprobes_work);
++      return;
++
++}
++#endif
++
++static int __init dprobes_init_module(void)
++{
++      int retval = 0;
++
++      dprobes_major = register_chrdev(0, "dprobes", &dprobes_ops);
++      if (dprobes_major < 0) {
++              printk("Failed to register dprobes device\n");
++              retval = dprobes_major;
++              goto err;
++      }
++
++      printk("IBM Dynamic Probes v%d.%d.%d loaded.\n", DP_MAJOR_VER, 
++                      DP_MINOR_VER, DP_PATCH_VER);
++
++#ifdef CONFIG_MAGIC_SYSRQ
++      if (!(dprobes_wq = create_workqueue("dprobes_wq"))) {
++              printk("dprobes create_workqueue failed\n");
++              retval = -ENOMEM;
++              goto err;
++      }
++      INIT_WORK(&dprobes_work, (void *)(void *)do_remove_sysrq, NULL);
++      if ((retval = register_sysrq_key('v', &key_op)))
++              printk("<1>register_sysrq_key returned %i\n", retval);
++#endif
++
++err:  return retval;
++}
++
++static void __exit dprobes_cleanup_module(void)
++{
++      int retval;
++      unregister_chrdev(dprobes_major, "dprobes");
++      
++      printk("IBM Dynamic Probes v%d.%d.%d unloaded.\n", DP_MAJOR_VER, 
++                      DP_MINOR_VER, DP_PATCH_VER);
++
++#ifdef CONFIG_MAGIC_SYSRQ        
++      destroy_workqueue(dprobes_wq);
++      if ((retval = unregister_sysrq_key('v', &key_op)))
++              printk("<1>unregister_sysrq_key returned %i\n", retval);
++#endif   
++      return;
++}
++
++module_init(dprobes_init_module);
++module_exit(dprobes_cleanup_module);
++
++MODULE_AUTHOR("IBM");
++MODULE_DESCRIPTION("Dynamic Probes");
++MODULE_LICENSE("GPL");
++
++void dprobes_code_end(void) { }
+diff -urNp linux-2.6.0-test9/drivers/dprobes/dprobes_in.c linux-2.6.0-test9+kp/drivers/dprobes/dprobes_in.c
+--- linux-2.6.0-test9/drivers/dprobes/dprobes_in.c     1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.0-test9+kp/drivers/dprobes/dprobes_in.c  2003-11-18 07:29:47.000000000 +0530
+@@ -0,0 +1,2014 @@
++/*
++ * IBM Dynamic Probes
++ * Copyright (c) International Business Machines Corp., 2000
++ *
++ * 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.  
++ */
++
++#include <linux/dprobes.h>
++#include <linux/dprobes_in.h>
++#include <asm/io.h>
++#include <asm/uaccess.h>
++
++static void dispatch_ex(void);
++static void gen_ex(unsigned long, unsigned long, unsigned long);
++static void log_st(void);
++
++void dprobes_interpreter_code_start(void) { }
++
++/*
++ * RPN stack manipulation
++ * Pushes a 32 bit number onto RPN stack.
++ */
++static inline void rpnpush(unsigned long arg)
++{
++      dprobes.rpn_tos--;
++      dprobes.rpn_tos &= RPN_STACK_SIZE - 1;
++      dprobes.rpn_stack[dprobes.rpn_tos] = arg;
++}
++
++/*
++ * Pops a 32 bit number from RPN stack.
++ */
++static inline unsigned long rpnpop(void)
++{
++      unsigned long ret = dprobes.rpn_stack[dprobes.rpn_tos];
++      dprobes.rpn_tos++;
++      dprobes.rpn_tos &= RPN_STACK_SIZE - 1;
++      return ret;
++}
++
++/*
++ * Returns a 32 bit number for RPN stack at a given position
++ * relative to RPN TOS, without poping.
++ */
++static unsigned long rpnmove(unsigned long pos)
++{
++      unsigned long index = dprobes.rpn_tos + pos;
++      index &= RPN_STACK_SIZE - 1;
++      return dprobes.rpn_stack[index];
++}
++
++/*
++ * Returns a byte(8 bit) operand from rpn code array
++ */
++static inline u8 get_u8_oprnd(void)
++{
++      return *dprobes.rpn_ip++;
++}
++
++
++/*
++ * Returns a word(16 bit) operand from rpn code array
++ */
++static inline u16 get_u16_oprnd(void)
++{
++      return *(((u16 *)dprobes.rpn_ip)++);
++}
++
++/*
++ * Returns an unsigned long operand from rpn code array
++ */
++static inline unsigned long get_ulong_oprnd(void)
++{
++      unsigned long dw;
++      dw = *((unsigned long *) (dprobes.rpn_ip));
++      dprobes.rpn_ip += sizeof(unsigned long);
++      return dw;
++}
++
++/*
++ * Returns a signed long(32 bit) operand from rpn code array
++ */
++static inline long get_long_oprnd(void)
++{
++      long l;
++      l = *((long *) (dprobes.rpn_ip));
++      dprobes.rpn_ip += sizeof(long);
++      return l;
++}
++
++#ifdef CONFIG_X86
++#include "i386/dprobes_in.c"
++#endif
++
++/*
++ * Jump instructions.
++ * Interpreter is terminated when total number of jumps and loops
++ * becomes equal to jmpmax.
++ */
++static void jmp(void)
++{
++      long offset = get_long_oprnd();
++      if (dprobes.jmp_count == dprobes.mod->pgm.jmpmax) {
++              gen_ex(EX_MAX_JMPS, dprobes.mod->pgm.jmpmax, 0);
++              return;
++      }       
++      dprobes.jmp_count++;
++      dprobes.rpn_ip += offset;
++}
++
++#define COND_JMPS(name, condition) \
++static void name(void) \
++{ \
++      long offset = get_long_oprnd(); \
++      if ((long) dprobes.rpn_stack[dprobes.rpn_tos] condition 0) { \
++              if (dprobes.jmp_count == dprobes.mod->pgm.jmpmax) { \
++                      gen_ex(EX_MAX_JMPS, dprobes.mod->pgm.jmpmax, 0); \
++                      return; \
++              } \
++              dprobes.jmp_count++; \
++              dprobes.rpn_ip += offset; \
++      } \
++}
++
++COND_JMPS(jlt, <)
++COND_JMPS(jgt, >)
++COND_JMPS(jle, <=)
++COND_JMPS(jge, >=)
++COND_JMPS(jz, ==)
++COND_JMPS(jnz, !=)
++      
++/*
++ * loop label: Decrement RPN TOS and jump to the label
++ * if TOS is not equal to 0.
++ * Interpreter is terminated when total number of jumps and loops
++ * becomes equal to jmpmax.
++ */
++static void loop(void)
++{
++      long offset = get_long_oprnd();
++      if (dprobes.jmp_count++ == dprobes.mod->pgm.jmpmax) {
++              gen_ex(EX_MAX_JMPS, dprobes.mod->pgm.jmpmax, 0);
++              return;
++      }
++      if ((long) (--dprobes.rpn_stack[dprobes.rpn_tos]) != 0)
++              dprobes.rpn_ip += offset;
++}
++
++/*
++ * Call and ret instructions. Number of nested calls is limited to 32.
++ */
++static void call(void)
++{
++      int i;
++      struct dprobes_struct *dp = &dprobes;
++      long offset = (long)get_long_oprnd();
++      unsigned long called_addr = (dp->rpn_ip - dp->rpn_code + offset);
++      if (dp->call_tos < CALL_FRAME_SIZE) {
++              gen_ex(EX_CALL_STACK_OVERFLOW, NR_NESTED_CALLS, 0);
++              return;
++      }
++      /*
++       * Push the return value(rpn_ip) onto the call stack.
++       */
++      dp->call_stack[--dp->call_tos] = dp->rpn_ip - dp->rpn_code;
++      dp->rpn_ip += offset;
++      /* 
++       * push the called subroutine address, default exception handler
++       * address, and initialize pv, lv and gv range to zeros.
++       */             
++      dp->call_stack[--dp->call_tos] = called_addr;
++      dp->call_stack[--dp->call_tos] = EX_NO_HANDLER;
++
++      for (i = 0; i < CALL_FRAME_SIZE - 4; i++)
++              dp->call_stack[--dp->call_tos] = 0;
++      /* Save the rpn stack base pointer */
++      dp->call_stack[--dp->call_tos] = dp->rpn_sbp;   
++}
++
++/*
++ * Pops the return value into rpn_ip.
++ */
++static void ret(void)
++{
++      struct dprobes_struct *dp = &dprobes;
++      if (dp->call_tos >= CALL_STACK_SIZE - CALL_FRAME_SIZE) {
++              gen_ex(EX_CALL_STACK_OVERFLOW, 0, 0);
++              return;
++      }
++      dp->rpn_sbp = dp->call_stack[dp->call_tos++];
++      dp->call_tos += CALL_FRAME_SIZE - 2;
++      /* pop the return address */
++      dp->rpn_ip = dp->rpn_code + dp->call_stack[dp->call_tos++];
++
++      if (dp->ex_pending) {
++              dp->ex_hand = dp->call_stack[dp->call_tos + 
++                              OFFSET_EX_HANDLER];
++              dispatch_ex();
++      }
++}
++
++/*
++ * Exception handling instructions.
++ */
++static void sx(void)
++{
++      long offset = get_long_oprnd();
++      dprobes.call_stack[dprobes.call_tos + OFFSET_EX_HANDLER] = 
++                              (long)dprobes.rpn_ip + offset;
++}
++      
++static void ux(void)
++{
++      dprobes.call_stack[dprobes.call_tos + OFFSET_EX_HANDLER] = 
++                                                      EX_NO_HANDLER;
++}
++
++static void dispatch_ex(void)
++{
++      struct dprobes_struct *dp = &dprobes;
++      long ex_handler;
++      /* We are at the outermost routine & no exception handler, terminate */
++      if ((dp->call_tos == CALL_STACK_SIZE - CALL_FRAME_SIZE) && 
++              (dp->call_stack[dp->call_tos + OFFSET_EX_HANDLER] == 
++                      EX_NO_HANDLER)) {
++              dp->status &= ~DP_STATUS_INTERPRETER;
++              return;
++      }
++      ex_handler = dp->ex_hand;
++      if (ex_handler != EX_NO_HANDLER) {
++              dp->ex_pending = 0;
++              dp->call_stack[dp->call_tos + OFFSET_EX_HANDLER] = 
++                                      EX_NO_HANDLER;
++              dp->rpn_ip = (byte_t *)ex_handler;
++      }
++      else {
++              ret();
++      }
++}
++
++static void rx(void)
++{
++      struct dprobes_struct *dp = &dprobes;
++      dp->ex_code = rpnmove(0);
++      dp->ex_parm1 = rpnmove(1);
++      dp->ex_parm2 = rpnmove(2);
++      dp->ex_pending = 1;
++      dp->ex_hand = dp->call_stack[dp->call_tos + 
++                                      OFFSET_EX_HANDLER];
++      if (dp->rec->mod->pgm.autostacktrace)
++              log_st();
++      dispatch_ex();
++}
++
++static void push_x(void)
++{
++      rpnpush(dprobes.ex_parm2);
++      rpnpush(dprobes.ex_parm1);
++      rpnpush(dprobes.ex_code);
++}
++
++static void gen_ex(unsigned long ex_code, unsigned long parm1, 
++              unsigned long parm2)
++{
++      struct dprobes_struct *dp = &dprobes;
++        if (ex_code & dp->rec->point.ex_mask) {
++              dp->ex_code = ex_code;
++              dp->ex_parm1 = parm1;
++              dp->ex_parm2 = parm2;
++              rpnpush(parm2);
++              rpnpush(parm1);
++              rpnpush(ex_code);
++              dp->ex_pending = 1;
++              dp->ex_hand = dp->call_stack[dp->call_tos + 
++                              OFFSET_EX_HANDLER];
++              if (dp->rec->mod->pgm.autostacktrace) {
++                      log_st();
++              }
++                dispatch_ex();
++        } else if (ex_code & EX_NON_MASKABLE_EX) {
++              dp->ex_hand = dp->call_stack[dp->call_tos + 
++                              OFFSET_EX_HANDLER];
++              if (dp->rec->mod->pgm.autostacktrace)
++                      log_st();
++                dp->status &= ~DP_STATUS_INTERPRETER;
++        }
++}
++
++static int write_st_buffer(unsigned char *ptr, int size)
++{
++      if (dprobes.ex_log_len + size >= dprobes.mod->pgm.ex_logmax)
++              return -1;
++      else {
++              memcpy(dprobes.ex_log + dprobes.ex_log_len, ptr, size);
++              dprobes.ex_log_len += size;
++              return 0;
++      }
++}
++
++static int log_gv_entries(unsigned long call_tos)
++{
++      struct dprobes_struct *dp = &dprobes;
++      unsigned char gv_prefix[PREFIX_SIZE] = {TOKEN_GV_ENTRY, 0, 0};
++      unsigned long range = dp->call_stack[call_tos + OFFSET_GV_RANGE];
++      unsigned long index = dp->call_stack[call_tos + OFFSET_GV_RANGE + 1];
++      int i;
++      dp->ex_off.gv = dp->ex_log_len + 1;
++      if (write_st_buffer(gv_prefix, PREFIX_SIZE))
++              return -1;
++      for (i = index; i < index + range; i++) {
++              if (i >= dp_num_gv) {
++                      dp->status &= ~DP_STATUS_INTERPRETER;
++                      return -1;
++              }
++              read_lock(&dp_gv_lock);
++              if (write_st_buffer((unsigned char *)(dp_gv + i), sizeof(unsigned long))) {
++                      read_unlock(&dp_gv_lock);
++                      return -1;
++              }
++              read_unlock(&dp_gv_lock);
++              (*(unsigned short *)(dp->ex_log + dp->ex_off.gv))++;
++      }
++      return 0;
++}
++
++static int log_lv_entries(unsigned long call_tos)
++{
++      struct dprobes_struct *dp = &dprobes;
++      unsigned char lv_prefix[PREFIX_SIZE] = {TOKEN_LV_ENTRY, 0, 0};
++      unsigned long range = dp->call_stack[call_tos + OFFSET_LV_RANGE];
++      unsigned long index = dp->call_stack[call_tos + OFFSET_LV_RANGE + 1];
++      int i;
++      dp->ex_off.lv = dp->ex_log_len + 1;
++      if (write_st_buffer(lv_prefix, PREFIX_SIZE))
++              return -1;
++      for (i = index; i < index + range; i++) {
++              if (i >= dp->rec->mod->pgm.num_lv) {
++                      dp->status &= ~DP_STATUS_INTERPRETER;
++                      return -1;
++              }
++              if (write_st_buffer((unsigned char *)(dp->mod->lv + i), sizeof(unsigned long))) 
++                      return -1;
++              (*(unsigned short *)(dp->ex_log + dp->ex_off.lv))++;
++      }
++      return 0;
++}
++
++static int log_rpnstack_entries(unsigned long call_tos)
++{
++      struct dprobes_struct *dp = &dprobes;
++      unsigned char rpn_prefix[PREFIX_SIZE] = {TOKEN_RPN_ENTRY, 0, 0};
++      unsigned long range = dp->call_stack[call_tos + 
++                                              OFFSET_RPN_STACK_RANGE];
++      unsigned long index = dp->call_stack[call_tos + 
++                                              OFFSET_RPN_STACK_RANGE + 1];
++      int i, j;
++      dp->ex_off.rpn = dp->ex_log_len + 1;
++      if (write_st_buffer(rpn_prefix, PREFIX_SIZE))
++              return -1;
++      for (i = j = index; i < index + range; i++, j++) {
++              j &= (RPN_STACK_SIZE - 1);
++              if (write_st_buffer((unsigned char *)(dp->rpn_stack + j), 
++                              sizeof(unsigned long)))
++                      return -1;
++              (*(unsigned short *)(dp->ex_log + dp->ex_off.rpn))++;
++      }       
++      return 0;
++}
++
++static int log_stackframes(void)
++{
++      struct dprobes_struct *dp = &dprobes;
++      unsigned long c_tos = dp->call_tos;
++      unsigned char sf_prefix[PREFIX_SIZE] = {TOKEN_STACK_FRAME, 0, 0};
++      dp->ex_off.sf = dp->ex_log_len + 1;
++      if (write_st_buffer(sf_prefix, PREFIX_SIZE))
++              return -1;
++      
++      while (c_tos < (CALL_STACK_SIZE - CALL_FRAME_SIZE)) {
++              if (write_st_buffer((unsigned char *)(dp->call_stack + 
++                      c_tos + OFFSET_CALLED_ADDR), sizeof(unsigned long)))
++                      return -1;
++              if (write_st_buffer((unsigned char *)(dp->call_stack +
++                      c_tos + OFFSET_RETURN_ADDR), sizeof(unsigned long)))
++                      return -1;
++
++              if (log_rpnstack_entries(c_tos))
++                      return -1;
++              if (log_lv_entries(c_tos))
++                      return -1;
++              if (log_gv_entries(c_tos))
++                      return -1;
++
++              (*(short *)(dp->ex_log + dp->ex_off.sf))++;
++              c_tos += CALL_FRAME_SIZE;
++      }
++      return 0;
++}
++
++static int log_stacktrace(void)
++{
++      struct dprobes_struct *dp = &dprobes;
++      long ex_handler;
++      if (write_st_buffer((unsigned char *)&dp->ex_code, sizeof(unsigned long)))
++              return -1;
++      ex_handler = dp->ex_hand;
++      if (ex_handler != EX_NO_HANDLER)
++              ex_handler -= (long)dp->rpn_code;
++      if (write_st_buffer((unsigned char *)&ex_handler, sizeof(long)))
++              return -1;
++      if (write_st_buffer((unsigned char *)&dp->ex_parm1, sizeof(unsigned long)))
++              return -1;
++      if (write_st_buffer((unsigned char *)&dp->ex_parm2, sizeof(unsigned long)))
++              return -1;
++      if (log_stackframes())
++              return -1;
++      (*(short *)(dp->ex_log + dp->ex_off.st))++;
++      return 0;
++}
++
++static int get_exlog_hdr(void)
++{
++      unsigned short name_len;
++      unsigned char st_prefix[PREFIX_SIZE] = {TOKEN_STACK_TRACE, 0, 0};
++      struct dprobes_struct *dp = &dprobes;
++
++      strcpy(dp->ex_log + dp->ex_log_len + PREFIX_SIZE, dp->mod->pgm.name);
++      name_len = strlen(dp->mod->pgm.name);
++      dp->ex_log[dp->ex_log_len] = TOKEN_ASCII_LOG;
++      *(unsigned short *)(dp->ex_log + dp->ex_log_len + 1) = name_len;
++      dp->ex_log_len += (name_len + PREFIX_SIZE);
++
++      *(loff_t *)(dp->ex_log + dp->ex_log_len) = 
++                      dp->rec->point.offset;
++      dp->ex_log_len += sizeof(loff_t);
++      
++      *(unsigned short *)(dp->ex_log + dp->ex_log_len) = 
++                      dp->mod->pgm.id;
++      dp->ex_log_len += sizeof(unsigned short);
++
++      *(unsigned short *)(dp->ex_log + dp->ex_log_len) = 
++                      dp->major;
++      dp->ex_log_len += sizeof(unsigned short);
++      
++      *(unsigned short *)(dp->ex_log + dp->ex_log_len) = 
++                      dp->minor;
++      dp->ex_log_len += sizeof(unsigned short);
++
++      dp->ex_off.st = dp->ex_log_len + 1;
++      if (write_st_buffer(st_prefix, PREFIX_SIZE))
++              return -1;
++      return 0;
++}
++
++static void log_st(void)
++{
++      if (dprobes.ex_log_len == MIN_ST_SIZE)
++              if(get_exlog_hdr()) return;
++      log_stacktrace();
++}
++
++static void purge_st(void)
++{
++      dprobes.ex_log_len = MIN_ST_SIZE;
++}
++
++static void trace_lv(void)
++{
++      dprobes.call_stack[dprobes.call_tos + OFFSET_LV_RANGE] = rpnpop();
++      dprobes.call_stack[dprobes.call_tos + OFFSET_LV_RANGE + 1] = rpnpop();
++}
++
++static void trace_gv(void)
++{
++      dprobes.call_stack[dprobes.call_tos + OFFSET_GV_RANGE] = rpnpop();
++      dprobes.call_stack[dprobes.call_tos + OFFSET_GV_RANGE + 1] = rpnpop();
++}
++
++static void trace_pv(void)
++{
++      dprobes.call_stack[dprobes.call_tos + OFFSET_RPN_STACK_RANGE] = 
++                                                              rpnpop();
++      dprobes.call_stack[dprobes.call_tos + OFFSET_RPN_STACK_RANGE + 1] =
++                                                              rpnpop();
++}
++
++static void push_tsp(void)
++{
++      long index = (long)rpnpop();
++      unsigned long tsp_index = ((signed)dprobes.rpn_tos + index) 
++                                      & (RPN_STACK_SIZE - 1);
++      rpnpush(dprobes.rpn_stack[tsp_index]);
++}
++
++static void pop_tsp(void)
++{
++      unsigned long value = rpnpop();
++      long index = (long)rpnpop();
++      unsigned long tsp_index = ((signed)dprobes.rpn_tos + index) 
++                                      & (RPN_STACK_SIZE - 1);
++      dprobes.rpn_stack[tsp_index] = value;
++}
++
++static void save_sbp(void)
++{
++      rpnpush(dprobes.rpn_sbp);
++}
++
++static void restore_sbp(void)
++{
++      dprobes.rpn_sbp = rpnpop() & (RPN_STACK_SIZE - 1);
++}
++
++static void save_tsp(void)
++{
++      rpnpush(dprobes.rpn_tos);
++}
++
++static void restore_tsp(void)
++{
++      dprobes.rpn_tos = rpnpop();
++}
++
++static void push_sbp(void)
++{
++      long index = (long)rpnpop();
++      unsigned long sbp_index = ((signed)dprobes.rpn_sbp + index) 
++                                      & (RPN_STACK_SIZE - 1);
++      rpnpush(dprobes.rpn_stack[sbp_index]);
++}
++
++static void pop_sbp(void)
++{
++      unsigned long value = rpnpop();
++      long index = (long)rpnpop();
++      unsigned long sbp_index = ((signed)dprobes.rpn_sbp + index) 
++                                      & (RPN_STACK_SIZE - 1);
++      dprobes.rpn_stack[sbp_index] = value;
++}
++
++static void push_stp(void)
++{
++      rpnpush(dprobes.ex_log_len);
++}
++
++static void pop_stp(void)
++{
++      dprobes.ex_log_len = rpnpop();
++}
++
++static void push_sbp_i(void)
++{
++      s16 index = (s16)get_u16_oprnd();
++      unsigned long sbp_index = ((signed)dprobes.rpn_sbp + index) 
++                                      & (RPN_STACK_SIZE - 1);
++      rpnpush(dprobes.rpn_stack[sbp_index]);
++}
++
++static void pop_sbp_i(void)
++{
++      s16 index = (s16)get_u16_oprnd();
++      unsigned long sbp_index = ((signed)dprobes.rpn_sbp + index) 
++                                      & (RPN_STACK_SIZE - 1);
++      dprobes.rpn_stack[sbp_index] = rpnpop();
++}
++
++static void push_tsp_i(void)
++{
++      s16 index = (s16)get_u16_oprnd();
++      unsigned long tsp_index = ((signed)dprobes.rpn_tos + index) 
++                                      & (RPN_STACK_SIZE - 1);
++      rpnpush(dprobes.rpn_stack[tsp_index]);
++}
++
++static void pop_tsp_i(void)
++{
++      s16 index = (s16)get_u16_oprnd();
++      unsigned long tsp_index = ((signed)dprobes.rpn_tos + index) 
++                                      & (RPN_STACK_SIZE - 1);
++      dprobes.rpn_stack[tsp_index] = rpnpop();
++}
++
++static void copy_sbp(void)
++{
++      long index = (long)rpnpop();
++      unsigned long sbp_index = ((signed)dprobes.rpn_sbp + index) 
++                                      & (RPN_STACK_SIZE - 1);
++      dprobes.rpn_stack[sbp_index] = dprobes.rpn_stack[dprobes.rpn_tos];
++}
++
++static void copy_sbp_i(void)
++{
++      s16 index = (s16)get_u16_oprnd();
++      unsigned long sbp_index = ((signed)dprobes.rpn_sbp + index) 
++                                      & (RPN_STACK_SIZE - 1);
++      dprobes.rpn_stack[sbp_index] = dprobes.rpn_stack[dprobes.rpn_tos];
++}
++
++static void copy_tsp(void)
++{
++      long index = (long)rpnpop();
++      unsigned long tsp_index = ((signed)dprobes.rpn_tos + index) 
++                                      & (RPN_STACK_SIZE - 1);
++      dprobes.rpn_stack[tsp_index] = dprobes.rpn_stack[dprobes.rpn_tos];
++}
++
++static void copy_tsp_i(void)
++{
++      s16 index = (s16)get_u16_oprnd();
++      unsigned long tsp_index = ((signed)dprobes.rpn_tos + index) 
++                                      & (RPN_STACK_SIZE - 1);
++      dprobes.rpn_stack[tsp_index] = dprobes.rpn_stack[dprobes.rpn_tos];
++}
++
++/* 
++ * Normal exit from the interpreter. 
++ */
++static inline void dp_exit(void)
++{
++      dprobes.status &= ~DP_STATUS_INTERPRETER;
++}
++
++/*
++ * Exit the interpreter without producing the log.
++ */
++static inline void dp_abort(void)
++{
++      dprobes.status |= DP_STATUS_ABORT;
++      dprobes.status &= ~DP_STATUS_INTERPRETER;
++}
++
++static inline void dp_remove(void)
++{
++      dprobes.rec->status |= DP_REC_STATUS_REMOVED;
++      dprobes.status &= ~DP_STATUS_INTERPRETER;
++}
++
++static inline void no_op(void)
++{
++}
++
++/*
++ * Stores the fault record in the log buffer, when logging is
++ * terminated due to invalid memory access.
++ * Fault record comprises of a token byte, which indicates the reason for 
++ * fault; an unsigned short length indicating how many bytes are logged, 
++ * which is 4; and the 4 logged bytes indicate the faulting address.
++ *
++ * Token byte -1: fault occurred while reading the memory, faulting address
++ * indicates the virtual(flat) address which caused the fault.
++ * Token byte -2: fault occurred when converting the segmented address to
++ * flat address. The fault address stored will indicate the selector of
++ * the segmented address.
++ * Note that the fault record will be stored only if sufficient space
++ * is available to store the entire fault record.
++ *
++ * The fault record will be stored when fault occurs because of the
++ * following instructions:
++ *    log mrf
++ *    log str
++ */
++static void store_fault_record(byte_t token, unsigned long addr, 
++      unsigned long ex_code)
++{
++      struct dprobes_struct *dp = &dprobes;
++      if (dp->log_len + 7 <= dp->mod->pgm.logmax) {
++              dp->log[dp->log_len++] = token;
++              *((unsigned short *)(dp->log + dp->log_len)) = 4;
++              dp->log_len += sizeof(unsigned short);
++              *((unsigned long *)(dp->log + dp->log_len)) = addr;
++              dp->log_len += sizeof(unsigned long);
++              gen_ex(ex_code, addr, 0);
++      }
++      else
++              gen_ex(EX_LOG_OVERFLOW, dp->mod->pgm.logmax, 0);
++      return;
++}
++
++/*
++ * Logging group
++ */
++static inline void push_lp(void) 
++{
++      rpnpush(dprobes.log_len);
++}
++
++static inline void push_plp(void) 
++{
++      rpnpush(dprobes.prev_log_len);
++}
++
++static inline void pop_lp(void) 
++{
++      dprobes.log_len = rpnpop();
++}
++
++static void 
++log_ascii(unsigned long len, u8 *faddr)
++{
++      struct dprobes_struct *dp = &dprobes;
++      u8 b;
++      dp->prev_log_len = dp->log_len;
++      if (dp->log_len + len + PREFIX_SIZE > dp->mod->pgm.logmax) {
++              len = dp->mod->pgm.logmax - dp->log_len;
++              if ((signed)len < 0) {
++                      gen_ex(EX_LOG_OVERFLOW, dp->mod->pgm.logmax, 0);
++                      return;
++              }
++      }
++      dp->log_len += PREFIX_SIZE; /* reserve for prefix */
++      while (len--) {
++              if (!dp_intr_copy_from_user(&b, (void *)faddr, 1)) {
++                      if(b) {
++                              faddr++;
++                              dp->log[dp->log_len++] = b;
++                      } else 
++                              break;
++
++              } else {
++                      dp->log_len = dp->prev_log_len;
++                      store_fault_record(TOKEN_MEMORY_FAULT, 
++                                      (unsigned long)faddr, EX_INVALID_ADDR);
++                      return;
++              }
++      }
++      if (b && (signed)len >= 0) {
++              dp->status |= DP_STATUS_LOG_OVERFLOW;
++              dp->log_len = dp->prev_log_len;
++              gen_ex(EX_LOG_OVERFLOW, dp->mod->pgm.logmax, 0);
++              return;
++      }
++      dp->log[dp->prev_log_len] = TOKEN_ASCII_LOG;
++      *(unsigned short *) (dp->log + dp->prev_log_len + 1) =
++              (unsigned short) (dp->log_len - dp->prev_log_len - PREFIX_SIZE);
++      dp->prev_log_len = dp->log_len;
++      return;
++}
++
++static void
++log_memory(unsigned long len, u8 *faddr)
++{
++      struct dprobes_struct *dp = &dprobes;
++      unsigned long num_remain;
++      dp->prev_log_len = dp->log_len;
++      if (dp->log_len + len + PREFIX_SIZE > dp->mod->pgm.logmax) {
++              dp->status |= DP_STATUS_LOG_OVERFLOW;
++              len = dp->mod->pgm.logmax - dp->log_len - PREFIX_SIZE;
++              if ((signed)len < 0) {
++                      gen_ex(EX_LOG_OVERFLOW, dp->mod->pgm.logmax, 0);
++                      return;
++              }
++      }
++
++      if ((num_remain = dp_intr_copy_from_user(
++              (dp->log + dp->log_len + PREFIX_SIZE), faddr, len))) {
++              store_fault_record(TOKEN_MEMORY_FAULT, 
++              (unsigned long)(faddr+len-num_remain), EX_INVALID_ADDR);
++              return;
++      }
++
++      dp->log[dp->log_len++] = TOKEN_MEMORY_LOG;
++      *((unsigned short *)(dp->log + dp->log_len)) = len;
++      dp->log_len += (len + sizeof(unsigned short));
++      dp->prev_log_len = dp->log_len;
++      return;
++}
++
++/* log str pops the flat address and length from
++ * the RPN stack. It tries to copy length number of
++ * bytes from flat address to the log buffer.
++ * Logging is discontinued if a NULL byte is encountered.
++ * NULL byte is not logged. If the log buffer becomes full
++ * LOG_OVERFLOW exception is generated.
++ * If the log is successful, the logged string is prefixed
++ * by a token byte of 1 and a word indicating the length of
++ * the string logged.
++ * INVALID_ADDR exception is generated if the flat address is invalid.
++ */ 
++static void log_str(void)
++{
++      u8 *faddr = (u8 *) rpnpop();
++      log_ascii(rpnpop(), faddr);
++}
++
++/*
++ * Log memory at flat range.
++ * INVALID_ADDR exception is generated if flat address is invalid.
++ * Log terminating conditions apply.
++ * token byte = 0.
++ */
++static void log_mrf(void)
++{
++        u8 *faddr = (u8 *) rpnpop();
++      log_memory(rpnpop(), faddr);
++}
++
++/* 
++ * Log count number of elements from rpn stack to log buffer.
++ */
++static void log_i(void)
++{
++      struct dprobes_struct *dp = &dprobes;
++      u16 oprnd = get_u16_oprnd();
++      u16 count, i;
++      unsigned long size = oprnd * sizeof(unsigned long);
++      dp->prev_log_len = dp->log_len;
++
++      if (dp->log_len + size > dp->mod->pgm.logmax) {
++              size = dp->mod->pgm.logmax - dp->log_len;
++      }
++      if ((signed)size < 0) {
++              gen_ex(EX_LOG_OVERFLOW, dp->mod->pgm.logmax, 0);
++              return;
++      }
++      i = count = size / sizeof(unsigned long);
++      while (i--) {
++              *(unsigned long *) (dp->log + dp->log_len) = rpnpop();
++              dp->log_len += sizeof(unsigned long);
++        }
++      if (count < oprnd) {
++              gen_ex(EX_LOG_OVERFLOW, dp->mod->pgm.logmax, 0);
++              return;
++      }
++        dp->prev_log_len = dp->log_len;
++}
++
++static void log(void)
++{
++      struct dprobes_struct *dp = &dprobes;
++      u16 oprnd = (u16) rpnpop();
++      u16 count, i;
++      unsigned long size = oprnd * sizeof(unsigned long) + PREFIX_SIZE;
++      dp->prev_log_len = dp->log_len;
++
++      if (dp->log_len + size > dp->mod->pgm.logmax) {
++              size = dp->mod->pgm.logmax - dp->log_len;
++      }
++      if ((signed)size < PREFIX_SIZE) {
++              gen_ex(EX_LOG_OVERFLOW, dp->mod->pgm.logmax, 0);
++              return;
++      }
++      dp->log_len += PREFIX_SIZE;
++      size -= PREFIX_SIZE;
++      i = count = size / sizeof(unsigned long);
++
++      while (i--) {
++              *(unsigned long *) (dp->log + dp->log_len) = rpnpop();
++              dp->log_len += sizeof(unsigned long);
++        }
++
++      dp->log[dp->prev_log_len] = TOKEN_LOG;
++      *(unsigned short *) (dp->log + dp->prev_log_len + 1) =
++              (unsigned short) (count);
++
++      if (count < oprnd) {
++              gen_ex(EX_LOG_OVERFLOW, dp->mod->pgm.logmax, 0);
++              return;
++      }
++      dp->prev_log_len = dp->log_len;
++}
++
++static void log_lv(void)
++{
++      struct dprobes_struct *dp = &dprobes;
++      unsigned long range = rpnpop();
++      unsigned long index = rpnpop();
++      unsigned long offset;
++      unsigned char lv_prefix[PREFIX_SIZE] = {TOKEN_LV_ENTRY, 0, 0};
++      int i;
++
++      if (dp->log_len + PREFIX_SIZE > dp->mod->pgm.logmax) {
++              gen_ex(EX_LOG_OVERFLOW, dp->mod->pgm.logmax, 0);
++              return;
++      }
++      memcpy(dp->log + dp->log_len, lv_prefix, PREFIX_SIZE);
++      offset = dp->log_len + 1;
++      dp->log_len += PREFIX_SIZE;
++
++      for (i = index; i < index + range; i++) {
++              if (i >= dp->rec->mod->pgm.num_lv) {
++                      gen_ex(EX_INVALID_OPERAND, 1, i);
++                      return;
++              }
++              if (dp->log_len + sizeof (unsigned long) > dp->mod->pgm.logmax) {
++                      gen_ex(EX_LOG_OVERFLOW, dp->mod->pgm.logmax, 0);
++                      return;
++              }
++              *(unsigned long *) (dp->log + dp->log_len) = 
++                              *(dp->mod->lv + i);
++              dp->log_len += sizeof(unsigned long);
++              (*(unsigned short *)(dp->log + offset))++;
++      }
++      return;
++}
++
++static void log_gv(void)
++{
++      struct dprobes_struct *dp = &dprobes;
++      unsigned long range = rpnpop();
++      unsigned long index = rpnpop();
++      unsigned long offset;
++      unsigned char gv_prefix[PREFIX_SIZE] = {TOKEN_GV_ENTRY, 0, 0};
++      int i;
++
++      if (dp->log_len + PREFIX_SIZE > dp->mod->pgm.logmax) {
++              gen_ex(EX_LOG_OVERFLOW, dp->mod->pgm.logmax, 0);
++              return;
++      }
++      memcpy(dp->log + dp->log_len, gv_prefix, PREFIX_SIZE);
++      offset = dp->log_len + 1;
++      dp->log_len += PREFIX_SIZE;
++
++      for (i = index; i < index + range; i++) {
++              if (i >= dp_num_gv) {
++                      gen_ex(EX_INVALID_OPERAND, 2, i);
++                      return;
++              }
++              if (dp->log_len + sizeof (unsigned long) > dp->mod->pgm.logmax) {
++                      gen_ex(EX_LOG_OVERFLOW, dp->mod->pgm.logmax, 0);
++                      return;
++              }
++              read_lock(&dp_gv_lock);
++              *(unsigned long *) (dp->log + dp->log_len) = 
++                              *(dp_gv + i);
++              read_unlock(&dp_gv_lock);
++              dp->log_len += sizeof(unsigned long);
++              (*(unsigned short *)(dp->log + offset))++;
++      }
++      return;
++}
++
++/*
++ * Overriding probepoint major and minor.
++ */
++static void setmin_i(void)
++{
++      dprobes.minor = get_u16_oprnd();
++}
++
++static void setmin(void)
++{
++      dprobes.minor = (unsigned short) rpnpop();
++}
++
++static void setmaj_i(void)
++{
++      dprobes.major = get_u16_oprnd();
++}
++
++static void setmaj(void)
++{
++      dprobes.major = (unsigned short) rpnpop();
++}
++
++/*
++ * Local Variables.
++ */
++
++static void do_push_lv(unsigned short index)
++{
++      if (index > dprobes.rec->mod->pgm.num_lv)
++              gen_ex(EX_INVALID_OPERAND, 1, index);
++      else
++              rpnpush(*(dprobes.mod->lv + index));
++}
++
++static void push_lvi(void)
++{
++      do_push_lv(get_u16_oprnd());
++}
++
++static void push_lv(void)
++{
++      do_push_lv(rpnpop());
++}
++
++static void pop_lvi(void)
++{
++      unsigned short index = get_u16_oprnd();
++        if (index > dprobes.rec->mod->pgm.num_lv)
++                gen_ex(EX_INVALID_OPERAND, 1, index);
++        else
++              *(dprobes.mod->lv + index) = rpnpop();
++}
++
++static void pop_lv(void)
++{
++      unsigned long value = rpnpop();
++      unsigned short index = (unsigned short) rpnpop();
++        if (index > dprobes.rec->mod->pgm.num_lv)
++                gen_ex(EX_INVALID_OPERAND, 1, index);
++        else
++              *(dprobes.mod->lv + index) = value;
++}
++
++static void do_inc_lv(unsigned short index)
++{
++      if (index > dprobes.rec->mod->pgm.num_lv)
++              gen_ex(EX_INVALID_OPERAND, 1, index);
++      else
++              (*(dprobes.mod->lv + index))++;
++}
++
++static void inc_lvi(void)
++{
++      do_inc_lv(get_u16_oprnd());
++}
++
++static void inc_lv(void)
++{
++      do_inc_lv(rpnpop());
++}
++                                              
++static void do_dec_lv(unsigned short index)
++{
++      if (index > dprobes.rec->mod->pgm.num_lv)
++              gen_ex(EX_INVALID_OPERAND, 1, index);
++      else
++              (*(dprobes.mod->lv + index))--;
++}
++
++static void dec_lvi(void)
++{
++      do_dec_lv(get_u16_oprnd());
++}
++
++static void dec_lv(void)
++{
++      do_dec_lv(rpnpop());
++}
++
++static void do_move_lv(unsigned short index)
++{
++      if (index > dprobes.rec->mod->pgm.num_lv)
++              gen_ex(EX_INVALID_OPERAND, 1, index);
++      else
++              *(dprobes.mod->lv + index) = dprobes.rpn_stack[dprobes.rpn_tos];
++}
++
++static void move_lvi(void)
++{
++      do_move_lv(get_u16_oprnd());
++}
++
++static void move_lv(void)
++{
++      do_move_lv(rpnpop());
++}
++              
++/*
++ * global variables.
++ */
++static void do_push_gv(unsigned short index)
++{
++      read_lock(&dp_gv_lock);
++      if (index >= dp_num_gv) {
++              read_unlock(&dp_gv_lock);
++              gen_ex(EX_INVALID_OPERAND, 2, index);
++              return;
++      } else {
++              rpnpush(*(dp_gv + index));
++              read_unlock(&dp_gv_lock);
++      }
++}
++
++static void push_gvi(void)
++{
++      do_push_gv(get_u16_oprnd());
++}
++
++static void push_gv(void)
++{
++      do_push_gv(rpnpop());
++}
++
++static void pop_gvi(void)
++{
++      unsigned short index = get_u16_oprnd();
++      write_lock(&dp_gv_lock);
++      if (index >= dp_num_gv) {
++              write_unlock(&dp_gv_lock);
++              gen_ex(EX_INVALID_OPERAND, 2, index);
++              return;
++      } else {
++              *(dp_gv + index) = rpnpop();
++              write_unlock(&dp_gv_lock);
++      }
++}
++
++static void pop_gv(void)
++{
++      unsigned long value = rpnpop();
++      unsigned short index = (unsigned short) rpnpop();
++      write_lock(&dp_gv_lock);
++      if (index >= dp_num_gv) {
++              write_unlock(&dp_gv_lock);
++              gen_ex(EX_INVALID_OPERAND, 2, index);
++              return;
++      } else {
++              *(dp_gv + index) = value;
++              write_unlock(&dp_gv_lock);
++      }
++}
++
++
++static void do_inc_gv(unsigned short index)
++{
++      write_lock(&dp_gv_lock);
++      if (index >= dp_num_gv) {
++              write_unlock(&dp_gv_lock);
++              gen_ex(EX_INVALID_OPERAND, 2, index);
++              return;
++      } else {
++              (*(dp_gv + index))++;
++              write_unlock(&dp_gv_lock);
++      }
++}
++
++static void inc_gvi(void)
++{
++      do_inc_gv(get_u16_oprnd());
++}
++
++static void inc_gv(void)
++{
++      do_inc_gv(rpnpop());
++}
++                                              
++static void do_dec_gv(unsigned short index)
++{
++      write_lock(&dp_gv_lock);
++      if (index >= dp_num_gv) {
++              write_unlock(&dp_gv_lock);
++              gen_ex(EX_INVALID_OPERAND, 2, index);
++              return;
++      } else {
++              (*(dp_gv + index))--;
++              write_unlock(&dp_gv_lock);
++      }
++}
++
++static void dec_gvi(void)
++{
++      do_dec_gv(get_u16_oprnd());
++}
++
++static void dec_gv(void)
++{
++      do_dec_gv(rpnpop());
++}
++
++static void do_move_gv(unsigned short index)
++{
++      write_lock(&dp_gv_lock);
++      if (index >= dp_num_gv) {
++              write_unlock(&dp_gv_lock);
++              gen_ex(EX_INVALID_OPERAND, 2, index);
++              return;
++      } else {
++              *(dp_gv + index) = dprobes.rpn_stack[dprobes.rpn_tos];
++              write_unlock(&dp_gv_lock);
++      }
++}
++
++static void move_gvi(void)
++{
++      do_move_gv(get_u16_oprnd());
++}
++
++static void move_gv(void)
++{
++      do_move_gv(rpnpop());
++}
++
++
++/*
++ * Arithmetic and logic group.
++ */
++static void add(void)
++{
++      rpnpush(rpnpop() + rpnpop());
++}
++
++static void mul(void)
++{
++      rpnpush(rpnpop() * rpnpop());
++}
++
++static void and(void)
++{
++      rpnpush(rpnpop() & rpnpop());
++}
++
++static void or(void)
++{
++      rpnpush(rpnpop() | rpnpop());
++}
++
++static void xor(void)
++{
++      rpnpush(rpnpop() ^ rpnpop());
++}
++
++static void neg(void)
++{
++      rpnpush(~rpnpop());
++}
++
++static void sub(void)
++{
++      rpnpush(rpnpop() - rpnpop());
++}
++
++/* pop divisor first and dividend next, pushes remainder first and quotient next */
++static void div(void)
++{
++      unsigned long divisor = rpnpop();
++      unsigned long dividend = rpnpop();
++      if (!divisor) {
++              gen_ex(EX_DIV_BY_ZERO, 0, 0);
++              return;
++      }
++      rpnpush(dividend % divisor);
++      rpnpush(dividend / divisor);
++}
++
++static void idiv(void)
++{
++      signed long divisor = (signed long) rpnpop();
++      signed long dividend = (signed long) rpnpop();
++      if (!divisor) {
++              gen_ex(EX_DIV_BY_ZERO, 0, 0);
++              return;
++      }
++      rpnpush(dividend % divisor);
++      rpnpush(dividend / divisor);
++}
++
++static void xchng(void)
++{
++      register unsigned long arg1, arg2;
++      arg1 = rpnpop();
++      arg2 = rpnpop();
++      rpnpush(arg1);
++      rpnpush(arg2);
++}
++
++static void shl_i(void)
++{
++      dprobes.rpn_stack[dprobes.rpn_tos] <<= get_u8_oprnd();
++}
++
++static void shr_i(void)
++{
++      dprobes.rpn_stack[dprobes.rpn_tos] >>= get_u8_oprnd();
++}
++
++static void shr(void)
++{
++      unsigned long oprnd = rpnpop();
++      unsigned long count = rpnpop();
++      oprnd >>= count;
++      rpnpush(oprnd);
++}
++
++static void shl(void)
++{
++      unsigned long oprnd = rpnpop();
++      unsigned long count = rpnpop();
++      oprnd <<= count;
++      rpnpush(oprnd);
++}
++
++static void dup(void)
++{
++      unsigned long dup = rpnpop();
++      u8 dupcount = rpnpop();
++      rpnpush(dup);
++      dupcount &= ~RPN_STACK_SIZE;
++      while (dupcount--)
++              rpnpush(dup);
++}
++
++static void dupn(void)
++{
++      unsigned long dup = rpnpop();
++      u8 dupcount = get_u8_oprnd();
++      dupcount &= ~RPN_STACK_SIZE;
++      while (dupcount--)
++              rpnpush(dup);
++}
++
++static void ros(void)
++{
++      dprobes.rpn_tos += get_u8_oprnd();
++      dprobes.rpn_tos &= RPN_STACK_SIZE - 1;
++}     
++
++/*
++ * Verify the read access to a byte pointed by the flat linear address.
++ */
++static void verify_access(int write)
++{
++      u8 b;
++      void * addr = (void *)rpnpop();
++      if (dp_intr_copy_from_user(&b, addr, 1)) {
++              goto fail;
++      }
++      if (write && dp_intr_copy_to_user(addr, &b, 1)) {
++              goto fail;
++      }
++      rpnpush(0);
++      return;
++fail:
++      rpnpush(1);
++      return;
++}
++
++/*
++ * Push immediate value (operand) onto the rpn stack.
++ */
++static void push_i (void)
++{
++      rpnpush(get_ulong_oprnd());
++}
++
++/*
++ * Push byte, word, dword, qword present at the flat address
++ * onto rpn stack.
++ */
++static int push_flat(void *val, void *faddr, unsigned long size)
++{
++      if (dp_intr_copy_from_user(val, faddr, size)) {
++              gen_ex(EX_INVALID_ADDR, (unsigned long)faddr, 0);
++              return 0;
++      }
++      return 1;
++}
++
++static void push_mem_u8 (void)
++{
++      u8 b;
++      if(push_flat((void *)&b, (void *)rpnpop(), sizeof(u8)))
++              rpnpush(b);
++}
++
++static void push_mem_u16 (void)
++{
++      u16 w;
++      if(push_flat((void *)&w, (void *)rpnpop(), sizeof(u16)))
++              rpnpush(w);
++}
++
++static void push_mem_u32 (void)
++{
++      u32 dw;
++      if(push_flat((void *)&dw, (void *)rpnpop(), sizeof(u32)))
++              rpnpush(dw);
++}
++
++static void push_mem_u64 (void)
++{
++      unsigned long q[2];
++      void *faddr = (void *) rpnpop();
++      if (dp_intr_copy_from_user(q, faddr, 2*sizeof(unsigned long))) {
++              gen_ex(EX_INVALID_ADDR, (unsigned long)faddr, 0);
++      } else {
++              rpnpush(q[1]);
++              rpnpush(q[0]);
++      }
++}
++
++/*
++ * Pop byte, word, dword, qword from rpn stack and write 
++ * them at the specified linear address.
++ */
++static void pop_flat(void *faddr, void * val, unsigned long size)
++{
++      if (dp_intr_copy_to_user(faddr, val, size))
++              gen_ex(EX_INVALID_ADDR, (unsigned long)faddr, 0);
++}
++
++static void pop_mem_u8 (void)
++{
++      u8 b = (unsigned char) rpnpop();
++      pop_flat((void *)rpnpop(), (void *)&b, sizeof(u8));
++}
++
++static void pop_mem_u16 (void)
++{
++      u16 w = (u16) rpnpop();
++      pop_flat((void *)rpnpop(), (void *)&w, sizeof(u16));
++}
++
++static void pop_mem_u32 (void)
++{
++      u32 d = (u32) rpnpop();
++      pop_flat((void *)rpnpop(), (void *)&d, sizeof(u32));
++}
++
++static void pop_mem_u64 (void)
++{
++      // PORT: on IA64
++      unsigned long q[2];
++      q[0] = rpnpop();
++      q[1] = rpnpop();
++      pop_flat((void *)rpnpop(), (void *)q, 2*sizeof(unsigned long));
++}
++
++/*
++ * Push pid onto rpn stack.
++ */
++static void push_pid(void)
++{
++      rpnpush((unsigned long) current->pid);
++}
++
++/*
++ * Push processor id onto rpn stack.
++ */
++static void push_procid(void)
++{
++      rpnpush((unsigned long)smp_processor_id());
++}
++
++/*
++ * Push the address of the current task structure onto rpn stack.
++ */
++static void push_task(void)
++{
++      rpnpush((unsigned long) current);
++}
++
++#ifdef DPROBES_CALLK_HOOK
++DECLARE_HOOK_HEAD(DPROBES_CALLK);
++USE_HOOK(DPROBES_CALLK);
++static void callk(void)
++{
++      struct dprobes_struct *dp = &dprobes;
++      dp->status &= ~DP_STATUS_INTERPRETER;
++      HOOK(DPROBES_CALLK, &dprobes);
++      dp->status |= DP_STATUS_INTERPRETER;
++}
++#endif
++
++/*
++ * Byte heap management routines.
++ */  
++#ifdef CONFIG_SMP
++struct list_head heap_list_set[NR_CPUS];
++#define heap_list heap_list_set[smp_processor_id()]
++#else
++struct list_head heap_list;
++#define heap_list_set (&heap_list)
++#endif
++
++/* Validates the heap handle. Returns the block size in @size */
++static int heap_validate_handle(byte_t *handle, unsigned long *size)
++{
++      struct list_head *tmp;
++      struct heap_hdr *h;
++
++      list_for_each(tmp, &heap_list) {
++              h = list_entry(tmp, struct heap_hdr, list);
++              if (h->addr == handle && h->flags == HEAP_ALLOCATED) {
++                      if (size) *size = h->size;
++                      return 1;
++              }
++      }
++      return 0;
++}
++
++static void heap_coalesce(struct heap_hdr *heap)
++{
++      struct heap_hdr *h;
++
++      /* Combine this block with the next free block (if available) */
++      if (heap->list.next != &heap_list) {
++              h = list_entry(heap->list.next, struct heap_hdr, list);
++              if (h->flags == HEAP_FREE) {
++                      heap->size += (h->size + HEAP_HDR_SIZE);
++                      list_del(&h->list);
++              }
++      }
++
++      /* Combine this block with the previous free block (if available) */
++      if (heap->list.prev != &heap_list) {
++              h = list_entry(heap->list.prev, struct heap_hdr, list);
++              if (h->flags == HEAP_FREE) {
++                      h->size += (heap->size + HEAP_HDR_SIZE);
++                      list_del(&heap->list);
++              }
++      }
++}
++
++/* Allocation succeeds only if (size + HEAP_HDR_SIZE) is available */
++static byte_t *heap_alloc(int size)
++{
++      unsigned long sz;
++      struct list_head *tmp;
++      struct heap_hdr *next;
++
++      list_for_each(tmp, &heap_list) {
++              struct heap_hdr *h = list_entry(tmp, struct heap_hdr, list);
++              sz = h->size;
++              if ((h->flags == HEAP_FREE) && (sz > size + HEAP_HDR_SIZE)) {
++                      h->size = size;
++                      h->flags = HEAP_ALLOCATED;
++                      
++                      if (sz > size) {
++                              next = (struct heap_hdr *)(h->addr + size);
++                              next->addr = h->addr + size + HEAP_HDR_SIZE;
++                              next->flags = HEAP_FREE;
++                              next->size = sz - size - HEAP_HDR_SIZE;
++                              list_add(&next->list, &h->list);
++                      }
++                      return h->addr;
++              }
++      }
++      return NULL;
++}
++
++/* Returns the amount of memory freed */
++static unsigned long heap_free(byte_t *ptr)
++{
++      struct list_head *tmp;
++      unsigned long size = 0;
++
++      list_for_each(tmp, &heap_list) {
++              struct heap_hdr *h = list_entry(tmp, struct heap_hdr, list);
++              if (h->addr == ptr && h->flags == HEAP_ALLOCATED) {
++                      h->flags = HEAP_FREE;
++                      size = h->size;
++                      heap_coalesce(h);
++                      break;
++              }
++      }
++      return size;
++}
++
++static void heap_init(byte_t *heap)
++{
++      struct heap_hdr *h;
++      
++      INIT_LIST_HEAD(&heap_list);
++      h = (struct heap_hdr *)heap;
++      h->addr = heap + HEAP_HDR_SIZE;
++      h->flags = HEAP_FREE;
++      h->size = dprobes.rec->point.heap_size - HEAP_HDR_SIZE;
++      list_add(&h->list, &heap_list);
++}
++
++/*
++ * Byte heap related instructions.
++ */
++static void pushh_u8_i(void)
++{
++      unsigned short count = get_u16_oprnd();
++      unsigned long offset = rpnpop();
++      byte_t *handle = (byte_t *)rpnpop();
++      unsigned long blk_size;
++      
++      /* validate the handle */
++      if (!heap_validate_handle(handle, &blk_size)) {
++              gen_ex(EX_HEAP_INVALID_HANDLE, (unsigned long)handle, offset);
++              return;
++      }
++      while (count) {
++              /* validate the offset */
++              if (offset >= blk_size) {
++                      gen_ex(EX_HEAP_INVALID_OFFSET, (unsigned long)handle, 
++                                      offset);
++                      return;
++              }
++              rpnpush((unsigned long)(*((u8 *)(handle + offset))));
++              offset++;
++              count--;
++      }
++}
++
++static void pushh_u16_i(void)
++{
++      unsigned short count = get_u16_oprnd();
++      unsigned long offset = rpnpop();
++      byte_t *handle = (byte_t *)rpnpop();
++      unsigned long blk_size;
++      
++      /* validate the handle */
++      if (!heap_validate_handle(handle, &blk_size)) {
++              gen_ex(EX_HEAP_INVALID_HANDLE, (unsigned long)handle, offset);
++              return;
++      }
++      while (count) {
++              /* validate the offset */
++              if (offset + 2 > blk_size) {
++                      gen_ex(EX_HEAP_INVALID_OFFSET, (unsigned long)handle, 
++                                      offset);
++                      return;
++              }
++              rpnpush((unsigned long)(*((u16 *)(handle + offset))));
++              offset += 2;
++              count--;
++      }
++}
++
++static void pushh_u32_i(void)
++{
++      unsigned short count = get_u16_oprnd();
++      unsigned long offset = rpnpop();
++      byte_t *handle = (byte_t *)rpnpop();
++      unsigned long blk_size;
++      
++      /* validate the handle */
++      if (!heap_validate_handle(handle, &blk_size)) {
++              gen_ex(EX_HEAP_INVALID_HANDLE, (unsigned long)handle, offset);
++              return;
++      }
++      while (count) {
++              /* validate the offset */
++              if (offset + 4 > blk_size) {
++                      gen_ex(EX_HEAP_INVALID_OFFSET, (unsigned long)handle, 
++                                      offset);
++                      return;
++              }
++              rpnpush((unsigned long)(*((u32 *)(handle + offset))));
++              offset += 4;
++              count--;
++      }
++}
++
++static void pushh_u64_i(void)
++{
++      unsigned short count = get_u16_oprnd();
++      unsigned long offset = rpnpop();
++      byte_t *handle = (byte_t *)rpnpop();
++      unsigned long blk_size;
++      
++      /* validate the handle */
++      if (!heap_validate_handle(handle, &blk_size)) {
++              gen_ex(EX_HEAP_INVALID_HANDLE, (unsigned long)handle, offset);
++              return;
++      }
++      while (count) {
++              /* validate the offset */
++              if (offset + 8 > blk_size) {
++                      gen_ex(EX_HEAP_INVALID_OFFSET, (unsigned long)handle, 
++                                      offset);
++                      return;
++              }
++              /* shouldn't this order depend on endianness ? */
++              rpnpush((unsigned long)(*((u64 *)(handle + offset))));
++              rpnpush((unsigned long)(*((u64 *)(handle + offset))));
++              offset += 8;
++              count--;
++      }
++}
++
++static void poph_u8_i(void)
++{
++      unsigned short count = get_u16_oprnd();
++      unsigned long offset = rpnpop();
++      byte_t *handle = (byte_t *)rpnpop();
++      unsigned long blk_size;
++      
++      /* validate the handle */
++      if (!heap_validate_handle(handle, &blk_size)) {
++              gen_ex(EX_HEAP_INVALID_HANDLE, (unsigned long)handle, offset);
++              return;
++      }
++      while (count) {
++              /* validate the offset */
++              if (offset > blk_size) {
++                      gen_ex(EX_HEAP_INVALID_OFFSET, (unsigned long)handle,
++                                      offset);
++                      return;
++              }
++              *((u8 *)(handle + offset)) = (u8)rpnpop();
++              offset++;
++              count--;
++      }
++}
++
++static void poph_u16_i(void)
++{
++      unsigned short count = get_u16_oprnd();
++      unsigned long offset = rpnpop();
++      byte_t *handle = (byte_t *)rpnpop();
++      unsigned long blk_size;
++      
++      /* validate the handle */
++      if (!heap_validate_handle(handle, &blk_size)) {
++              gen_ex(EX_HEAP_INVALID_HANDLE, (unsigned long)handle, offset);
++              return;
++      }
++      while (count) {
++              /* validate the offset */
++              if (offset + 2 > blk_size) {
++                      gen_ex(EX_HEAP_INVALID_OFFSET, (unsigned long)handle,
++                                      offset);
++                      return;
++              }
++              *((u16 *)(handle + offset)) = (u16)rpnpop();
++              offset += 2;
++              count--;
++      }
++}
++
++static void poph_u32_i(void)
++{
++      unsigned short count = get_u16_oprnd();
++      unsigned long offset = rpnpop();
++      byte_t *handle = (byte_t *)rpnpop();
++      unsigned long blk_size;
++      
++      /* validate the handle */
++      if (!heap_validate_handle(handle, &blk_size)) {
++              gen_ex(EX_HEAP_INVALID_HANDLE, (unsigned long)handle, offset);
++              return;
++      }
++      while (count) {
++              /* validate the offset */
++              if (offset + 4 > blk_size) {
++                      gen_ex(EX_HEAP_INVALID_OFFSET, (unsigned long)handle,
++                                      offset);
++                      return;
++              }
++              *((u32 *)(handle + offset)) = (u32)rpnpop();
++              offset += 4;
++              count--;
++      }
++}
++
++static void poph_u64_i(void)
++{
++      unsigned short count = get_u16_oprnd();
++      unsigned long offset = rpnpop();
++      byte_t *handle = (byte_t *)rpnpop();
++      unsigned long blk_size;
++      
++      /* validate the handle */
++      if (!heap_validate_handle(handle, &blk_size)) {
++              gen_ex(EX_HEAP_INVALID_HANDLE, (unsigned long)handle, offset);
++              return;
++      }
++      while (count) {
++              /* validate the offset */
++              if (offset + 8 > blk_size) {
++                      gen_ex(EX_HEAP_INVALID_OFFSET, (unsigned long)handle,
++                                      offset);
++                      return;
++              }
++              /* shouldn't this order depend on endianness ? */
++              *((u32 *)(handle + offset)) = (u32)rpnpop();
++              *((u32 *)(handle + offset + 4)) = (u32)rpnpop();
++              offset += 8;
++              count--;
++      }
++}
++
++static void malloc(void)
++{
++      unsigned long size = rpnpop();
++      byte_t *handle;
++
++      /* 
++       * Does this allocation exceed the maximum heapsize specified for
++       * this probe ?
++       */ 
++      if (size + dprobes.heap_size > dprobes.rec->point.heap_size) {
++              gen_ex(EX_HEAP_NOMEM, size, 0);
++              return;
++      }
++      handle = heap_alloc(size);
++      if (!handle) {
++              gen_ex(EX_HEAP_NOMEM, size, 0);
++              return;
++      }
++      dprobes.heap_size += size;
++      rpnpush((unsigned long)handle);
++}
++
++static void free(void)
++{
++      byte_t *handle = (byte_t *)rpnpop();
++      unsigned long size;
++
++      if (!(size = heap_free(handle))) {
++              gen_ex(EX_HEAP_INVALID_HANDLE, (unsigned long)handle, 0);
++              return;
++      }
++      dprobes.heap_size -= size;
++}
++
++static void push_wid(void)
++{
++      union wid {
++              short a;
++              char b[sizeof(short)];
++      } w;
++      w.a = 0x0102;
++      
++      if (sizeof(short) != 2) {
++              rpnpush(0);
++              return;
++      }
++      
++      if (w.b[0] == 0x01 && w.b[1] == 0x02) {
++              rpnpush(BITS_PER_LONG);
++      } else if (w.b[0] == 0x02 && w.b[1] == 0x01) {
++              rpnpush(-BITS_PER_LONG);
++      } else {
++              rpnpush(0);
++      }
++}
++
++/*
++ * Entry point for the dprobes interpreter(Probe handler).
++ */
++void dp_interpreter(void)
++{
++      struct dprobes_struct *dp = &dprobes;
++
++      dp->call_tos = CALL_STACK_SIZE - CALL_FRAME_SIZE;
++      dp->call_stack[dp->call_tos + OFFSET_EX_HANDLER] = EX_NO_HANDLER;
++      dp->rpn_tos = dp->rpn_sbp = RPN_STACK_SIZE;
++      dp->rpn_code = dp->rec->mod->pgm.rpn_code;
++      dp->rpn_ip = dp->rec->mod->pgm.rpn_code + dp->rec->point.rpn_offset;
++      dp->log_len = dp->rec->mod->hdr.len;
++      dp->ex_log_len = MIN_ST_SIZE;
++      dp->jmp_count = 0;
++      dp->ex_parm1 = dp->ex_parm2 = 0;
++      if (dp->rec->point.heap_size > 2*HEAP_HDR_SIZE) {
++              read_lock(&dp_heap_lock);
++              heap_init(dp_heap + dp->mod->pgm.heapmax * smp_processor_id());
++              dp->heap_size = 0;
++      }
++      
++      dp->status |= DP_STATUS_INTERPRETER;
++      while (dp->status & DP_STATUS_INTERPRETER) {
++              register u8 rpn_instr = *dp->rpn_ip++;
++              switch(rpn_instr) {
++                      case DP_NOP:            no_op(); break;         
++
++                      case DP_JMP:            jmp(); break;                   
++                      case DP_JLT:            jlt(); break;                   
++                      case DP_JLE:            jle(); break;                   
++                      case DP_JGT:            jgt(); break;           
++                      case DP_JGE:            jge(); break;                   
++                      case DP_JZ:             jz(); break;    
++                      case DP_JNZ:            jnz(); break;                   
++                      case DP_LOOP:           loop(); break;                  
++                      case DP_CALL:           call(); break;                  
++                      case DP_RET:            ret(); break;                   
++                      case DP_ABORT:          dp_abort(); break;              
++                      case DP_REM:            dp_remove(); break;             
++                      case DP_EXIT:           dp_exit(); break;               
++                      case DP_EXIT_N:         dp_exit_n(); break;             
++
++                      case DP_SETMIN_I:       setmin_i(); break;              
++                      case DP_SETMIN:         setmin(); break;                
++                      case DP_SETMAJ_I:       setmaj_i(); break;              
++                      case DP_SETMAJ:         setmaj(); break;                
++                      case DP_LOG_STR:        log_str(); break;               
++                      case DP_LOG_MRF:        log_mrf(); break;               
++                      case DP_LOG_I:          log_i(); break;         
++
++                      case DP_PUSH_LVI:       push_lvi(); break;      
++                      case DP_PUSH_LV:        push_lv(); break;               
++                      case DP_POP_LVI:        pop_lvi(); break;               
++                      case DP_POP_LV:         pop_lv(); break;                
++                      case DP_MOVE_LVI:       move_lvi(); break;              
++                      case DP_MOVE_LV:        move_lv(); break;               
++                      case DP_INC_LVI:        inc_lvi(); break;               
++                      case DP_INC_LV:         inc_lv(); break;                
++                      case DP_DEC_LVI:        dec_lvi(); break;               
++                      case DP_DEC_LV:         dec_lv(); break;                
++
++                      case DP_PUSH_GVI:       push_gvi(); break;
++                      case DP_PUSH_GV:        push_gv(); break;
++                      case DP_POP_GVI:        pop_gvi(); break;
++                      case DP_POP_GV:         pop_gv(); break;
++                      case DP_MOVE_GVI:       move_gvi(); break;              
++                      case DP_MOVE_GV:        move_gv(); break;               
++                      case DP_INC_GVI:        inc_gvi(); break;               
++                      case DP_INC_GV:         inc_gv(); break;                
++                      case DP_DEC_GVI:        dec_gvi(); break;               
++                      case DP_DEC_GV:         dec_gv(); break;                
++
++                      case DP_ADD:            add(); break;                   
++                      case DP_SUB:            sub(); break;                   
++                      case DP_MUL:            mul(); break;                   
++                      case DP_DIV:            div(); break;
++                      case DP_IDIV:           idiv(); break;
++
++                      case DP_NEG:            neg(); break;                   
++                      case DP_AND:            and(); break;                   
++                      case DP_OR:             or(); break;                    
++                      case DP_XOR:            xor(); break;                   
++                      case DP_ROL_I:          rol_i(); break;         
++                      case DP_ROL:            rol(); break;                   
++                      case DP_ROR_I:          ror_i(); break;         
++                      case DP_ROR:            ror(); break;                   
++                      case DP_SHL_I:          shl_i(); break;         
++                      case DP_SHL:            shl(); break;                   
++                      case DP_SHR_I:          shr_i(); break;         
++                      case DP_SHR:            shr(); break;                   
++                      case DP_PBL:            pbl(); break;
++                      case DP_PBR:            pbr(); break;
++                      case DP_PBL_I:          pbl_i(); break;
++                      case DP_PBR_I:          pbr_i(); break;
++                      case DP_PZL:            pzl(); break;
++                      case DP_PZR:            pzr(); break;
++                      case DP_PZL_I:          pzl_i(); break;
++                      case DP_PZR_I:          pzr_i(); break;
++#ifdef DPROBES_CALLK_HOOK
++                      case DP_CALLK:          callk(); break;
++#endif
++
++                      case DP_XCHG:           xchng(); break; 
++                      case DP_DUP_I:          dupn(); break;          
++                      case DP_DUP:            dup(); break;                   
++                      case DP_ROS:            ros(); break;           
++
++                      case DP_PUSH_R:         pushr(); break;         
++                      case DP_POP_R:          popr(); break;          
++                      case DP_PUSH_U:         pushu(); break;         
++                      case DP_POP_U:          popu(); break;          
++
++                      case DP_PUSH:           push_i(); break;                
++                      case DP_PUSH_MEM_U8:    push_mem_u8(); break;           
++                      case DP_PUSH_MEM_U16:   push_mem_u16(); break;          
++                      case DP_PUSH_MEM_U32:   push_mem_u32(); break;                          
++                      case DP_PUSH_MEM_U64:   push_mem_u64(); break;          
++                      case DP_POP_MEM_U8:     pop_mem_u8(); break;            
++                      case DP_POP_MEM_U16:    pop_mem_u16(); break;           
++                      case DP_POP_MEM_U32:    pop_mem_u32(); break;           
++                      case DP_POP_MEM_U64:    pop_mem_u64(); break;           
++
++                      case DP_PUSH_TASK:      push_task(); break;             
++                      case DP_PUSH_PID:       push_pid(); break;              
++                      case DP_PUSH_PROCID:    push_procid(); break;           
++
++                      case DP_VFY_R:          verify_access(0); break;
++                      case DP_VFY_RW:         verify_access(1); break;
++
++                      case DP_SX:             sx(); break;
++                      case DP_UX:             ux(); break;
++                      case DP_RX:             rx(); break;
++                      case DP_PUSH_X:         push_x(); break;
++                      case DP_PUSH_LP:        push_lp(); break;
++                      case DP_PUSH_PLP:       push_plp(); break;
++                      case DP_POP_LP:         pop_lp(); break;
++                      case DP_LOG_ST:         log_st(); break;
++                      case DP_PURGE_ST:       purge_st(); break;
++                      case DP_TRACE_LV:       trace_lv(); break;      
++                      case DP_TRACE_GV:       trace_gv(); break;      
++                      case DP_TRACE_PV:       trace_pv(); break;      
++
++                      case DP_PUSH_SBP:       push_sbp(); break;      
++                      case DP_POP_SBP:        pop_sbp(); break;       
++                      case DP_PUSH_TSP:       push_tsp(); break;      
++                      case DP_POP_TSP:        pop_tsp(); break;       
++                      case DP_COPY_SBP:       copy_sbp(); break;      
++                      case DP_COPY_TSP:       copy_tsp(); break;      
++                      case DP_PUSH_SBP_I:     push_sbp_i(); break;    
++                      case DP_POP_SBP_I:      pop_sbp_i(); break;     
++                      case DP_PUSH_TSP_I:     push_tsp_i(); break;    
++                      case DP_POP_TSP_I:      pop_tsp_i(); break;     
++                      case DP_COPY_SBP_I:     copy_sbp_i(); break;    
++                      case DP_COPY_TSP_I:     copy_tsp_i(); break;    
++                      case DP_PUSH_STP:       push_stp(); break;
++                      case DP_POP_STP:        pop_stp(); break;
++                      case DP_SAVE_SBP:       save_sbp(); break;
++                      case DP_RESTORE_SBP:    restore_sbp(); break;
++                      case DP_SAVE_TSP:       save_tsp(); break;
++                      case DP_RESTORE_TSP:    restore_tsp(); break;
++
++                      case DP_LOG:            log(); break;
++                      case DP_LOG_LV:         log_lv(); break;
++                      case DP_LOG_GV:         log_gv(); break;
++
++                      case DP_MALLOC:         malloc(); break;
++                      case DP_FREE:           free(); break;
++                      case DP_PUSH_WID:       push_wid(); break;
++                      case DP_PUSHH_U8_I:     pushh_u8_i(); break;
++                      case DP_PUSHH_U16_I:    pushh_u16_i(); break;
++                      case DP_PUSHH_U32_I:    pushh_u32_i(); break;
++                      case DP_PUSHH_U64_I:    pushh_u64_i(); break;
++                      case DP_POPH_U8_I:      poph_u8_i(); break;
++                      case DP_POPH_U16_I:     poph_u16_i(); break;
++                      case DP_POPH_U32_I:     poph_u32_i(); break;
++                      case DP_POPH_U64_I:     poph_u64_i(); break;
++
++                      default: dp_asm_interpreter(rpn_instr); break;
++              }
++      }
++      if (dp->rec->point.heap_size > 2*HEAP_HDR_SIZE)
++              read_unlock(&dp_heap_lock);
++      return;
++}
++
++void dprobes_interpreter_code_end(void) { }
+diff -urNp linux-2.6.0-test9/drivers/dprobes/i386/dprobes.c linux-2.6.0-test9+kp/drivers/dprobes/i386/dprobes.c
+--- linux-2.6.0-test9/drivers/dprobes/i386/dprobes.c   1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.0-test9+kp/drivers/dprobes/i386/dprobes.c        2003-11-18 08:15:13.000000000 +0530
+@@ -0,0 +1,808 @@
++/*
++ * IBM Dynamic Probes
++ * Copyright (c) International Business Machines Corp., 2000
++ *
++ * 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.
++ */
++
++#include <linux/dprobes.h>
++#include <linux/vmalloc.h>
++#include <linux/module.h>
++#include <linux/serial_reg.h>
++#include <linux/ctype.h>
++
++#include <asm/kwatch.h>
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include <asm/dprobes_exclude.h>
++#ifdef CONFIG_DEBUGREG
++#include <asm/debugreg.h>
++#endif
++
++void dprobes_asm_code_start(void) { }
++
++#ifdef CONFIG_MAGIC_SYSRQ
++extern unsigned long emergency_remove;
++#endif
++
++/*
++ * Format strings for printing out the log.
++ */
++#define DP_LOG_HDR_FMT                "dprobes(%d,%d) "
++#define DP_LOG_CPU_FMT                "cpu=%d "
++#define DP_LOG_PROCNAME_FMT   "name=%s "
++#define DP_LOG_PID_FMT                "pid=%d "
++#define DP_LOG_UID_FMT                "uid=%d "
++#define DP_LOG_CS_EIP_FMT     "cs=%x eip=%08lx "
++#define DP_LOG_SS_ESP_FMT     "ss=%x esp=%08lx "
++#define DP_LOG_TSC_FMT                "tsc=%08lx:%08lx "
++#define DP_LOG_NEWLINE_FMT    "\n"
++#define DP_LOG_DATA_FMT               "%x "
++#define DP_LOG_DATA_FT                "%x"
++
++static void log_stack_trace(struct dprobes_struct *dp)
++{
++      unsigned long i;
++      byte_t *ex_log;
++      unsigned char *tmp = dp->log_hdr;
++      unsigned long ex_log_len = dp->ex_log_len;
++
++      if (ex_log_len > MIN_ST_SIZE) {
++              tmp += sprintf(tmp, DP_LOG_HDR_FMT, 0, 0);
++
++#ifdef CONFIG_SMP
++              tmp += sprintf(tmp, DP_LOG_CPU_FMT, smp_processor_id());
++#endif
++              printk("%s ", dp->log_hdr);
++
++              ex_log_len -= MIN_ST_SIZE;
++              ex_log = dp->ex_log + MIN_ST_SIZE;
++              for (i = 0; i < ex_log_len; i++)
++                      printk(DP_LOG_DATA_FMT, ex_log[i]);
++              printk(DP_LOG_NEWLINE_FMT);
++      }
++}
++
++static void fmt_log_hdr(struct dprobes_struct *dp)
++{
++      unsigned char *tmp = dp->log_hdr;
++      unsigned long log_flags = dp->mod->pgm.flags & DP_LOG_MASK;
++
++      tmp += sprintf(tmp, DP_LOG_HDR_FMT, dp->major, dp->minor);
++
++#ifdef CONFIG_SMP
++      tmp += sprintf(tmp, DP_LOG_CPU_FMT, smp_processor_id());
++#endif
++      if (log_flags & DP_LOG_PID)
++              tmp += sprintf(tmp, DP_LOG_PID_FMT, current->pid);
++      if (log_flags & DP_LOG_UID)
++              tmp += sprintf(tmp, DP_LOG_UID_FMT, current->uid);
++      if (log_flags & DP_LOG_CS_EIP)
++              tmp += sprintf(tmp, DP_LOG_CS_EIP_FMT, dp->cs, dp->eip);
++      if (log_flags & DP_LOG_SS_ESP)
++              tmp += sprintf(tmp, DP_LOG_SS_ESP_FMT, dp->ss, dp->esp);
++      if (log_flags & DP_LOG_TSC) {
++              struct timeval ts;
++              do_gettimeofday(&ts);
++              tmp += sprintf(tmp, DP_LOG_TSC_FMT, ts.tv_sec, ts.tv_usec);
++      }
++      if (log_flags & DP_LOG_PROCNAME)
++              tmp += sprintf(tmp, DP_LOG_PROCNAME_FMT, current->comm);
++      tmp += sprintf(tmp, DP_LOG_NEWLINE_FMT);
++
++      tmp += sprintf(tmp, DP_LOG_HDR_FMT, dp->major, dp->minor);
++      *tmp = '\0';
++
++      return;
++}
++
++
++#define ROWS 16
++/*
++ * Saves (writes) the log to the standard kernel log.
++ */
++static void log_dumpformat(unsigned long log_len, byte_t *log)
++{
++      unsigned long i, start = 0, end = ROWS;
++      unsigned int  off=0x0;
++      char c;
++
++      while (start < log_len) {
++              printk("0x%8.8x : ", (unsigned int)off);
++              for( i = start; i < end; i++) {
++                      printk("%2.2x", 0xff & log[i]);
++                      if (((i + 1) % 4) == 0)
++                              printk(" ");
++              }
++
++              if ((end - start) < ROWS)
++                      for (i = 0; i < ((ROWS - (end - start)) * 2) + 4 - ((end - start) / 4); i++)
++                              printk(" ");
++
++              printk(": ");
++              for( i = start ; i < end ; i++ )       /* Now print the ASCII field. */
++               { 
++                      c = 0x7f & log[i];            /* mask out bit 7 */
++                      if (!(isprint(c)))              /* If not printable */
++                              printk(".");                    /* print a dot */
++                      else 
++                              printk("%c",c);
++           
++              }
++
++              printk(DP_LOG_NEWLINE_FMT);
++              if ( (log_len - end) > ROWS) 
++                      end += ROWS;
++              else 
++                      end = log_len;
++              start += ROWS;
++              off +=0x10;
++      }
++
++}     
++
++static void log_stack_trace_dump(struct dprobes_struct *dp)
++{
++      byte_t *ex_log;
++      unsigned char *tmp = dp->log_hdr;
++      unsigned long ex_log_len = dp->ex_log_len;
++      if (ex_log_len > MIN_ST_SIZE) {
++              tmp += sprintf(tmp, DP_LOG_HDR_FMT, 0, 0);
++
++#ifdef CONFIG_SMP
++              tmp += sprintf(tmp, DP_LOG_CPU_FMT, smp_processor_id());
++#endif
++              printk("%s \n", dp->log_hdr);
++
++              ex_log_len -= MIN_ST_SIZE;
++              ex_log = dp->ex_log + MIN_ST_SIZE;
++              log_dumpformat(ex_log_len, ex_log);
++
++      }
++}
++
++/*
++ * Saves (writes) the log to the standard kernel log.
++ */
++static int log_to_klog_dump(struct dprobes_struct *dp)
++{
++      byte_t *log = dp->log + dp->mod->hdr.len;
++      unsigned long log_len = dp->log_len - dp->mod->hdr.len;
++      
++      
++      fmt_log_hdr(dp);
++      printk("%s \n", dp->log_hdr);
++      log_dumpformat( log_len, log);
++      return 0;
++}     
++
++/*
++ * Saves (writes) the log to the standard kernel log.
++ */
++static int log_to_klog(struct dprobes_struct *dp)
++{
++      unsigned long i;
++      byte_t *log = dp->log + dp->mod->hdr.len;
++      unsigned long log_len = dp->log_len - dp->mod->hdr.len;
++
++      fmt_log_hdr(dp);
++      printk("%s ", dp->log_hdr);
++
++      for (i = 0; i < log_len; i++) {
++              if (log[i] < 0xf)
++                      printk(DP_LOG_DATA_FT, 0);
++              printk(DP_LOG_DATA_FMT, log[i]);
++      }
++      printk(DP_LOG_NEWLINE_FMT);
++      return 0;
++}     
++
++/*
++ * The order in which the optional header elements is written out has to be the
++ * same order in which the DP_HDR_* constants are defined in 
++ * include/linux/dprobes.h. The formatter is expected to look for the optional
++ * elements in the same order.
++ */
++static void fmt_log_hdr_raw(struct dprobes_struct *dp)
++{
++      unsigned char *tmp = dp->log;
++      unsigned long mask = dp->mod->hdr.mask;
++
++      dp->mod->hdr.major = dp->major;
++      dp->mod->hdr.minor = dp->minor;
++      *(struct dp_trace_hdr_struct *)tmp = dp->mod->hdr;      
++      tmp += sizeof(dp->mod->hdr);
++
++#ifdef CONFIG_SMP
++      *(unsigned int *)tmp = smp_processor_id();
++      tmp += sizeof(int);
++#endif
++      if (mask & DP_HDR_PID) {
++              *(pid_t *)tmp = current->pid;
++              tmp += sizeof(pid_t);
++      }
++      if (mask & DP_HDR_UID) {
++              *(uid_t *)tmp = current->uid;
++              tmp += sizeof(uid_t);
++      }
++      if (mask & DP_HDR_CS) {
++              *(unsigned short *)tmp = dp->cs;
++              tmp += sizeof(dp->cs);
++      }
++      if (mask & DP_HDR_EIP) {
++              *(unsigned long *)tmp = dp->eip;
++              tmp += sizeof(dp->eip);
++      }
++      if (mask & DP_HDR_SS) {
++              *(unsigned short *)tmp = dp->ss;
++              tmp += sizeof(dp->ss);
++      }
++      if (mask & DP_HDR_ESP) {
++              *(unsigned long *)tmp = dp->esp;
++              tmp += sizeof(dp->esp);
++      }
++      if (mask & DP_HDR_TSC) {
++              struct timeval ts;
++              do_gettimeofday(&ts);
++              *(struct timeval *)tmp = ts;
++              tmp += sizeof(ts);
++      }
++      if (mask & DP_HDR_PROCNAME) {
++              memcpy(tmp, current->comm, 16);
++              tmp += 16;
++      }
++      return;
++}
++
++/*
++ * dp->mod->hdr is changed here. Hence should be called only after
++ * fmt_log_hdr_raw().
++ */
++static void fmt_st_hdr_raw(struct dprobes_struct *dp)
++{
++      unsigned char *tmp = dp->ex_log;
++      dp->mod->hdr.mask = DP_HDR_MAJOR | DP_HDR_MINOR;
++      dp->mod->hdr.major = DP_ST_MAJOR;
++      dp->mod->hdr.minor = DP_ST_MINOR;
++      dp->mod->hdr.len = MIN_ST_SIZE;
++      *(struct dp_trace_hdr_struct *)tmp = dp->mod->hdr;      
++      tmp += sizeof(dp->mod->hdr);
++#ifdef CONFIG_SMP
++      dp->mod->hdr.mask |= DP_HDR_CPU;
++      *(unsigned int *)tmp = smp_processor_id();
++      tmp += sizeof(int);
++      dp->mod->hdr.len += sizeof(int);
++#endif
++}
++
++#if defined(CONFIG_TRACE) || defined(CONFIG_TRACE_MODULE)
++#include <linux/trace.h>
++
++static int log_to_ltt(struct dprobes_struct *dp)
++{
++      trace_raw_event(dp->mod->trace_id, dp->log_len, dp->log);       
++      return 0;
++}
++
++static int log_st_to_ltt(struct dprobes_struct *dp)
++{
++      trace_raw_event(dp->mod->trace_id, dp->ex_log_len, dp->ex_log);
++      return 0;
++}
++#else 
++static int log_to_ltt(struct dprobes_struct *dp)
++{
++      printk(KERN_WARNING "dprobes: Linux Trace Toolkit not available.\n");
++      return 0;
++}
++
++static int log_st_to_ltt(struct dprobes_struct *dp)
++{
++      printk(KERN_WARNING "dprobes: Linux Trace Toolkit not available.\n");
++      return 0;
++}
++#endif
++
++#ifdef CONFIG_EVLOG
++#include <linux/evl_log.h>
++static int log_to_evl(struct dprobes_struct *dp)
++{
++      /*
++       * We will need to modify this in future to create a DPROBES facility
++       * type and use dp->id instead of (major,minor) for event type. Even the
++       * priority ought to be something other than LOG_KERN.
++       */
++      posix_log_write(LOG_KERN, 
++                      (dp->major << 16) | dp->minor, /* dp->id */
++                      LOG_INFO,
++                      (dp->log + dp->mod->hdr.len),
++                      (dp->log_len - dp->mod->hdr.len),
++                      POSIX_LOG_BINARY,
++                      0);
++      return 0;
++}
++#else
++static int log_to_evl(struct dprobes_struct *dp)
++{
++      printk(KERN_WARNING "dprobes: POSIX Event Logging not available.\n");
++      return 0;
++}
++#endif
++
++#define BOTH_EMPTY_TR         (UART_LSR_TEMT | UART_LSR_THRE)
++#define COM1_ADDR     0x3f8
++#define COM2_ADDR     0x2f8
++
++/*
++ * Wait for the transmitter buffer to become empty.
++ */  
++static inline void wait_for_xmitr_empty(int port)
++{
++      int lsr;
++      unsigned int tmout = 1000000;
++      do {
++                      lsr = inb(port + UART_LSR);
++                      if (--tmout == 0) break;
++              } while ((lsr & BOTH_EMPTY_TR) != BOTH_EMPTY_TR);
++}
++
++/*
++ * This routine sends the raw binary data to com port. The receiving
++ * end should be capable of handling raw bytes.
++ */  
++static int log_to_com_port(struct dprobes_struct *dp, int port)
++{
++      int i, ier;
++      byte_t *log = dp->log;
++      byte_t *ex_log = dp->ex_log;
++      unsigned long log_len = dp->log_len;
++      unsigned long ex_log_len = dp->ex_log_len;
++      
++      /* store UART configuration and program it in polled mode */
++      ier = inb(port + UART_IER);     
++      outb(0x00, port + UART_IER);
++
++      /* send the log data to com port */
++      fmt_log_hdr_raw(dp);
++      for (i = 0; i < log_len; i++) {
++              wait_for_xmitr_empty(port);
++              outb(log[i], port + UART_TX);
++      }
++      
++      /* send CR and LF characters */
++      wait_for_xmitr_empty(port);
++      outb(0x0d, port + UART_TX);
++      wait_for_xmitr_empty(port);
++      outb(0x0a, port + UART_TX);
++
++      /* send the stack trace data(if present) to com port */
++      if (ex_log_len > MIN_ST_SIZE) {
++              fmt_st_hdr_raw(dp);
++              for (i = 0; i < ex_log_len; i++) {
++                      wait_for_xmitr_empty(port);
++                      outb(ex_log[i], port + UART_TX);
++              }
++
++              /* send CR and LF characters */
++              wait_for_xmitr_empty(port);
++              outb(0x0d, port + UART_TX);
++              wait_for_xmitr_empty(port);
++              outb(0x0a, port + UART_TX);
++      }       
++
++      /* restore the configuration of UART */
++      wait_for_xmitr_empty(port);
++      outb(ier, port + UART_IER);
++      return 0;
++}
++
++static void save_log(struct dprobes_struct *dp)
++{
++      switch(dp->mod->pgm.flags & DP_LOG_TARGET_MASK) {
++      case DP_LOG_TARGET_COM1:
++              log_to_com_port(dp, COM1_ADDR);
++              break;
++      case DP_LOG_TARGET_COM2:
++              log_to_com_port(dp, COM2_ADDR);
++              break;
++      case DP_LOG_TARGET_LTT:
++              fmt_log_hdr_raw(dp);
++              log_to_ltt(dp);
++              if (dp->ex_log_len > MIN_ST_SIZE) {
++                      fmt_st_hdr_raw(dp);
++                      log_st_to_ltt(dp);
++              }
++              break;
++      case DP_LOG_TARGET_EVL:
++              log_to_evl(dp);
++              break;
++      case DP_UNFORMATTED_OUTPUT:
++              log_to_klog(dp);
++              log_stack_trace(dp);
++              break;
++      default:
++              log_to_klog_dump(dp);
++              log_stack_trace_dump(dp);
++              break;
++      }
++      return;
++}
++
++#ifdef CONFIG_DEBUGREG
++static inline void set_rf(struct dp_record_struct *rec, struct pt_regs *regs)
++{
++      unsigned short wtype = rec->point.probe & DP_WATCHTYPE_MASK;
++      if (wtype == DP_WATCHTYPE_EXECUTE) {
++              regs->eflags |= EF_RF;
++      }
++      return;
++}
++
++inline void delete_watchpoint(unsigned int cond, struct pt_regs *regs, struct dp_record_struct *rec)
++{
++      int dbno = rec->dbregno;
++      unsigned long dr = read_dr(7);
++      RESET_DR7(dr, dbno);
++      dr_free(dbno);
++      write_dr(7, dr);
++}
++
++#else
++inline void delete_watchpoint(unsigned int cond, struct pt_regs *regs, struct dp_record_struct *rec) 
++{
++      return;
++}
++
++static inline void set_rf(struct dp_record_struct *rec, struct pt_regs *regs) 
++{
++      return; 
++}
++
++inline int dr_trap_type(unsigned int cond) 
++{
++      return 0;
++}
++#endif
++/*
++ * This routine save the registers during handling of kernel, userspace and 
++ * watchpoint probes and also updates the status in the dp_record_struct.
++ */
++void save_regs(struct dp_record_struct *rec, unsigned long addr,
++               struct pt_regs *regs)
++{
++      struct dprobes_struct *dp = &dprobes;
++
++      dp->rec = rec;
++      dp->probe_addr = addr;
++      dp->regs = regs;
++      dp->mod = rec->mod;
++      dp->major = rec->point.major;
++      dp->minor = rec->point.minor;
++      dp->status = 0UL;
++      dp->cs = regs->xcs;
++      dp->eip = regs->eip - sizeof(opcode_t);
++      dp->ss = regs->xss;
++      dp->esp = regs->esp;
++      if (regs->xcs & 3) {
++              dp->status |= DP_USER_PROBE;
++              dp->uregs = regs;
++      } else {
++              dp->status |= DP_KERNEL_PROBE;
++              dp->uregs = (struct pt_regs * )((unsigned long)(current) + 2 * PAGE_SIZE - sizeof(struct pt_regs));
++      }
++      dp->status |= DP_STATUS_FIRSTFPU;
++
++      /* rec->count > 0 for passcount */
++      if (rec->status & DP_REC_STATUS_ACTIVE && rec->count >= 0) {
++              dp_interpreter();
++              if (rec->status & (DP_REC_STATUS_DISABLED | DP_REC_STATUS_REMOVED)) {
++                      if (rec->status & DP_REC_STATUS_ACTIVE) {
++                              rec->status &= ~DP_REC_STATUS_ACTIVE;
++                              rec->status |= DP_REC_STATUS_DISABLED;
++                      }
++              }
++      } else {
++                      dp->status |= DP_STATUS_ABORT;
++      }
++}
++int dp_pre_handler(struct kprobe *kp, struct pt_regs *regs)
++{
++      struct dprobes_struct *dp = &dprobes;
++      struct dp_record_struct *rec = container_of(kp, typeof(*rec), kp);
++
++      if (rec->status & (DP_REC_STATUS_DISABLED | DP_REC_STATUS_REMOVED)) {
++              return 1;
++              }
++
++#ifdef CONFIG_MAGIC_SYSRQ
++      /* check if probes are marked for emergency removal */
++      if (test_bit(0, &emergency_remove)) 
++              return 1; 
++#endif
++      dp->rec = rec;
++      save_regs(rec, (unsigned long)rec->kp.addr, regs);
++      dp->status |= DP_STATUS_SS;
++      return 0;
++}
++
++void dp_post_handler(struct kprobe *kp, struct pt_regs *regs, unsigned long flags)
++{
++      struct dprobes_struct *dp = &dprobes;
++
++      dp->rec->count++;
++      if (dp->rec->count >= dp->rec->point.maxhits) {
++              dp->rec->status &= ~DP_REC_STATUS_ACTIVE;
++              dp->rec->status |= DP_REC_STATUS_DISABLED;
++      }
++      if (dp->status & DP_STATUS_ABORT)
++              return;
++      save_log(dp);
++}
++
++int dp_fault_handler(struct kprobe *kp, struct pt_regs *regs, int trapnr)
++{
++      struct dprobes_struct *dp = &dprobes;
++
++      if (trapnr != 13 && trapnr != 14)
++              return 0;
++      
++      if (dp->status & DP_STATUS_INTERPRETER) {
++              const struct exception_table_entry *fixup;
++              if ((fixup = search_exception_tables(regs->eip)) != 0) {
++                      regs->eip = fixup->fixup;
++                      return 1;
++              }
++      } else if (dp->status & DP_STATUS_SS) {
++              if (dp->rec->point.logonfault) {
++                      dp->rec->count++;
++                      save_log(dp);
++              }
++      }
++      return 0;
++}
++
++/*
++ * If there are multiple debug traps simultaneously, we handle the
++ * single step condition first (DR_STEP) as it is related to completing
++ * a previous debug trap. We then handle the debug register hits.
++ */
++int dp_do_debug(struct pt_regs * regs, unsigned long condition)
++{
++#ifdef CONFIG_DEBUGREG
++#if 0
++      /* assume that only one watchpoint possible on an address. */
++      if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
++              if (dp_trap(regs, DP_PROBE_WATCHPOINT, condition, dr_trap_addr(condition))) {
++                      return 1;
++              }
++      }
++#endif
++#endif
++      return 0;
++}
++
++#include <asm/desc.h>
++#include <asm/ldt.h>
++#ifndef GDT_ENTRIES
++#define GDT_ENTRIES     (__TSS(NR_CPUS))
++#endif
++static inline int is_fpu_instn(byte_t *addr)
++{
++      if (((*addr & 0xf8) == 0xd8) || (*addr == 0x9b)) 
++              return 1;
++      return 0;
++}
++/* Use this array to store the dp_record_struct during registration, and index
++ * using the debugreg number in the handler to get back, the dp_record_struct.
++ */
++static struct dp_record_struct *kwatch_rec[DP_MAX_WATCHPOINT];
++      
++/* 
++ * dp_kwatch_handler: Dprobes handler for watchpoint probes, registerd through
++ * kwatch interface. This routine is called by the watch point probe handler, 
++ * when the probe is hit.
++ */
++
++void dp_kwatch_handler(struct kwatch *kw, struct pt_regs *regs, int debugreg)
++{
++      struct dprobes_struct *dp = &dprobes;
++      struct dp_record_struct *rec = kwatch_rec[debugreg];
++      if ((!rec) || (rec->status & (DP_REC_STATUS_DISABLED | 
++                              DP_REC_STATUS_REMOVED))) {
++              return ;
++      }
++      rec->count++;
++      save_regs(rec, kw->addr, regs);
++      if (dp->status & DP_STATUS_ABORT)
++              return;
++      save_log(dp);
++      dp->status &= ~DP_STATUS_DONE;
++      return;
++}
++
++/* 
++ * Unregister watchpoint probes.
++ */
++
++static inline int remove_wp(byte_t *addr, struct dp_record_struct *rec)
++{
++      kwatch_rec[rec->dbregno] = NULL;
++      unregister_kwatch(rec->dbregno);
++      return 0;
++}
++
++/* Check the range for debug register watchpoint */
++static inline int invalid_range(unsigned long len)
++{
++      return (len > 3 ) ? 1 : 0;
++}
++
++/*
++ * Insert watchpoint probes, using the kwatch interface.
++ */
++static inline int insert_wp(byte_t *addr, struct dp_record_struct *rec,
++      struct dp_module_struct *m, struct page * page)
++{
++      int ret;
++
++      if (invalid_range(rec->point.len)) {
++              rec->status |= DP_REC_STATUS_WATCHPOINT_LEN_INVALID;
++              return -1;
++      }
++      ret = register_kwatch((unsigned long)addr, (u8)(rec->point.len + 1),
++               (u8)(rec->point.probe & DP_WATCHTYPE_MASK), dp_kwatch_handler);
++
++      if (ret < 0) {
++              rec->status |= DP_REC_STATUS_KPROBE_ERR;
++              return -1;
++      }
++
++      kwatch_rec[ret] = rec;
++      rec->status |= DP_REC_STATUS_ACTIVE;
++      rec->dbregno = ret;
++      return 0;
++}
++
++/* 
++ * Writing the breakpoint instruction should be the last thing done
++ * in this function to ensure that all the structures that
++ * are needed to locate the probe are in place before a probe can
++ * be hit.
++ */
++static inline int insert_bp(byte_t *addr, struct dp_record_struct *rec,
++      struct dp_module_struct *m, struct page * page)
++{
++      if (dprobes_excluded((unsigned long)addr)) {
++              rec->status |= DP_REC_STATUS_EXCLUDED;
++              return -1;
++      }
++
++      if (!(m->pgm.flags & DP_MODTYPE_USER) &&
++              !(((unsigned long)addr) >= m->base && 
++              ((unsigned long)addr) < (m->end + m->base))) {
++              rec->status |= DP_REC_STATUS_INVALID_OFFSET;
++              return -1;
++      }
++      if (*addr != rec->point.opcode)  {
++              if (m->pgm.flags & DP_DONT_VERIFY_OPCODES) {
++                      rec->point.opcode = *addr;
++              } else {
++                      if (!(m->pgm.flags & DP_MODTYPE_USER) || 
++                          !IS_COW_PAGE(page, m->inode)) {
++                              rec->point.actual_opcode = *addr;
++                              rec->status |= DP_REC_STATUS_MISMATCH;
++                      }
++                      return -1;
++              }
++      }
++
++      /* all okay, register the probe */
++      rec->kp.addr = addr;
++      rec->kp.pre_handler = dp_pre_handler;
++      rec->kp.post_handler = dp_post_handler;
++      rec->kp.fault_handler = dp_fault_handler;
++      
++      if (register_kprobe(&rec->kp)) {
++              rec->status |= DP_REC_STATUS_KPROBE_ERR;
++              return -1;
++      }
++      rec->status |= DP_REC_STATUS_ACTIVE;
++      return 0;
++}
++
++int __insert_probe(byte_t *addr, struct dp_record_struct *rec, 
++      struct dp_module_struct *m, struct page * page)
++{
++      if (rec->point.probe & DP_PROBE_BREAKPOINT)
++              return insert_bp(addr, rec, m, page);
++      else 
++              return insert_wp(addr, rec, m, page);
++}
++
++static inline void remove_bp(byte_t *addr, struct dp_record_struct *rec)
++{
++      unregister_kprobe(&rec->kp);
++}
++
++int __remove_probe(byte_t * addr, struct dp_record_struct *rec)
++{
++      if (rec->point.probe & DP_PROBE_BREAKPOINT)
++              remove_bp(addr, rec);
++      else 
++              remove_wp(addr, rec);
++      return 0;
++}
++/*
++ * Insert breakpoints in the user space at the given address.
++ * Need to specify address, page and vma in kprobe structure.
++ */
++inline int insert_probe_userspace(byte_t *addr, struct dp_record_struct *rec, 
++      struct page *page, struct vm_area_struct *vma)
++{
++      rec->kp.user->addr = addr;
++      rec->kp.user->page = page;
++      rec->kp.user->vma = vma;
++      if (insert_kprobe_user(&rec->kp)) {
++              rec->status |= DP_REC_STATUS_KPROBE_ERR;
++              return -1;
++      }
++      rec->status |= DP_REC_STATUS_ACTIVE;
++      return 0;
++}
++
++/*
++ * Remove breakpoints in the user space previously inserted at the given
++ * address. Need to specify address, page and vma in kprobe structure.
++ */
++inline int remove_probe_userspace(byte_t *addr, struct dp_record_struct *rec, 
++      struct page *page, struct vm_area_struct *vma)
++{
++      rec->kp.user->addr = addr;
++      rec->kp.user->page = page;
++      rec->kp.user->vma = vma;
++      return remove_kprobe_user(&rec->kp);
++              
++}
++
++
++/*
++ * register user space probes before actually inserting the probes.
++ */
++int register_userspace_probes(struct dp_record_struct *rec)
++{
++      rec->kp.pre_handler = dp_pre_handler;
++      rec->kp.post_handler = dp_post_handler;
++      rec->kp.fault_handler = dp_fault_handler;
++      rec->up.offset = rec->point.offset;
++      rec->up.inode = rec->mod->inode;
++      rec->kp.user = &(rec->up);
++      if (register_kprobe_user(&rec->kp)) {
++              rec->status |= DP_REC_STATUS_KPROBE_ERR;
++              return -1;
++      }
++      rec->status |= DP_REC_STATUS_ACTIVE;
++      return 0;
++}
++
++/*
++ * Unregister the user space probes previously registered.
++ * Make sure all the probes for a pair of inode and offset are removed
++ * before unregistering. 
++ */
++void unregister_userspace_probes(struct dp_record_struct *rec)
++{
++      unregister_kprobe_user(&rec->kp);
++}
++void dprobes_asm_code_end(void) { }
+diff -urNp linux-2.6.0-test9/drivers/dprobes/i386/dprobes_in.c linux-2.6.0-test9+kp/drivers/dprobes/i386/dprobes_in.c
+--- linux-2.6.0-test9/drivers/dprobes/i386/dprobes_in.c        1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.0-test9+kp/drivers/dprobes/i386/dprobes_in.c     2003-11-18 07:29:47.000000000 +0530
+@@ -0,0 +1,903 @@
++/*
++ * IBM Dynamic Probes
++ * Copyright (c) International Business Machines Corp., 2000
++ *
++ * 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.  
++ */
++
++/*
++ * This is a special file, part of the dprobes interpreter that contains
++ * architecture-specific functions. It is not compiled as a seperate unit.
++ * It is #included into the arch-independent dprobes_in.c at a specific
++ * location.
++ */
++#include <linux/binfmts.h>
++#ifdef CONFIG_DUMP
++#include <linux/dump.h>
++#endif
++#ifdef CONFIG_KDB
++#include <linux/kdb.h>
++#endif
++#include <asm/desc.h>
++#include <asm/ldt.h>
++#ifndef GDT_ENTRIES
++#define GDT_ENTRIES     (__TSS(NR_CPUS))
++#endif
++
++/*
++ * Convert segmented address (selector : offset) to flat linear address.
++ */
++static int dp_seg_to_flat(unsigned long sel, unsigned long off, void **faddr)
++{
++      struct Xgt_desc_struct g;
++      unsigned long ldt_desc, ldt_base, ldtr, seg_desc, seg_base;
++      unsigned long gdt_index = (sel & ~7);
++      mm_context_t *x = &current->mm->context;
++
++      __asm__ __volatile__ ("sgdt (%0)" : : "r"((unsigned long) &g));
++
++      if (sel & 4) {
++              if (!(x->ldt && ((sel >> 3) < x->size)))
++                      return 1;
++
++              __asm__ __volatile__ ("sldt %0" :"=r"(ldtr));
++              ldt_desc = g.address + ((ldtr & ~7));
++              ldt_base = _get_base ((char *)ldt_desc);
++              seg_desc = ldt_base + (gdt_index);
++              seg_base = _get_base ((char *)seg_desc);
++      }
++      else {
++              if ((sel >> 3) > GDT_ENTRIES)
++                      return 1;
++              seg_desc = g.address + gdt_index;
++              seg_base = _get_base ((char *)seg_desc);
++      }
++      *faddr = (void *)(seg_base + off);
++      return 0;
++}
++
++static void seg2lin(void)
++{
++      void *faddr;
++        unsigned long off = rpnpop();
++        unsigned long sel = rpnpop();
++
++      if (dp_seg_to_flat(sel, off, &faddr)) {
++              gen_ex(EX_SEG_FAULT, sel, 0);
++              return;
++      }
++      rpnpush((unsigned long) faddr);
++}
++
++#ifdef CONFIG_KDB
++/* 
++ * Temporarily restore the orignal opcode befor calling the kdb 
++ * so that kdb shows correct disassembly.
++ */
++static inline void restore_opcode(void)
++{
++      if (dprobes.rec->point.probe & DP_PROBE_BREAKPOINT) {
++              dprobes.reset_addr = dprobes.probe_addr;
++              *((byte_t *)dprobes.reset_addr) = dprobes.opcode;
++              flush_page_to_ram(dprobes.reset_addr);
++      }
++}
++
++/*
++ * After kdb terminates, restore the breakpoint.
++ */
++static inline void restore_int3(void)
++{     
++      if (dprobes.rec->point.probe & DP_PROBE_BREAKPOINT) {
++              dprobes.reset_addr = dprobes.probe_addr;
++              *((byte_t *)dprobes.reset_addr) = DP_INSTR_BREAKPOINT;
++              flush_page_to_ram(dprobes.reset_addr);
++      }
++}
++      
++void call_kdb(void)
++{
++      unsigned long eip = dprobes.regs->eip - 1;
++      if (dprobes.status & DP_KERNEL_PROBE) {
++              if (dprobes.rec->point.probe & DP_PROBE_BREAKPOINT)
++                      dprobes.regs->eip--;
++              restore_opcode();
++              kdb(KDB_REASON_CALL, 0, dprobes.regs);
++              restore_int3();
++              if (eip == dprobes.regs->eip)
++                      dprobes.regs->eip++;
++      }
++}
++#else
++
++void call_kdb(void)
++{
++      printk("Dprobes: Kernel Debugger is not present.\n");
++      return;
++}
++#endif
++/*
++ * Exiting the interpreter through the registered facility n.
++ */
++static void dp_exit_n(void)
++{
++      u8 facility = get_u8_oprnd();
++      switch(facility) {
++      case DP_EXIT_TO_SGI_KDB:
++              call_kdb();     
++              break;
++
++      case DP_EXIT_TO_SGI_VMDUMP:
++#ifdef CONFIG_DUMP
++              if (dprobes.status & DP_KERNEL_PROBE)
++                      dump("Dumping due to dprobes", dprobes.regs);
++#else
++              printk("dprobes: Crash dump facility is not present.\n");
++#endif
++              break;
++      case DP_EXIT_TO_CORE_DUMP:
++              if (dprobes.status & DP_USER_PROBE) {
++                      if (do_coredump(SIGINT, SIGINT, dprobes.regs)) {        
++                              current->mm->dumpable = 1;
++                              printk("dprobes(%d,%d) process %s dumped core\n", dprobes.major, dprobes.minor, current->comm);
++                      }
++                      else
++                              printk("dprobes(%d,%d) exit to core dump failed\n", dprobes.major, dprobes.minor);
++              }
++              break;
++      default: gen_ex(EX_INVALID_OPERAND, 4, facility); return;
++      
++      }
++      dprobes.status &= ~DP_STATUS_INTERPRETER;
++}
++
++/*
++ * Interpreter's version of copy_xxx_user functions. These need to save
++ * and restore cr2 contents to be able to correctly handle probes in
++ * page fault handler.
++ */
++static int dp_intr_copy_from_user(void *to, void *from, int len) 
++{
++      unsigned long address;
++      int retval;
++      __asm__("movl %%cr2,%0":"=r" (address)); /* save cr2 contents */
++      retval = __copy_from_user(to, from, len);
++      __asm__("movl %0,%%cr2": :"r" (address)); /* restore cr2 contents */
++      return retval;
++}
++
++static int dp_intr_copy_to_user(void *to, void *from, int len) 
++{
++      unsigned long address;
++      int retval;
++      __asm__("movl %%cr2,%0":"=r" (address)); /* save cr2 contents */
++      retval = __copy_to_user(to, from, len);
++      __asm__("movl %0,%%cr2": :"r" (address)); /* restore cr2 contents */
++      return retval;
++}
++
++#define BITS_IN_UL    32
++
++#define PROPAGATE_BIT(name, OPERATOR) \
++static void name(void) \
++{ \
++      unsigned long index, num, pos, val; \
++      index = rpnpop(); \
++      if (!index || index > BITS_IN_UL) { \
++              gen_ex(EX_INVALID_OPERAND, 3, index); \
++              return; \
++      } \
++      num = rpnpop(); \
++      pos = 1UL << (index - 1); \
++      val = num & pos; \
++      for (; pos; pos OPERATOR 1, val OPERATOR 1) \
++              num &= ~pos, num |= val; \
++      rpnpush(num); \
++}     
++
++PROPAGATE_BIT(pbl, <<=)
++PROPAGATE_BIT(pbr, >>=)
++
++#define PROPAGATE_BIT_IMM(name, OPERATOR) \
++static void name(void) \
++{ \
++      unsigned long index, num, pos, val; \
++      index = (unsigned long)get_u8_oprnd(); \
++      if (!index || index > BITS_IN_UL) { \
++              dprobes.status &= ~DP_STATUS_INTERPRETER; \
++              return; \
++      } \
++      num = rpnpop(); \
++      pos = 1UL << (index - 1); \
++      val = num & pos; \
++      for (; pos; pos OPERATOR 1, val OPERATOR 1) \
++              num &= ~pos, num |= val; \
++      rpnpush(num); \
++}
++
++PROPAGATE_BIT_IMM(pbl_i, <<=)
++PROPAGATE_BIT_IMM(pbr_i, >>=)
++
++static void pzl(void) 
++{ 
++      unsigned long index, num, pos;
++      index = rpnpop(); 
++      if (!index || index > BITS_IN_UL) {
++              gen_ex(EX_INVALID_OPERAND, 3, index); \
++              return;
++      }
++      num = rpnpop();
++      pos = 1UL << index;
++      for (; pos; pos <<= 1)
++              num &= ~pos;
++      rpnpush(num);
++}
++      
++static void pzl_i(void) 
++{ 
++      unsigned long index, num, pos;
++      index = (unsigned long)get_u8_oprnd();
++      if (!index || index > BITS_IN_UL) {
++              gen_ex(EX_INVALID_OPERAND, 3, index);
++              return;
++      }
++      num = rpnpop();
++      pos = 1UL << index;
++      for (; pos; pos <<= 1)
++              num &= ~pos;
++      rpnpush(num);
++}
++
++static void pzr(void)
++{
++      unsigned long index, num, pos;
++      index = rpnpop();
++      if (!index || index > BITS_IN_UL) {
++              gen_ex(EX_INVALID_OPERAND, 3, index);
++              return;
++      }
++      if (index == 1)
++              return;
++      num = rpnpop();
++      pos = 1UL << (index - 2);
++      for (; pos; pos >>= 1)
++              num &= ~pos;
++      rpnpush(num);
++}
++
++static void pzr_i(void)
++{
++      unsigned long index, num, pos;
++      index = (unsigned long)get_u8_oprnd();
++      if (!index || index > BITS_IN_UL) {
++              gen_ex(EX_INVALID_OPERAND, 3, index);
++              return;
++      }
++      if (index == 1)
++              return;
++      num = rpnpop();
++      pos = 1UL << (index - 2);
++      for (; pos; pos >>= 1)
++              num &= ~pos;
++      rpnpush(num);
++}
++
++static void ror_i(void)
++{
++      byte_t count = get_u8_oprnd();
++      __asm__ __volatile__("rorl %%cl, %0" 
++                              :"=m"(dprobes.rpn_stack[dprobes.rpn_tos])
++                              :"c"((unsigned long) count));
++}
++
++static void rol_i(void)
++{
++      byte_t count = get_u8_oprnd();
++      __asm__ __volatile__("roll %%cl, %0" 
++                              :"=m"(dprobes.rpn_stack[dprobes.rpn_tos])
++                              :"c"((unsigned long) count));
++}
++
++static void ror(void)
++{
++      unsigned long oprnd = rpnpop();
++      unsigned long count = rpnpop();
++      __asm__ __volatile__("rorl %%cl, %0" : "=m"(oprnd)
++                              :"c"(count) );
++      rpnpush(oprnd);
++}
++
++static void rol(void)
++{
++      unsigned long oprnd = rpnpop();
++      unsigned long count = rpnpop();
++      __asm__ __volatile__("roll %%cl, %0" : "=m"(oprnd)
++                              :"c"(count));
++      rpnpush(oprnd);
++}
++
++/*
++ * IO group
++ */
++static void push_io_u8(void)
++{
++      rpnpush(inb(rpnpop()));
++}
++static void push_io_u16(void)
++{
++        rpnpush(inw(rpnpop()));
++}
++
++static void push_io_u32(void)
++{
++        rpnpush(inl(rpnpop()));
++}
++
++static void pop_io_u8(void)
++{
++      u8 b = (u8)rpnpop();
++      outb(b, rpnpop());
++}
++
++static void pop_io_u16(void)
++{
++        u16 w = (u16)rpnpop();
++      outw(w, rpnpop());
++}
++
++static void pop_io_u32(void)
++{
++        u32 d = (u32)rpnpop();
++      outl(d, rpnpop());
++}
++
++/*
++ * Register push and pop, current and user registers.
++ */
++
++/*
++ * y -- allowed and implemented, n -- not allowed and not implemented.
++ *
++ * Index      Register        push u  push r  pop u   pop r   
++ *
++ * 0          cs              y       y       n       n
++ * 1          ds              y       y       y       y
++ * 2          es              y       y       y       y
++ * 3          fs              y       y       y       y
++ * 4          gs              y       y       y       y                       
++ * 5          ss              y       y       n       n
++ * 6          eax             y       y       y       y
++ * 7          ebx             y       y       y       y
++ * 8          ecx             y       y       y       y
++ * 9          edx             y       y       y       y
++ * a          edi             y       y       y       y
++ * b          esi             y       y       y       y       
++ * c          eflags          y       y       n       n
++ * d          eip             y       y       n       n
++ * e          esp             y       y       n       n
++ * f          ebp             y       y       y       y
++ * 20         tr              n       y       n       n
++ * 21         ldtr            n       y       n       n
++ * 22         gdtr            n       y       n       n
++ * 23         idtr            n       y       n       n
++ * 24         cr0             n       y       n       n
++ * 25         cr1                     RESERVED                        
++ * 26         cr2             n       y       n       n
++ * 27         cr3             n       y       n       n
++ * 28         cr4             n       y       n       n
++ * 29         cr5                     RESERVED
++ * 2a         cr6                     RESERVED
++ * 2b         cr7                     RESERVED
++ * 2c         dr0             n       y       n       n
++ * 2d         dr1             n       y       n       n
++ * 2e         dr2             n       y       n       n
++ * 2f         dr3             n       y       n       n
++ * 30         dr4                     RESERVED        
++ * 31         dr5                     RESERVED
++ * 32         dr6             n       y       n       n
++ * 33         dr7             n       y       n       n
++ * 34         tr0                     RESERVED
++ * 35         tr1                     RESERVED
++ * 36         tr2                     RESERVED
++ * 37         tr3                     RESERVED        
++ * 38         tr4                     RESERVED
++ * 39         tr5                     RESERVED
++ * 3a         tr6                     RESERVED
++ * 3b         tr7                     RESERVED
++ * 3c         cpuid           y       y       n       n
++ * 3d         msr             y       y       n       n
++ * 3e         fr0             y       n       n       n
++ * 3f         fr1             y       n       n       n
++ * 40         fr2             y       n       n       n
++ * 41         fr3             y       n       n       n
++ * 42         fr4             y       n       n       n
++ * 43         fr5             y       n       n       n
++ * 44         fr6             y       n       n       n
++ * 45         fr7             y       n       n       n
++ * 46         fcw             y       n       n       n
++ * 47         fsw             y       n       n       n
++ * 48         ftw             y       n       n       n
++ * 49         fip             y       n       n       n
++ * 4a         fcs             y       n       n       n
++ * 4b         fdp             y       n       n       n
++ * 4c         fds             y       n       n       n
++ * 4d         xmm0            y       n       n       n
++ * 4e         xmm1            y       n       n       n
++ * 4f         xmm2            y       n       n       n
++ * 50         xmm3            y       n       n       n
++ * 51         xmm4            y       n       n       n
++ * 52         xmm5            y       n       n       n
++ * 53         xmm6            y       n       n       n
++ * 54         xmm7            y       n       n       n
++ * 55         mxcsr           y       n       n       n
++ */
++
++static void dp_save_fpu(void)
++{
++      dprobes.status &= ~DP_STATUS_FIRSTFPU;
++      if (HAVE_HWFP) {
++              if (!current->used_math) {
++                      memset(&dprobes.fpu_save_area,0, sizeof(dprobes.fpu_save_area));
++                      return;
++              }
++
++              if ((read_cr0()) & CR0_TS) {
++                      dprobes.fpu_save_area = current->thread.i387;
++              }
++              else {
++                      if (cpu_has_fxsr) {
++                              __asm__ __volatile__ (
++                                      "fxsave %0\n"   
++                                      "fxrstor %0" :"=m" (dprobes.fpu_save_area));
++                      } else {
++                              __asm__ __volatile__ (
++                                      "fsave %0\n"    
++                                      "frstor %0" :"=m" (dprobes.fpu_save_area));
++              
++                      }
++              }
++      }
++      else
++              memset(&dprobes.fpu_save_area,0, sizeof(dprobes.fpu_save_area));
++
++}
++
++/*
++ * Define Floating Point Control Registers' push functions.
++ */
++
++#define DEFINE_PUSHFP(REG) \
++static void pushfp_##REG(void) \
++{ \
++      if (dprobes.status & DP_STATUS_FIRSTFPU) \
++              dp_save_fpu(); \
++      if (cpu_has_fxsr) \
++              rpnpush(dprobes.fpu_save_area.fxsave.REG); \
++      else \
++              rpnpush(dprobes.fpu_save_area.fsave.REG); \
++}
++
++DEFINE_PUSHFP(cwd)
++DEFINE_PUSHFP(swd)
++DEFINE_PUSHFP(twd)
++DEFINE_PUSHFP(fip)
++DEFINE_PUSHFP(fcs)
++DEFINE_PUSHFP(foo)
++DEFINE_PUSHFP(fos)
++
++static void pushfp_mxcsr(void)
++{
++      if (dprobes.status & DP_STATUS_FIRSTFPU)
++              dp_save_fpu();
++      if (cpu_has_xmm)
++              rpnpush(dprobes.fpu_save_area.fxsave.mxcsr);
++      else
++              rpnpush(0); /* could we return 0x1f80 ? */
++}
++
++/*
++ * Floating Point Data Registers' push function.
++ */
++static void pushfp_st(int offset)
++{
++      unsigned long st_0, st_4, st_8;
++      if (dprobes.status & DP_STATUS_FIRSTFPU)
++              dp_save_fpu();
++      if (cpu_has_fxsr) {
++              offset = (offset - 0x3e) * 16;
++              st_0 = *(unsigned long *) ((unsigned char *)
++                      (dprobes.fpu_save_area.fxsave.st_space) + offset);
++              st_4 = *(unsigned long *) ((unsigned char *)
++                      (dprobes.fpu_save_area.fxsave.st_space) + offset + 4);
++              st_8 = *(unsigned long *) ((unsigned char *)
++                      (dprobes.fpu_save_area.fxsave.st_space) + offset + 8);
++      }
++      else {
++              offset = (offset - 0x3e) * 10;
++              st_0 = *(unsigned long *) ((unsigned char *)
++                      (dprobes.fpu_save_area.fsave.st_space) + offset);
++              st_4 = *(unsigned long *) ((unsigned char *)
++                      (dprobes.fpu_save_area.fsave.st_space) + offset + 4);
++              st_8 = *(unsigned short *) ((unsigned char *)
++                      (dprobes.fpu_save_area.fsave.st_space) + offset + 8);
++      }
++      rpnpush(st_8);
++      rpnpush(st_4);
++      rpnpush(st_0);
++}
++
++static void push_xmm(int offset)
++{
++      unsigned long xmm_0 = 0, xmm_4 = 0, xmm_8 = 0, xmm_12 = 0;
++      if (dprobes.status & DP_STATUS_FIRSTFPU)
++              dp_save_fpu();
++      if (cpu_has_xmm) {
++              offset = (offset - 0x4d) * 16;
++              xmm_0 = *(unsigned long *) ((unsigned char *)
++                      (dprobes.fpu_save_area.fxsave.xmm_space) + offset);
++              xmm_4 = *(unsigned long *) ((unsigned char *)
++                      (dprobes.fpu_save_area.fxsave.xmm_space) + offset + 4);
++              xmm_8 = *(unsigned long *) ((unsigned char *)
++                      (dprobes.fpu_save_area.fxsave.xmm_space) + offset + 8);
++              xmm_12 = *(unsigned long *) ((unsigned char *)
++                      (dprobes.fpu_save_area.fxsave.xmm_space) + offset + 12);
++      }
++      rpnpush(xmm_12);
++      rpnpush(xmm_8);
++      rpnpush(xmm_4);
++      rpnpush(xmm_0);
++}
++
++/*
++ * push r, ss.
++ */
++static unsigned long getr_ss(void)
++{
++      unsigned long reg;
++      if (dprobes.status & DP_KERNEL_PROBE)
++              __asm__ __volatile__("movw %%ss, %%ax\n\t"
++                                    :"=a"(reg)
++                                   );
++      else 
++              reg = dprobes.regs->xss;
++      return reg;
++}
++
++/*
++ * push r, esp
++ */
++static unsigned long getr_esp(void)
++{
++      if (dprobes.status & DP_KERNEL_PROBE)
++              return (unsigned long)&dprobes.regs->esp;
++      else 
++              return dprobes.regs->esp;
++}
++
++/*
++ * Push GDTR
++ */
++static void push_gdtr(void)
++{
++      struct Xgt_desc_struct gdtr;
++      __asm__ __volatile__("sgdt (%0)" : : "r"((unsigned long) &gdtr));
++
++      rpnpush(gdtr.address);
++      rpnpush((unsigned long) gdtr.size);
++}
++
++/*
++ * Push LDTR
++ */
++static void push_ldtr(void)
++{
++      unsigned long ldtr = 0; 
++      __asm__ __volatile__("sldt %0" : "=r"(ldtr));
++      rpnpush(ldtr);
++}
++
++/*
++ * Push IDTR
++ */
++static void push_idtr(void)
++{
++      struct Xgt_desc_struct idtr;
++      __asm__ __volatile__("sidt (%0)" : : "r"((unsigned long) &idtr));
++
++      rpnpush(idtr.address);
++      rpnpush((unsigned long)idtr.size);
++}
++
++/*
++ * Push TR
++ */
++static void push_tr(void)
++{
++      unsigned long tr;
++      __asm__ __volatile__("str %%ax" : "=a"(tr));
++      rpnpush(tr);
++}
++
++/*
++ * Push cpuid.
++ */
++static void push_cpuid(void)
++{
++      int op, cpuid_eax = 0, cpuid_ebx = 0, cpuid_ecx = 0, cpuid_edx = 0;
++      op = (int) rpnpop();
++      if ((boot_cpu_data.x86 >= 5) && (op <= boot_cpu_data.cpuid_level)) 
++              cpuid(op, &cpuid_eax, &cpuid_ebx, &cpuid_ecx, &cpuid_edx);
++      rpnpush(cpuid_edx);
++      rpnpush(cpuid_ecx);
++      rpnpush(cpuid_ebx);
++      rpnpush(cpuid_eax);
++}
++      
++/*
++ * push msr. 
++ */
++static void push_msr(void)
++{
++      unsigned long msr, val1 =0, val2 = 0;
++      msr = rpnpop();
++      if (boot_cpu_data.x86 >= 5) 
++              __asm__ __volatile__ (
++                      "0:     rdmsr\n"
++                      "1:\n"
++                      ".section .fixup,\"ax\"\n"
++                      "2:     jmp 1b\n"
++                      ".previous\n"
++                      ".section __ex_table,\"a\"\n"
++                      "       .align 4\n"
++                      "       .long 0b,2b\n"
++                      ".previous"
++                      :"=a"(val1), "=d"(val2)
++                      :"c"(msr));
++      rpnpush(val2);
++      rpnpush(val1);
++}
++
++/*    
++ * Prototype for control registers'(CR0 TO CR4) and debug registers'(DR0 TO DR7)
++ * push functions.
++ */
++#define DEFINE_PUSHCRDB(REG) \
++static void push_##REG(void) \
++{ \
++      unsigned long reg; \
++      __asm__ __volatile__ ("movl %%" #REG ", %0" : "=r"(reg)); \
++      rpnpush(reg); \
++}
++
++/*
++ * Define control and debug registers' push functions.
++ */
++DEFINE_PUSHCRDB(cr0)
++DEFINE_PUSHCRDB(cr2)
++DEFINE_PUSHCRDB(cr3)
++DEFINE_PUSHCRDB(cr4)
++DEFINE_PUSHCRDB(dr0)
++DEFINE_PUSHCRDB(dr1)
++DEFINE_PUSHCRDB(dr2)
++DEFINE_PUSHCRDB(dr3)
++DEFINE_PUSHCRDB(dr6)
++DEFINE_PUSHCRDB(dr7)
++
++/*
++ * Since fs and gs are not in pt_regs, these
++ * are directly taken from the processor.
++ */
++static unsigned long read_fs(void)
++{
++      unsigned long val;
++      __asm__ __volatile__("movw %%fs, %%ax" :"=a"(val));
++      return val;
++}
++
++static unsigned long read_gs(void)
++{
++      unsigned long val;
++      __asm__ __volatile__("movw %%gs, %%ax" :"=a"(val));
++      return val;
++}
++
++static void write_fs(unsigned long val)
++{
++      __asm__ __volatile__("movw %%ax, %%fs" : : "a"(val));
++}
++
++static void write_gs(unsigned long val)
++{
++      __asm__ __volatile__("movw %%ax, %%gs" : :"a"(val));
++}
++
++/*
++ * Current register main push function.
++ */
++static void pushr(void)
++{
++      struct dprobes_struct *dp = &dprobes;
++      unsigned short index = get_u16_oprnd();
++      unsigned long val;
++      switch(index) {
++              case DP_CS:     val = dp->regs->xcs; break;
++              case DP_DS:     val = dp->regs->xds; break;
++              case DP_ES:     val = dp->regs->xes; break;
++              case DP_FS:     val = read_fs(); break;
++              case DP_GS:     val = read_gs(); break;
++              case DP_SS:     val = getr_ss(); break;
++              case DP_EAX:    val = dp->regs->eax; break;
++              case DP_EBX:    val = dp->regs->ebx; break;
++              case DP_ECX:    val = dp->regs->ecx; break;
++              case DP_EDX:    val = dp->regs->edx; break;
++              case DP_EDI:    val = dp->regs->edi; break;
++              case DP_ESI:    val = dp->regs->esi; break;
++              case DP_EFLAGS: val = dp->regs->eflags; break;
++              case DP_EIP:    val = dp->regs->eip; break;
++              case DP_ESP:    val = getr_esp(); break;
++              case DP_EBP:    val = dp->regs->ebp; break;
++
++              /* special registers */
++              case DP_TR:     push_tr(); return;
++              case DP_LDTR:   push_ldtr(); return;
++              case DP_GDTR:   push_gdtr(); return;
++              case DP_IDTR:   push_idtr(); return;
++              case DP_CR0:    push_cr0(); return;
++              case DP_CR2:    push_cr2(); return;
++              case DP_CR3:    push_cr3(); return;
++              case DP_CR4:    push_cr4(); return;
++              case DP_DR0:    push_dr0(); return;
++              case DP_DR1:    push_dr1(); return;
++              case DP_DR2:    push_dr2(); return;
++              case DP_DR3:    push_dr3(); return;
++              case DP_DR6:    push_dr6(); return;
++              case DP_DR7:    push_dr7(); return;
++              case DP_CPUID:  push_cpuid(); return;
++              case DP_MSR:    push_msr(); return;
++              default:        val = 0; break;
++      }
++      rpnpush(val);
++      return;
++}
++
++/*
++ * User register main push function.
++ */
++static void pushu(void)
++{
++      struct dprobes_struct *dp = &dprobes;
++      unsigned short index = get_u16_oprnd();
++      unsigned long val;
++      switch(index) {
++              case DP_CS:     val = dp->uregs->xcs; break;
++              case DP_DS:     val = dp->uregs->xds; break;
++              case DP_ES:     val = dp->uregs->xes; break;
++              case DP_FS:     val = read_fs(); break;
++              case DP_GS:     val = read_gs(); break;
++              case DP_SS:     val = dp->uregs->xss; break;
++              case DP_EAX:    val = dp->uregs->eax; break;
++              case DP_EBX:    val = dp->uregs->ebx; break;
++              case DP_ECX:    val = dp->uregs->ecx; break;
++              case DP_EDX:    val = dp->uregs->edx; break;
++              case DP_EDI:    val = dp->uregs->edi; break;
++              case DP_ESI:    val = dp->uregs->esi; break;
++              case DP_EFLAGS: val = dp->uregs->eflags; break;
++              case DP_EIP:    val = dp->uregs->eip; break;
++              case DP_ESP:    val = dp->uregs->esp; break;
++              case DP_EBP:    val = dp->uregs->ebp; break;
++              case DP_CPUID:  push_cpuid(); return;
++              case DP_MSR:    push_msr(); return;
++              case DP_FR0:    pushfp_st(0x3e); return;
++              case DP_FR1:    pushfp_st(0x3f); return;
++              case DP_FR2:    pushfp_st(0x40); return;
++              case DP_FR3:    pushfp_st(0x41); return;
++              case DP_FR4:    pushfp_st(0x42); return;
++              case DP_FR5:    pushfp_st(0x43); return;
++              case DP_FR6:    pushfp_st(0x44); return;
++              case DP_FR7:    pushfp_st(0x45); return;
++              case DP_FCW:    pushfp_cwd(); return;
++              case DP_FSW:    pushfp_swd(); return;
++              case DP_FTW:    pushfp_twd(); return;
++              case DP_FIP:    pushfp_fip(); return;
++              case DP_FCS:    pushfp_fcs(); return;
++              case DP_FDP:    pushfp_foo(); return;
++              case DP_FDS:    pushfp_fos(); return;
++              
++              case DP_XMM0:   push_xmm(0x4d); return;
++              case DP_XMM1:   push_xmm(0x4e); return;
++              case DP_XMM2:   push_xmm(0x4f); return;
++              case DP_XMM3:   push_xmm(0x50); return;
++              case DP_XMM4:   push_xmm(0x51); return;
++              case DP_XMM5:   push_xmm(0x52); return;
++              case DP_XMM6:   push_xmm(0x53); return;
++              case DP_XMM7:   push_xmm(0x54); return;
++              case DP_MXCSR:  pushfp_mxcsr(); return;
++
++              default:        val = 0; break;
++      }
++      rpnpush(val);
++      return;
++}
++
++/*
++ * Current register main pop function.
++ */
++static void popr(void)
++{
++      struct dprobes_struct *dp = &dprobes;
++      unsigned short index = get_u16_oprnd();
++      unsigned long val = rpnpop();
++      switch(index) {
++              case DP_DS:     dp->regs->xds = val; break;
++              case DP_ES:     dp->regs->xes = val; break;
++              case DP_FS:     write_fs(val); break;
++              case DP_GS:     write_gs(val); break;
++              case DP_EAX:    dp->regs->eax = val; break;
++              case DP_EBX:    dp->regs->ebx = val; break;
++              case DP_ECX:    dp->regs->ecx = val; break;
++              case DP_EDX:    dp->regs->edx = val; break;
++              case DP_EDI:    dp->regs->edi = val; break;
++              case DP_ESI:    dp->regs->esi = val; break;
++              case DP_EBP:    dp->regs->ebp = val; break;
++              default:        break;
++      }
++}
++
++/*
++ * User register main pop function.
++ */
++static void popu(void)
++{
++      struct dprobes_struct *dp = &dprobes;
++      unsigned short index = get_u16_oprnd();
++      unsigned long val = rpnpop();
++      switch(index) {
++              case DP_DS:     dp->uregs->xds = val; break;
++              case DP_ES:     dp->uregs->xes = val; break;
++              case DP_FS:     write_fs(val); break;
++              case DP_GS:     write_gs(val); break;
++              case DP_EAX:    dp->uregs->eax = val; break;
++              case DP_EBX:    dp->uregs->ebx = val; break;
++              case DP_ECX:    dp->uregs->ecx = val; break;
++              case DP_EDX:    dp->uregs->edx = val; break;
++              case DP_EDI:    dp->uregs->edi = val; break;
++              case DP_ESI:    dp->uregs->esi = val; break;
++              case DP_EBP:    dp->uregs->ebp = val; break;
++              default:        break;
++      }
++}
++
++/*
++ * Entry point for the dprobes interpreter(Probe handler).
++ */
++static void dp_asm_interpreter(byte_t rpn_instr)
++{
++      struct dprobes_struct *dp = &dprobes;
++
++              switch(rpn_instr) {
++
++                      case DP_SEG2LIN:        seg2lin(); break;               
++
++                      case DP_PUSH_IO_U8:     push_io_u8(); break;            
++                      case DP_PUSH_IO_U16:    push_io_u16(); break;           
++                      case DP_PUSH_IO_U32:    push_io_u32(); break;           
++                      case DP_POP_IO_U8:      pop_io_u8(); break;             
++                      case DP_POP_IO_U16:     pop_io_u16(); break;
++                      case DP_POP_IO_U32:     pop_io_u32(); break;
++
++                      default: gen_ex(EX_INVALID_OPCODE, *(dp->rpn_ip - 1),
++                      (unsigned long)(dp->rpn_ip -dp->rpn_code - 1)); break;          }
++      return;
++}
+diff -urNp linux-2.6.0-test9/drivers/dprobes/Makefile linux-2.6.0-test9+kp/drivers/dprobes/Makefile
+--- linux-2.6.0-test9/drivers/dprobes/Makefile 1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.0-test9+kp/drivers/dprobes/Makefile      2003-11-18 07:29:47.000000000 +0530
+@@ -0,0 +1,13 @@
++#
++# Makefile for IBM Dynamic Probes
++#
++
++# Multipart objects.
++dp-objs               := dprobes.o dprobes_in.o
++
++# Optional parts of multipart objects.
++ifeq ($(CONFIG_X86),y)
++      dp-objs += i386/dprobes.o
++endif
++
++obj-$(CONFIG_DPROBES) += dp.o
+diff -urNp linux-2.6.0-test9/drivers/Makefile linux-2.6.0-test9+kp/drivers/Makefile
+--- linux-2.6.0-test9/drivers/Makefile 2003-10-26 00:14:30.000000000 +0530
++++ linux-2.6.0-test9+kp/drivers/Makefile      2003-11-18 07:29:47.000000000 +0530
+@@ -49,3 +49,4 @@ obj-$(CONFIG_ISDN_BOOL)              += isdn/
+ obj-$(CONFIG_MCA)             += mca/
+ obj-$(CONFIG_EISA)            += eisa/
+ obj-$(CONFIG_CPU_FREQ)                += cpufreq/
++obj-$(CONFIG_DPROBES)         += dprobes/
+diff -urNp linux-2.6.0-test9/fs/exec.c linux-2.6.0-test9+kp/fs/exec.c
+--- linux-2.6.0-test9/fs/exec.c        2003-10-26 00:13:25.000000000 +0530
++++ linux-2.6.0-test9+kp/fs/exec.c     2003-11-18 07:29:47.000000000 +0530
+@@ -1391,3 +1391,4 @@ fail:
+       unlock_kernel();
+       return retval;
+ }
++EXPORT_SYMBOL(do_coredump);
+diff -urNp linux-2.6.0-test9/fs/namei.c linux-2.6.0-test9+kp/fs/namei.c
+--- linux-2.6.0-test9/fs/namei.c       2003-10-26 00:13:22.000000000 +0530
++++ linux-2.6.0-test9+kp/fs/namei.c    2003-11-18 07:29:48.000000000 +0530
+@@ -264,6 +264,18 @@ int deny_write_access(struct file * file
+       return 0;
+ }
++int deny_write_access_to_inode(struct inode * inode)
++{
++      spin_lock(&arbitration_lock);
++      if (atomic_read(&inode->i_writecount) > 0) {
++              spin_unlock(&arbitration_lock);
++              return -ETXTBSY;
++      }
++      atomic_dec(&inode->i_writecount);
++      spin_unlock(&arbitration_lock);
++      return 0;
++}
++
+ void path_release(struct nameidata *nd)
+ {
+       dput(nd->dentry);
+@@ -2307,3 +2319,8 @@ EXPORT_SYMBOL(vfs_rename);
+ EXPORT_SYMBOL(vfs_rmdir);
+ EXPORT_SYMBOL(vfs_symlink);
+ EXPORT_SYMBOL(vfs_unlink);
++#ifdef CONFIG_DPROBES_MODULE
++extern int deny_write_access_to_inode(struct inode *);
++EXPORT_SYMBOL(deny_write_access_to_inode);
++#endif
++
+diff -urNp linux-2.6.0-test9/include/asm-i386/debugreg.h linux-2.6.0-test9+kp/include/asm-i386/debugreg.h
+--- linux-2.6.0-test9/include/asm-i386/debugreg.h      2003-10-26 00:14:17.000000000 +0530
++++ linux-2.6.0-test9+kp/include/asm-i386/debugreg.h   2003-11-18 07:29:47.000000000 +0530
+@@ -61,4 +61,166 @@
+ #define DR_LOCAL_SLOWDOWN (0x100)   /* Local slow the pipeline */
+ #define DR_GLOBAL_SLOWDOWN (0x200)  /* Global slow the pipeline */
++struct debugreg {
++      unsigned long flag;
++      unsigned long use_count;
++};
++
++/* debugreg flags */
++#define DR_UNUSED     0
++#define DR_LOCAL      1
++#define DR_GLOBAL     2
++      
++#define DR_MAX        4
++#define DR_ANY        DR_MAX + 1
++
++/* global or local allocation requests */
++#define DR_ALLOC_GLOBAL               0
++#define DR_ALLOC_LOCAL                1
++
++#define DR7_RW_SET(dr, regnum, rw) do {       \
++              (dr) &= ~(0x3 << (16 + (4 * (regnum)))); \
++              (dr) |= (((rw) & 0x3) << (16 + (4 * (regnum)))); \
++      } while (0)
++
++#define DR7_RW_VAL(dr, regnum) \
++      (((dr) >> (16 + (4 * (regnum)))) & 0x3)
++
++#define DR7_LEN_SET(dr, regnum, len) do { \
++              (dr) &= ~(0x3 << (18 + (4 * (regnum)))); \
++              (dr) |= (((len-1) & 0x3) << (18 + (4 * (regnum)))); \
++      } while (0)
++
++#define DR7_LEN_VAL(dr, regnum) \
++      (((dr) >> (18 + (4 * (regnum)))) & 0x3)
++
++#define DR7_L0(dr)    (((dr))&0x1)
++#define DR7_L1(dr)    (((dr)>>2)&0x1)
++#define DR7_L2(dr)    (((dr)>>4)&0x1)
++#define DR7_L3(dr)    (((dr)>>6)&0x1)
++
++#define DR_IS_LOCAL(dr, num) ((dr) & (1UL << (num <<1)))
++
++/* Set the rw, len and global flag in dr7 for a debug register */
++#define SET_DR7(dr, regnum, access, len) do { \
++              DR7_RW_SET(dr, regnum, access); \
++              DR7_LEN_SET(dr, regnum, len); \
++              dr |= (2UL << regnum*2); \
++      } while (0)
++
++/* Disable a debug register by clearing the global/local flag in dr7 */
++#define RESET_DR7(dr, regnum) dr &= ~(3UL << regnum*2)
++
++#define DR7_DR0_BITS          0x000F0003
++#define DR7_DR1_BITS          0x00F0000C
++#define DR7_DR2_BITS          0x0F000030
++#define DR7_DR3_BITS          0xF00000C0
++
++#define DR_TRAP_MASK          0xF
++
++#define DR_TYPE_EXECUTE               0x0
++#define DR_TYPE_WRITE         0x1
++#define DR_TYPE_IO            0x2
++#define DR_TYPE_RW            0x3
++
++#define get_dr(regnum, val) \
++              __asm__("movl %%db" #regnum ", %0"  \
++                      :"=r" (val))
++static inline unsigned long read_dr(int regnum)
++{
++      unsigned long val = 0;
++      switch (regnum) {
++              case 0: get_dr(0, val); break;
++              case 1: get_dr(1, val); break;
++              case 2: get_dr(2, val); break;
++              case 3: get_dr(3, val); break;
++              case 6: get_dr(6, val); break;
++              case 7: get_dr(7, val); break;
++      }
++      return val;
++}
++#undef get_dr
++      
++#define set_dr(regnum, val) \
++              __asm__("movl %0,%%db" #regnum  \
++                      : /* no output */ \
++                      :"r" (val))
++static inline void write_dr(int regnum, unsigned long val)
++{
++      switch (regnum) {
++              case 0: set_dr(0, val); break;
++              case 1: set_dr(1, val); break;
++              case 2: set_dr(2, val); break;
++              case 3: set_dr(3, val); break;
++              case 7: set_dr(7, val); break;
++      }
++      return;
++}
++#undef set_dr
++
++#ifdef CONFIG_DEBUGREG
++/*
++ * Given the debug status register, returns the debug register number
++ * which caused the debug trap.
++ */
++static inline int dr_trap(unsigned int condition)
++{
++      int i, reg_shift = 1UL;
++      for (i = 0; i < DR_MAX; i++, reg_shift <<= 1)
++              if ((condition & reg_shift))
++                      return i;       
++      return -1;
++}
++
++/*
++ * Given the debug status register, returns the address due to which
++ * the debug trap occured.
++ */
++static inline unsigned long dr_trap_addr(unsigned int condition)
++{
++      int regnum = dr_trap(condition);
++
++      if (regnum == -1)
++              return -1;
++      return read_dr(regnum);
++}
++
++/*
++ * Given the debug status register, returns the type of debug trap:
++ * execute, read/write, write or io.
++ */
++static inline int dr_trap_type(unsigned int condition)
++{
++      int regnum = dr_trap(condition);
++
++      if (regnum == -1)
++              return -1;
++      return DR7_RW_VAL(read_dr(7), regnum);
++}
++
++/* Function declarations */
++
++extern int dr_alloc(int regnum, int flag);
++extern int dr_free(int regnum);
++extern void dr_inc_use_count(unsigned long mask);
++extern void dr_dec_use_count(unsigned long mask);
++extern struct debugreg dr_list[DR_MAX];
++extern unsigned long dr7_global_mask;
++extern int enable_debugreg(unsigned long old_dr7, unsigned long new_dr7);
++
++static inline void load_process_dr7(unsigned long curr_dr7)
++{
++      write_dr(7, (read_dr(7) & dr7_global_mask) | curr_dr7);
++}
++#else
++static inline int enable_debugreg(unsigned long old_dr7, unsigned long new_dr7) { return 0; }
++static inline void load_process_dr7(unsigned long curr_dr7)
++{
++      write_dr(7, curr_dr7);
++}
++
++static void dr_inc_use_count(unsigned long mask) { }
++static void dr_dec_use_count(unsigned long mask) { }
++
++#endif /* CONFIG_DEBUGREG */
+ #endif
+diff -urNp linux-2.6.0-test9/include/asm-i386/dprobes_exclude.h linux-2.6.0-test9+kp/include/asm-i386/dprobes_exclude.h
+--- linux-2.6.0-test9/include/asm-i386/dprobes_exclude.h       1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.0-test9+kp/include/asm-i386/dprobes_exclude.h    2003-11-18 07:30:12.000000000 +0530
+@@ -0,0 +1,84 @@
++#ifndef __ASM_I386_DPROBES_EXCLUDE_H__
++#define __ASM_I386_DPROBES_EXCLUDE_H__
++
++/*
++ * IBM Dynamic Probes
++ * Copyright (c) International Business Machines Corp., 2000
++ *
++ * 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.  
++ */
++
++/*
++ * Exclude regions markers: We do not allow probes to be placed in these
++ * code areas to _prevent_ recursion into dp_trap3. Note that this does
++ * not eliminate the possibility of recursion completely. dp_trap3 handles
++ * recursion by silently and permanently removing the recursed probe point.
++ */
++#include <linux/kprobes.h>
++#include <asm/kwatch.h>
++
++extern void kprobes_code_start(void);
++extern void kprobes_code_end(void);
++extern void kprobes_asm_code_start(void);
++extern void kprobes_asm_code_end(void);
++extern void dprobes_code_start(void);
++extern void dprobes_code_end(void);
++extern void dprobes_asm_code_start(void);
++extern void dprobes_asm_code_end(void);
++extern void dprobes_interpreter_code_start(void);
++extern void dprobes_interpreter_code_end(void);
++
++#ifdef CONFIG_DR_ALLOC
++extern void kwatch_asm_start(void);
++extern void kwatch_asm_end(void);
++#endif
++
++struct region {
++      unsigned long start;
++      unsigned long end;
++};
++
++#define NR_EXCLUDED_REGIONS 6
++static struct region exclude[] = {
++#ifdef CONFIG_DR_ALLOC
++      {(unsigned long)kwatch_asm_start,
++              (unsigned long)kwatch_asm_end},
++#else 
++      {0, 0},
++#endif
++      {(unsigned long)kprobes_code_start,
++              (unsigned long)kprobes_code_end},
++      {(unsigned long)kprobes_asm_code_start,
++              (unsigned long)kprobes_asm_code_end},
++      {(unsigned long)dprobes_code_start,
++              (unsigned long)dprobes_code_end},
++      {(unsigned long)dprobes_asm_code_start,
++              (unsigned long)dprobes_asm_code_end},
++      {(unsigned long)dprobes_interpreter_code_start,
++              (unsigned long)dprobes_interpreter_code_end}
++};
++
++static inline int dprobes_excluded(unsigned long addr)
++{
++      int i;
++      for (i = 0; i < NR_EXCLUDED_REGIONS; i++) {
++              if (addr >= exclude[i].start && addr <= exclude[i].end) {
++                      return 1;
++              }
++      }
++      return 0;
++}
++
++#endif /* __ASM_I386_DPROBES_EXCLUDE_H__ */
+diff -urNp linux-2.6.0-test9/include/asm-i386/dprobes.h linux-2.6.0-test9+kp/include/asm-i386/dprobes.h
+--- linux-2.6.0-test9/include/asm-i386/dprobes.h       1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.0-test9+kp/include/asm-i386/dprobes.h    2003-11-18 07:29:48.000000000 +0530
+@@ -0,0 +1,202 @@
++#ifndef __ASM_I386_DPROBES_H__
++#define __ASM_I386_DPROBES_H__
++
++/*
++ * IBM Dynamic Probes
++ * Copyright (c) International Business Machines Corp., 2000
++ *
++ * 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.  
++ */
++
++/*
++ * RPN stack width will always be equal to the machine register width.
++ */
++#define RPN_STACK_SIZE        1024
++#define CALL_FRAME_SIZE               10
++#define NR_NESTED_CALLS               32
++/* 1st is a dummy frame, not used by call instruction */
++#define CALL_STACK_SIZE               (NR_NESTED_CALLS+1)*CALL_FRAME_SIZE 
++#define FMT_LOG_HDR_SIZE      256
++
++/* Offsets of different items on call stack */
++#define OFFSET_SBP            0
++#define OFFSET_GV_RANGE               1
++#define OFFSET_LV_RANGE               3
++#define OFFSET_RPN_STACK_RANGE        5
++#define OFFSET_EX_HANDLER     7
++#define OFFSET_CALLED_ADDR    8
++#define OFFSET_RETURN_ADDR    9
++
++/* 
++ * offsets of different repitition entries (3 byte prefix) in the 
++ * exception stacktrace buffer.
++ */
++struct ex_buffer_offset {
++      unsigned long st;       /* ex stack traces */
++      unsigned long sf;       /* ex stack frames */
++      unsigned long rpn;      /* rpn stack entries */
++      unsigned long lv;       /* lv entries */
++      unsigned long gv;       /* gv entries */
++};
++
++/* Token bytes of all available 3 byte prefixes */
++#define TOKEN_SEG_FAULT               -2
++#define TOKEN_MEMORY_FAULT    -1
++#define TOKEN_MEMORY_LOG      0
++#define TOKEN_ASCII_LOG               1
++#define TOKEN_STACK_TRACE     2
++#define TOKEN_STACK_FRAME     3
++#define TOKEN_RPN_ENTRY               4
++#define TOKEN_LV_ENTRY                5
++#define TOKEN_GV_ENTRY                6
++#define TOKEN_LOG             7
++
++#define PREFIX_SIZE           3
++
++struct dprobes_struct {
++      unsigned long status;   /* status */
++      /*
++       * details about the probe that is hit, kept here for quick access at
++       * trap1 time.
++       */
++      unsigned long probe_addr;
++      struct pt_regs *regs;
++      struct pt_regs *uregs;
++      struct dp_module_struct *mod;
++      struct dp_record_struct *rec;
++
++      /* fpu registers are saved here */
++      union i387_union fpu_save_area;
++
++      /*
++       * Optional data to store with the log record. This data is collected
++       * in the interpreter and used in the trap1 handler when writing the
++       * log to the specified log target.
++       */
++      unsigned long eip;
++      unsigned short cs;
++      unsigned long esp;
++      unsigned short ss;
++      unsigned short major, minor;
++
++      /*
++       * per-processor data used by the interpreter.
++       */
++      unsigned long rpn_tos, call_tos, log_len, prev_log_len, ex_log_len;
++      byte_t * rpn_code;
++      byte_t * rpn_ip;
++      unsigned short jmp_count;
++      byte_t opcode;
++      byte_t reserved;
++      byte_t ex_pending;
++      unsigned long ex_code;
++      unsigned long ex_parm1, ex_parm2, ex_hand;
++      struct ex_buffer_offset ex_off;
++      unsigned long rpn_sbp;
++      unsigned long heap_size;
++
++      /*
++       * locks used to handle recursion.
++       */
++      spinlock_t lock;
++      long sem;
++
++      unsigned long rpn_stack[RPN_STACK_SIZE];
++      unsigned long call_stack[CALL_STACK_SIZE];
++      unsigned char log[LOG_SIZE];
++      unsigned char ex_log[EX_LOG_SIZE];
++      unsigned char log_hdr[FMT_LOG_HDR_SIZE];
++};
++
++/*
++ * status
++ *
++ * DP_KENREL_PROBE: When this is set, we will not use the pte* fields in the
++ * alias structure at trap1 time, we can write directly to the probe_addr.
++ *
++ * DP_STATUS_ERROR: Contains all the bits to check for error conditions.
++ *
++ * DP_STATUS_DONE: Contains all the per-probe hit bits that need to be turned
++ * off after a probe handler is executed.
++ *
++ * DP_STATUS_ABORT: Indicates that the designated exit facility should not
++ * be called after the original instruction is successfully single-stepped.
++ */
++#define DP_STATUS_INACTIVE      0x00000000
++#define DP_STATUS_ACTIVE      0x00000001
++
++#define DP_STATUS_ERROR               0x00ff0000
++#define DP_STATUS_GPF         0x00010000
++#define DP_STATUS_PF          0x00020000
++#define DP_STATUS_LOG_OVERFLOW        0x00040000
++
++#define DP_STATUS_INTERPRETER   0x01000000
++#define DP_STATUS_SS          0x02000000
++#define DP_KERNEL_PROBE               0x04000000
++#define DP_USER_PROBE         0x08000000
++#define DP_STATUS_ABORT               0x10000000
++#define DP_STATUS_FIRSTFPU    0x20000000
++#define DP_STATUS_DONE                0xffff0000
++
++#define DP_INSTR_BREAKPOINT   0xcc
++
++/* arch-specific rec flags */
++#define DP_REC_OPCODE_EMULATED                0x01000000
++#define DP_REC_OPCODE_IF_MODIFIER     0x02000000
++
++#ifndef EF_CF
++#define EF_CF 0x00000001
++#endif
++#ifndef EF_TF
++#define EF_TF 0x00000100
++#endif
++#ifndef EF_IE
++#define EF_IE 0x00000200
++#endif
++#ifndef EF_DF
++#define EF_DF 0x00000400
++#endif
++#ifndef EF_RF
++#define EF_RF 0x00010000
++#endif
++
++#define CR0_TS  0x00000008
++
++#ifndef HAVE_HWFP
++#ifdef CONFIG_MATH_EMULATION
++#define HAVE_HWFP (boot_cpu_data.hard_math)
++#else
++#define HAVE_HWFP 1
++#endif
++#endif
++
++/*
++ *  Function declarations
++ */
++extern void dp_interpreter(void);
++extern int dp_gpf(struct pt_regs *);
++extern int dp_pf(struct pt_regs *);
++extern int dp_handle_fault(struct pt_regs *);
++extern int dp_do_debug(struct pt_regs *, unsigned long);
++extern int dp_trap1(struct pt_regs *);
++extern int dp_trap(struct pt_regs *, int, unsigned int, unsigned long);
++extern int __remove_probe(byte_t *, struct dp_record_struct *);
++extern int __insert_probe(byte_t *, struct dp_record_struct *, struct dp_module_struct *, struct page *);
++extern int register_userspace_probes(struct dp_record_struct *);
++extern void unregister_userspace_probes(struct dp_record_struct *);
++extern inline int insert_probe_userspace(byte_t *, struct dp_record_struct *, struct page *, struct vm_area_struct *);
++extern inline int remove_probe_userspace(byte_t *, struct dp_record_struct *, struct page *, struct vm_area_struct *);
++
++#endif
+diff -urNp linux-2.6.0-test9/include/asm-i386/dprobes_in.h linux-2.6.0-test9+kp/include/asm-i386/dprobes_in.h
+--- linux-2.6.0-test9/include/asm-i386/dprobes_in.h    1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.0-test9+kp/include/asm-i386/dprobes_in.h 2003-11-18 07:29:47.000000000 +0530
+@@ -0,0 +1,120 @@
++#ifndef __ASM_I386_DPROBES_IN_H__
++#define __ASM_I386_DPROBES_IN_H__
++
++/*
++ * IBM Dynamic Probes
++ * Copyright (c) International Business Machines Corp., 2000
++ *
++ * 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.  
++ */
++
++/*
++ * This header file defines the opcodes for the RPN instructions
++ *
++ * Opcodes 0x00 to 0xAF are for common, arch-independent instructions.
++ * Opcodes 0xB0 to 0xDF are for arch-dependent instructions.
++ * Opcodes 0xF1 to 0xFF are for two byte instructions.
++ */
++
++/*
++ * Misc
++ */
++#define DP_SEG2LIN            0xB0
++
++/*
++ * IO Group.
++ */
++#define DP_PUSH_IO_U8         0xB1
++#define DP_PUSH_IO_U16                0xB2
++#define DP_PUSH_IO_U32                0xB3
++#define DP_POP_IO_U8          0xB4
++#define DP_POP_IO_U16         0xB5
++#define DP_POP_IO_U32         0xB6
++
++/*
++ * Intel32 Register Assignments.
++ */
++#define DP_CS                 0x0000
++#define DP_DS                 0x0001
++#define DP_ES                 0x0002
++#define DP_FS                 0x0003
++#define DP_GS                 0x0004
++#define DP_SS                 0x0005
++#define DP_EAX                        0x0006
++#define DP_EBX                        0x0007
++#define DP_ECX                        0x0008
++#define DP_EDX                        0x0009
++#define DP_EDI                        0x000a
++#define DP_ESI                        0x000b
++#define DP_EFLAGS             0x000c
++#define DP_EIP                        0x000d
++#define DP_ESP                        0x000e
++#define DP_EBP                        0x000f
++
++#define DP_TR                 0x0020
++#define DP_LDTR                       0x0021
++#define DP_GDTR                       0x0022
++#define DP_IDTR                       0x0023
++#define DP_CR0                        0x0024
++#define DP_CR1                        0x0025
++#define DP_CR2                        0x0026
++#define DP_CR3                        0x0027
++#define DP_CR4                        0x0028
++
++#define DP_DR0                        0x002c
++#define DP_DR1                        0x002d
++#define DP_DR2                        0x002e
++#define DP_DR3                        0x002f
++#define DP_DR4                        0x0030
++#define DP_DR5                        0x0031
++#define DP_DR6                        0x0032
++#define DP_DR7                        0x0033
++
++#define DP_CPUID              0x003c
++#define DP_MSR                        0x003d
++
++#define DP_FR0                        0x003e
++#define DP_FR1                        0x003f
++#define DP_FR2                        0x0040
++#define DP_FR3                        0x0041
++#define DP_FR4                        0x0042
++#define DP_FR5                        0x0043
++#define DP_FR6                        0x0044
++#define DP_FR7                        0x0045
++#define DP_FCW                        0x0046
++#define DP_FSW                        0x0047
++#define DP_FTW                        0x0048
++#define DP_FIP                        0x0049
++#define DP_FCS                        0x004a
++#define DP_FDP                        0x004b
++#define DP_FDS                        0x004c
++
++#define DP_XMM0                       0x004d
++#define DP_XMM1                       0x004e
++#define DP_XMM2                       0x004f
++#define DP_XMM3                       0x0050
++#define DP_XMM4                       0x0051
++#define DP_XMM5                       0x0052
++#define DP_XMM6                       0x0053
++#define DP_XMM7                       0x0054
++#define DP_MXCSR              0x0055
++
++#ifndef __KERNEL__
++#ifndef PAGE_OFFSET
++#define PAGE_OFFSET           0xc0000000
++#endif
++#endif /* !__KERNEL__ */
++
++#endif
+diff -urNp linux-2.6.0-test9/include/asm-i386/kprobes.h linux-2.6.0-test9+kp/include/asm-i386/kprobes.h
+--- linux-2.6.0-test9/include/asm-i386/kprobes.h       1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.0-test9+kp/include/asm-i386/kprobes.h    2003-11-18 07:30:12.000000000 +0530
+@@ -0,0 +1,38 @@
++#ifndef _ASM_KPROBES_H
++#define _ASM_KPROBES_H
++/*
++ *  Dynamic Probes (kprobes) support
++ *    Vamsi Krishna S <vamsi_krishna@in.ibm.com>, July, 2002
++ *    Mailing list: dprobes@www-124.ibm.com
++ */
++#include <linux/types.h>
++#include <linux/ptrace.h>
++
++struct pt_regs;
++
++typedef u8 kprobe_opcode_t;
++#define BREAKPOINT_INSTRUCTION        0xcc
++#define MAX_INSN_SIZE 16
++
++/* trap3/1 are intr gates for kprobes.  So, restore the status of IF,
++ * if necessary, before executing the original int3/1 (trap) handler.
++ */
++static inline void restore_interrupts(struct pt_regs *regs)
++{
++      if (regs->eflags & IF_MASK)
++              __asm__ __volatile__ ("sti");
++}
++
++void kprobes_asm_code_start(void);
++void kprobes_asm_code_end(void);
++
++#ifdef CONFIG_KPROBES
++extern int kprobe_fault_handler(struct pt_regs *regs, int trapnr);
++extern int post_kprobe_handler(struct pt_regs *regs);
++extern int kprobe_handler(struct pt_regs *regs);
++#else /* !CONFIG_KPROBES */
++static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr) { return 0; }
++static inline int post_kprobe_handler(struct pt_regs *regs) { return 0; }
++static inline int kprobe_handler(struct pt_regs *regs) { return 0; }
++#endif
++#endif /* _ASM_KPROBES_H */
+diff -urNp linux-2.6.0-test9/include/asm-i386/kwatch.h linux-2.6.0-test9+kp/include/asm-i386/kwatch.h
+--- linux-2.6.0-test9/include/asm-i386/kwatch.h        1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.0-test9+kp/include/asm-i386/kwatch.h     2003-11-18 07:29:48.000000000 +0530
+@@ -0,0 +1,31 @@
++#ifndef _ASM_KWATCH_H
++#define _ASM_KWATCH_H
++/*
++ * Dynamic Probes (kwatch points) support
++ *    Vamsi Krishna S <vamsi_krishna@in.ibm.com>, Oct, 2002
++ */
++#include <linux/types.h>
++#include <linux/ptrace.h>
++
++struct kwatch;
++typedef void (*kwatch_handler_t)(struct kwatch *, struct pt_regs *, int );
++
++struct kwatch {
++      unsigned long addr;     /* location of watchpoint */
++      u8 length;      /* range of address */
++      u8 type;        /* type of watchpoint */
++      kwatch_handler_t handler;
++};
++
++#define RF_MASK       0x00010000
++
++#ifdef CONFIG_KWATCH
++extern int register_kwatch(unsigned long addr, u8 length, u8 type, kwatch_handler_t handler);
++extern void unregister_kwatch(int debugreg);
++extern int kwatch_handler(unsigned long condition, struct pt_regs *regs);
++#else
++static inline int register_kwatch(unsigned long addr, u8 length, u8 type, kwatch_handler_t handler) { return -ENOSYS; }
++static inline void unregister_kwatch(int debugreg) { }
++static inline int kwatch_handler(unsigned long condition, struct pt_regs *regs) { return 0; }
++#endif
++#endif /* _ASM_KWATCH_H */
+diff -urNp linux-2.6.0-test9/include/linux/dprobes.h linux-2.6.0-test9+kp/include/linux/dprobes.h
+--- linux-2.6.0-test9/include/linux/dprobes.h  1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.0-test9+kp/include/linux/dprobes.h       2003-11-18 07:30:29.000000000 +0530
+@@ -0,0 +1,450 @@
++#ifndef _LINUX_DPROBES_H
++#define _LINUX_DPROBES_H
++
++/*
++ * IBM Dynamic Probes
++ * Copyright (c) International Business Machines Corp., 2000
++ *
++ */
++
++#ifdef __KERNEL__
++#include <linux/types.h>
++#else
++#include <sys/types.h>
++#endif
++
++#define DP_MAJOR_VER  5
++#define DP_MINOR_VER  0
++#define DP_PATCH_VER  0
++
++/* main command codes */
++#define DP_CMD_MASK           0x000000ff
++#define DP_INSERT             0x00000001
++#define DP_REMOVE             0x00000002
++#define DP_GETVARS            0x00000004
++#define DP_QUERY              0x00000008
++#define DP_HELP                       0x00000010
++#define DP_VERSION            0x00000020
++#define DP_BUILDPPDF          0x00000040
++#define DP_APPLYPPDF          0x00000080
++
++/* command modifiers */
++#define DP_FLAGS_MASK         0xff000000
++#define DP_ALL                        0x80000000
++
++/* insert cmd modifiers */
++#define DP_MERGE              0x01000000
++#define DP_REPLACE            0x02000000
++#define DP_STOP_CPUS          0x04000000
++#define DP_DONT_VERIFY_OPCODES        0x08000000
++#define DP_AUTOSTACKTRACE     0x10000000
++
++/* getvars cmd modifiers */
++#define DP_GETVARS_INDEX      0x01000000
++#define DP_GETVARS_RESET      0x02000000
++#define DP_GETVARS_LOCAL      0x04000000
++#define DP_GETVARS_GLOBAL     0x08000000
++
++/* query cmd modifiers */
++#define DP_QUERY_EXTENDED     0x01000000
++
++/* pgm->flags: default data that will be part of each log record */
++#define DP_LOG_MASK           0x0000ff00
++#define DP_LOG_PROCNAME               0x00000100
++#define DP_LOG_PID            0x00000200
++#define DP_LOG_UID            0x00000400
++#define DP_LOG_NIP             0x00000800
++#define DP_LOG_PSW             0x00000800
++#define DP_LOG_UPSW            0x00001000
++#define DP_LOG_SS_ESP         0x00000800
++#define DP_LOG_CS_EIP         0x00001000
++#define DP_LOG_TSC            0x00002000
++#define DP_LOG_CPU            0x00004000
++#define DP_LOG_ALL            0x0000ff00
++
++/* pgm->flags: default log target */
++#define DP_LOG_TARGET_MASK    0x00ff0000
++#define DP_LOG_TARGET_KLOG    0x00010000
++#define DP_LOG_TARGET_LTT     0x00020000
++#define DP_LOG_TARGET_COM1    0x00040000
++#define DP_LOG_TARGET_COM2    0x00080000
++#define DP_LOG_TARGET_EVL     0x00100000
++#define DP_UNFORMATTED_OUTPUT 0x00200000
++
++/* exit facilities for use with "exit_to" instruction */
++#define DP_EXIT_TO_SGI_KDB    0x01
++#define DP_EXIT_TO_SGI_VMDUMP 0x02
++#define DP_EXIT_TO_CORE_DUMP  0x03
++
++/* bit flags to indicate elements present in the trace buffer header. */
++#define DP_HDR_MAJOR          0x00000001
++#define DP_HDR_MINOR          0x00000002
++#define DP_HDR_CPU            0x00000004
++#define DP_HDR_PID            0x00000008
++#define DP_HDR_UID            0x00000010
++#define DP_HDR_CS             0x00000020
++#define DP_HDR_EIP            0x00000040
++#define DP_HDR_SS             0x00000080
++#define DP_HDR_ESP            0x00000100
++#define DP_HDR_TSC            0x00000200
++#define DP_HDR_PROCNAME               0x00000400
++
++typedef unsigned char byte_t;
++/* FIXME: Well, we're working on getting this in arch headers */
++#if defined(CONFIG_X86) || defined(CONFIG_IA64)
++typedef byte_t opcode_t;
++#endif
++
++/*
++ * This captures the header information of each probe point. It also contains
++ * links to the rpn code of this dprobe handler.
++ *
++ * maxhits: This field indicates the number of times this probe will be
++ * executed before being disabled. A negative value here means that the
++ * probe will not be disabled automatically.
++ *
++ * count: This field keeps track of number of times this probe is hit,
++ * and executed successfully. There is a reason this is "long" and not
++ * "unsigned long". We would implement "pass-count" feature that specifies
++ * the number of times we pass over this probe with actually executing the
++ * probe handler, using the fact that count is a signed value.
++ */
++struct dp_point_struct {
++      loff_t offset;  /* file offset or absolute address */
++      unsigned short address_flag;
++      opcode_t opcode;
++      opcode_t actual_opcode; /* in case of opcode mismatch */
++      unsigned short major;
++      unsigned short minor;
++      unsigned short group;
++      unsigned short type;
++      unsigned long rpn_offset; /* offset into rpn_code of dp_pgm_struct */
++      unsigned long rpn_end;
++      unsigned short probe; /* watchpoint info, probe and access types */
++      unsigned long len;      /* range of the watchpoint probe */
++      int dbregno;    /* the debug reg used for this watchpoint */
++      long maxhits;
++      long passcount;
++      unsigned char logonfault;
++      unsigned short ex_mask;
++      unsigned long heap_size; /* no of heap elements specified by this probe */
++};
++
++#define DP_ADDRESS_ABSOLUTE   0x0001
++
++/*
++ * Flags related to watchpoint probes.
++ */
++#define DP_PROBE_BREAKPOINT   0x8000
++#define DP_PROBE_WATCHPOINT   0x4000
++#define DP_PROBE_MASK         0xc000
++#define DP_MAX_WATCHPOINT     0x4 /* maximum number of watchpoint probes */
++
++#define DP_WATCHTYPE_EXECUTE  0x0000
++#define DP_WATCHTYPE_WRITE    0x0001
++#define DP_WATCHTYPE_IO               0x0002
++#define DP_WATCHTYPE_RDWR     0x0003
++#define DP_WATCHTYPE_MASK     0x0003
++
++/*
++ * This captures the information specified in the dprobe program file header.
++ *
++ * User application passes the details of the pgm header to the system call in
++ * this structure. It is also used in the kernel as part of dp_module_struct.
++ */
++struct dp_pgm_struct {
++      unsigned char *name; /* module for which the probe program is written */
++      unsigned long flags;
++      unsigned short major;
++      unsigned long id;
++      unsigned short jmpmax;
++      unsigned short logmax;
++      unsigned short ex_logmax; /* length of exception stack trace buffer */ 
++      unsigned short num_lv;  /* num of local variables */
++      unsigned short num_gv;  /* num of global variables */
++      unsigned long heapmax; /* num of heap elements required 
++                                 by this probe program */
++
++      unsigned short rpn_length; /* rpn code */
++      unsigned char autostacktrace;
++      byte_t *rpn_code;
++
++      unsigned short align; /* kernel module alignment */
++      unsigned short num_points;
++      struct dp_point_struct *point;
++};
++
++/* pgm flags */
++#define DP_MODTYPE_MASK               0x000f
++#define DP_MODTYPE_USER               0x0001
++#define DP_MODTYPE_KERNEL     0x0002
++#define DP_MODTYPE_KMOD               0x0004
++
++#define LOG_SIZE              1024
++#define EX_LOG_SIZE           1024
++#define JMP_MAX                       65535
++#define MAX_MAXHITS           0x7fffffff
++#define HEAPMAX                       16*1024
++
++#define DEFAULT_LOGMAX                LOG_SIZE
++#define DEFAULT_EX_LOG_MAX    EX_LOG_SIZE
++#define DEFAULT_JMPMAX                JMP_MAX
++#define DEFAULT_MAXHITS               MAX_MAXHITS
++#define DEFAULT_HEAPMAX               HEAPMAX
++
++/* compiled in limits */
++#define DP_MAX_LVARS          256
++#define DP_MAX_GVARS          256
++
++/* exception codes */
++#define EX_INVALID_ADDR         0x0001
++#define EX_SEG_FAULT            0x0002
++#define EX_MAX_JMPS             0x0004
++#define EX_CALL_STACK_OVERFLOW  0x0010
++#define EX_DIV_BY_ZERO          0x0020
++#define EX_INVALID_OPERAND      0x0040
++#define EX_INVALID_OPCODE       0x0080
++#define EX_HEAP_NOMEM         0x0100
++#define EX_HEAP_INVALID_HANDLE        0x0200
++#define EX_HEAP_INVALID_OFFSET        0x0400
++#define EX_LOG_OVERFLOW         0x1000
++#define EX_RPN_STACK_WRAP       0x2000
++#define EX_USER                 0x8000
++#define DEFAULT_EX_MASK         0x0fff
++
++/* If a non-maskable ex is masked out, the interpreter will be terminated. */
++#define EX_NON_MASKABLE_EX      0x0fff
++
++#define EX_NO_HANDLER         0xffffffff
++
++/*
++ * This defines the Dynamic Probe getvars Request Packet, passed in from
++ * the user for subfunction DP_GETVARS.
++ */
++struct  dp_getvars_in_struct  {
++      unsigned char *name;    /* loadable module name */
++      unsigned short from;
++      unsigned short to;
++      unsigned long allocated; /* Allocated size of result pkt */
++      unsigned long returned; /* Returned size of result pkt */
++};
++
++/*
++ * The output from getvars command is returned in this format. First all
++ * global variables will be there as dp_getvars_global_out_struct followed
++ * by local variables for each module in form of dp_getvars_local_out_struct.
++ */
++struct  dp_getvars_global_out_struct  {
++      unsigned long num_vars; /* number of the variables to follow */
++      /* variables */
++};
++
++struct dp_getvars_local_out_struct {
++      unsigned long length;  /* length of this element */
++      unsigned long num_vars; /* number of the variables to follow */
++      /* variables followed by the name of loadable module*/
++};
++
++/*
++ * This defines the Dynamic Probe query Request Packet passed in
++ * from the user for subfunction DP_QUERY.
++ */
++struct dp_query_in_struct {
++      unsigned char *name; /* loadable module name */
++      unsigned long allocated; /* Allocated size of result pkt */
++      unsigned long returned; /* Returned size of result pkt */
++};
++
++struct dp_outrec_struct {
++      unsigned long status;
++      long count;
++      int dbregno;    /* the debug reg used for this watchpoint */
++      struct dp_point_struct point;
++};
++
++/*
++ * flags
++ *
++ * Initially a probe record starts out with zero flags.
++ *
++ * DP_REC_STATUS_COMPILED: A probe record is compiled, after successfully
++ * validating the rpn code.
++ *
++ * DP_REC_STATUS_ACTIVE: A probe record becomes valid after it is verified
++ * that the opcode as specified in the probe program matches with the one
++ * at the specified location. We would probably do this verification the
++ * first time this probe is inserted.
++ *
++ * DP_REC_STATUS_MISMATCH: This means the opcode specified by the probe
++ * does not match with the one present when we try to insert it.
++ *
++ * DP_REC_STATUS_DISABLED: A probe will be disabled after being executed
++ * for max-hit number of times automatically.
++ *
++ * DP_REC_STATUS_REMOVED: The status of a probe will be removed if user
++ * explicitly removes it using dprobe --remove --major-minor command.
++ * Note that if a specific probe is removed by its major-minor, we
++ * don't remove the dp_record_struct from memory as it is too much
++ * work. We simply note that fact in the status flags and leave the
++ * dp_record_struct alone. But, if an entire probe program is removed,
++ * all its structures will be removed permanently.
++ *
++ * DP_REC_STATUS_INVALID_OFFSET: Set if the address specified for probe insertion
++ * is out of bounds for that executable module. 
++ *
++ * DP_REC_STATUS_DEBUGREG_UNAVAIL: Set if the probe is of type watchpoint and
++ * no free debug registers are free for use.
++ * 
++ * DP_REC_STATUS_WATCHPOINT_LEN_INVALID: Set if the probe is of type watchpoint
++ * and the range of address specified is not valid.
++ */
++#define DP_REC_STATUS_COMPILED                0x00000001
++#define DP_REC_STATUS_ACTIVE                  0x00000002
++#define DP_REC_STATUS_MISMATCH                        0x00000004
++#define DP_REC_STATUS_DISABLED                0x00000008
++#define DP_REC_STATUS_REMOVED                 0x00000010
++#define DP_REC_STATUS_INVALID_OFFSET          0x00000020
++#define DP_REC_STATUS_DEBUGREG_UNAVAIL                0x00000040
++#define DP_REC_STATUS_WATCHPOINT_LEN_INVALID  0x00000080
++#define DP_REC_STATUS_DEBUGREG_PATCH_NEEDED   0x00000100
++#define DP_REC_STATUS_KPROBE_ERR              0x00000200
++#define DP_REC_STATUS_EXCLUDED                        0x00000400
++#define DP_REC_ARCH_FLAGS                     0xff000000
++
++struct dp_outmod_struct {
++      struct dp_outmod_struct *next;  /* link */
++      unsigned long flags;    /* cmdline switches */
++      struct dp_outrec_struct * rec;  /* array of dp_outrec_structs. */
++      unsigned long * lv;     /* local variables */
++      struct dp_pgm_struct pgm;
++      unsigned long base;
++      unsigned long end;
++};
++
++struct dp_ioctl_arg {
++      void * input;
++      void * output;
++      unsigned long cmd;
++};
++
++/* 
++ * This should ideally be 2*HEAP_HDR_SIZE, but the latter is 
++ *  __KERNEL__  specific. Hence hardcoded here.
++ */
++#define MIN_HEAP_SIZE 40
++
++#ifdef __KERNEL__
++
++#include <linux/sched.h>
++#include <linux/dcache.h>
++#include <linux/namei.h>
++#include <linux/mm.h>
++#include <linux/kprobes.h>
++#include <asm/page.h>
++#include <asm/pgtable.h>
++#include <asm/ptrace.h>
++
++struct dp_record_struct {
++      struct kprobe kp;
++      struct uprobe up;
++      struct dp_module_struct *mod;
++      spinlock_t lock;
++      unsigned long status;
++      long count;
++      int dbregno;    /* the debug reg used for this watchpoint */
++      struct dp_point_struct point;
++};
++
++/* 
++ * When Dprobes stores it's log in a trace buffer, the log data is preceded
++ * by the header information as in this structure, followed by optional 
++ * header elements.
++ */
++#define DP_TRACE_HDR_ID 1
++struct dp_trace_hdr_struct {
++      unsigned short facility_id;
++      unsigned short len;
++      unsigned long mask;
++      unsigned short major;
++      unsigned short minor;
++};
++
++#ifdef CONFIG_SMP
++#define MIN_ST_SIZE   sizeof(struct dp_trace_hdr_struct) + sizeof(int)
++#else
++#define MIN_ST_SIZE   sizeof(struct dp_trace_hdr_struct)
++#endif
++
++/* Major number 0 is reserved for stack trace log record */
++#define DP_ST_MAJOR   0x0000
++#define DP_ST_MINOR   0x0000
++
++/*
++ * This is the data structure that we maintain in kernel for each module
++ * that has any probes applied on it.
++ */
++struct dp_module_struct {
++      struct dp_module_struct *next;  /* link */
++      unsigned long flags;
++      struct dp_record_struct * rec;  /* array of dp_record_structs. */
++      unsigned long * lv;     /* local variables */
++      struct inode * inode;   /* for quicker access to inode */
++      int trace_id;           /* ltt trace event id */
++      struct dp_trace_hdr_struct hdr;
++      struct dp_pgm_struct pgm;
++      unsigned long base; /* used to store kmod base address */
++      unsigned long end; /* used to store kmod base address */
++      struct nameidata nd; /* to hold path/dentry etc. */
++      struct address_space_operations * ori_a_ops;
++      struct address_space_operations dp_a_ops;
++};
++
++/* flags used to keep track of allocations */
++#define DP_MOD_FLAGS_LARGE_REC        0x01
++
++#ifdef CONFIG_SMP
++extern struct dprobes_struct dprobes_set[];
++#define dprobes dprobes_set[smp_processor_id()]
++#else 
++extern struct dprobes_struct dprobes;
++#define dprobes_set (&dprobes)
++#endif /* CONFIG_SMP */
++
++/*extern char _stext, _etext;  kernel start and end */
++
++/*
++ * global variables stuff
++ */
++extern unsigned long *dp_gv;
++extern unsigned long dp_num_gv;
++extern rwlock_t dp_gv_lock;
++
++extern byte_t *dp_heap;
++extern unsigned long dp_num_heap;
++extern rwlock_t dp_heap_lock;
++
++extern int dp_insmod(struct module *kmod);
++extern int dp_remmod(struct module *kmod);
++extern int dp_readpage(struct file *, struct page *);
++extern int dp_writepage(struct page *page);
++
++#define IS_COW_PAGE(page, inode) (!(page->mapping) || \
++      (page->mapping->host != (void *)inode)) 
++
++#include <linux/list.h>
++struct heap_hdr {
++      byte_t *addr;
++      unsigned char flags;
++      unsigned long size;
++      struct list_head list;
++};
++
++#define HEAP_HDR_SIZE sizeof(struct heap_hdr)
++#define HEAP_FREE     1
++#define       HEAP_ALLOCATED  2
++
++#include <asm/dprobes.h>
++
++#endif /* __KERNEL__ */
++
++#endif
+diff -urNp linux-2.6.0-test9/include/linux/dprobes_in.h linux-2.6.0-test9+kp/include/linux/dprobes_in.h
+--- linux-2.6.0-test9/include/linux/dprobes_in.h       1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.0-test9+kp/include/linux/dprobes_in.h    2003-11-18 07:29:47.000000000 +0530
+@@ -0,0 +1,218 @@
++#ifndef _LINUX_DPROBES_IN_H
++#define _LINUX_DPROBES_IN_H
++
++/*
++ * IBM Dynamic Probes
++ * Copyright (c) International Business Machines Corp., 2000
++ */
++
++/*
++ * This header file defines the opcodes for the RPN instructions.
++ *
++ * Opcodes 0x00 to 0xAF are for common, arch-independent instructions.
++ * Opcodes 0xB0 to 0xDF are for arch-dependent instructions.
++ * Opcodes 0xF1 to 0xFF are for two byte instructions.
++ */
++
++#define DP_NOP                        0x00                                    
++
++/*
++ * RPN execution group.
++ */
++#define DP_JMP                        0x01
++#define DP_JLT                        0x02
++#define DP_JLE                        0x03
++#define DP_JGT                        0x04
++#define DP_JGE                        0x05
++#define DP_JZ                 0x06
++#define DP_JNZ                        0x07
++#define DP_LOOP                       0x08
++#define DP_CALL                       0x09
++#define DP_RET                        0x0a
++#define DP_ABORT              0x0b
++#define DP_REM                        0x0c
++#define DP_EXIT                       0x0d
++#define DP_EXIT_N             0x0e
++#define DP_SUSPEND            0x0f
++
++/*
++ * Logging Group.
++ */
++#define DP_RESUME             0x10
++#define DP_SETMIN_I           0x11
++#define DP_SETMIN             0x12
++#define DP_SETMAJ_I           0x13
++#define DP_SETMAJ             0x14
++#define DP_LOG_STR            0x15
++#define DP_LOG_MRF            0x17
++#define DP_LOG_I              0x1b
++
++/*
++ * Global Variable Group.
++ */
++#define DP_ALLOC_GV           0x1c
++#define DP_FREE_GV            0x1d
++#define DP_FREE_GVI           0x1e
++#define DP_PUSH_GVI           0x1f
++#define DP_PUSH_GV            0x20
++#define DP_POP_GVI            0x21
++#define DP_POP_GV             0x22
++#define DP_MOVE_GVI           0x23
++#define DP_MOVE_GV            0x24
++#define DP_INC_GVI            0x25
++#define DP_INC_GV             0x26
++#define DP_DEC_GVI            0x27
++#define DP_DEC_GV             0x28
++
++/*
++ * Local Variable Group.
++ */
++#define DP_PUSH_LVI           0x29
++#define DP_PUSH_LV            0x2a
++#define DP_POP_LVI            0x2b
++#define DP_POP_LV             0x2c
++#define DP_MOVE_LVI           0x2d
++#define DP_MOVE_LV            0x2e
++#define DP_INC_LVI            0x2f
++#define DP_INC_LV             0x30
++#define DP_DEC_LVI            0x31
++#define DP_DEC_LV             0x32
++
++/*
++ * Arithmetic Group.
++ */
++#define DP_ADD                        0x33
++#define DP_SUB                        0x34
++#define DP_MUL                        0x35
++
++/*
++ * Logic Group.
++ */
++#define DP_NEG                        0x36
++#define DP_AND                        0x37
++#define DP_OR                 0x38
++#define DP_XOR                        0x39
++#define DP_ROL_I              0x3a
++#define DP_ROL                        0x3b
++#define DP_ROR_I              0x3c
++#define DP_ROR                        0x3d
++#define DP_SHL_I              0x3e
++#define DP_SHL                        0x3f
++#define DP_SHR_I              0x40
++#define DP_SHR                        0x41
++
++/*
++ * RPN Stack Group.
++ */
++#define DP_XCHG                       0x42
++#define DP_DUP_I              0x43
++#define DP_DUP                        0x44
++#define DP_ROS                        0x45
++
++/*
++ * Register Group.
++ */
++#define DP_PUSH_R             0x46
++#define DP_POP_R              0x47
++#define DP_PUSH_U             0x48
++#define DP_POP_U              0x49
++
++/* 
++ * Data Group.
++ */
++#define DP_PUSH                       0x4c
++#define DP_PUSH_MEM_U8                0x4d
++#define DP_PUSH_MEM_U16               0x4e
++#define DP_PUSH_MEM_U32               0x4f
++#define DP_PUSH_MEM_U64               0x50
++#define DP_POP_MEM_U8         0x51
++#define DP_POP_MEM_U16                0x52
++#define DP_POP_MEM_U32                0x53
++#define DP_POP_MEM_U64                0x54
++
++/*
++ * System Variable Group.
++ */
++#define DP_PUSH_TASK          0x5d
++#define DP_PUSH_PID           0x5e
++#define DP_PUSH_PROCID                0x5f
++
++/*
++ * Address Verification.
++ */
++#define DP_VFY_R              0x60
++#define DP_VFY_RW             0x61
++
++/*
++ * Some more arithmetic/logic instructions.
++ */
++#define DP_DIV                        0x62
++#define DP_IDIV                       0x63
++#define DP_PBL                        0x64
++#define DP_PBR                        0x65
++#define DP_PBL_I              0x66
++#define DP_PBR_I              0x67
++#define DP_PZL                        0x68
++#define DP_PZR                        0x69
++#define DP_PZL_I              0x6a
++#define DP_PZR_I              0x6b
++
++/*
++ * Exception handling/Stacktrace instructions.
++ */
++#define DP_SX                 0x6c
++#define DP_UX                 0x6d
++#define DP_RX                 0x6e
++#define DP_PUSH_X             0x6f
++#define DP_PUSH_LP            0x70
++#define DP_PUSH_PLP           0x71
++#define DP_POP_LP             0x72
++#define DP_LOG_ST             0x73
++#define DP_PURGE_ST           0x74
++#define DP_TRACE_LV           0x75
++#define DP_TRACE_GV           0x76
++#define DP_TRACE_PV           0x77
++
++#define DP_PUSH_SBP           0x78
++#define DP_POP_SBP            0x79
++#define DP_PUSH_TSP           0x7a
++#define DP_POP_TSP            0x7b
++#define DP_PUSH_SBP_I         0x7c
++#define DP_POP_SBP_I          0x7d
++#define DP_PUSH_TSP_I         0x7e
++#define DP_POP_TSP_I          0x7f
++#define DP_COPY_SBP_I         0x80
++#define DP_COPY_TSP_I         0x81
++#define DP_PUSH_STP           0x82
++#define DP_POP_STP            0x83
++
++#define DP_SAVE_SBP           0x84
++#define DP_RESTORE_SBP                0x85
++#define DP_SAVE_TSP           0x86
++#define DP_RESTORE_TSP                0x87
++#define DP_COPY_SBP           0x88
++#define DP_COPY_TSP           0x89
++
++/* stack based log instructions */
++#define DP_LOG                        0x8a
++#define DP_LOG_LV             0x8b
++#define DP_LOG_GV             0x8c
++
++#define DP_CALLK              0x8d
++
++/* byte heap instructions */
++#define DP_MALLOC             0x8e
++#define DP_FREE                       0x8f
++#define DP_PUSH_WID           0x90
++#define DP_PUSHH_U8_I         0x91
++#define DP_PUSHH_U16_I                0x92
++#define DP_PUSHH_U32_I                0x93
++#define DP_PUSHH_U64_I                0x94
++#define DP_POPH_U8_I          0x95
++#define DP_POPH_U16_I         0x96
++#define DP_POPH_U32_I         0x97
++#define DP_POPH_U64_I         0x98
++
++#include <asm/dprobes_in.h>
++
++#endif
+diff -urNp linux-2.6.0-test9/include/linux/kprobes.h linux-2.6.0-test9+kp/include/linux/kprobes.h
+--- linux-2.6.0-test9/include/linux/kprobes.h  1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.0-test9+kp/include/linux/kprobes.h       2003-11-18 07:30:12.000000000 +0530
+@@ -0,0 +1,88 @@
++#ifndef _LINUX_KPROBES_H
++#define _LINUX_KPROBES_H
++#include <linux/config.h>
++#include <linux/list.h>
++#include <linux/fs.h>
++#include <linux/notifier.h>
++#include <linux/smp.h>
++#include <asm/kprobes.h>
++
++struct kprobe;
++struct pt_regs;
++
++typedef int (*kprobe_pre_handler_t)(struct kprobe *, struct pt_regs *);
++typedef void (*kprobe_post_handler_t)(struct kprobe *, struct pt_regs *,
++                                    unsigned long flags);
++typedef int (*kprobe_fault_handler_t)(struct kprobe *, struct pt_regs *,
++                                    int trapnr);
++struct kprobe {
++      struct list_head list;
++
++      /* location of the probe point */
++      kprobe_opcode_t *addr;
++
++      /* user space probe info */
++      struct uprobe *user;
++ 
++       /* Called before addr is executed. */
++      kprobe_pre_handler_t pre_handler;
++
++      /* Called after addr is executed, unless... */
++      kprobe_post_handler_t post_handler;
++
++       /* ... called if executing addr causes a fault (eg. page fault).
++        * Return 1 if it handled fault, otherwise kernel will see it. */
++      kprobe_fault_handler_t fault_handler;
++
++      /* Saved opcode (which has been replaced with breakpoint) */
++      kprobe_opcode_t opcode;
++
++      /* copy of the original instruction */
++      kprobe_opcode_t insn[MAX_INSN_SIZE];
++};
++
++struct uprobe {
++      struct inode *inode;
++      unsigned long offset;
++      kprobe_opcode_t *addr;
++
++      /* for kprobes internal use */
++      struct vm_area_struct *vma;
++      struct page *page;
++};
++
++#ifdef CONFIG_KPROBES
++/* Locks kprobe: irq must be disabled */
++void lock_kprobes(void);
++void unlock_kprobes(void);
++
++/* kprobe running now on this CPU? */
++static inline int kprobe_running(void)
++{
++      extern unsigned int kprobe_cpu;
++      return kprobe_cpu == smp_processor_id();
++}
++
++extern void arch_prepare_kprobe(struct kprobe *p);
++
++/* Get the kprobe at this addr (if any).  Must have called lock_kprobes */
++extern struct kprobe *get_kprobe(void *addr);
++extern void put_kprobe(struct kprobe *p);
++extern void set_opcode(struct kprobe *p, kprobe_opcode_t opcode);
++
++extern int register_kprobe(struct kprobe *p);
++extern void unregister_kprobe(struct kprobe *p);
++extern int register_kprobe_user(struct kprobe *p);
++extern void unregister_kprobe_user(struct kprobe *p);
++extern int insert_kprobe_user(struct kprobe *p);
++extern int remove_kprobe_user(struct kprobe *p);
++#else
++static inline int kprobe_running(void) { return 0; }
++static inline int register_kprobe(struct kprobe *p) { return -ENOSYS; }
++static inline void unregister_kprobe(struct kprobe *p) { }
++static inline int register_kprobe_user(struct kprobe *p) { return -ENOSYS; }
++static inline void unregister_kprobe_user(struct kprobe *p) { }
++static inline int insert_kprobe_user(struct kprobe *p) { return -ENOSYS; }
++static inline int remove_kprobe_user(struct kprobe *p) { }
++#endif
++#endif /* _LINUX_KPROBES_H */
+diff -urNp linux-2.6.0-test9/kernel/extable.c linux-2.6.0-test9+kp/kernel/extable.c
+--- linux-2.6.0-test9/kernel/extable.c 2003-10-26 00:13:20.000000000 +0530
++++ linux-2.6.0-test9+kp/kernel/extable.c      2003-11-18 07:29:47.000000000 +0530
+@@ -32,6 +32,7 @@ const struct exception_table_entry *sear
+               e = search_module_extables(addr);
+       return e;
+ }
++EXPORT_SYMBOL(search_exception_tables);
+ int kernel_text_address(unsigned long addr)
+ {
+diff -urNp linux-2.6.0-test9/kernel/fork.c linux-2.6.0-test9+kp/kernel/fork.c
+--- linux-2.6.0-test9/kernel/fork.c    2003-10-26 00:12:56.000000000 +0530
++++ linux-2.6.0-test9+kp/kernel/fork.c 2003-11-18 07:29:48.000000000 +0530
+@@ -1228,3 +1228,7 @@ void __init proc_caches_init(void)
+       if(!mm_cachep)
+               panic("vma_init: Cannot alloc mm_struct SLAB cache");
+ }
++#ifdef CONFIG_DPROBES_MODULE
++EXPORT_SYMBOL(mmput);
++#endif
++
+diff -urNp linux-2.6.0-test9/kernel/kprobes.c linux-2.6.0-test9+kp/kernel/kprobes.c
+--- linux-2.6.0-test9/kernel/kprobes.c 1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.0-test9+kp/kernel/kprobes.c      2003-11-18 07:30:12.000000000 +0530
+@@ -0,0 +1,379 @@
++/* Support for kernel probes.
++   (C) 2002 Vamsi Krishna S <vamsi_krishna@in.ibm.com>.
++   Support for user space probes.
++   (C) 2003 Prasanna S Panchamukhi <prasanna@in.ibm.com>.
++*/
++#include <linux/kprobes.h>
++#include <linux/sysrq.h>
++#include <linux/kallsyms.h>
++#include <linux/spinlock.h>
++#include <linux/hash.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/highmem.h>
++#include <linux/pagemap.h>
++#include <asm/cacheflush.h>
++#include <asm/errno.h>
++
++#define KPROBE_HASH_BITS 6
++#define KPROBE_TABLE_SIZE (1 << KPROBE_HASH_BITS)
++
++static struct list_head kprobe_table[KPROBE_TABLE_SIZE];
++
++unsigned int kprobe_cpu = NR_CPUS;
++static spinlock_t kprobe_lock = SPIN_LOCK_UNLOCKED;
++
++void kprobes_code_start(void){}
++
++/* Locks kprobe: irqs must be disabled */
++void lock_kprobes(void)
++{
++      spin_lock(&kprobe_lock);
++      kprobe_cpu = smp_processor_id();
++}
++
++void unlock_kprobes(void)
++{
++      kprobe_cpu = NR_CPUS;
++      spin_unlock(&kprobe_lock);
++}
++
++static struct kprobe *get_uprobe_at(struct inode *inode, unsigned long offset)
++{
++      struct list_head *head;
++      struct kprobe *p;
++      
++      head = &kprobe_table[hash_long((unsigned long)inode*offset, 
++                                      KPROBE_HASH_BITS)];
++      list_for_each_entry(p, head, list) {
++              if (p->user->inode == inode && p->user->offset == offset)
++                      return p;
++      }
++      return NULL;
++}
++
++/*
++ * This leaves with page, and kmap held. They will be released in 
++ * put_kprobe_user. Not sure if holding page_table_lock is also 
++ * needed, it is a very small, probably can't happen, race where 
++ * vma could be gone by the time we complete the single-step.
++ */
++static void get_kprobe_user(struct uprobe *u)
++{
++      kprobe_opcode_t *addr;
++      u->page = find_get_page(u->inode->i_mapping, u->offset >> PAGE_CACHE_SHIFT);
++      addr = (kprobe_opcode_t *)kmap_atomic(u->page, KM_USER0);
++      u->addr = (kprobe_opcode_t *) ((unsigned long) addr + (unsigned long) ( u->offset & ~PAGE_MASK));
++
++}
++
++static void put_kprobe_user(struct uprobe *u)
++{
++      kunmap_atomic(u->addr, KM_USER0);       
++      page_cache_release(u->page);
++}
++
++/*
++ * We need to look up the inode and offset from the vma. We can't depend on
++ * the page->(mapping, index) as that would be incorrect if we ever swap this
++ * page out (possible for pages which are dirtied by GDB breakpoints etc)
++ * 
++ * We acquire page_table_lock here to ensure that:
++ *    - current page doesn't go away from under us (kswapd)
++ *    - mm->mmap consistancy (vma are always added under this lock)
++ *
++ * We will never deadlock on page_table_lock, we always come here due to a
++ * probe in user space, no kernel code could have executed to take the
++ * page_table_lock.
++ */
++static struct kprobe *get_uprobe(void *addr)
++{
++      struct mm_struct *mm = current->mm;
++      struct vm_area_struct *vma;
++      struct inode *inode;
++      unsigned long offset;
++      struct kprobe *p;
++
++      spin_lock(&mm->page_table_lock); 
++      vma = find_vma(mm, (unsigned long)addr);
++      offset = (unsigned long)addr - vma->vm_start + (vma->vm_pgoff << PAGE_SHIFT);
++      if (!vma->vm_file) {
++              spin_unlock(&mm->page_table_lock);
++              return NULL;
++      }
++      inode = vma->vm_file->f_dentry->d_inode;
++      spin_unlock(&mm->page_table_lock);
++
++      p = get_uprobe_at(inode, offset);
++      if (p) {
++              get_kprobe_user(p->user);
++              p->addr = addr;
++              p->user->vma = vma;
++      }
++      return p;
++}
++
++/* You have to be holding the kprobe_lock */
++struct kprobe *get_kprobe(void *addr)
++{
++      struct list_head *head, *tmp;
++
++      if ((unsigned long)addr < PAGE_OFFSET)
++              return get_uprobe(addr);
++
++      head = &kprobe_table[hash_ptr(addr, KPROBE_HASH_BITS)];
++      list_for_each(tmp, head) {
++              struct kprobe *p = list_entry(tmp, struct kprobe, list);
++              if (p->addr == addr)
++                      return p;
++      }
++      return NULL;
++}
++
++void put_kprobe(struct kprobe *p)
++{
++      if (p->user)
++              put_kprobe_user(p->user);
++}
++
++static void set_opcode_user(struct kprobe *p, kprobe_opcode_t opcode)
++{
++      *p->user->addr = opcode;
++      flush_icache_user_range(p->user->vma, p->user->page, addr, sizeof(kprobe_opcode_t));
++}
++
++static void set_opcode_k(struct kprobe *p, kprobe_opcode_t opcode)
++{
++      kprobe_opcode_t *addr = p->addr;
++      *addr = opcode;
++      flush_icache_range(addr, addr + sizeof(kprobe_opcode_t));
++}
++
++void set_opcode(struct kprobe *p, kprobe_opcode_t opcode)
++{
++      if ((unsigned long)p->addr > PAGE_OFFSET)
++              set_opcode_k(p, opcode);
++      else
++              set_opcode_user(p, opcode);
++}
++
++int register_kprobe(struct kprobe *p)
++{
++      int ret = 0;
++      kprobe_opcode_t *addr = p->addr;
++
++      spin_lock_irq(&kprobe_lock);
++      if (get_kprobe(addr)) {
++              ret = -EEXIST;
++              goto out;
++      }
++      list_add(&p->list, &kprobe_table[hash_ptr(addr, 
++                                       KPROBE_HASH_BITS)]);
++      arch_prepare_kprobe(p);
++      p->opcode = *addr;
++      set_opcode_k(p, BREAKPOINT_INSTRUCTION);
++ out:
++      spin_unlock_irq(&kprobe_lock);
++      return ret;
++}
++
++void unregister_kprobe(struct kprobe *p)
++{
++      spin_lock_irq(&kprobe_lock);
++      set_opcode_k(p, p->opcode);
++      list_del(&p->list);
++      spin_unlock_irq(&kprobe_lock);
++}
++
++/* 
++ * User space probes defines four simple and lightweight interfaces :
++ *
++ * register_kprobe_user :
++ *    Registration of user space probes is defined for a pair of inode and
++ *    offset within the executable where the probes need to be inserted.
++ *    Similar to kernel space probes registration, the user space 
++ *    registration provides three callback functions. 
++ *    User space registration requires a kprobes structure as an argument 
++ *    with the following fields initialized:
++ *
++ * pre_handler - pointer to the function that will be called when the 
++ *    probed instruction is about to execute.
++ * post_handler - pointer to the function that will be called after the 
++ *    successful execution of the instruction.
++ * fault_handler - pointer to the function that will be called if a 
++ *    software exception occurs, while executing inside the probe_handler
++ *    or while single stepping.
++ * user - pointer to the struct uprobe. The following fields within this 
++ *    structure must be initialized:
++ * 
++ *    inode -  pointer to the inode of the executable.
++ *    offset - offset within the executable, where probes are 
++ *            inserted/removed. Each unique pair of inode and offset is 
++ *            used as a hashing function.
++ *
++ * User is required to retain this structure until the probes are unregistered.
++ * This routine should be called only once for a given pair of inode and 
++ * offset. Only after the user space probes are registered, the user
++ * can insert and remove probes at the given address.
++ */
++
++int register_kprobe_user(struct kprobe *p)
++{
++      int ret = 0;
++      spin_lock_irq(&kprobe_lock);
++      if (get_uprobe_at(p->user->inode, p->user->offset)) {
++              ret = -EEXIST;
++              goto out;
++      } 
++      list_add(&p->list, &kprobe_table[hash_long(
++              (unsigned long)p->user->inode * p->user->offset,
++              KPROBE_HASH_BITS)]);
++      p->opcode = BREAKPOINT_INSTRUCTION;
++ out :
++      spin_unlock_irq(&kprobe_lock);
++      return ret;
++
++}
++
++/* 
++ * unregister_kprobe_user:
++ *    Every registered user space probe must be unregistered.
++ *    For unregistering, kprobes structure must be passed with
++ *    the following fields initialized:
++ *
++ * user->inode -  pointer to the inode of the executable.
++ * user->offset - offset within the executable, where the probe was registered.
++ *
++ * This routine must be called after all the probes for a given 
++ * pair of inode and offset are removed.
++ */
++
++void unregister_kprobe_user(struct kprobe *p)
++{
++      spin_lock_irq(&kprobe_lock);
++      if (get_uprobe_at(p->user->inode, p->user->offset)) 
++              list_del(&p->list);
++      spin_unlock_irq(&kprobe_lock);
++}
++
++/* 
++ * insert_kprobe_userspace:
++ *    To insert a user space probe within a page at a given address,
++ *    this routine must be called with the following fields initialized:
++ *
++ * user->inode -  pointer to the inode of the executable.
++ * user->offset - offset within the executable, where we need to insert a probe.
++ * user->addr - address in the user address space where probes need to inserted.
++ * user->page - pointer to the page containing the address.
++ * user->vma - pointer to the vma containing the address.
++ *
++ * The user space probes can be inserted into the pages existing in the memory or 
++ * pages read via readpage routine of the inode's address space operations or 
++ * swapping in of the process private page. 
++ * User has to ensure that the page containing the specified address 
++ * (user->addr) must be present in the memory before calling.
++ * User has to first register user space probes for a given pair of 
++ * of inode and offset before calling this routine to insert probes.
++ * 
++ */
++
++int insert_kprobe_user(struct kprobe *p)
++{
++      int ret = 0;
++      spin_lock_irq(&kprobe_lock);
++      if (!get_uprobe_at(p->user->inode, p->user->offset)) {
++              ret = -ENODATA;
++              goto out;
++      }
++
++      if (*p->user->addr == BREAKPOINT_INSTRUCTION) {
++              ret = -EEXIST;
++              goto out;
++      }
++              
++      p->opcode = *p->user->addr;
++      set_opcode_user(p, BREAKPOINT_INSTRUCTION);
++ out :
++      spin_unlock_irq(&kprobe_lock);
++      return ret;
++}
++
++/*
++ * remove_kprobe_user:
++ * For removing user space probe from a page at the given address, this routine must be
++ * called with the following fields initialized:
++ *
++ * user->inode -  pointer to the inode of the executable.
++ * user->offset - offset within the executable,where we need to remove a probe.
++ * user->addr - address in user address space where probes need to removed.
++ * user->page - pointer to the page containing the address.
++ * user->vma - pointer to the vma containing the address.
++ * 
++ * User has to ensure that the page containing the specified address 
++ * (user->addr) must be present in the memory before calling this routine.
++ * Before unregistering, all the probes inserted at a given inode and offset
++ * must be removed. 
++ */
++
++int remove_kprobe_user(struct kprobe *p)
++{
++      int ret = 0;
++      spin_lock_irq(&kprobe_lock);
++      if (!get_uprobe_at(p->user->inode, p->user->offset)) {
++              ret = -ENODATA;
++              goto out;
++      }
++      set_opcode_user(p, p->opcode);
++ out:
++      spin_unlock_irq(&kprobe_lock);
++      return ret;
++}
++
++static void show_kprobes(int key, struct pt_regs *pt_regs, struct tty_struct *tty)
++{
++      int i;
++      struct kprobe *p;
++      
++      /* unsafe: kprobe_lock ought to be taken here */
++      for(i = 0; i < KPROBE_TABLE_SIZE; i++) {
++              if (!list_empty(&kprobe_table[i])) {
++                      list_for_each_entry(p, &kprobe_table[i], list) {
++                              printk("[<%p>] ", p->addr);
++                              print_symbol("%s\t", (unsigned long)p->addr);
++                              print_symbol("%s\n", (unsigned long)p->pre_handler);
++                      }
++              }
++      }
++}
++
++static struct sysrq_key_op sysrq_show_kprobes = {
++      .handler        = show_kprobes,
++      .help_msg       = "shoWkprobes",
++      .action_msg     = "Show kprobes\n"
++};
++
++static int __init init_kprobes(void)
++{
++      int i;
++
++      register_sysrq_key('w', &sysrq_show_kprobes);
++      /* FIXME allocate the probe table, currently defined statically */
++      /* initialize all list heads */
++      for (i = 0; i < KPROBE_TABLE_SIZE; i++)
++              INIT_LIST_HEAD(&kprobe_table[i]);
++      return 0;
++}
++
++void kprobes_code_end(void) {}
++__initcall(init_kprobes);
++
++EXPORT_SYMBOL_GPL(register_kprobe);
++EXPORT_SYMBOL_GPL(unregister_kprobe);
++EXPORT_SYMBOL_GPL(register_kprobe_user);
++EXPORT_SYMBOL_GPL(unregister_kprobe_user);
++EXPORT_SYMBOL_GPL(insert_kprobe_user);
++EXPORT_SYMBOL_GPL(remove_kprobe_user);
++EXPORT_SYMBOL_GPL(kprobes_code_start);
++EXPORT_SYMBOL_GPL(kprobes_code_end);
++EXPORT_SYMBOL_GPL(kprobes_asm_code_start);
++EXPORT_SYMBOL_GPL(kprobes_asm_code_end);
+diff -urNp linux-2.6.0-test9/kernel/Makefile linux-2.6.0-test9+kp/kernel/Makefile
+--- linux-2.6.0-test9/kernel/Makefile  2003-10-26 00:13:05.000000000 +0530
++++ linux-2.6.0-test9+kp/kernel/Makefile       2003-11-18 07:29:47.000000000 +0530
+@@ -19,6 +19,7 @@ obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
+ obj-$(CONFIG_COMPAT) += compat.o
+ obj-$(CONFIG_IKCONFIG) += configs.o
+ obj-$(CONFIG_IKCONFIG_PROC) += configs.o
++obj-$(CONFIG_KPROBES) += kprobes.o
+ ifneq ($(CONFIG_IA64),y)
+ # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
+diff -urNp linux-2.6.0-test9/mm/memory.c linux-2.6.0-test9+kp/mm/memory.c
+--- linux-2.6.0-test9/mm/memory.c      2003-10-26 00:13:32.000000000 +0530
++++ linux-2.6.0-test9+kp/mm/memory.c   2003-11-18 07:29:48.000000000 +0530
+@@ -1701,3 +1701,7 @@ struct page * vmalloc_to_page(void * vma
+ }
+ EXPORT_SYMBOL(vmalloc_to_page);
++#ifdef CONFIG_DPROBES_MODULE
++EXPORT_SYMBOL(handle_mm_fault);
++#endif
++
+diff -urNp linux-2.6.0-test9/mm/swap.c linux-2.6.0-test9+kp/mm/swap.c
+--- linux-2.6.0-test9/mm/swap.c        2003-10-26 00:13:26.000000000 +0530
++++ linux-2.6.0-test9+kp/mm/swap.c     2003-11-18 08:14:41.000000000 +0530
+@@ -398,3 +398,8 @@ void __init swap_setup(void)
+        * _really_ don't want to cluster much more
+        */
+ }
++#ifdef CONFIG_DPROBES_MODULE
++EXPORT_SYMBOL(swapper_space);
++EXPORT_SYMBOL(delete_from_swap_cache);
++#endif
++
diff --git a/kprobes/releases/kprobes-full-20031215.patch b/kprobes/releases/kprobes-full-20031215.patch
new file mode 100644 (file)
index 0000000..a195383
--- /dev/null
@@ -0,0 +1,8197 @@
+diff -urNp linux.orig/arch/i386/Kconfig linux-2.6.0-test11/arch/i386/Kconfig
+--- linux.orig/arch/i386/Kconfig       2003-11-27 02:13:07.000000000 +0530
++++ linux-2.6.0-test11/arch/i386/Kconfig       2003-12-15 15:51:47.000000000 +0530
+@@ -1133,6 +1133,37 @@ config DEBUG_KERNEL
+         Say Y here if you are developing drivers or trying to debug and
+         identify kernel problems.
++config KPROBES
++      bool "Kprobes"
++      depends on DEBUG_KERNEL
++      help
++        Kprobes allows you to trap at almost any kernel address, using
++        register_kprobe(), and providing a callback function.  This is useful
++        for kernel debugging, non-intrusive instrumentation and testing.  If
++        in doubt, say "N".
++
++config DEBUGREG
++      bool "Global Debug Registers"
++      depends on DEBUG_KERNEL
++      help
++        Global debug register settings will be honoured if this is turned on.
++        If in doubt, say "N".
++
++config KWATCH
++      bool "Kwatch points"
++      depends on DEBUG_KERNEL && DEBUGREG
++      help
++        This enables kernel-space watchpoints using processor's debug
++        registers. If in doubt, say "N".
++
++config DPROBES
++      tristate "Dynamic Probes"
++      depends on DEBUG_KERNEL && KPROBES
++      help
++        DProbes provides a higher level interface to kprobes. DProbes
++        enables you to write probe programs in a RPN language. If
++        in doubt, say "N".
++
+ config DEBUG_STACKOVERFLOW
+       bool "Check for stack overflows"
+       depends on DEBUG_KERNEL
+diff -urNp linux.orig/arch/i386/kernel/debugreg.c linux-2.6.0-test11/arch/i386/kernel/debugreg.c
+--- linux.orig/arch/i386/kernel/debugreg.c     1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.0-test11/arch/i386/kernel/debugreg.c     2003-12-15 15:51:47.000000000 +0530
+@@ -0,0 +1,178 @@
++/*
++ * This provides a debug register allocation mechanism, to be 
++ * used by all debuggers, which need debug registers.
++ *
++ * Author: vamsi_krishna@in.ibm.com
++ *       bharata@in.ibm.com
++ */
++#include <linux/kernel.h>
++#include <linux/spinlock.h>
++#include <linux/module.h>
++#include <asm/system.h>
++#include <asm/debugreg.h>
++
++struct debugreg dr_list[DR_MAX];
++unsigned long dr7_global_mask = 0;
++static spinlock_t dr_lock = SPIN_LOCK_UNLOCKED;
++
++static inline void set_dr7_global_mask(int regnum) 
++{
++      switch (regnum) {
++              case 0: dr7_global_mask |= DR7_DR0_BITS; break;
++              case 1: dr7_global_mask |= DR7_DR1_BITS; break;
++              case 2: dr7_global_mask |= DR7_DR2_BITS; break;
++              case 3: dr7_global_mask |= DR7_DR3_BITS; break;
++      }
++      return;
++}
++
++static inline void clear_dr7_global_mask(int regnum) 
++{
++      switch (regnum) {
++              case 0: dr7_global_mask &= ~DR7_DR0_BITS; break;
++              case 1: dr7_global_mask &= ~DR7_DR1_BITS; break;
++              case 2: dr7_global_mask &= ~DR7_DR2_BITS; break;
++              case 3: dr7_global_mask &= ~DR7_DR3_BITS; break;
++      }
++      return;
++}
++
++static int get_dr(int regnum, int flag)
++{
++      if ((flag == DR_ALLOC_GLOBAL) && (dr_list[regnum].flag == DR_UNUSED)) {
++              dr_list[regnum].flag = DR_GLOBAL;
++              set_dr7_global_mask(regnum);
++              return regnum;
++      }
++      else if ((dr_list[regnum].flag == DR_UNUSED) || (dr_list[regnum].flag == DR_LOCAL)) {
++              dr_list[regnum].use_count++;
++              dr_list[regnum].flag = DR_LOCAL;
++              return regnum;
++      }
++      return -1;
++}
++      
++static int get_any_dr(int flag)
++{
++      int i;
++      if (flag == DR_ALLOC_LOCAL) {
++              for (i = 0; i < DR_MAX; i++) {
++                      if (dr_list[i].flag == DR_LOCAL) {
++                              dr_list[i].use_count++;
++                              return i;
++                      } else if (dr_list[i].flag == DR_UNUSED) {
++                              dr_list[i].flag = DR_LOCAL;
++                              dr_list[i].use_count = 1;
++                              return i;
++                      }
++              }
++      } else {
++              for (i = DR_MAX-1; i >= 0; i--) {
++                      if (dr_list[i].flag == DR_UNUSED) {
++                              dr_list[i].flag = DR_GLOBAL;
++                              set_dr7_global_mask(i);
++                              return i;
++                      }
++              }
++      }
++      return -1;
++}
++
++static inline void dr_free_local(int regnum)
++{
++      if (! (--dr_list[regnum].use_count)) 
++              dr_list[regnum].flag = DR_UNUSED;
++      return;
++}
++
++static inline void dr_free_global(int regnum) 
++{
++      dr_list[regnum].flag = DR_UNUSED;
++      dr_list[regnum].use_count = 0;
++      clear_dr7_global_mask(regnum);
++      return;
++}
++              
++int dr_alloc(int regnum, int flag)
++{
++      int ret;
++      
++      spin_lock(&dr_lock);
++      if (regnum == DR_ANY) 
++              ret = get_any_dr(flag);
++      else if (regnum >= DR_MAX)
++              ret = -1;
++      else
++              ret = get_dr(regnum, flag);
++      spin_unlock(&dr_lock);
++      return ret;
++}
++
++int dr_free(int regnum)
++{
++      spin_lock(&dr_lock);
++      if (regnum >= DR_MAX || dr_list[regnum].flag == DR_UNUSED) {
++              spin_unlock(&dr_lock);
++              return -1;
++      }
++      if (dr_list[regnum].flag == DR_LOCAL)
++              dr_free_local(regnum);
++      else 
++              dr_free_global(regnum);
++      spin_unlock(&dr_lock);
++      return 0;
++}
++
++void dr_inc_use_count(unsigned long mask)
++{
++      int i;
++      
++      spin_lock(&dr_lock);
++      for (i =0; i < DR_MAX; i++) {
++              if (DR_IS_LOCAL(mask, i))
++                      dr_list[i].use_count++;
++      }
++      spin_unlock(&dr_lock);
++}
++
++void dr_dec_use_count(unsigned long mask)
++{
++      int i;
++      
++      spin_lock(&dr_lock);
++      for (i =0; i < DR_MAX; i++) {
++              if (DR_IS_LOCAL(mask, i))
++                      dr_free_local(i);
++      }
++      spin_unlock(&dr_lock);
++}
++
++/*
++ * This routine decides if the ptrace request is for enabling or disabling 
++ * a debug reg, and accordingly calls dr_alloc() or dr_free().
++ *
++ * gdb uses ptrace to write to debug registers. It assumes that writing to
++ * debug register always succeds and it doesn't check the return value of 
++ * ptrace. Now with this new global debug register allocation/freeing,
++ * ptrace request for a local debug register can fail, if the required debug
++ * register is already globally allocated. Since gdb fails to notice this 
++ * failure, it sometimes tries to free a debug register, which is not 
++ * allocated for it.
++ */
++int enable_debugreg(unsigned long old_dr7, unsigned long new_dr7)
++{
++      int i, dr_shift = 1UL;
++      for (i = 0; i < DR_MAX; i++, dr_shift <<= 2) {
++              if ((old_dr7 ^ new_dr7) & dr_shift) {
++                      if (new_dr7 & dr_shift)
++                              dr_alloc(i, DR_ALLOC_LOCAL);
++                      else
++                              dr_free(i);
++                      return 0;
++              }
++      }
++      return -1;
++}
++
++EXPORT_SYMBOL(dr_alloc);
++EXPORT_SYMBOL(dr_free);
+diff -urNp linux.orig/arch/i386/kernel/entry.S linux-2.6.0-test11/arch/i386/kernel/entry.S
+--- linux.orig/arch/i386/kernel/entry.S        2003-11-27 02:13:26.000000000 +0530
++++ linux-2.6.0-test11/arch/i386/kernel/entry.S        2003-12-15 15:51:47.000000000 +0530
+@@ -495,10 +495,17 @@ ENTRY(debug)
+       jne debug_stack_correct
+       FIX_STACK(12, debug_stack_correct, debug_esp_fix_insn)
+ debug_stack_correct:
+-      pushl $0
+-      pushl $do_debug
+-      jmp error_code
+-
++      pushl $-1                       # mark this as an int
++      SAVE_ALL
++      movl %esp,%edx
++      pushl $0
++      pushl %edx
++      call do_debug
++      addl $8,%esp
++      testl %eax,%eax 
++      jnz restore_all
++      jmp ret_from_exception
++  
+ /*
+  * NMI is doubly nasty. It can happen _while_ we're handling
+  * a debug fault, and the debug fault hasn't yet been able to
+@@ -546,9 +553,16 @@ nmi_debug_stack_fixup:
+       jmp nmi_stack_correct
+ ENTRY(int3)
++      pushl $-1                       # mark this as an int
++      SAVE_ALL
++      movl %esp,%edx
+       pushl $0
+-      pushl $do_int3
+-      jmp error_code
++      pushl %edx
++      call do_int3
++      addl $8,%esp
++      testl %eax,%eax 
++      jnz restore_all
++      jmp ret_from_exception
+ ENTRY(overflow)
+       pushl $0
+diff -urNp linux.orig/arch/i386/kernel/kprobes.c linux-2.6.0-test11/arch/i386/kernel/kprobes.c
+--- linux.orig/arch/i386/kernel/kprobes.c      1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.0-test11/arch/i386/kernel/kprobes.c      2003-12-15 15:51:47.000000000 +0530
+@@ -0,0 +1,249 @@
++/* 
++ * Support for kernel probes.
++ * (C) 2002 Vamsi Krishna S <vamsi_krishna@in.ibm.com>.
++ */
++
++#include <linux/config.h>
++#include <linux/kprobes.h>
++#include <linux/ptrace.h>
++#include <linux/spinlock.h>
++#include <linux/preempt.h>
++
++/* kprobe_status settings */
++#define KPROBE_HIT_ACTIVE     0x00000001
++#define KPROBE_HIT_SS         0x00000002
++
++static struct kprobe *current_kprobe;
++static unsigned long kprobe_status, kprobe_old_eflags, kprobe_saved_eflags;
++
++void kprobes_asm_code_start(void){}
++/*
++ * returns non-zero if opcode modifies the interrupt flag.
++ */
++static inline int is_IF_modifier(kprobe_opcode_t opcode)
++{
++      switch(opcode) {
++              case 0xfa:      /* cli */
++              case 0xfb:      /* sti */
++              case 0xcf:      /* iret/iretd */
++              case 0x9d:      /* popf/popfd */
++                      return 1;
++      }
++      return 0;
++}
++
++void arch_prepare_kprobe(struct kprobe *p)
++{
++      memcpy(p->insn, p->addr, MAX_INSN_SIZE);
++}
++
++static inline void disarm_kprobe(struct kprobe *p, struct pt_regs *regs)
++{
++      set_opcode(p, p->opcode);
++      regs->eip = (unsigned long)p->addr;
++}
++
++static void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
++{
++      regs->eflags |= TF_MASK;
++      regs->eflags &= ~IF_MASK;
++
++      if (!(p->user)) {
++              regs->eip = (unsigned long)&p->insn;
++      } else {
++              set_opcode(p, p->opcode);
++              regs->eip = (unsigned long)p->addr;
++              }
++}
++
++/*
++ * Interrupts are disabled on entry as trap3 is an interrupt gate and they
++ * remain disabled thorough out this function.
++ */
++int kprobe_handler(struct pt_regs *regs)
++{
++      struct kprobe *p;
++      int ret = 0;
++      kprobe_opcode_t *addr = (kprobe_opcode_t *)(regs->eip - sizeof(kprobe_opcode_t));
++
++      /* We're in an interrupt, but this is clear and BUG()-safe. */
++      preempt_disable();
++
++      /* Check we're not actually recursing */
++      if (kprobe_running()) {
++              /* We *are* holding lock here, so this is safe.
++                   Disarm the probe we just hit, and ignore it. */
++              p = get_kprobe(addr);
++              if (p) {
++                      disarm_kprobe(p, regs);
++                      put_kprobe(p);
++                      ret = 1;
++              }
++              /* If it's not ours, can't be delete race, (we hold lock). */
++              goto no_kprobe;
++      }
++
++      lock_kprobes();
++      p = get_kprobe(addr); 
++      if (!p) {
++              unlock_kprobes();
++              /* Unregistered (on another cpu) after this hit?  Ignore */
++              if (*addr != BREAKPOINT_INSTRUCTION)
++                      ret = 1;
++              /* Not one of ours: let kernel handle it */
++              goto no_kprobe;
++      }
++      /* If p->opcode == BREAKPOINT_INSTRUCTION, means we haven't yet inserted
++       * breakpoint corresponding to this probe.No need to handle this probe.
++       */ 
++      if (p->user && p->opcode == BREAKPOINT_INSTRUCTION) {
++              unlock_kprobes();
++              ret = 1;
++              goto no_kprobe;
++      }
++              
++      kprobe_status = KPROBE_HIT_ACTIVE;
++      current_kprobe = p;
++      kprobe_saved_eflags = kprobe_old_eflags 
++              = (regs->eflags & (TF_MASK|IF_MASK));
++      if (is_IF_modifier(p->opcode))
++              kprobe_saved_eflags &= ~IF_MASK;
++
++      /* If the pre_handler returns 1, means probes are marked for emergency
++       *  removal. Restore back the original opcode.
++       */
++      if (p->pre_handler(p, regs)) {
++              if (!p->user)
++                      disarm_kprobe(p, regs);
++              else {
++                      set_opcode(p, p->opcode);
++                      regs->eip = (unsigned long)p->addr;
++              }
++              ret = 1;
++              unlock_kprobes();
++              goto no_kprobe;
++      }
++
++      prepare_singlestep(p, regs);
++      //disarm_kprobe(p, regs);
++      kprobe_status = KPROBE_HIT_SS;
++      return 1;
++
++      if (p->post_handler)
++              p->post_handler(p, regs, 0);
++      unlock_kprobes();
++      preempt_enable_no_resched();
++      return 1;
++
++no_kprobe:
++      preempt_enable_no_resched();
++      return ret;
++}
++
++static void resume_execution(struct kprobe *p, struct pt_regs *regs)
++{
++      unsigned long *tos = &regs->esp;
++      unsigned long next_eip = 0;
++      unsigned long copy_eip = (unsigned long)&p->insn;
++      unsigned long orig_eip = (unsigned long)p->addr;
++
++      /*
++       * We singlestepped with interrupts disabled. So, the result on
++       * the stack would be incorrect for "pushfl" instruction.
++       * Note that regs->esp is actually the top of the stack when the
++       * trap occurs in kernel space.
++       */
++      switch(p->insn[0]) {
++              case 0x9c:      /* pushfl */
++                      if (regs->eip < PAGE_OFFSET)
++                              tos = (unsigned long *)regs->esp;
++                      *tos &= ~(TF_MASK | IF_MASK);
++                      *tos |= kprobe_old_eflags;
++                      break;
++              case 0xe8:      /* call relative */
++                      *tos = orig_eip + (*tos - copy_eip);
++                      break;
++              case 0xff:      
++                      if ((p->insn[1] & 0x30) == 0x10) { /* call absolute, indirect */
++                              next_eip = regs->eip;
++                              *tos = orig_eip + (*tos - copy_eip);
++                      } else if (((p->insn[1] & 0x31) == 0x20) || /* jmp near, absolute indirect */
++                                 ((p->insn[1] & 0x31) == 0x21)) { /* jmp far, absolute indirect */
++                              next_eip = regs->eip;
++                      }
++                      break;
++              case 0xea:      /* jmp absolute */
++                      next_eip = regs->eip;
++                      break;
++              default:
++                      break;
++      }
++      
++      regs->eflags &= ~TF_MASK;
++      if (next_eip) {
++              regs->eip = next_eip;
++      } else {
++              regs->eip = orig_eip + (regs->eip - copy_eip);
++      }
++}
++
++static void resume_execution_user(struct kprobe *p, struct pt_regs *regs)
++{
++      regs->eflags &= ~TF_MASK;
++      set_opcode(p, BREAKPOINT_INSTRUCTION);
++}
++
++/*
++ * Interrupts are disabled on entry as trap1 is an interrupt gate and they
++ * remain disabled thorough out this function.  And we hold kprobe lock.
++ */
++int post_kprobe_handler(struct pt_regs *regs)
++{
++      if (!kprobe_running())
++              return 0;
++
++      if (current_kprobe->post_handler)
++              current_kprobe->post_handler(current_kprobe, regs, 0);
++
++      if (!(current_kprobe->user))
++              resume_execution(current_kprobe, regs);
++      else
++              resume_execution_user(current_kprobe, regs);
++      regs->eflags |= kprobe_saved_eflags;
++
++      put_kprobe(current_kprobe);
++      unlock_kprobes();
++      preempt_enable_no_resched();
++
++        /*
++       * if somebody else is singlestepping across a probe point, eflags
++       * will have TF set, in which case, continue the remaining processing
++       * of do_debug, as if this is not a probe hit.
++       */
++      if (regs->eflags & TF_MASK)
++              return 0;
++
++      return 1;
++}
++
++/* Interrupts disabled, kprobe_lock held. */
++int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
++{
++      if (current_kprobe->fault_handler
++          && current_kprobe->fault_handler(current_kprobe, regs, trapnr))
++              return 1;
++
++      if (kprobe_status & KPROBE_HIT_SS) {
++              if (!(current_kprobe->user))
++                      resume_execution(current_kprobe, regs);
++              else
++                      resume_execution_user(current_kprobe, regs);
++
++              regs->eflags |= kprobe_old_eflags;
++              put_kprobe(current_kprobe);
++              unlock_kprobes();
++              preempt_enable_no_resched();
++      }
++      return 0;
++}
++void kprobes_asm_code_end(void) {}
+diff -urNp linux.orig/arch/i386/kernel/kwatch.c linux-2.6.0-test11/arch/i386/kernel/kwatch.c
+--- linux.orig/arch/i386/kernel/kwatch.c       1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.0-test11/arch/i386/kernel/kwatch.c       2003-12-15 15:51:47.000000000 +0530
+@@ -0,0 +1,142 @@
++/* 
++ * Support for kernel watchpoints.
++ * (C) 2002 Vamsi Krishna S <vamsi_krishna@in.ibm.com>.
++ */
++#include <linux/config.h>
++#include <linux/kprobes.h>
++#include <linux/ptrace.h>
++#include <linux/spinlock.h>
++#include <linux/module.h>
++#include <asm/kwatch.h>
++#include <asm/debugreg.h>
++#include <asm/bitops.h>
++
++static struct kwatch kwatch_list[DR_MAX];
++static spinlock_t kwatch_lock = SPIN_LOCK_UNLOCKED;
++static unsigned long kwatch_in_progress; /* currently being handled */
++
++struct dr_info {
++      int debugreg;
++      unsigned long addr;
++      int type;
++};
++
++void kwatch_asm_start(void) {}
++static inline void write_smp_dr(void *info)
++{
++      struct dr_info *dr = (struct dr_info *)info;
++
++      if (cpu_has_de && dr->type == DR_TYPE_IO)
++              set_in_cr4(X86_CR4_DE);
++      write_dr(dr->debugreg, dr->addr);
++}
++
++/* Update the debug register on all CPUs */
++static void sync_dr(int debugreg, unsigned long addr, int type)
++{
++      struct dr_info dr;
++      dr.debugreg = debugreg;
++      dr.addr = addr;
++      dr.type = type;
++      smp_call_function(write_smp_dr, &dr, 0, 0);
++}
++
++/*
++ * Interrupts are disabled on entry as trap1 is an interrupt gate and they
++ * remain disabled thorough out this function.
++ */
++int kwatch_handler(unsigned long condition, struct pt_regs *regs)
++{
++      int debugreg = dr_trap(condition);
++      unsigned long addr = dr_trap_addr(condition);
++      int retval = 0;
++
++      if (!(condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3))) {
++              return 0;
++      }
++      
++      /* We're in an interrupt, but this is clear and BUG()-safe. */
++      preempt_disable();
++
++      /* If we are recursing, we already hold the lock. */
++      if (kwatch_in_progress) {
++              goto recursed;
++      }
++      set_bit(debugreg, &kwatch_in_progress);
++      
++      spin_lock(&kwatch_lock);
++      if (kwatch_list[debugreg].addr != addr)
++              goto out;
++
++      if (kwatch_list[debugreg].handler) {
++              kwatch_list[debugreg].handler(&kwatch_list[debugreg], regs, debugreg);
++      }
++      
++      if (kwatch_list[debugreg].type == DR_TYPE_EXECUTE)
++              regs->eflags |= RF_MASK;
++out:
++      clear_bit(debugreg, &kwatch_in_progress);
++      spin_unlock(&kwatch_lock);
++      preempt_enable_no_resched();
++      return retval;
++
++recursed:
++      if (kwatch_list[debugreg].type == DR_TYPE_EXECUTE)
++              regs->eflags |= RF_MASK;
++      preempt_enable_no_resched();
++      return 1;
++}
++
++int register_kwatch(unsigned long addr, u8 length, u8 type, 
++              kwatch_handler_t handler)
++{
++      int debugreg;
++      unsigned long dr7, flags;
++
++      debugreg = dr_alloc(DR_ANY, DR_ALLOC_GLOBAL);
++      if (debugreg < 0) {
++              return -1;
++      }
++
++      spin_lock_irqsave(&kwatch_lock, flags);
++      kwatch_list[debugreg].addr = addr;
++      kwatch_list[debugreg].length = length;
++      kwatch_list[debugreg].type = type;
++      kwatch_list[debugreg].handler = handler;
++      spin_unlock_irqrestore(&kwatch_lock, flags);
++
++      write_dr(debugreg, (unsigned long)addr);
++      sync_dr(debugreg, (unsigned long)addr, type);
++      if (cpu_has_de && type == DR_TYPE_IO)
++              set_in_cr4(X86_CR4_DE);
++      
++      dr7 = read_dr(7);
++      SET_DR7(dr7, debugreg, type, length);
++      write_dr(7, dr7);
++      sync_dr(7, dr7, 0);
++      return debugreg;
++}
++
++void unregister_kwatch(int debugreg)
++{
++      unsigned long flags;
++      unsigned long dr7 = read_dr(7);
++
++      RESET_DR7(dr7, debugreg);
++      write_dr(7, dr7);
++      sync_dr(7, dr7, 0);
++      dr_free(debugreg);
++
++      spin_lock_irqsave(&kwatch_lock, flags);
++      kwatch_list[debugreg].addr = 0;
++      kwatch_list[debugreg].handler = NULL;
++      spin_unlock_irqrestore(&kwatch_lock, flags);
++}
++
++void kwatch_asm_end(void) {}
++
++EXPORT_SYMBOL_GPL(register_kwatch);
++EXPORT_SYMBOL_GPL(unregister_kwatch);
++EXPORT_SYMBOL_GPL(kwatch_asm_start);
++EXPORT_SYMBOL_GPL(kwatch_asm_end);
++
+diff -urNp linux.orig/arch/i386/kernel/Makefile linux-2.6.0-test11/arch/i386/kernel/Makefile
+--- linux.orig/arch/i386/kernel/Makefile       2003-11-27 02:13:09.000000000 +0530
++++ linux-2.6.0-test11/arch/i386/kernel/Makefile       2003-12-15 15:51:47.000000000 +0530
+@@ -26,10 +26,13 @@ obj-$(CONFIG_X86_IO_APIC)  += io_apic.o
+ obj-$(CONFIG_X86_NUMAQ)               += numaq.o
+ obj-$(CONFIG_X86_SUMMIT)      += summit.o
+ obj-$(CONFIG_EDD)                     += edd.o
++obj-$(CONFIG_KPROBES)         += kprobes.o
+ obj-$(CONFIG_MODULES)         += module.o
+ obj-y                         += sysenter.o vsyscall.o
+ obj-$(CONFIG_ACPI_SRAT)       += srat.o
+ obj-$(CONFIG_HPET_TIMER)      += time_hpet.o
++obj-$(CONFIG_DEBUGREG)                += debugreg.o
++obj-$(CONFIG_KWATCH)          += kwatch.o
+ EXTRA_AFLAGS   := -traditional
+diff -urNp linux.orig/arch/i386/kernel/process.c linux-2.6.0-test11/arch/i386/kernel/process.c
+--- linux.orig/arch/i386/kernel/process.c      2003-11-27 02:12:37.000000000 +0530
++++ linux-2.6.0-test11/arch/i386/kernel/process.c      2003-12-15 15:51:47.000000000 +0530
+@@ -50,6 +50,7 @@
+ #ifdef CONFIG_MATH_EMULATION
+ #include <asm/math_emu.h>
+ #endif
++#include <asm/debugreg.h>
+ #include <linux/irq.h>
+ #include <linux/err.h>
+@@ -295,12 +296,16 @@ void exit_thread(void)
+               kfree(tsk->thread.io_bitmap_ptr);
+               tsk->thread.io_bitmap_ptr = NULL;
+       }
++      if (tsk->thread.debugreg[7])
++              dr_dec_use_count(tsk->thread.debugreg[7]);
+ }
+ void flush_thread(void)
+ {
+       struct task_struct *tsk = current;
++      if (tsk->thread.debugreg[7])
++              dr_dec_use_count(tsk->thread.debugreg[7]); 
+       memset(tsk->thread.debugreg, 0, sizeof(unsigned long)*8);
+       memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array));        
+       /*
+@@ -390,6 +395,9 @@ int copy_thread(int nr, unsigned long cl
+               desc->b = LDT_entry_b(&info);
+       }
++      if (tsk->thread.debugreg[7])
++              dr_inc_use_count(tsk->thread.debugreg[7]);
++
+       err = 0;
+  out:
+       if (err && p->thread.io_bitmap_ptr)
+@@ -532,6 +540,24 @@ struct task_struct * __switch_to(struct 
+       /*
+        * Now maybe reload the debug registers
+        */
++#ifdef CONFIG_DEBUGREG
++{
++      /*
++       * Don't reload global debug registers. Don't touch the global debug
++       * register settings in dr7.
++       */
++      unsigned long next_dr7 = next->debugreg[7];
++      if (unlikely(next_dr7)) {
++              if (DR7_L0(next_dr7)) loaddebug(next, 0);
++              if (DR7_L1(next_dr7)) loaddebug(next, 1);
++              if (DR7_L2(next_dr7)) loaddebug(next, 2);
++              if (DR7_L3(next_dr7)) loaddebug(next, 3);
++              /* no 4 and 5 */
++              loaddebug(next, 6);
++              load_process_dr7(next_dr7);
++      }
++}
++#else
+       if (unlikely(next->debugreg[7])) {
+               loaddebug(next, 0);
+               loaddebug(next, 1);
+@@ -541,7 +567,7 @@ struct task_struct * __switch_to(struct 
+               loaddebug(next, 6);
+               loaddebug(next, 7);
+       }
+-
++#endif
+       if (unlikely(prev->io_bitmap_ptr || next->io_bitmap_ptr)) {
+               if (next->io_bitmap_ptr) {
+                       /*
+diff -urNp linux.orig/arch/i386/kernel/ptrace.c linux-2.6.0-test11/arch/i386/kernel/ptrace.c
+--- linux.orig/arch/i386/kernel/ptrace.c       2003-11-27 02:13:27.000000000 +0530
++++ linux-2.6.0-test11/arch/i386/kernel/ptrace.c       2003-12-15 15:51:48.000000000 +0530
+@@ -350,6 +350,11 @@ asmlinkage int sys_ptrace(long request, 
+                         addr -= (long) &dummy->u_debugreg;
+                         addr = addr >> 2;
++
++                        if (addr == 7 && (enable_debugreg(child->thread.debugreg[addr], data)) < 0) {
++                                ret = -EBUSY;
++                                break;
++                        }
+                         child->thread.debugreg[addr] = data;
+                         ret = 0;
+                 }
+diff -urNp linux.orig/arch/i386/kernel/signal.c linux-2.6.0-test11/arch/i386/kernel/signal.c
+--- linux.orig/arch/i386/kernel/signal.c       2003-11-27 02:13:51.000000000 +0530
++++ linux-2.6.0-test11/arch/i386/kernel/signal.c       2003-12-15 15:51:48.000000000 +0530
+@@ -23,6 +23,7 @@
+ #include <asm/ucontext.h>
+ #include <asm/uaccess.h>
+ #include <asm/i387.h>
++#include <asm/debugreg.h>
+ #include "sigframe.h"
+ #define DEBUG_SIG 0
+@@ -580,7 +581,7 @@ int do_signal(struct pt_regs *regs, sigs
+                * have been cleared if the watchpoint triggered
+                * inside the kernel.
+                */
+-              __asm__("movl %0,%%db7" : : "r" (current->thread.debugreg[7]));
++              load_process_dr7(current->thread.debugreg[7]);
+               /* Whee!  Actually deliver the signal.  */
+               handle_signal(signr, &info, oldset, regs);
+diff -urNp linux.orig/arch/i386/kernel/traps.c linux-2.6.0-test11/arch/i386/kernel/traps.c
+--- linux.orig/arch/i386/kernel/traps.c        2003-11-27 02:13:09.000000000 +0530
++++ linux-2.6.0-test11/arch/i386/kernel/traps.c        2003-12-15 15:51:48.000000000 +0530
+@@ -25,6 +25,7 @@
+ #include <linux/highmem.h>
+ #include <linux/kallsyms.h>
+ #include <linux/ptrace.h>
++#include <linux/kprobes.h>
+ #ifdef CONFIG_EISA
+ #include <linux/ioport.h>
+@@ -41,6 +42,7 @@
+ #include <asm/io.h>
+ #include <asm/atomic.h>
+ #include <asm/debugreg.h>
++#include <asm/kwatch.h>
+ #include <asm/desc.h>
+ #include <asm/i387.h>
+ #include <asm/nmi.h>
+@@ -362,7 +364,6 @@ asmlinkage void do_##name(struct pt_regs
+ }
+ DO_VM86_ERROR_INFO( 0, SIGFPE,  "divide error", divide_error, FPE_INTDIV, regs->eip)
+-DO_VM86_ERROR( 3, SIGTRAP, "int3", int3)
+ DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow)
+ DO_VM86_ERROR( 5, SIGSEGV, "bounds", bounds)
+ DO_ERROR_INFO( 6, SIGILL,  "invalid operand", invalid_op, ILL_ILLOPN, regs->eip)
+@@ -379,6 +380,9 @@ asmlinkage void do_general_protection(st
+  
+       if (regs->eflags & VM_MASK)
+               goto gp_in_vm86;
++      
++      if (kprobe_running() && kprobe_fault_handler(regs, 13))
++              return;
+       if (!(regs->xcs & 3))
+               goto gp_in_kernel;
+@@ -500,6 +504,17 @@ void unset_nmi_callback(void)
+       nmi_callback = dummy_nmi_callback;
+ }
++asmlinkage int do_int3(struct pt_regs *regs, long error_code)
++{
++      if (kprobe_handler(regs))
++              return 1;
++      /* This is an interrupt gate, because kprobes wants interrupts
++           disabled.  Normal trap handlers don't. */
++      restore_interrupts(regs);
++      do_trap(3, SIGTRAP, "int3", 1, regs, error_code, NULL);
++      return 0;
++}
++
+ /*
+  * Our handling of the processor debug registers is non-trivial.
+  * We do not clear them on entry and exit from the kernel. Therefore
+@@ -522,14 +537,20 @@ void unset_nmi_callback(void)
+  * find every occurrence of the TF bit that could be saved away even
+  * by user code)
+  */
+-asmlinkage void do_debug(struct pt_regs * regs, long error_code)
++asmlinkage int do_debug(struct pt_regs * regs, long error_code)
+ {
+       unsigned int condition;
+       struct task_struct *tsk = current;
+       siginfo_t info;
++      if (post_kprobe_handler(regs))
++              return 1;
++
+       __asm__ __volatile__("movl %%db6,%0" : "=r" (condition));
++      if (kwatch_handler(condition, regs))
++              return 1;
++
+       /* It's safe to allow irq's after DR6 has been saved */
+       if (regs->eflags & X86_EFLAGS_IF)
+               local_irq_enable();
+@@ -581,20 +602,18 @@ asmlinkage void do_debug(struct pt_regs 
+        * the signal is delivered.
+        */
+ clear_dr7:
+-      __asm__("movl %0,%%db7"
+-              : /* no output */
+-              : "r" (0));
+-      return;
++      load_process_dr7(0);
++      return 0;
+ debug_vm86:
+       handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
+-      return;
++      return 0;
+ clear_TF_reenable:
+       set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
+ clear_TF:
+       regs->eflags &= ~TF_MASK;
+-      return;
++      return 0;
+ }
+ /*
+@@ -760,6 +779,8 @@ asmlinkage void math_state_restore(struc
+       struct thread_info *thread = current_thread_info();
+       struct task_struct *tsk = thread->task;
++      if (kprobe_running() && kprobe_fault_handler(&regs, 7))
++              return;
+       clts();         /* Allow maths ops (or we recurse) */
+       if (!tsk->used_math)
+               init_fpu(tsk);
+@@ -854,7 +875,7 @@ void __init trap_init(void)
+       set_trap_gate(0,&divide_error);
+       set_intr_gate(1,&debug);
+       set_intr_gate(2,&nmi);
+-      set_system_gate(3,&int3);       /* int3-5 can be called from all */
++      _set_gate(idt_table+3,14,3,&int3,__KERNEL_CS); /* int3-5 can be called from all */
+       set_system_gate(4,&overflow);
+       set_system_gate(5,&bounds);
+       set_trap_gate(6,&invalid_op);
+diff -urNp linux.orig/arch/i386/mm/fault.c linux-2.6.0-test11/arch/i386/mm/fault.c
+--- linux.orig/arch/i386/mm/fault.c    2003-11-27 02:12:46.000000000 +0530
++++ linux-2.6.0-test11/arch/i386/mm/fault.c    2003-12-15 15:51:48.000000000 +0530
+@@ -21,6 +21,7 @@
+ #include <linux/vt_kern.h>            /* For unblank_screen() */
+ #include <linux/highmem.h>
+ #include <linux/module.h>
++#include <linux/kprobes.h>
+ #include <asm/system.h>
+ #include <asm/uaccess.h>
+@@ -222,6 +223,9 @@ asmlinkage void do_page_fault(struct pt_
+       /* get the address */
+       __asm__("movl %%cr2,%0":"=r" (address));
++      if (kprobe_running() && kprobe_fault_handler(regs, 14))
++              return;
++
+       /* It's safe to allow irq's after cr2 has been saved */
+       if (regs->eflags & (X86_EFLAGS_IF|VM_MASK))
+               local_irq_enable();
+diff -urNp linux.orig/drivers/dprobes/dprobes.c linux-2.6.0-test11/drivers/dprobes/dprobes.c
+--- linux.orig/drivers/dprobes/dprobes.c       1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.0-test11/drivers/dprobes/dprobes.c       2003-12-15 15:51:48.000000000 +0530
+@@ -0,0 +1,1589 @@
++/*
++ * IBM Dynamic Probes
++ * Copyright (c) International Business Machines Corp., 2000
++ *
++ * 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.  
++ */
++
++#include <linux/dprobes.h>
++#include <linux/dcache.h>
++#include <linux/pagemap.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/vmalloc.h>
++#include <linux/swap.h>
++#include <linux/smp.h>
++#ifdef CONFIG_MAGIC_SYSRQ
++#include <linux/sysrq.h>
++#endif
++
++#include <asm/semaphore.h>
++#include <asm/uaccess.h>
++#include <asm/errno.h>
++#ifdef CONFIG_DEBUGREG
++#include <asm/debugreg.h>
++#endif
++
++#ifdef CONFIG_SMP
++struct dprobes_struct dprobes_set[NR_CPUS];
++#else
++struct dprobes_struct dprobes;
++#endif
++
++struct dp_module_struct *dp_module_list = NULL;
++DECLARE_RWSEM(dp_modlist_sem);
++
++byte_t *dp_heap = NULL;
++unsigned long dp_num_heap = 0;
++rwlock_t dp_heap_lock = RW_LOCK_UNLOCKED;
++
++unsigned long *dp_gv = NULL;
++unsigned long dp_num_gv = 0;
++rwlock_t dp_gv_lock = RW_LOCK_UNLOCKED;
++
++
++#ifdef CONFIG_MAGIC_SYSRQ
++static struct work_struct dprobes_work;
++static struct workqueue_struct *dprobes_wq;
++static void dprobes_sysrq( int , struct pt_regs *, struct tty_struct *);
++static struct sysrq_key_op key_op = {
++      .handler = &dprobes_sysrq,
++      .help_msg = "remoVe_dynamic_probes",
++      .action_msg = "Deactivating all probepoints",
++};
++unsigned long emergency_remove = 0; /*Flag to disable active dprobes*/
++#endif
++
++
++void dprobes_code_start(void) { }
++
++static void init_trace_hdr(struct dp_module_struct *m)
++{
++      unsigned long log_flags = m->pgm.flags & DP_LOG_MASK;
++      unsigned long mask = 0;
++      unsigned short len = sizeof(m->hdr);
++
++      mask |= DP_HDR_MAJOR | DP_HDR_MINOR;
++#ifdef CONFIG_SMP
++      mask |= DP_HDR_CPU;
++      len += sizeof(int);
++#endif        
++      if (log_flags & DP_LOG_PID) {
++              mask |= DP_HDR_PID;
++              len += sizeof(pid_t);
++      }
++      if (log_flags & DP_LOG_UID) {
++              mask |= DP_HDR_UID;
++              len += sizeof(uid_t);
++      }
++      if (log_flags & DP_LOG_CS_EIP) {
++              mask |= DP_HDR_CS | DP_HDR_EIP;
++              len += (sizeof(unsigned short) + sizeof(unsigned long));
++      }
++      if (log_flags & DP_LOG_SS_ESP) {
++              mask |= DP_HDR_SS | DP_HDR_ESP;
++              len += (sizeof(unsigned short) + sizeof(unsigned long));
++      }
++      if (log_flags & DP_LOG_TSC) {
++              mask |= DP_HDR_TSC;
++              len += sizeof(struct timeval);
++      }
++      if (log_flags & DP_LOG_PROCNAME) {
++              mask |= DP_HDR_PROCNAME;
++              len += 16; /* size of task_struct.comm */
++      }
++      m->hdr.facility_id = DP_TRACE_HDR_ID;
++      m->hdr.mask = mask;
++      m->hdr.len = len;
++      /* Adjust the logmax to take care of log header bytes */
++      m->pgm.logmax += len;
++      return;
++}
++
++#if defined(CONFIG_TRACE) || defined(CONFIG_TRACE_MODULE)
++#include <linux/trace.h>
++static inline void get_trace_id(struct dp_module_struct *m)
++{
++      m->trace_id = trace_create_event(m->pgm.name, NULL, CUSTOM_EVENT_FORMAT_TYPE_HEX, NULL);
++}     
++static inline void free_trace_id(struct dp_module_struct *m)
++{
++      trace_destroy_event(m->trace_id);
++}
++#else
++#define get_trace_id(m)
++#define free_trace_id(m)
++#endif
++
++static inline struct dp_module_struct * find_mod_by_inode(struct inode *inode)
++{
++      struct dp_module_struct *m;
++      for (m = dp_module_list; m; m = m->next) {
++              if (m->inode == inode)
++                      break;
++      }
++      return m;
++}
++
++static inline struct dp_module_struct * find_mod_by_name(const char * name)
++{
++      struct dp_module_struct *m;
++      for (m = dp_module_list; m ; m = m->next) {
++              if (!strcmp(m->pgm.name, name))
++                      break;
++      }
++      return m;
++}
++
++static inline void link_module(struct dp_module_struct *m)
++{
++      m->next = dp_module_list;
++      dp_module_list = m;
++      return;
++}
++
++static inline void unlink_module(struct dp_module_struct *m)
++{
++      struct dp_module_struct *prev;
++
++      if (m == dp_module_list) {
++              dp_module_list = m->next;
++              return;
++      }
++      prev = dp_module_list;
++      while (prev->next && prev->next != m)
++              prev = prev->next;
++      if (prev->next)
++              prev->next = prev->next->next;
++      return;
++}
++
++/*
++ * copied from kernel/module.c find_module().
++ */
++static struct module * find_kmodule(const char *name)
++{
++      struct module *kmod = NULL;
++#if 0
++      extern struct list_head *modules;
++      list_for_each_entry(kmod, modules, list) {
++              if (!strcmp(kmod->name, name))
++                      break;
++      }
++#endif
++      return kmod;
++}
++
++/*
++ * Returns the index of the last dp_record that lies in the same page as the
++ * dp_record at start index.
++ */
++static inline unsigned short
++find_last(struct dp_module_struct *m, unsigned short start)
++{
++      int i;
++      struct dp_record_struct * rec = &m->rec[start];
++      unsigned short num_recs = m->pgm.num_points;
++      unsigned long end_offset = (rec->point.offset & PAGE_MASK) + PAGE_SIZE;
++
++      for (i = start; i < num_recs && rec->point.offset < end_offset; i++, rec++)
++              ;
++
++      return i;
++}
++
++/*
++ * Unlinks the given module from dp_module_list and frees all the memory
++ * taken by it.
++ */
++static int free_dp_module(struct dp_module_struct *m)
++{
++      /* unlink mod */
++      unlink_module(m);
++
++      if (m->flags & DP_MOD_FLAGS_LARGE_REC)
++              vfree(m->rec);
++      else
++              kfree(m->rec);
++      kfree(m->lv);
++      kfree(m->pgm.rpn_code);
++      putname(m->pgm.name);
++      kfree(m);
++      return 0;
++}
++
++/*
++ * Allocates dp_record_structs, copies dp_point_structs from user space into
++ * the dp_record_structs in the kernel space.
++ */
++static int
++copy_point_from_user (struct dp_module_struct *m, struct dp_pgm_struct *pgm)
++{
++      unsigned short count = m->pgm.num_points, i;
++      struct dp_record_struct *rec;
++      unsigned long rec_size;
++
++      if (!count)
++              return 0;
++
++      rec_size = count * sizeof(*rec);
++      if (rec_size > PAGE_SIZE) {
++              rec = vmalloc(rec_size);
++              m->flags |= DP_MOD_FLAGS_LARGE_REC;
++      } else {
++              rec = kmalloc(rec_size, GFP_KERNEL);
++      }
++      if (!rec)
++              return -ENOMEM;
++      memset(rec, 0, rec_size);
++      m->rec = rec;
++
++      for (i = 0; i < count; i++, rec++) {
++              if (copy_from_user (&rec->point, &pgm->point[i],
++                              sizeof (struct dp_point_struct))) {
++                      if (m->flags & DP_MOD_FLAGS_LARGE_REC)
++                              vfree(m->rec);
++                      else
++                              kfree(m->rec);
++                      m->rec = NULL;
++                      return -EFAULT;
++              }
++              rec->status = DP_REC_STATUS_COMPILED;
++              rec->lock = SPIN_LOCK_UNLOCKED;
++              rec->mod = m;
++              rec->count = -rec->point.passcount;
++              if (!rec->point.maxhits) rec->point.maxhits =DEFAULT_MAXHITS;
++      }
++      return 0;
++}
++
++/* 
++ * We may have to realloc global variables area.
++ */
++static int check_gv_space(unsigned short num_gv)
++{
++      unsigned long *tmp, *tmp1;      
++      unsigned long eflags;
++
++      if (num_gv <= dp_num_gv)
++              return 0;
++
++      tmp = kmalloc(num_gv * sizeof(*tmp), GFP_KERNEL);
++      if (!tmp) 
++              return -ENOMEM;
++      memset(tmp, 0, num_gv * sizeof(*tmp));
++
++      write_lock_irqsave(&dp_gv_lock, eflags);
++      if (dp_num_gv) {
++              memcpy((void *)tmp, (void *)dp_gv, 
++                      sizeof(unsigned long)*dp_num_gv);
++      }
++      tmp1 = dp_gv;
++      dp_gv = tmp;
++      dp_num_gv = num_gv;
++      write_unlock_irqrestore(&dp_gv_lock, eflags);
++
++      kfree(tmp1);
++      return 0;
++} 
++
++static int check_heap_space(unsigned short num_heap)
++{
++      byte_t *tmp, *tmp1;     
++      unsigned long eflags;
++
++      if (num_heap * num_online_cpus() <= dp_num_heap)
++              return 0;
++
++      tmp = kmalloc(num_heap * sizeof(*tmp) * num_online_cpus(), GFP_KERNEL);
++      if (!tmp) 
++              return -ENOMEM;
++
++      write_lock_irqsave(&dp_heap_lock, eflags);
++      tmp1 = dp_heap;
++      dp_heap = tmp;
++      dp_num_heap = num_heap * num_online_cpus();
++      write_unlock_irqrestore(&dp_heap_lock, eflags);
++      kfree(tmp1);
++
++      return 0;
++} 
++
++/*
++ * Allocates a dp_module_struct and copies the dp_pgm_struct from user space
++ * into it, in kernel space.
++ */
++static int
++copy_pgm_from_user(struct dp_module_struct **mod, struct dp_pgm_struct *pgm)
++{
++      int  retval = 0;
++      struct dp_module_struct *m;
++
++      pgm->name = getname(pgm->name);
++      if (IS_ERR(pgm->name)) {
++              retval = PTR_ERR(pgm->name);
++              goto error;
++      }
++
++      m = find_mod_by_name(pgm->name);
++      if (m) {
++              retval = -EEXIST;
++              goto err1;
++      }
++
++      m = kmalloc(sizeof(*m), GFP_KERNEL);
++      if (!m) {
++              retval = -ENOMEM;
++              goto err1;
++      }
++      memset(m, 0, sizeof(*m));
++
++      m->pgm = *pgm;
++
++      if (m->pgm.logmax > LOG_SIZE) m->pgm.logmax = DEFAULT_LOGMAX;
++      if (m->pgm.jmpmax > JMP_MAX) m->pgm.jmpmax = DEFAULT_JMPMAX;
++      if (m->pgm.ex_logmax > EX_LOG_SIZE) m->pgm.ex_logmax = DEFAULT_EX_LOG_MAX;
++      if (m->pgm.heapmax > HEAPMAX)
++              m->pgm.heapmax = DEFAULT_HEAPMAX;
++
++      if (pgm->num_lv != 0) {
++              m->lv = kmalloc(pgm->num_lv * sizeof(*m->lv), GFP_KERNEL);
++              if (!m->lv) {
++                      retval = -ENOMEM;
++                      goto err2;
++              }
++              memset(m->lv, 0, pgm->num_lv * sizeof(*m->lv));
++      }
++
++      if (pgm->num_gv != 0) {
++              retval = check_gv_space(pgm->num_gv);
++              if (retval < 0)
++                      goto err3;
++      }
++
++      if (pgm->heapmax != 0) {
++              retval = check_heap_space(pgm->heapmax);
++              if (retval < 0)
++                      goto err3;
++      }
++
++      m->pgm.rpn_code = kmalloc(pgm->rpn_length, GFP_KERNEL);
++      if (!m->pgm.rpn_code) {
++              retval = -ENOMEM;
++              goto err3;
++      }
++      if (copy_from_user(m->pgm.rpn_code, pgm->rpn_code, pgm->rpn_length)) {
++              retval = -EFAULT;
++              goto err4;
++      }
++
++      retval = copy_point_from_user(m, pgm);
++      if (retval)
++              goto err4;
++      *mod = m;
++      return 0;
++
++err4:         kfree(m->pgm.rpn_code);
++err3:         kfree(m->lv);
++err2:         kfree(m);
++err1: putname(pgm->name);
++error:        return retval;
++
++}
++
++/*
++ * Fills up the base and end fields of the given dp_module_struct with the
++ * starting and end addresses of the given kernel module, accounting for
++ * correct alignment of the code segment.
++ */
++static inline int get_kmod_bounds(struct dp_module_struct *m, struct module *kmod)
++{
++      m->base = (unsigned long)kmod->module_core;
++      m->end = kmod->core_size;
++      return 1;
++}
++
++/*
++ * Fills up the base and end fields of the dp_module_struct with the details
++ * of where the corresponding kernel module is loaded.
++ */
++static inline int get_mod_load_addr(struct dp_module_struct *m)
++{
++      struct module * kmod;
++      kmod = find_kmodule(m->pgm.name);
++      if (!kmod)
++              return 0; // module not yet loaded.
++      return get_kmod_bounds(m, kmod);
++}
++
++/*
++ * Fills up the base and end fields of dp_module_struct if this module is
++ * for a kernel or a kernel module.
++ */
++static int get_load_addr(struct dp_module_struct *m)
++{
++      if (m->pgm.flags & DP_MODTYPE_KMOD)
++              return get_mod_load_addr(m);
++      m->base = PAGE_OFFSET;
++      m->end = init_mm.end_code - PAGE_OFFSET;
++      return 1;
++}
++
++/* last thing we do should be to remove the breakpoint setting. */
++static int insert_probe(byte_t *addr, struct dp_record_struct *rec, 
++      struct dp_module_struct *m, struct page * page, 
++      struct vm_area_struct *vma)
++{
++      /* 
++       * remove residual status bits, applicable only to probes in kernel
++       * modules when they are being reinserted. 
++       */
++      rec->status &= ~(DP_REC_STATUS_REMOVED | DP_REC_STATUS_DISABLED);
++      if(!(m->pgm.flags & DP_MODTYPE_USER))
++              return __insert_probe(addr, rec, m, page);
++      else
++              return insert_probe_userspace(addr, rec, page, vma);
++}
++
++/* first thing we do should be to remove the breakpoint setting. */
++static int remove_probe(byte_t * addr, struct dp_record_struct *rec,
++      struct dp_module_struct *m, struct page * page, 
++      struct vm_area_struct *vma)
++{
++      unsigned long eflags;
++      spin_lock_irqsave(&rec->lock, eflags);
++      if(!(m->pgm.flags & DP_MODTYPE_USER))
++              __remove_probe(addr, rec);
++      else 
++              remove_probe_userspace(addr, rec, page, vma);
++      rec->status &= ~(DP_REC_STATUS_ACTIVE | DP_REC_STATUS_MISMATCH);
++      rec->status |= DP_REC_STATUS_REMOVED;
++      spin_unlock_irqrestore(&rec->lock, eflags);
++      return 0;
++}
++
++/*
++ * Creates hash table links and inserts all records in kernel / kmodule.
++ */
++static int insert_all_recs_k(struct dp_module_struct *m)
++{
++      struct dp_record_struct * rec;
++      byte_t * addr;
++      int i;
++      unsigned short num_recs = m->pgm.num_points;
++
++      for (i = 0, rec = m->rec; i < num_recs; i++, rec++) {
++              if (!(rec->point.address_flag & DP_ADDRESS_ABSOLUTE)) { 
++                      rec->point.offset += m->base;
++              }
++              addr = (byte_t *)((unsigned long)rec->point.offset);
++              insert_probe(addr, rec, m, NULL, NULL);
++      }
++      return 0;
++}                             
++
++/*
++ * Removes probes in kernel / kmodules: all _will_ be in memory.
++ * Note that rec->point.offset is now the linear address itself.
++ */
++static int remove_all_recs_k(struct dp_module_struct *m)
++{
++      struct dp_record_struct * rec;
++      int i;
++      byte_t * addr;
++      unsigned short num_recs = m->pgm.num_points;
++
++      for (i = 0, rec = m->rec; i < num_recs; i++, rec++) {
++              addr = (byte_t *) ((unsigned long)rec->point.offset);
++              if (rec->status & DP_REC_STATUS_ACTIVE) {
++                      remove_probe(addr, rec, m, NULL, NULL);
++              }
++              if (!(rec->point.address_flag & DP_ADDRESS_ABSOLUTE))
++                      rec->point.offset -= m->base;
++
++      }
++      m->base = m->end = 0;
++      return 0;
++}
++
++/*
++ * mod->pgm.name is already in kernel space.
++ */
++static int insert_k (struct dp_module_struct * m)
++{
++      if (!get_load_addr(m))
++              return 0;
++      return insert_all_recs_k(m);
++}
++
++static int remove_k(struct dp_module_struct *m)
++{
++      return remove_all_recs_k(m);
++}
++
++/*
++ * Inserts user probes into the page. Insert probes that lie in the same page 
++ * after waiting for the page to be unlocked, if it was locked.
++ */
++static unsigned short insert_recs_in_page (struct dp_module_struct *m,
++      struct page * page, unsigned short start, unsigned short end, 
++              struct vm_area_struct *vma)
++{
++      unsigned long alias;
++      byte_t * addr;
++      unsigned short i;
++      struct dp_record_struct * rec = &m->rec[start];
++
++      if (!page) {
++              return 1;
++      }
++      wait_on_page_locked(page);
++      if (!PageUptodate(page)) { /* we could probably retry readpage here. */
++              return 1;
++      }
++
++      alias = (unsigned long)kmap(page);
++      for (i = start; i < end; i++, rec++) {
++              addr = (byte_t *) (alias +
++                      (unsigned long)(rec->point.offset & ~PAGE_MASK));
++              insert_probe(addr, rec, m, page, vma);
++      }
++      kunmap(page);
++      return 1;
++}
++
++/*
++ * Removes user probes that lie in the same page after waiting for the page to
++ * be unlocked, if it was locked. Make sure the page does not get swapped out.
++ */
++static unsigned short remove_recs_from_page (struct dp_module_struct *m,
++      struct page * page, unsigned short start, unsigned short end, 
++              struct vm_area_struct *vma)
++{
++      struct dp_record_struct * rec = &m->rec[start];
++      unsigned long alias;
++      byte_t * addr;
++      unsigned short i;
++
++      if (!page)
++              return 1;
++      wait_on_page_locked(page);
++      lock_page(page);
++      alias = (unsigned long)kmap(page); 
++      for (i = start; i < end; i++, rec++) {
++              addr = (byte_t *) (alias +
++                      (unsigned long)(rec->point.offset & ~PAGE_MASK)); 
++              remove_probe(addr, rec, m, page, vma);
++      }
++      kunmap(page);
++      unlock_page(page);
++
++      return 1;
++}
++
++typedef unsigned short
++(*process_recs_func_t)(struct dp_module_struct *m, struct page *page,
++              unsigned short start, unsigned short end, struct vm_area_struct *);
++
++static inline pte_t *get_one_pte(struct mm_struct *mm, unsigned long addr)
++{
++      pgd_t * pgd;
++      pmd_t * pmd;
++      pte_t * pte = NULL;
++
++      pgd = pgd_offset(mm, addr);
++      if (pgd_none(*pgd))
++              goto end;
++      if (pgd_bad(*pgd)) {
++              pgd_ERROR(*pgd);
++              pgd_clear(pgd);
++              goto end;
++      }
++
++      pmd = pmd_offset(pgd, addr);
++      if (pmd_none(*pmd))
++              goto end;
++      if (pmd_bad(*pmd)) {
++              pmd_ERROR(*pmd);
++              pmd_clear(pmd);
++              goto end;
++      }
++
++      pte = pte_offset_kernel(pmd, addr);
++      if (pte_none(*pte))
++              pte = NULL;
++end:
++      return pte;
++}
++
++struct dp_page_locator_struct {
++      struct list_head list;
++      struct mm_struct *mm;
++      unsigned long addr;
++};
++
++/*
++ * Get the page corresponding to a given virtual addr, marking it as needing
++ * to be brought in later and checked, if it has been swapped out. 
++ * It doesn't bring in discarded pages as a_ops->readpage
++ * takes care of that.
++ */
++struct page * dp_vaddr_to_page(struct vm_area_struct *vma, unsigned long addr,
++struct list_head  *swapped_list_head)
++{
++      struct mm_struct *mm = vma->vm_mm;
++      pte_t *pte = get_one_pte(mm, addr);
++      struct page *page;
++      struct dp_page_locator_struct *pageloc;
++
++      if (!pte) {
++              return NULL;
++      }
++      /*
++       * If the page has been swapped out, we want to bring it in.
++       * We can't do it right away since we are holding spin locks.
++       * So just queue it up on the swapped pages list.
++       */
++      if (!pte_present(*pte)) {
++              if (swapped_list_head == NULL) return NULL;     
++              pageloc = kmalloc(sizeof(*pageloc), GFP_ATOMIC);
++              if (!pageloc) return NULL;
++              pageloc->mm = mm;
++              pageloc->addr = addr;
++              atomic_inc(&mm->mm_users); /* so that mm won't go away */
++              list_add(&pageloc->list, swapped_list_head);
++              return NULL;
++      }
++
++      page = pte_page(*pte);
++      page_cache_get(page); /* TODO: Check if we need the page_cache_lock */
++
++      /*
++       * If this is a COW page, then we want to make sure that any changes
++       * made to the page get written back when swapped out. We need to do
++       * the following explicitly because dprobes will write via an alias.
++       */
++      if (IS_COW_PAGE(page, vma->vm_file->f_dentry->d_inode)) {
++              if (PageSwapCache(page))
++                      delete_from_swap_cache(page);
++              set_pte(pte, pte_mkdirty(*pte));
++      }
++
++      return page;
++}
++
++/*
++ * Tracks all COW pages for the page containing the specified probe point
++ * and inserts/removes all the probe points for that page.
++ * Avoid the inserts/removes if the page's inode matches the module's inode.
++ * since that means that it is the original page and not a copied page.
++ */
++static int process_recs_in_cow_pages (struct dp_module_struct *m,
++              unsigned short start, unsigned short end,
++              process_recs_func_t process_recs_in_page)
++{
++      unsigned long offset = m->rec[start].point.offset;
++      struct vm_area_struct *vma;
++      struct page *page;
++      unsigned long addr;
++      struct mm_struct *mm;
++      struct address_space *mapping = m->inode->i_mapping;
++      struct list_head *head = &mapping->i_mmap;
++      struct list_head swapped_pages_list, *ptr;
++      struct dp_page_locator_struct *pageloc;
++
++      INIT_LIST_HEAD(&swapped_pages_list);
++      down(&mapping->i_shared_sem);
++
++      list_for_each_entry(vma, head, shared) {
++              mm = vma->vm_mm;
++              spin_lock(&mm->page_table_lock);        
++                                                      
++              /* Locate the page in this vma */
++              addr = vma->vm_start - (vma->vm_pgoff << PAGE_SHIFT) + offset;
++              /*
++               * The following routine would also bring in the page if it is
++               * swapped out
++               */
++              page = dp_vaddr_to_page (vma, addr, &swapped_pages_list);
++              spin_unlock(&mm->page_table_lock);
++              if (!page)
++                      continue;
++              if (IS_COW_PAGE(page, m->inode)) {      
++                      (*process_recs_in_page)(m, page, start, end, vma);
++              }
++              page_cache_release(page); /* TODO: Do we need a lock ? */
++      }
++      up(&mapping->i_shared_sem);
++
++      while (!list_empty(&swapped_pages_list)) { 
++              ptr = swapped_pages_list.next;
++              pageloc = list_entry(ptr, struct dp_page_locator_struct, list);
++              mm = pageloc->mm;      
++              addr = pageloc->addr;      
++              down_read(&mm->mmap_sem); 
++              /* first make sure that the vma didn't go away  */
++              vma = find_vma(mm, addr);
++              /* and that this is the same one we had */
++              if (vma && vma->vm_file && 
++              (vma->vm_file->f_dentry->d_inode == m->inode) &&
++              (vma->vm_start - (vma->vm_pgoff << PAGE_SHIFT) + offset 
++              == addr)) {
++                      if (handle_mm_fault(mm, vma, addr, 0) <= 0) {
++                              goto next;
++                      }
++                      page = dp_vaddr_to_page(vma, addr, NULL); 
++                      if (!page) /* could this ever happen ? */ {
++                              goto next;
++                      }
++                      if (IS_COW_PAGE(page, m->inode)) {
++                              (*process_recs_in_page)(m, page, start, end, vma);
++                      }
++                      page_cache_release(page); /*TODO: Do we need a lock ?*/
++              }
++next:         
++              up_read(&mm->mmap_sem); 
++              mmput(mm);
++              list_del(ptr);
++              kfree(pageloc);
++      }
++      return 1;
++}
++/* 
++ * find_get_vma walks through the list of process private mappings and
++ * returns the pointer to vma containing the offset if found.
++ */
++static struct vm_area_struct * find_get_vma(unsigned long offset, 
++      struct address_space *mapping)
++{
++      struct vm_area_struct *vma = NULL;
++      struct list_head *head = &mapping->i_mmap;
++      struct mm_struct *mm;
++      unsigned long start, end;
++
++      down(&mapping->i_shared_sem);
++        list_for_each_entry(vma, head, shared) {
++              mm = vma->vm_mm;
++              spin_lock(&mm->page_table_lock);
++              start = vma->vm_start - (vma->vm_pgoff << PAGE_SHIFT);
++              end = vma->vm_end - (vma->vm_pgoff << PAGE_SHIFT);
++              spin_unlock(&mm->page_table_lock);
++              if ((start + offset) < end) {
++                      up(&mapping->i_shared_sem);
++                      return vma;
++              }
++      }
++      up(&mapping->i_shared_sem);
++      return NULL;
++}
++/*
++ * physical insertion/removal of probes in the actual pages of the module.
++ * Register user space probes before actually instering probes in the page for 
++ * a given pair of inode and offset.
++ * 
++ */
++static int process_recs(struct dp_module_struct *m,
++              process_recs_func_t process_recs_in_page)
++{
++      struct address_space * mapping = m->inode->i_mapping;
++      struct page *page;
++      unsigned short i = 0, j;
++      unsigned short num_recs = m->pgm.num_points;
++      unsigned short start, end;
++      struct vm_area_struct *vma = NULL;
++
++      while (i < num_recs) {
++              start = i;
++              i = end = find_last(m, start);
++              vma = find_get_vma(m->rec[start].point.offset, mapping);
++              page = find_get_page(mapping, 
++                              m->rec[start].point.offset >> PAGE_CACHE_SHIFT);
++              
++              for (j = start; j < end; j++) {
++                      if (process_recs_in_page == insert_recs_in_page)
++                              register_userspace_probes(&m->rec[j]);
++              }
++                              
++              (*process_recs_in_page)(m, page, start, end, vma);
++              if (page) 
++                      page_cache_release(page); /* TODO: Lock needed ? */
++              process_recs_in_cow_pages(m, start, end, process_recs_in_page);
++
++              for (j = start; j < end; j++) {
++                      if (process_recs_in_page == remove_recs_from_page)
++                              unregister_userspace_probes(&m->rec[j]);
++              }
++      }
++      return 1;
++}
++
++static inline int insert_recs(struct dp_module_struct *m)
++{
++      return process_recs(m, insert_recs_in_page);
++}
++
++static inline int remove_recs(struct dp_module_struct *m)
++{
++      return process_recs(m, remove_recs_from_page);
++}
++
++/*
++ * Gets exclusive write access to the given inode to ensure that the file
++ * on which probes are currently applied does not change. Use the function,
++ * deny_write_access_to_inode() we added in fs/namei.c.
++ */
++extern int deny_write_access_to_inode(struct inode * inode);
++static inline int ex_write_lock(struct inode * inode)
++{
++      return deny_write_access_to_inode(inode);
++}
++
++/*
++ * Called when removing user space probes to release the write lock on the
++ * inode.
++ */
++static inline int ex_write_unlock(struct inode * inode)
++{
++      atomic_inc(&inode->i_writecount);
++      return 0;
++}
++
++/*
++ * Inserts user space probes.
++ *
++ * mod->pgm.name is already in user space. This function leaves with the
++ * dentry held and taking with the inode writelock held to ensure that the
++ * file on which probes are currently active does not change from under us.
++ */
++static int insert_u (struct dp_module_struct * m)
++{
++      struct address_space *as;
++      int error;
++
++      error = user_path_walk(m->pgm.name, &m->nd);
++      if (error)
++              return error;
++
++      m->inode = m->nd.dentry->d_inode;
++      as = m->inode->i_mapping;
++
++      error = ex_write_lock(m->inode);
++      if (error) {
++              path_release(&m->nd);
++              return error;
++      }
++
++      /* switch i_op to hook into readpage */
++      m->ori_a_ops = as->a_ops;
++      m->dp_a_ops = *as->a_ops;
++      m->dp_a_ops.readpage = dp_readpage;
++      as->a_ops = &m->dp_a_ops;
++
++      /* physically insert the probes in existing pages */
++      insert_recs(m);
++
++      return 0;
++}
++
++/*
++ * Removes user space probes.
++ */
++static int remove_u(struct dp_module_struct *m)
++{
++      m->inode->i_mapping->a_ops = m->ori_a_ops; /* unhook readpage */
++      remove_recs(m); /* remove the probes */
++      ex_write_unlock(m->inode);
++      path_release(&m->nd); /* release path */
++      return 0;
++}
++
++/*
++ * Entry routine for the insert command. It checks for existing probes in this
++ * module to avoid any duplications, creates the necessary data structures
++ * calls insert_k() or insert_u() depending on whether it is a kernel space or
++ * user space probe.
++ */
++static int do_insert(struct dp_pgm_struct *upgm)
++{
++      struct dp_module_struct *m;
++      struct dp_pgm_struct *pgm;
++      char *uname, *kname;
++      int retval;
++
++      if (!upgm)
++              return -EINVAL;
++
++      pgm = kmalloc (sizeof(*pgm), GFP_KERNEL);
++      if (!pgm)
++              return -ENOMEM;
++
++      if (copy_from_user(pgm, upgm, sizeof(*pgm))) {
++              retval = -EFAULT;
++              goto done;
++      }
++
++      if (!pgm->name || !pgm->num_points) {
++              retval = -EINVAL;
++              goto done;
++      }
++      uname = pgm->name;
++      retval = copy_pgm_from_user(&m, pgm);
++      if (retval)
++              goto done;
++
++      try_module_get(THIS_MODULE);
++      down_write(&dp_modlist_sem);
++      link_module(m);
++      if (pgm->flags & DP_MODTYPE_USER) {
++              /* kludge: needed to use user_path_walk. */
++              kname = m->pgm.name;
++              m->pgm.name = uname;
++              retval = insert_u(m);
++              m->pgm.name = kname;
++      } else {
++              retval = insert_k(m);
++      }
++      
++      if (retval) {
++              free_dp_module(m);
++              module_put(THIS_MODULE);
++      } else {
++              init_trace_hdr(m);
++              get_trace_id(m);
++      }
++      up_write(&dp_modlist_sem);
++
++done: kfree(pgm);
++      return retval;
++}
++
++static int remove_module(struct dp_module_struct *m)
++{
++      /* remove probes */
++      if (m->pgm.flags & DP_MODTYPE_USER) {
++              remove_u(m);
++      } else {
++              remove_k(m);
++      }
++      free_trace_id(m);
++
++      /* free module and all its contents */
++      free_dp_module(m);
++      return 0;
++}
++
++/*
++ * Entry routine for removing probes.
++ */
++static int do_remove (unsigned long cmd, char * uname)
++{
++      struct dp_module_struct *m, *tmp;
++      char *name;
++
++      if (cmd & DP_ALL) {
++              down_write(&dp_modlist_sem);
++              m = dp_module_list;
++              while (m) {
++                      tmp = m->next;
++                      remove_module (m);
++                      m = tmp;
++                      module_put(THIS_MODULE);
++              }
++              up_write(&dp_modlist_sem);
++      } else {
++              if (!uname)
++                      return -EINVAL;
++              name = getname(uname);
++              if (IS_ERR(name))
++                      return (PTR_ERR(name));
++
++              down_write(&dp_modlist_sem);
++              m = find_mod_by_name (name);
++              putname(name);
++              if (!m) {
++                      up_write(&dp_modlist_sem);
++                      return -EINVAL;
++              }
++              remove_module (m);
++              module_put(THIS_MODULE);
++              up_write(&dp_modlist_sem);
++      }
++      return 0;
++}
++
++static int 
++dp_get_globalvars(unsigned long cmd, struct dp_getvars_in_struct * req, 
++              byte_t * result)
++{
++      unsigned long num_vars;
++      unsigned long *tmp_gv = NULL;
++      unsigned long eflags;
++      unsigned short orig_to = req->to;
++      int retval = 0;
++
++      read_lock_irqsave(&dp_gv_lock, eflags);
++      if (!(cmd & DP_GETVARS_INDEX)) {
++              req->from = 0;
++              req->to = dp_num_gv - 1;
++              num_vars = dp_num_gv;
++      } else if (req->from >= dp_num_gv) {
++              num_vars = 0;
++      } else if (req->to >= dp_num_gv) {
++              req->to = dp_num_gv - 1;
++              num_vars = req->to - req->from + 1;
++      } else {
++              num_vars = req->to - req->from + 1;
++      }
++
++      if (cmd & DP_GETVARS_RESET) {
++              memset(dp_gv + req->from, 0, num_vars*sizeof(unsigned long));
++              read_unlock_irqrestore(&dp_gv_lock, eflags);
++              goto done;
++      }
++
++      read_unlock_irqrestore(&dp_gv_lock, eflags);
++
++      if (num_vars) {
++              tmp_gv = kmalloc(num_vars * sizeof(*tmp_gv), GFP_KERNEL);
++              if (!tmp_gv) {
++                      retval = -ENOMEM;
++                      goto done;
++              }
++
++              read_lock_irqsave(&dp_gv_lock, eflags);
++
++              /*
++               * dp_num_gv can change(only increase) during kmalloc. In such
++               * a case, only copy the previously determined number
++               * of global vars.
++               */
++              memcpy((void *)tmp_gv, (void *)(dp_gv + req->from), 
++                      sizeof(unsigned long) * num_vars);
++              read_unlock_irqrestore(&dp_gv_lock, eflags);
++      }
++      
++      req->returned +=  (num_vars + 1) * sizeof(unsigned long); 
++              if (req->returned < req->allocated) {
++              if (copy_to_user(result, &num_vars, sizeof(unsigned long)))
++                      retval = -EFAULT;
++              else if (num_vars) {
++                      if (copy_to_user(result + sizeof(unsigned long), 
++                              tmp_gv, sizeof(unsigned long) * num_vars))
++                      retval = -EFAULT;
++                      kfree(tmp_gv);
++              }
++      }
++      else
++              retval = -ENOMEM;
++done:
++      req->to = orig_to;
++      return retval;
++}
++
++static int
++cp_lvars_for_mod(struct dp_module_struct *m, struct dp_getvars_in_struct * req,
++              byte_t * result, unsigned long var_bytes)
++{
++      unsigned long len = 0;
++      unsigned long offset = 0;
++      unsigned long num_vars = req->to - req->from + 1;
++
++              len = sizeof(struct dp_getvars_local_out_struct) +
++                      var_bytes + strlen(m->pgm.name) + 1;
++      req->returned += len;
++
++              if (req->returned < req->allocated) {
++              if (copy_to_user(result, &len, sizeof(unsigned long)))
++                      return -EFAULT;
++              else
++                      offset = sizeof(unsigned long);
++
++              if (copy_to_user(result+offset, &num_vars,
++                              sizeof(unsigned long)))
++                      return -EFAULT;
++              else
++                      offset += sizeof(unsigned long);
++
++              if (copy_to_user(result+offset, m->lv + req->from, var_bytes))
++                      return -EFAULT;
++              else
++                      offset += var_bytes;
++
++              if (copy_to_user(result+offset, m->pgm.name,
++                              strlen(m->pgm.name)+1))
++                      return -EFAULT;
++      }
++      else
++              return -ENOMEM;
++
++      return 0;
++}
++
++static int
++getvars_m(struct dp_module_struct *m, unsigned long cmd,
++              struct dp_getvars_in_struct *req, byte_t *result)
++{
++      int retval = 0;
++      unsigned long var_bytes;
++      unsigned short orig_to = req->to;
++
++      if (cmd & DP_GETVARS_INDEX) {
++              if (req->from >= m->pgm.num_lv)
++                      return 0;
++              if(req->to >= m->pgm.num_lv)
++                      req->to = m->pgm.num_lv - 1;
++      }
++      else {
++              req->from = 0;
++              req->to = m->pgm.num_lv - 1;
++      }
++      var_bytes = (req->to - req->from + 1) * sizeof(unsigned long);
++
++      if (cmd & DP_GETVARS_RESET)
++              memset(m->lv + req->from, 0, var_bytes);
++      else
++              retval = cp_lvars_for_mod(m, req, result, var_bytes);
++      req->to = orig_to;
++      return retval;
++}
++
++static int
++do_getvars(unsigned long cmd, struct dp_getvars_in_struct * ureq,
++              byte_t * result)
++{
++      struct dp_module_struct *m;
++      struct dp_getvars_in_struct req;
++      int retval = 0;
++
++      if (!ureq)
++              return -EINVAL;
++
++      if (copy_from_user(&req, ureq, sizeof(req))) {
++              retval = -EFAULT;
++              goto failed;
++      }
++      if (req.name) {
++              req.name = getname(req.name);
++              if (IS_ERR(req.name)) {
++                      retval = PTR_ERR(req.name);
++                      goto failed;
++              }
++      }
++      else
++              req.name = NULL;
++
++              req.returned = 0;
++      if (cmd & DP_GETVARS_GLOBAL) {
++              retval = dp_get_globalvars(cmd, &req, result);
++              if (retval) 
++                      goto done;
++      }
++
++      if (cmd & DP_GETVARS_LOCAL) {
++              down_read(&dp_modlist_sem);
++              if (cmd & DP_ALL) {
++                      for (m = dp_module_list; m; m = m->next) {
++                              if (!m->lv) 
++                                      continue;
++                              retval = getvars_m(m, cmd, &req, result + req.returned);
++                              if (retval && (retval != -ENOMEM))
++                                      break;
++                      }
++              } else if (req.name) {
++                      m = find_mod_by_name(req.name);
++                      if (m && m->lv)
++                              retval = getvars_m(m, cmd, &req, result + req.returned);
++                      else 
++                              retval = -EINVAL;
++              }
++              up_read(&dp_modlist_sem);
++      }
++done:
++      if (copy_to_user(&ureq->returned, &req.returned,
++                      sizeof(unsigned long)))
++              retval = -EFAULT;
++
++      if (req.name)
++              putname(req.name);
++failed:
++      return retval;
++}
++
++#define dp_copy_to_user(destination, source, length) \
++do { \
++      if (copy_to_user(destination, source, length)) \
++              return -EFAULT; \
++      destination += length; \
++} while(0)
++
++static int query_r(struct dp_module_struct *m, byte_t **result)
++{
++      struct dp_outrec_struct outrec;
++      struct dp_record_struct * rec;
++      unsigned short i;
++      unsigned short num_recs = m->pgm.num_points;
++      byte_t * offset = *result;
++      unsigned long eflags;
++
++      for (i = 0, rec = m->rec; i < num_recs; i++, rec++) {
++              spin_lock_irqsave(&rec->lock, eflags);
++              outrec.status = rec->status;
++              outrec.count = rec->count;
++              outrec.dbregno = rec->dbregno;
++              outrec.point = rec->point;
++              spin_unlock_irqrestore(&rec->lock, eflags);
++              dp_copy_to_user(offset, &outrec, sizeof(outrec));
++      }
++      *result = offset;
++      return 0;
++}
++
++static int
++query_m(struct dp_module_struct *m, struct dp_query_in_struct *req,
++              byte_t * result)
++{
++      unsigned long len = 0;
++      byte_t * offset = result;
++      struct dp_outmod_struct outmod;
++      int retval;
++      unsigned long rec_bytes = m->pgm.num_points *
++                                sizeof(struct dp_outrec_struct);
++      unsigned long var_bytes = m->pgm.num_lv * sizeof(m->lv);
++      unsigned long rpn_bytes = m->pgm.rpn_length;
++      unsigned long mod_name_len = strlen(m->pgm.name) + 1;
++
++      len = sizeof(struct dp_outmod_struct) + var_bytes + rec_bytes
++              + rpn_bytes + mod_name_len;
++
++      req->returned += len;
++      if (req->returned <= req->allocated) {
++              outmod.pgm = m->pgm;
++              outmod.flags = m->flags;
++              outmod.base = m->base;
++              outmod.end = m->end;
++
++              offset += sizeof(outmod);
++
++              outmod.rec = (struct dp_outrec_struct *) offset ;
++              retval = query_r(m, &offset);
++              if (retval)
++                      return retval;
++
++              if (var_bytes) {
++                      outmod.lv = (unsigned long *) offset;
++                      dp_copy_to_user(offset, m->lv, var_bytes);
++              } else
++                      outmod.lv = NULL;
++
++              outmod.pgm.rpn_code = offset;
++              dp_copy_to_user(offset, m->pgm.rpn_code, rpn_bytes);
++
++              outmod.pgm.name = (char *) offset;
++              dp_copy_to_user(offset, m->pgm.name, mod_name_len);
++              if (m->next && !(req->name))
++                      outmod.next = (struct dp_outmod_struct *) offset;
++              else
++                      outmod.next = NULL;
++              offset = result;
++              dp_copy_to_user(offset, &outmod, sizeof(outmod));
++      }
++      else
++              return -ENOMEM;
++      return 0;
++}
++
++static int
++do_query(unsigned long cmd, struct dp_query_in_struct * ureq, byte_t * result)
++{
++      struct dp_query_in_struct req;
++      struct dp_module_struct *m;
++      int retval = 0;
++
++      if (!ureq)
++              return -EINVAL;
++      if (copy_from_user(&req, ureq, sizeof(req))) {
++              retval = -EFAULT;
++              goto failed;
++      }
++      if (req.name) {
++              req.name = getname(req.name);
++              if (IS_ERR(req.name)) {
++                      retval = PTR_ERR(req.name);
++                      goto failed;
++              }
++      }
++      else
++              req.name = NULL;
++      req.returned = 0;
++
++      down_read(&dp_modlist_sem);
++      if (cmd & DP_ALL) {
++              for (m = dp_module_list; m; m = m->next) {
++                      retval = query_m(m, &req, result + req.returned);
++                      if (retval && (retval != -ENOMEM))
++                              break;
++              }
++      }
++      else if (req.name) {
++              m = find_mod_by_name(req.name);
++              if (m) 
++                      retval = query_m(m, &req, result + req.returned);
++              else 
++                      retval = -EINVAL;
++      }
++      up_read(&dp_modlist_sem);
++
++      if (copy_to_user(&ureq->returned, &req.returned,
++                      sizeof(unsigned long)))
++              retval = -EFAULT;
++      if (req.name)
++              putname(req.name);
++failed:
++      return retval;
++}
++
++/*
++ * Returns the index of the first probe record that lies in the page
++ * starting with given offset.
++ */
++static inline int
++find_first_in_page(struct dp_module_struct * m, unsigned long offset)
++{
++      int i;
++      unsigned short num_recs = m->pgm.num_points;
++      struct dp_record_struct * rec;
++      unsigned long end = offset + PAGE_SIZE;
++
++      for (i = 0, rec = m->rec; i < num_recs; i++, rec++) {
++              if (rec->point.offset >=offset && rec->point.offset < end)
++                      return i;
++      }
++      return -1;
++}
++
++/*
++ * This routine does the post processing for all pages that are brought
++ * in from a user module which has active probes in it.
++ */
++static int fixup_page (struct dp_module_struct *m, struct page *page)
++{
++      int start;
++      unsigned short end;
++      struct vm_area_struct *vma = NULL;
++
++      /* find and insert all probes in this page */
++      start = find_first_in_page(m, (page->index << PAGE_CACHE_SHIFT));
++      if (start < 0)
++              return -1;
++      end = find_last(m, start);
++
++      return insert_recs_in_page (m, page, start, end, vma);
++}
++
++/*
++ * This function handles the readpage of all modules that have active probes
++ * in them. Here, we first call the original readpage() of this
++ * inode / address_space to actually read the page into memory. Then, we will
++ * insert all the probes that are specified in this page before returning.
++ */
++int dp_readpage(struct file *file, struct page *page)
++{
++      int retval = 0;
++      struct dp_module_struct *m;
++
++      down_read(&dp_modlist_sem);
++      m = find_mod_by_inode(file->f_dentry->d_inode);
++      if (!m) {
++              printk("dp_readpage: major problem. we don't have mod for this !!!\n");
++              up_read(&dp_modlist_sem);
++              return -EINVAL;
++      }
++
++      /* call original readpage() */
++      retval = m->ori_a_ops->readpage(file, page);
++      if (retval >= 0)
++              fixup_page (m, page);
++
++      up_read(&dp_modlist_sem);
++      return retval;
++}
++
++/*
++ * This is called from kernel/module.c,sys_init_module() after a kernel module
++ * is loaded before it is initialized to give us a chance to insert any probes
++ * in it.
++ */
++int dp_insmod(struct module *kmod)
++{
++      struct dp_module_struct *m;
++      int retval;
++
++      down_read(&dp_modlist_sem);
++      m = find_mod_by_name(kmod->name);
++      if (!m) {
++              retval = -1;
++      } else {
++              get_kmod_bounds(m, kmod);
++              retval = insert_all_recs_k(m);
++      }
++      up_read(&dp_modlist_sem);
++      return retval;
++}
++
++/*
++ * This is called from kernel/module.c, free_module() before freeing a kernel
++ * module and from sys_init_module() when a kernel module initialization fails
++ * to give us a chance to remove any probes in it.
++ */
++int dp_remmod(struct module *kmod)
++{
++      struct dp_module_struct *m;
++      int retval;
++
++      down_read(&dp_modlist_sem);
++      m = find_mod_by_name(kmod->name);
++      if (!m)
++              retval = -1;
++      else
++              retval = remove_all_recs_k(m);
++      up_read(&dp_modlist_sem);
++      return retval;
++}
++
++/* 
++ * ioctl function for dprobes driver.
++ */
++static int dp_ioctl (struct inode *in, struct file *fp, unsigned int ioctl_cmd,
++             unsigned long arg)
++{
++      struct dp_ioctl_arg dp_arg;
++      int retval = 0;
++
++      if (current->euid) {
++              return -EACCES;
++      }
++
++      if (copy_from_user((void *)&dp_arg, (void *)arg, sizeof(dp_arg))) {
++              module_put(THIS_MODULE);
++              return -EFAULT;
++      }
++
++      switch (dp_arg.cmd & DP_CMD_MASK) {
++      case DP_INSERT:
++              retval = do_insert(dp_arg.input); 
++              break;
++      case DP_REMOVE:
++              retval = do_remove(dp_arg.cmd, dp_arg.input); 
++              break; 
++      case DP_GETVARS:
++              retval = do_getvars(dp_arg.cmd, dp_arg.input, dp_arg.output); 
++              break;
++      case DP_QUERY:
++              retval = do_query(dp_arg.cmd, dp_arg.input, dp_arg.output); 
++              break;
++      default:
++              retval = -EINVAL;
++              break;
++      }
++      return retval;  
++}
++
++static struct file_operations dprobes_ops = {
++      owner:  THIS_MODULE,
++      ioctl:  dp_ioctl
++};
++
++static int dprobes_major;
++
++#ifdef CONFIG_MAGIC_SYSRQ
++
++/* SysRq handler - emergency removal of all probes via Alt-SysRq-V */
++
++static void do_remove_sysrq(struct dprobes_struct *dp) 
++{
++      int retval;
++      if ((retval = do_remove(DP_ALL, NULL)))
++              printk("<1>Probe removal failed rc %i\n", retval);
++      else
++              printk("<1> All probes removed\n");
++      test_and_clear_bit(0, &emergency_remove);
++      return;
++}
++
++static void dprobes_sysrq( int key, struct pt_regs *ptr, struct tty_struct *tty) 
++{
++
++      int retval;
++      retval = test_and_set_bit(0,&emergency_remove);
++      if (!retval) 
++              queue_work(dprobes_wq, &dprobes_work);
++      return;
++
++}
++#endif
++
++static int __init dprobes_init_module(void)
++{
++      int retval = 0;
++
++      dprobes_major = register_chrdev(0, "dprobes", &dprobes_ops);
++      if (dprobes_major < 0) {
++              printk("Failed to register dprobes device\n");
++              retval = dprobes_major;
++              goto err;
++      }
++
++      printk("IBM Dynamic Probes v%d.%d.%d loaded.\n", DP_MAJOR_VER, 
++                      DP_MINOR_VER, DP_PATCH_VER);
++
++#ifdef CONFIG_MAGIC_SYSRQ
++      if (!(dprobes_wq = create_workqueue("dprobes_wq"))) {
++              printk("dprobes create_workqueue failed\n");
++              retval = -ENOMEM;
++              goto err;
++      }
++      INIT_WORK(&dprobes_work, (void *)(void *)do_remove_sysrq, NULL);
++      if ((retval = register_sysrq_key('v', &key_op)))
++              printk("<1>register_sysrq_key returned %i\n", retval);
++#endif
++
++err:  return retval;
++}
++
++static void __exit dprobes_cleanup_module(void)
++{
++      int retval;
++      unregister_chrdev(dprobes_major, "dprobes");
++      
++      printk("IBM Dynamic Probes v%d.%d.%d unloaded.\n", DP_MAJOR_VER, 
++                      DP_MINOR_VER, DP_PATCH_VER);
++
++#ifdef CONFIG_MAGIC_SYSRQ        
++      destroy_workqueue(dprobes_wq);
++      if ((retval = unregister_sysrq_key('v', &key_op)))
++              printk("<1>unregister_sysrq_key returned %i\n", retval);
++#endif   
++      return;
++}
++
++module_init(dprobes_init_module);
++module_exit(dprobes_cleanup_module);
++
++MODULE_AUTHOR("IBM");
++MODULE_DESCRIPTION("Dynamic Probes");
++MODULE_LICENSE("GPL");
++
++void dprobes_code_end(void) { }
+diff -urNp linux.orig/drivers/dprobes/dprobes_in.c linux-2.6.0-test11/drivers/dprobes/dprobes_in.c
+--- linux.orig/drivers/dprobes/dprobes_in.c    1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.0-test11/drivers/dprobes/dprobes_in.c    2003-12-15 15:51:48.000000000 +0530
+@@ -0,0 +1,2014 @@
++/*
++ * IBM Dynamic Probes
++ * Copyright (c) International Business Machines Corp., 2000
++ *
++ * 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.  
++ */
++
++#include <linux/dprobes.h>
++#include <linux/dprobes_in.h>
++#include <asm/io.h>
++#include <asm/uaccess.h>
++
++static void dispatch_ex(void);
++static void gen_ex(unsigned long, unsigned long, unsigned long);
++static void log_st(void);
++
++void dprobes_interpreter_code_start(void) { }
++
++/*
++ * RPN stack manipulation
++ * Pushes a 32 bit number onto RPN stack.
++ */
++static inline void rpnpush(unsigned long arg)
++{
++      dprobes.rpn_tos--;
++      dprobes.rpn_tos &= RPN_STACK_SIZE - 1;
++      dprobes.rpn_stack[dprobes.rpn_tos] = arg;
++}
++
++/*
++ * Pops a 32 bit number from RPN stack.
++ */
++static inline unsigned long rpnpop(void)
++{
++      unsigned long ret = dprobes.rpn_stack[dprobes.rpn_tos];
++      dprobes.rpn_tos++;
++      dprobes.rpn_tos &= RPN_STACK_SIZE - 1;
++      return ret;
++}
++
++/*
++ * Returns a 32 bit number for RPN stack at a given position
++ * relative to RPN TOS, without poping.
++ */
++static unsigned long rpnmove(unsigned long pos)
++{
++      unsigned long index = dprobes.rpn_tos + pos;
++      index &= RPN_STACK_SIZE - 1;
++      return dprobes.rpn_stack[index];
++}
++
++/*
++ * Returns a byte(8 bit) operand from rpn code array
++ */
++static inline u8 get_u8_oprnd(void)
++{
++      return *dprobes.rpn_ip++;
++}
++
++
++/*
++ * Returns a word(16 bit) operand from rpn code array
++ */
++static inline u16 get_u16_oprnd(void)
++{
++      return *(((u16 *)dprobes.rpn_ip)++);
++}
++
++/*
++ * Returns an unsigned long operand from rpn code array
++ */
++static inline unsigned long get_ulong_oprnd(void)
++{
++      unsigned long dw;
++      dw = *((unsigned long *) (dprobes.rpn_ip));
++      dprobes.rpn_ip += sizeof(unsigned long);
++      return dw;
++}
++
++/*
++ * Returns a signed long(32 bit) operand from rpn code array
++ */
++static inline long get_long_oprnd(void)
++{
++      long l;
++      l = *((long *) (dprobes.rpn_ip));
++      dprobes.rpn_ip += sizeof(long);
++      return l;
++}
++
++#ifdef CONFIG_X86
++#include "i386/dprobes_in.c"
++#endif
++
++/*
++ * Jump instructions.
++ * Interpreter is terminated when total number of jumps and loops
++ * becomes equal to jmpmax.
++ */
++static void jmp(void)
++{
++      long offset = get_long_oprnd();
++      if (dprobes.jmp_count == dprobes.mod->pgm.jmpmax) {
++              gen_ex(EX_MAX_JMPS, dprobes.mod->pgm.jmpmax, 0);
++              return;
++      }       
++      dprobes.jmp_count++;
++      dprobes.rpn_ip += offset;
++}
++
++#define COND_JMPS(name, condition) \
++static void name(void) \
++{ \
++      long offset = get_long_oprnd(); \
++      if ((long) dprobes.rpn_stack[dprobes.rpn_tos] condition 0) { \
++              if (dprobes.jmp_count == dprobes.mod->pgm.jmpmax) { \
++                      gen_ex(EX_MAX_JMPS, dprobes.mod->pgm.jmpmax, 0); \
++                      return; \
++              } \
++              dprobes.jmp_count++; \
++              dprobes.rpn_ip += offset; \
++      } \
++}
++
++COND_JMPS(jlt, <)
++COND_JMPS(jgt, >)
++COND_JMPS(jle, <=)
++COND_JMPS(jge, >=)
++COND_JMPS(jz, ==)
++COND_JMPS(jnz, !=)
++      
++/*
++ * loop label: Decrement RPN TOS and jump to the label
++ * if TOS is not equal to 0.
++ * Interpreter is terminated when total number of jumps and loops
++ * becomes equal to jmpmax.
++ */
++static void loop(void)
++{
++      long offset = get_long_oprnd();
++      if (dprobes.jmp_count++ == dprobes.mod->pgm.jmpmax) {
++              gen_ex(EX_MAX_JMPS, dprobes.mod->pgm.jmpmax, 0);
++              return;
++      }
++      if ((long) (--dprobes.rpn_stack[dprobes.rpn_tos]) != 0)
++              dprobes.rpn_ip += offset;
++}
++
++/*
++ * Call and ret instructions. Number of nested calls is limited to 32.
++ */
++static void call(void)
++{
++      int i;
++      struct dprobes_struct *dp = &dprobes;
++      long offset = (long)get_long_oprnd();
++      unsigned long called_addr = (dp->rpn_ip - dp->rpn_code + offset);
++      if (dp->call_tos < CALL_FRAME_SIZE) {
++              gen_ex(EX_CALL_STACK_OVERFLOW, NR_NESTED_CALLS, 0);
++              return;
++      }
++      /*
++       * Push the return value(rpn_ip) onto the call stack.
++       */
++      dp->call_stack[--dp->call_tos] = dp->rpn_ip - dp->rpn_code;
++      dp->rpn_ip += offset;
++      /* 
++       * push the called subroutine address, default exception handler
++       * address, and initialize pv, lv and gv range to zeros.
++       */             
++      dp->call_stack[--dp->call_tos] = called_addr;
++      dp->call_stack[--dp->call_tos] = EX_NO_HANDLER;
++
++      for (i = 0; i < CALL_FRAME_SIZE - 4; i++)
++              dp->call_stack[--dp->call_tos] = 0;
++      /* Save the rpn stack base pointer */
++      dp->call_stack[--dp->call_tos] = dp->rpn_sbp;   
++}
++
++/*
++ * Pops the return value into rpn_ip.
++ */
++static void ret(void)
++{
++      struct dprobes_struct *dp = &dprobes;
++      if (dp->call_tos >= CALL_STACK_SIZE - CALL_FRAME_SIZE) {
++              gen_ex(EX_CALL_STACK_OVERFLOW, 0, 0);
++              return;
++      }
++      dp->rpn_sbp = dp->call_stack[dp->call_tos++];
++      dp->call_tos += CALL_FRAME_SIZE - 2;
++      /* pop the return address */
++      dp->rpn_ip = dp->rpn_code + dp->call_stack[dp->call_tos++];
++
++      if (dp->ex_pending) {
++              dp->ex_hand = dp->call_stack[dp->call_tos + 
++                              OFFSET_EX_HANDLER];
++              dispatch_ex();
++      }
++}
++
++/*
++ * Exception handling instructions.
++ */
++static void sx(void)
++{
++      long offset = get_long_oprnd();
++      dprobes.call_stack[dprobes.call_tos + OFFSET_EX_HANDLER] = 
++                              (long)dprobes.rpn_ip + offset;
++}
++      
++static void ux(void)
++{
++      dprobes.call_stack[dprobes.call_tos + OFFSET_EX_HANDLER] = 
++                                                      EX_NO_HANDLER;
++}
++
++static void dispatch_ex(void)
++{
++      struct dprobes_struct *dp = &dprobes;
++      long ex_handler;
++      /* We are at the outermost routine & no exception handler, terminate */
++      if ((dp->call_tos == CALL_STACK_SIZE - CALL_FRAME_SIZE) && 
++              (dp->call_stack[dp->call_tos + OFFSET_EX_HANDLER] == 
++                      EX_NO_HANDLER)) {
++              dp->status &= ~DP_STATUS_INTERPRETER;
++              return;
++      }
++      ex_handler = dp->ex_hand;
++      if (ex_handler != EX_NO_HANDLER) {
++              dp->ex_pending = 0;
++              dp->call_stack[dp->call_tos + OFFSET_EX_HANDLER] = 
++                                      EX_NO_HANDLER;
++              dp->rpn_ip = (byte_t *)ex_handler;
++      }
++      else {
++              ret();
++      }
++}
++
++static void rx(void)
++{
++      struct dprobes_struct *dp = &dprobes;
++      dp->ex_code = rpnmove(0);
++      dp->ex_parm1 = rpnmove(1);
++      dp->ex_parm2 = rpnmove(2);
++      dp->ex_pending = 1;
++      dp->ex_hand = dp->call_stack[dp->call_tos + 
++                                      OFFSET_EX_HANDLER];
++      if (dp->rec->mod->pgm.autostacktrace)
++              log_st();
++      dispatch_ex();
++}
++
++static void push_x(void)
++{
++      rpnpush(dprobes.ex_parm2);
++      rpnpush(dprobes.ex_parm1);
++      rpnpush(dprobes.ex_code);
++}
++
++static void gen_ex(unsigned long ex_code, unsigned long parm1, 
++              unsigned long parm2)
++{
++      struct dprobes_struct *dp = &dprobes;
++        if (ex_code & dp->rec->point.ex_mask) {
++              dp->ex_code = ex_code;
++              dp->ex_parm1 = parm1;
++              dp->ex_parm2 = parm2;
++              rpnpush(parm2);
++              rpnpush(parm1);
++              rpnpush(ex_code);
++              dp->ex_pending = 1;
++              dp->ex_hand = dp->call_stack[dp->call_tos + 
++                              OFFSET_EX_HANDLER];
++              if (dp->rec->mod->pgm.autostacktrace) {
++                      log_st();
++              }
++                dispatch_ex();
++        } else if (ex_code & EX_NON_MASKABLE_EX) {
++              dp->ex_hand = dp->call_stack[dp->call_tos + 
++                              OFFSET_EX_HANDLER];
++              if (dp->rec->mod->pgm.autostacktrace)
++                      log_st();
++                dp->status &= ~DP_STATUS_INTERPRETER;
++        }
++}
++
++static int write_st_buffer(unsigned char *ptr, int size)
++{
++      if (dprobes.ex_log_len + size >= dprobes.mod->pgm.ex_logmax)
++              return -1;
++      else {
++              memcpy(dprobes.ex_log + dprobes.ex_log_len, ptr, size);
++              dprobes.ex_log_len += size;
++              return 0;
++      }
++}
++
++static int log_gv_entries(unsigned long call_tos)
++{
++      struct dprobes_struct *dp = &dprobes;
++      unsigned char gv_prefix[PREFIX_SIZE] = {TOKEN_GV_ENTRY, 0, 0};
++      unsigned long range = dp->call_stack[call_tos + OFFSET_GV_RANGE];
++      unsigned long index = dp->call_stack[call_tos + OFFSET_GV_RANGE + 1];
++      int i;
++      dp->ex_off.gv = dp->ex_log_len + 1;
++      if (write_st_buffer(gv_prefix, PREFIX_SIZE))
++              return -1;
++      for (i = index; i < index + range; i++) {
++              if (i >= dp_num_gv) {
++                      dp->status &= ~DP_STATUS_INTERPRETER;
++                      return -1;
++              }
++              read_lock(&dp_gv_lock);
++              if (write_st_buffer((unsigned char *)(dp_gv + i), sizeof(unsigned long))) {
++                      read_unlock(&dp_gv_lock);
++                      return -1;
++              }
++              read_unlock(&dp_gv_lock);
++              (*(unsigned short *)(dp->ex_log + dp->ex_off.gv))++;
++      }
++      return 0;
++}
++
++static int log_lv_entries(unsigned long call_tos)
++{
++      struct dprobes_struct *dp = &dprobes;
++      unsigned char lv_prefix[PREFIX_SIZE] = {TOKEN_LV_ENTRY, 0, 0};
++      unsigned long range = dp->call_stack[call_tos + OFFSET_LV_RANGE];
++      unsigned long index = dp->call_stack[call_tos + OFFSET_LV_RANGE + 1];
++      int i;
++      dp->ex_off.lv = dp->ex_log_len + 1;
++      if (write_st_buffer(lv_prefix, PREFIX_SIZE))
++              return -1;
++      for (i = index; i < index + range; i++) {
++              if (i >= dp->rec->mod->pgm.num_lv) {
++                      dp->status &= ~DP_STATUS_INTERPRETER;
++                      return -1;
++              }
++              if (write_st_buffer((unsigned char *)(dp->mod->lv + i), sizeof(unsigned long))) 
++                      return -1;
++              (*(unsigned short *)(dp->ex_log + dp->ex_off.lv))++;
++      }
++      return 0;
++}
++
++static int log_rpnstack_entries(unsigned long call_tos)
++{
++      struct dprobes_struct *dp = &dprobes;
++      unsigned char rpn_prefix[PREFIX_SIZE] = {TOKEN_RPN_ENTRY, 0, 0};
++      unsigned long range = dp->call_stack[call_tos + 
++                                              OFFSET_RPN_STACK_RANGE];
++      unsigned long index = dp->call_stack[call_tos + 
++                                              OFFSET_RPN_STACK_RANGE + 1];
++      int i, j;
++      dp->ex_off.rpn = dp->ex_log_len + 1;
++      if (write_st_buffer(rpn_prefix, PREFIX_SIZE))
++              return -1;
++      for (i = j = index; i < index + range; i++, j++) {
++              j &= (RPN_STACK_SIZE - 1);
++              if (write_st_buffer((unsigned char *)(dp->rpn_stack + j), 
++                              sizeof(unsigned long)))
++                      return -1;
++              (*(unsigned short *)(dp->ex_log + dp->ex_off.rpn))++;
++      }       
++      return 0;
++}
++
++static int log_stackframes(void)
++{
++      struct dprobes_struct *dp = &dprobes;
++      unsigned long c_tos = dp->call_tos;
++      unsigned char sf_prefix[PREFIX_SIZE] = {TOKEN_STACK_FRAME, 0, 0};
++      dp->ex_off.sf = dp->ex_log_len + 1;
++      if (write_st_buffer(sf_prefix, PREFIX_SIZE))
++              return -1;
++      
++      while (c_tos < (CALL_STACK_SIZE - CALL_FRAME_SIZE)) {
++              if (write_st_buffer((unsigned char *)(dp->call_stack + 
++                      c_tos + OFFSET_CALLED_ADDR), sizeof(unsigned long)))
++                      return -1;
++              if (write_st_buffer((unsigned char *)(dp->call_stack +
++                      c_tos + OFFSET_RETURN_ADDR), sizeof(unsigned long)))
++                      return -1;
++
++              if (log_rpnstack_entries(c_tos))
++                      return -1;
++              if (log_lv_entries(c_tos))
++                      return -1;
++              if (log_gv_entries(c_tos))
++                      return -1;
++
++              (*(short *)(dp->ex_log + dp->ex_off.sf))++;
++              c_tos += CALL_FRAME_SIZE;
++      }
++      return 0;
++}
++
++static int log_stacktrace(void)
++{
++      struct dprobes_struct *dp = &dprobes;
++      long ex_handler;
++      if (write_st_buffer((unsigned char *)&dp->ex_code, sizeof(unsigned long)))
++              return -1;
++      ex_handler = dp->ex_hand;
++      if (ex_handler != EX_NO_HANDLER)
++              ex_handler -= (long)dp->rpn_code;
++      if (write_st_buffer((unsigned char *)&ex_handler, sizeof(long)))
++              return -1;
++      if (write_st_buffer((unsigned char *)&dp->ex_parm1, sizeof(unsigned long)))
++              return -1;
++      if (write_st_buffer((unsigned char *)&dp->ex_parm2, sizeof(unsigned long)))
++              return -1;
++      if (log_stackframes())
++              return -1;
++      (*(short *)(dp->ex_log + dp->ex_off.st))++;
++      return 0;
++}
++
++static int get_exlog_hdr(void)
++{
++      unsigned short name_len;
++      unsigned char st_prefix[PREFIX_SIZE] = {TOKEN_STACK_TRACE, 0, 0};
++      struct dprobes_struct *dp = &dprobes;
++
++      strcpy(dp->ex_log + dp->ex_log_len + PREFIX_SIZE, dp->mod->pgm.name);
++      name_len = strlen(dp->mod->pgm.name);
++      dp->ex_log[dp->ex_log_len] = TOKEN_ASCII_LOG;
++      *(unsigned short *)(dp->ex_log + dp->ex_log_len + 1) = name_len;
++      dp->ex_log_len += (name_len + PREFIX_SIZE);
++
++      *(loff_t *)(dp->ex_log + dp->ex_log_len) = 
++                      dp->rec->point.offset;
++      dp->ex_log_len += sizeof(loff_t);
++      
++      *(unsigned short *)(dp->ex_log + dp->ex_log_len) = 
++                      dp->mod->pgm.id;
++      dp->ex_log_len += sizeof(unsigned short);
++
++      *(unsigned short *)(dp->ex_log + dp->ex_log_len) = 
++                      dp->major;
++      dp->ex_log_len += sizeof(unsigned short);
++      
++      *(unsigned short *)(dp->ex_log + dp->ex_log_len) = 
++                      dp->minor;
++      dp->ex_log_len += sizeof(unsigned short);
++
++      dp->ex_off.st = dp->ex_log_len + 1;
++      if (write_st_buffer(st_prefix, PREFIX_SIZE))
++              return -1;
++      return 0;
++}
++
++static void log_st(void)
++{
++      if (dprobes.ex_log_len == MIN_ST_SIZE)
++              if(get_exlog_hdr()) return;
++      log_stacktrace();
++}
++
++static void purge_st(void)
++{
++      dprobes.ex_log_len = MIN_ST_SIZE;
++}
++
++static void trace_lv(void)
++{
++      dprobes.call_stack[dprobes.call_tos + OFFSET_LV_RANGE] = rpnpop();
++      dprobes.call_stack[dprobes.call_tos + OFFSET_LV_RANGE + 1] = rpnpop();
++}
++
++static void trace_gv(void)
++{
++      dprobes.call_stack[dprobes.call_tos + OFFSET_GV_RANGE] = rpnpop();
++      dprobes.call_stack[dprobes.call_tos + OFFSET_GV_RANGE + 1] = rpnpop();
++}
++
++static void trace_pv(void)
++{
++      dprobes.call_stack[dprobes.call_tos + OFFSET_RPN_STACK_RANGE] = 
++                                                              rpnpop();
++      dprobes.call_stack[dprobes.call_tos + OFFSET_RPN_STACK_RANGE + 1] =
++                                                              rpnpop();
++}
++
++static void push_tsp(void)
++{
++      long index = (long)rpnpop();
++      unsigned long tsp_index = ((signed)dprobes.rpn_tos + index) 
++                                      & (RPN_STACK_SIZE - 1);
++      rpnpush(dprobes.rpn_stack[tsp_index]);
++}
++
++static void pop_tsp(void)
++{
++      unsigned long value = rpnpop();
++      long index = (long)rpnpop();
++      unsigned long tsp_index = ((signed)dprobes.rpn_tos + index) 
++                                      & (RPN_STACK_SIZE - 1);
++      dprobes.rpn_stack[tsp_index] = value;
++}
++
++static void save_sbp(void)
++{
++      rpnpush(dprobes.rpn_sbp);
++}
++
++static void restore_sbp(void)
++{
++      dprobes.rpn_sbp = rpnpop() & (RPN_STACK_SIZE - 1);
++}
++
++static void save_tsp(void)
++{
++      rpnpush(dprobes.rpn_tos);
++}
++
++static void restore_tsp(void)
++{
++      dprobes.rpn_tos = rpnpop();
++}
++
++static void push_sbp(void)
++{
++      long index = (long)rpnpop();
++      unsigned long sbp_index = ((signed)dprobes.rpn_sbp + index) 
++                                      & (RPN_STACK_SIZE - 1);
++      rpnpush(dprobes.rpn_stack[sbp_index]);
++}
++
++static void pop_sbp(void)
++{
++      unsigned long value = rpnpop();
++      long index = (long)rpnpop();
++      unsigned long sbp_index = ((signed)dprobes.rpn_sbp + index) 
++                                      & (RPN_STACK_SIZE - 1);
++      dprobes.rpn_stack[sbp_index] = value;
++}
++
++static void push_stp(void)
++{
++      rpnpush(dprobes.ex_log_len);
++}
++
++static void pop_stp(void)
++{
++      dprobes.ex_log_len = rpnpop();
++}
++
++static void push_sbp_i(void)
++{
++      s16 index = (s16)get_u16_oprnd();
++      unsigned long sbp_index = ((signed)dprobes.rpn_sbp + index) 
++                                      & (RPN_STACK_SIZE - 1);
++      rpnpush(dprobes.rpn_stack[sbp_index]);
++}
++
++static void pop_sbp_i(void)
++{
++      s16 index = (s16)get_u16_oprnd();
++      unsigned long sbp_index = ((signed)dprobes.rpn_sbp + index) 
++                                      & (RPN_STACK_SIZE - 1);
++      dprobes.rpn_stack[sbp_index] = rpnpop();
++}
++
++static void push_tsp_i(void)
++{
++      s16 index = (s16)get_u16_oprnd();
++      unsigned long tsp_index = ((signed)dprobes.rpn_tos + index) 
++                                      & (RPN_STACK_SIZE - 1);
++      rpnpush(dprobes.rpn_stack[tsp_index]);
++}
++
++static void pop_tsp_i(void)
++{
++      s16 index = (s16)get_u16_oprnd();
++      unsigned long tsp_index = ((signed)dprobes.rpn_tos + index) 
++                                      & (RPN_STACK_SIZE - 1);
++      dprobes.rpn_stack[tsp_index] = rpnpop();
++}
++
++static void copy_sbp(void)
++{
++      long index = (long)rpnpop();
++      unsigned long sbp_index = ((signed)dprobes.rpn_sbp + index) 
++                                      & (RPN_STACK_SIZE - 1);
++      dprobes.rpn_stack[sbp_index] = dprobes.rpn_stack[dprobes.rpn_tos];
++}
++
++static void copy_sbp_i(void)
++{
++      s16 index = (s16)get_u16_oprnd();
++      unsigned long sbp_index = ((signed)dprobes.rpn_sbp + index) 
++                                      & (RPN_STACK_SIZE - 1);
++      dprobes.rpn_stack[sbp_index] = dprobes.rpn_stack[dprobes.rpn_tos];
++}
++
++static void copy_tsp(void)
++{
++      long index = (long)rpnpop();
++      unsigned long tsp_index = ((signed)dprobes.rpn_tos + index) 
++                                      & (RPN_STACK_SIZE - 1);
++      dprobes.rpn_stack[tsp_index] = dprobes.rpn_stack[dprobes.rpn_tos];
++}
++
++static void copy_tsp_i(void)
++{
++      s16 index = (s16)get_u16_oprnd();
++      unsigned long tsp_index = ((signed)dprobes.rpn_tos + index) 
++                                      & (RPN_STACK_SIZE - 1);
++      dprobes.rpn_stack[tsp_index] = dprobes.rpn_stack[dprobes.rpn_tos];
++}
++
++/* 
++ * Normal exit from the interpreter. 
++ */
++static inline void dp_exit(void)
++{
++      dprobes.status &= ~DP_STATUS_INTERPRETER;
++}
++
++/*
++ * Exit the interpreter without producing the log.
++ */
++static inline void dp_abort(void)
++{
++      dprobes.status |= DP_STATUS_ABORT;
++      dprobes.status &= ~DP_STATUS_INTERPRETER;
++}
++
++static inline void dp_remove(void)
++{
++      dprobes.rec->status |= DP_REC_STATUS_REMOVED;
++      dprobes.status &= ~DP_STATUS_INTERPRETER;
++}
++
++static inline void no_op(void)
++{
++}
++
++/*
++ * Stores the fault record in the log buffer, when logging is
++ * terminated due to invalid memory access.
++ * Fault record comprises of a token byte, which indicates the reason for 
++ * fault; an unsigned short length indicating how many bytes are logged, 
++ * which is 4; and the 4 logged bytes indicate the faulting address.
++ *
++ * Token byte -1: fault occurred while reading the memory, faulting address
++ * indicates the virtual(flat) address which caused the fault.
++ * Token byte -2: fault occurred when converting the segmented address to
++ * flat address. The fault address stored will indicate the selector of
++ * the segmented address.
++ * Note that the fault record will be stored only if sufficient space
++ * is available to store the entire fault record.
++ *
++ * The fault record will be stored when fault occurs because of the
++ * following instructions:
++ *    log mrf
++ *    log str
++ */
++static void store_fault_record(byte_t token, unsigned long addr, 
++      unsigned long ex_code)
++{
++      struct dprobes_struct *dp = &dprobes;
++      if (dp->log_len + 7 <= dp->mod->pgm.logmax) {
++              dp->log[dp->log_len++] = token;
++              *((unsigned short *)(dp->log + dp->log_len)) = 4;
++              dp->log_len += sizeof(unsigned short);
++              *((unsigned long *)(dp->log + dp->log_len)) = addr;
++              dp->log_len += sizeof(unsigned long);
++              gen_ex(ex_code, addr, 0);
++      }
++      else
++              gen_ex(EX_LOG_OVERFLOW, dp->mod->pgm.logmax, 0);
++      return;
++}
++
++/*
++ * Logging group
++ */
++static inline void push_lp(void) 
++{
++      rpnpush(dprobes.log_len);
++}
++
++static inline void push_plp(void) 
++{
++      rpnpush(dprobes.prev_log_len);
++}
++
++static inline void pop_lp(void) 
++{
++      dprobes.log_len = rpnpop();
++}
++
++static void 
++log_ascii(unsigned long len, u8 *faddr)
++{
++      struct dprobes_struct *dp = &dprobes;
++      u8 b;
++      dp->prev_log_len = dp->log_len;
++      if (dp->log_len + len + PREFIX_SIZE > dp->mod->pgm.logmax) {
++              len = dp->mod->pgm.logmax - dp->log_len;
++              if ((signed)len < 0) {
++                      gen_ex(EX_LOG_OVERFLOW, dp->mod->pgm.logmax, 0);
++                      return;
++              }
++      }
++      dp->log_len += PREFIX_SIZE; /* reserve for prefix */
++      while (len--) {
++              if (!dp_intr_copy_from_user(&b, (void *)faddr, 1)) {
++                      if(b) {
++                              faddr++;
++                              dp->log[dp->log_len++] = b;
++                      } else 
++                              break;
++
++              } else {
++                      dp->log_len = dp->prev_log_len;
++                      store_fault_record(TOKEN_MEMORY_FAULT, 
++                                      (unsigned long)faddr, EX_INVALID_ADDR);
++                      return;
++              }
++      }
++      if (b && (signed)len >= 0) {
++              dp->status |= DP_STATUS_LOG_OVERFLOW;
++              dp->log_len = dp->prev_log_len;
++              gen_ex(EX_LOG_OVERFLOW, dp->mod->pgm.logmax, 0);
++              return;
++      }
++      dp->log[dp->prev_log_len] = TOKEN_ASCII_LOG;
++      *(unsigned short *) (dp->log + dp->prev_log_len + 1) =
++              (unsigned short) (dp->log_len - dp->prev_log_len - PREFIX_SIZE);
++      dp->prev_log_len = dp->log_len;
++      return;
++}
++
++static void
++log_memory(unsigned long len, u8 *faddr)
++{
++      struct dprobes_struct *dp = &dprobes;
++      unsigned long num_remain;
++      dp->prev_log_len = dp->log_len;
++      if (dp->log_len + len + PREFIX_SIZE > dp->mod->pgm.logmax) {
++              dp->status |= DP_STATUS_LOG_OVERFLOW;
++              len = dp->mod->pgm.logmax - dp->log_len - PREFIX_SIZE;
++              if ((signed)len < 0) {
++                      gen_ex(EX_LOG_OVERFLOW, dp->mod->pgm.logmax, 0);
++                      return;
++              }
++      }
++
++      if ((num_remain = dp_intr_copy_from_user(
++              (dp->log + dp->log_len + PREFIX_SIZE), faddr, len))) {
++              store_fault_record(TOKEN_MEMORY_FAULT, 
++              (unsigned long)(faddr+len-num_remain), EX_INVALID_ADDR);
++              return;
++      }
++
++      dp->log[dp->log_len++] = TOKEN_MEMORY_LOG;
++      *((unsigned short *)(dp->log + dp->log_len)) = len;
++      dp->log_len += (len + sizeof(unsigned short));
++      dp->prev_log_len = dp->log_len;
++      return;
++}
++
++/* log str pops the flat address and length from
++ * the RPN stack. It tries to copy length number of
++ * bytes from flat address to the log buffer.
++ * Logging is discontinued if a NULL byte is encountered.
++ * NULL byte is not logged. If the log buffer becomes full
++ * LOG_OVERFLOW exception is generated.
++ * If the log is successful, the logged string is prefixed
++ * by a token byte of 1 and a word indicating the length of
++ * the string logged.
++ * INVALID_ADDR exception is generated if the flat address is invalid.
++ */ 
++static void log_str(void)
++{
++      u8 *faddr = (u8 *) rpnpop();
++      log_ascii(rpnpop(), faddr);
++}
++
++/*
++ * Log memory at flat range.
++ * INVALID_ADDR exception is generated if flat address is invalid.
++ * Log terminating conditions apply.
++ * token byte = 0.
++ */
++static void log_mrf(void)
++{
++        u8 *faddr = (u8 *) rpnpop();
++      log_memory(rpnpop(), faddr);
++}
++
++/* 
++ * Log count number of elements from rpn stack to log buffer.
++ */
++static void log_i(void)
++{
++      struct dprobes_struct *dp = &dprobes;
++      u16 oprnd = get_u16_oprnd();
++      u16 count, i;
++      unsigned long size = oprnd * sizeof(unsigned long);
++      dp->prev_log_len = dp->log_len;
++
++      if (dp->log_len + size > dp->mod->pgm.logmax) {
++              size = dp->mod->pgm.logmax - dp->log_len;
++      }
++      if ((signed)size < 0) {
++              gen_ex(EX_LOG_OVERFLOW, dp->mod->pgm.logmax, 0);
++              return;
++      }
++      i = count = size / sizeof(unsigned long);
++      while (i--) {
++              *(unsigned long *) (dp->log + dp->log_len) = rpnpop();
++              dp->log_len += sizeof(unsigned long);
++        }
++      if (count < oprnd) {
++              gen_ex(EX_LOG_OVERFLOW, dp->mod->pgm.logmax, 0);
++              return;
++      }
++        dp->prev_log_len = dp->log_len;
++}
++
++static void log(void)
++{
++      struct dprobes_struct *dp = &dprobes;
++      u16 oprnd = (u16) rpnpop();
++      u16 count, i;
++      unsigned long size = oprnd * sizeof(unsigned long) + PREFIX_SIZE;
++      dp->prev_log_len = dp->log_len;
++
++      if (dp->log_len + size > dp->mod->pgm.logmax) {
++              size = dp->mod->pgm.logmax - dp->log_len;
++      }
++      if ((signed)size < PREFIX_SIZE) {
++              gen_ex(EX_LOG_OVERFLOW, dp->mod->pgm.logmax, 0);
++              return;
++      }
++      dp->log_len += PREFIX_SIZE;
++      size -= PREFIX_SIZE;
++      i = count = size / sizeof(unsigned long);
++
++      while (i--) {
++              *(unsigned long *) (dp->log + dp->log_len) = rpnpop();
++              dp->log_len += sizeof(unsigned long);
++        }
++
++      dp->log[dp->prev_log_len] = TOKEN_LOG;
++      *(unsigned short *) (dp->log + dp->prev_log_len + 1) =
++              (unsigned short) (count);
++
++      if (count < oprnd) {
++              gen_ex(EX_LOG_OVERFLOW, dp->mod->pgm.logmax, 0);
++              return;
++      }
++      dp->prev_log_len = dp->log_len;
++}
++
++static void log_lv(void)
++{
++      struct dprobes_struct *dp = &dprobes;
++      unsigned long range = rpnpop();
++      unsigned long index = rpnpop();
++      unsigned long offset;
++      unsigned char lv_prefix[PREFIX_SIZE] = {TOKEN_LV_ENTRY, 0, 0};
++      int i;
++
++      if (dp->log_len + PREFIX_SIZE > dp->mod->pgm.logmax) {
++              gen_ex(EX_LOG_OVERFLOW, dp->mod->pgm.logmax, 0);
++              return;
++      }
++      memcpy(dp->log + dp->log_len, lv_prefix, PREFIX_SIZE);
++      offset = dp->log_len + 1;
++      dp->log_len += PREFIX_SIZE;
++
++      for (i = index; i < index + range; i++) {
++              if (i >= dp->rec->mod->pgm.num_lv) {
++                      gen_ex(EX_INVALID_OPERAND, 1, i);
++                      return;
++              }
++              if (dp->log_len + sizeof (unsigned long) > dp->mod->pgm.logmax) {
++                      gen_ex(EX_LOG_OVERFLOW, dp->mod->pgm.logmax, 0);
++                      return;
++              }
++              *(unsigned long *) (dp->log + dp->log_len) = 
++                              *(dp->mod->lv + i);
++              dp->log_len += sizeof(unsigned long);
++              (*(unsigned short *)(dp->log + offset))++;
++      }
++      return;
++}
++
++static void log_gv(void)
++{
++      struct dprobes_struct *dp = &dprobes;
++      unsigned long range = rpnpop();
++      unsigned long index = rpnpop();
++      unsigned long offset;
++      unsigned char gv_prefix[PREFIX_SIZE] = {TOKEN_GV_ENTRY, 0, 0};
++      int i;
++
++      if (dp->log_len + PREFIX_SIZE > dp->mod->pgm.logmax) {
++              gen_ex(EX_LOG_OVERFLOW, dp->mod->pgm.logmax, 0);
++              return;
++      }
++      memcpy(dp->log + dp->log_len, gv_prefix, PREFIX_SIZE);
++      offset = dp->log_len + 1;
++      dp->log_len += PREFIX_SIZE;
++
++      for (i = index; i < index + range; i++) {
++              if (i >= dp_num_gv) {
++                      gen_ex(EX_INVALID_OPERAND, 2, i);
++                      return;
++              }
++              if (dp->log_len + sizeof (unsigned long) > dp->mod->pgm.logmax) {
++                      gen_ex(EX_LOG_OVERFLOW, dp->mod->pgm.logmax, 0);
++                      return;
++              }
++              read_lock(&dp_gv_lock);
++              *(unsigned long *) (dp->log + dp->log_len) = 
++                              *(dp_gv + i);
++              read_unlock(&dp_gv_lock);
++              dp->log_len += sizeof(unsigned long);
++              (*(unsigned short *)(dp->log + offset))++;
++      }
++      return;
++}
++
++/*
++ * Overriding probepoint major and minor.
++ */
++static void setmin_i(void)
++{
++      dprobes.minor = get_u16_oprnd();
++}
++
++static void setmin(void)
++{
++      dprobes.minor = (unsigned short) rpnpop();
++}
++
++static void setmaj_i(void)
++{
++      dprobes.major = get_u16_oprnd();
++}
++
++static void setmaj(void)
++{
++      dprobes.major = (unsigned short) rpnpop();
++}
++
++/*
++ * Local Variables.
++ */
++
++static void do_push_lv(unsigned short index)
++{
++      if (index > dprobes.rec->mod->pgm.num_lv)
++              gen_ex(EX_INVALID_OPERAND, 1, index);
++      else
++              rpnpush(*(dprobes.mod->lv + index));
++}
++
++static void push_lvi(void)
++{
++      do_push_lv(get_u16_oprnd());
++}
++
++static void push_lv(void)
++{
++      do_push_lv(rpnpop());
++}
++
++static void pop_lvi(void)
++{
++      unsigned short index = get_u16_oprnd();
++        if (index > dprobes.rec->mod->pgm.num_lv)
++                gen_ex(EX_INVALID_OPERAND, 1, index);
++        else
++              *(dprobes.mod->lv + index) = rpnpop();
++}
++
++static void pop_lv(void)
++{
++      unsigned long value = rpnpop();
++      unsigned short index = (unsigned short) rpnpop();
++        if (index > dprobes.rec->mod->pgm.num_lv)
++                gen_ex(EX_INVALID_OPERAND, 1, index);
++        else
++              *(dprobes.mod->lv + index) = value;
++}
++
++static void do_inc_lv(unsigned short index)
++{
++      if (index > dprobes.rec->mod->pgm.num_lv)
++              gen_ex(EX_INVALID_OPERAND, 1, index);
++      else
++              (*(dprobes.mod->lv + index))++;
++}
++
++static void inc_lvi(void)
++{
++      do_inc_lv(get_u16_oprnd());
++}
++
++static void inc_lv(void)
++{
++      do_inc_lv(rpnpop());
++}
++                                              
++static void do_dec_lv(unsigned short index)
++{
++      if (index > dprobes.rec->mod->pgm.num_lv)
++              gen_ex(EX_INVALID_OPERAND, 1, index);
++      else
++              (*(dprobes.mod->lv + index))--;
++}
++
++static void dec_lvi(void)
++{
++      do_dec_lv(get_u16_oprnd());
++}
++
++static void dec_lv(void)
++{
++      do_dec_lv(rpnpop());
++}
++
++static void do_move_lv(unsigned short index)
++{
++      if (index > dprobes.rec->mod->pgm.num_lv)
++              gen_ex(EX_INVALID_OPERAND, 1, index);
++      else
++              *(dprobes.mod->lv + index) = dprobes.rpn_stack[dprobes.rpn_tos];
++}
++
++static void move_lvi(void)
++{
++      do_move_lv(get_u16_oprnd());
++}
++
++static void move_lv(void)
++{
++      do_move_lv(rpnpop());
++}
++              
++/*
++ * global variables.
++ */
++static void do_push_gv(unsigned short index)
++{
++      read_lock(&dp_gv_lock);
++      if (index >= dp_num_gv) {
++              read_unlock(&dp_gv_lock);
++              gen_ex(EX_INVALID_OPERAND, 2, index);
++              return;
++      } else {
++              rpnpush(*(dp_gv + index));
++              read_unlock(&dp_gv_lock);
++      }
++}
++
++static void push_gvi(void)
++{
++      do_push_gv(get_u16_oprnd());
++}
++
++static void push_gv(void)
++{
++      do_push_gv(rpnpop());
++}
++
++static void pop_gvi(void)
++{
++      unsigned short index = get_u16_oprnd();
++      write_lock(&dp_gv_lock);
++      if (index >= dp_num_gv) {
++              write_unlock(&dp_gv_lock);
++              gen_ex(EX_INVALID_OPERAND, 2, index);
++              return;
++      } else {
++              *(dp_gv + index) = rpnpop();
++              write_unlock(&dp_gv_lock);
++      }
++}
++
++static void pop_gv(void)
++{
++      unsigned long value = rpnpop();
++      unsigned short index = (unsigned short) rpnpop();
++      write_lock(&dp_gv_lock);
++      if (index >= dp_num_gv) {
++              write_unlock(&dp_gv_lock);
++              gen_ex(EX_INVALID_OPERAND, 2, index);
++              return;
++      } else {
++              *(dp_gv + index) = value;
++              write_unlock(&dp_gv_lock);
++      }
++}
++
++
++static void do_inc_gv(unsigned short index)
++{
++      write_lock(&dp_gv_lock);
++      if (index >= dp_num_gv) {
++              write_unlock(&dp_gv_lock);
++              gen_ex(EX_INVALID_OPERAND, 2, index);
++              return;
++      } else {
++              (*(dp_gv + index))++;
++              write_unlock(&dp_gv_lock);
++      }
++}
++
++static void inc_gvi(void)
++{
++      do_inc_gv(get_u16_oprnd());
++}
++
++static void inc_gv(void)
++{
++      do_inc_gv(rpnpop());
++}
++                                              
++static void do_dec_gv(unsigned short index)
++{
++      write_lock(&dp_gv_lock);
++      if (index >= dp_num_gv) {
++              write_unlock(&dp_gv_lock);
++              gen_ex(EX_INVALID_OPERAND, 2, index);
++              return;
++      } else {
++              (*(dp_gv + index))--;
++              write_unlock(&dp_gv_lock);
++      }
++}
++
++static void dec_gvi(void)
++{
++      do_dec_gv(get_u16_oprnd());
++}
++
++static void dec_gv(void)
++{
++      do_dec_gv(rpnpop());
++}
++
++static void do_move_gv(unsigned short index)
++{
++      write_lock(&dp_gv_lock);
++      if (index >= dp_num_gv) {
++              write_unlock(&dp_gv_lock);
++              gen_ex(EX_INVALID_OPERAND, 2, index);
++              return;
++      } else {
++              *(dp_gv + index) = dprobes.rpn_stack[dprobes.rpn_tos];
++              write_unlock(&dp_gv_lock);
++      }
++}
++
++static void move_gvi(void)
++{
++      do_move_gv(get_u16_oprnd());
++}
++
++static void move_gv(void)
++{
++      do_move_gv(rpnpop());
++}
++
++
++/*
++ * Arithmetic and logic group.
++ */
++static void add(void)
++{
++      rpnpush(rpnpop() + rpnpop());
++}
++
++static void mul(void)
++{
++      rpnpush(rpnpop() * rpnpop());
++}
++
++static void and(void)
++{
++      rpnpush(rpnpop() & rpnpop());
++}
++
++static void or(void)
++{
++      rpnpush(rpnpop() | rpnpop());
++}
++
++static void xor(void)
++{
++      rpnpush(rpnpop() ^ rpnpop());
++}
++
++static void neg(void)
++{
++      rpnpush(~rpnpop());
++}
++
++static void sub(void)
++{
++      rpnpush(rpnpop() - rpnpop());
++}
++
++/* pop divisor first and dividend next, pushes remainder first and quotient next */
++static void div(void)
++{
++      unsigned long divisor = rpnpop();
++      unsigned long dividend = rpnpop();
++      if (!divisor) {
++              gen_ex(EX_DIV_BY_ZERO, 0, 0);
++              return;
++      }
++      rpnpush(dividend % divisor);
++      rpnpush(dividend / divisor);
++}
++
++static void idiv(void)
++{
++      signed long divisor = (signed long) rpnpop();
++      signed long dividend = (signed long) rpnpop();
++      if (!divisor) {
++              gen_ex(EX_DIV_BY_ZERO, 0, 0);
++              return;
++      }
++      rpnpush(dividend % divisor);
++      rpnpush(dividend / divisor);
++}
++
++static void xchng(void)
++{
++      register unsigned long arg1, arg2;
++      arg1 = rpnpop();
++      arg2 = rpnpop();
++      rpnpush(arg1);
++      rpnpush(arg2);
++}
++
++static void shl_i(void)
++{
++      dprobes.rpn_stack[dprobes.rpn_tos] <<= get_u8_oprnd();
++}
++
++static void shr_i(void)
++{
++      dprobes.rpn_stack[dprobes.rpn_tos] >>= get_u8_oprnd();
++}
++
++static void shr(void)
++{
++      unsigned long oprnd = rpnpop();
++      unsigned long count = rpnpop();
++      oprnd >>= count;
++      rpnpush(oprnd);
++}
++
++static void shl(void)
++{
++      unsigned long oprnd = rpnpop();
++      unsigned long count = rpnpop();
++      oprnd <<= count;
++      rpnpush(oprnd);
++}
++
++static void dup(void)
++{
++      unsigned long dup = rpnpop();
++      u8 dupcount = rpnpop();
++      rpnpush(dup);
++      dupcount &= ~RPN_STACK_SIZE;
++      while (dupcount--)
++              rpnpush(dup);
++}
++
++static void dupn(void)
++{
++      unsigned long dup = rpnpop();
++      u8 dupcount = get_u8_oprnd();
++      dupcount &= ~RPN_STACK_SIZE;
++      while (dupcount--)
++              rpnpush(dup);
++}
++
++static void ros(void)
++{
++      dprobes.rpn_tos += get_u8_oprnd();
++      dprobes.rpn_tos &= RPN_STACK_SIZE - 1;
++}     
++
++/*
++ * Verify the read access to a byte pointed by the flat linear address.
++ */
++static void verify_access(int write)
++{
++      u8 b;
++      void * addr = (void *)rpnpop();
++      if (dp_intr_copy_from_user(&b, addr, 1)) {
++              goto fail;
++      }
++      if (write && dp_intr_copy_to_user(addr, &b, 1)) {
++              goto fail;
++      }
++      rpnpush(0);
++      return;
++fail:
++      rpnpush(1);
++      return;
++}
++
++/*
++ * Push immediate value (operand) onto the rpn stack.
++ */
++static void push_i (void)
++{
++      rpnpush(get_ulong_oprnd());
++}
++
++/*
++ * Push byte, word, dword, qword present at the flat address
++ * onto rpn stack.
++ */
++static int push_flat(void *val, void *faddr, unsigned long size)
++{
++      if (dp_intr_copy_from_user(val, faddr, size)) {
++              gen_ex(EX_INVALID_ADDR, (unsigned long)faddr, 0);
++              return 0;
++      }
++      return 1;
++}
++
++static void push_mem_u8 (void)
++{
++      u8 b;
++      if(push_flat((void *)&b, (void *)rpnpop(), sizeof(u8)))
++              rpnpush(b);
++}
++
++static void push_mem_u16 (void)
++{
++      u16 w;
++      if(push_flat((void *)&w, (void *)rpnpop(), sizeof(u16)))
++              rpnpush(w);
++}
++
++static void push_mem_u32 (void)
++{
++      u32 dw;
++      if(push_flat((void *)&dw, (void *)rpnpop(), sizeof(u32)))
++              rpnpush(dw);
++}
++
++static void push_mem_u64 (void)
++{
++      unsigned long q[2];
++      void *faddr = (void *) rpnpop();
++      if (dp_intr_copy_from_user(q, faddr, 2*sizeof(unsigned long))) {
++              gen_ex(EX_INVALID_ADDR, (unsigned long)faddr, 0);
++      } else {
++              rpnpush(q[1]);
++              rpnpush(q[0]);
++      }
++}
++
++/*
++ * Pop byte, word, dword, qword from rpn stack and write 
++ * them at the specified linear address.
++ */
++static void pop_flat(void *faddr, void * val, unsigned long size)
++{
++      if (dp_intr_copy_to_user(faddr, val, size))
++              gen_ex(EX_INVALID_ADDR, (unsigned long)faddr, 0);
++}
++
++static void pop_mem_u8 (void)
++{
++      u8 b = (unsigned char) rpnpop();
++      pop_flat((void *)rpnpop(), (void *)&b, sizeof(u8));
++}
++
++static void pop_mem_u16 (void)
++{
++      u16 w = (u16) rpnpop();
++      pop_flat((void *)rpnpop(), (void *)&w, sizeof(u16));
++}
++
++static void pop_mem_u32 (void)
++{
++      u32 d = (u32) rpnpop();
++      pop_flat((void *)rpnpop(), (void *)&d, sizeof(u32));
++}
++
++static void pop_mem_u64 (void)
++{
++      // PORT: on IA64
++      unsigned long q[2];
++      q[0] = rpnpop();
++      q[1] = rpnpop();
++      pop_flat((void *)rpnpop(), (void *)q, 2*sizeof(unsigned long));
++}
++
++/*
++ * Push pid onto rpn stack.
++ */
++static void push_pid(void)
++{
++      rpnpush((unsigned long) current->pid);
++}
++
++/*
++ * Push processor id onto rpn stack.
++ */
++static void push_procid(void)
++{
++      rpnpush((unsigned long)smp_processor_id());
++}
++
++/*
++ * Push the address of the current task structure onto rpn stack.
++ */
++static void push_task(void)
++{
++      rpnpush((unsigned long) current);
++}
++
++#ifdef DPROBES_CALLK_HOOK
++DECLARE_HOOK_HEAD(DPROBES_CALLK);
++USE_HOOK(DPROBES_CALLK);
++static void callk(void)
++{
++      struct dprobes_struct *dp = &dprobes;
++      dp->status &= ~DP_STATUS_INTERPRETER;
++      HOOK(DPROBES_CALLK, &dprobes);
++      dp->status |= DP_STATUS_INTERPRETER;
++}
++#endif
++
++/*
++ * Byte heap management routines.
++ */  
++#ifdef CONFIG_SMP
++struct list_head heap_list_set[NR_CPUS];
++#define heap_list heap_list_set[smp_processor_id()]
++#else
++struct list_head heap_list;
++#define heap_list_set (&heap_list)
++#endif
++
++/* Validates the heap handle. Returns the block size in @size */
++static int heap_validate_handle(byte_t *handle, unsigned long *size)
++{
++      struct list_head *tmp;
++      struct heap_hdr *h;
++
++      list_for_each(tmp, &heap_list) {
++              h = list_entry(tmp, struct heap_hdr, list);
++              if (h->addr == handle && h->flags == HEAP_ALLOCATED) {
++                      if (size) *size = h->size;
++                      return 1;
++              }
++      }
++      return 0;
++}
++
++static void heap_coalesce(struct heap_hdr *heap)
++{
++      struct heap_hdr *h;
++
++      /* Combine this block with the next free block (if available) */
++      if (heap->list.next != &heap_list) {
++              h = list_entry(heap->list.next, struct heap_hdr, list);
++              if (h->flags == HEAP_FREE) {
++                      heap->size += (h->size + HEAP_HDR_SIZE);
++                      list_del(&h->list);
++              }
++      }
++
++      /* Combine this block with the previous free block (if available) */
++      if (heap->list.prev != &heap_list) {
++              h = list_entry(heap->list.prev, struct heap_hdr, list);
++              if (h->flags == HEAP_FREE) {
++                      h->size += (heap->size + HEAP_HDR_SIZE);
++                      list_del(&heap->list);
++              }
++      }
++}
++
++/* Allocation succeeds only if (size + HEAP_HDR_SIZE) is available */
++static byte_t *heap_alloc(int size)
++{
++      unsigned long sz;
++      struct list_head *tmp;
++      struct heap_hdr *next;
++
++      list_for_each(tmp, &heap_list) {
++              struct heap_hdr *h = list_entry(tmp, struct heap_hdr, list);
++              sz = h->size;
++              if ((h->flags == HEAP_FREE) && (sz > size + HEAP_HDR_SIZE)) {
++                      h->size = size;
++                      h->flags = HEAP_ALLOCATED;
++                      
++                      if (sz > size) {
++                              next = (struct heap_hdr *)(h->addr + size);
++                              next->addr = h->addr + size + HEAP_HDR_SIZE;
++                              next->flags = HEAP_FREE;
++                              next->size = sz - size - HEAP_HDR_SIZE;
++                              list_add(&next->list, &h->list);
++                      }
++                      return h->addr;
++              }
++      }
++      return NULL;
++}
++
++/* Returns the amount of memory freed */
++static unsigned long heap_free(byte_t *ptr)
++{
++      struct list_head *tmp;
++      unsigned long size = 0;
++
++      list_for_each(tmp, &heap_list) {
++              struct heap_hdr *h = list_entry(tmp, struct heap_hdr, list);
++              if (h->addr == ptr && h->flags == HEAP_ALLOCATED) {
++                      h->flags = HEAP_FREE;
++                      size = h->size;
++                      heap_coalesce(h);
++                      break;
++              }
++      }
++      return size;
++}
++
++static void heap_init(byte_t *heap)
++{
++      struct heap_hdr *h;
++      
++      INIT_LIST_HEAD(&heap_list);
++      h = (struct heap_hdr *)heap;
++      h->addr = heap + HEAP_HDR_SIZE;
++      h->flags = HEAP_FREE;
++      h->size = dprobes.rec->point.heap_size - HEAP_HDR_SIZE;
++      list_add(&h->list, &heap_list);
++}
++
++/*
++ * Byte heap related instructions.
++ */
++static void pushh_u8_i(void)
++{
++      unsigned short count = get_u16_oprnd();
++      unsigned long offset = rpnpop();
++      byte_t *handle = (byte_t *)rpnpop();
++      unsigned long blk_size;
++      
++      /* validate the handle */
++      if (!heap_validate_handle(handle, &blk_size)) {
++              gen_ex(EX_HEAP_INVALID_HANDLE, (unsigned long)handle, offset);
++              return;
++      }
++      while (count) {
++              /* validate the offset */
++              if (offset >= blk_size) {
++                      gen_ex(EX_HEAP_INVALID_OFFSET, (unsigned long)handle, 
++                                      offset);
++                      return;
++              }
++              rpnpush((unsigned long)(*((u8 *)(handle + offset))));
++              offset++;
++              count--;
++      }
++}
++
++static void pushh_u16_i(void)
++{
++      unsigned short count = get_u16_oprnd();
++      unsigned long offset = rpnpop();
++      byte_t *handle = (byte_t *)rpnpop();
++      unsigned long blk_size;
++      
++      /* validate the handle */
++      if (!heap_validate_handle(handle, &blk_size)) {
++              gen_ex(EX_HEAP_INVALID_HANDLE, (unsigned long)handle, offset);
++              return;
++      }
++      while (count) {
++              /* validate the offset */
++              if (offset + 2 > blk_size) {
++                      gen_ex(EX_HEAP_INVALID_OFFSET, (unsigned long)handle, 
++                                      offset);
++                      return;
++              }
++              rpnpush((unsigned long)(*((u16 *)(handle + offset))));
++              offset += 2;
++              count--;
++      }
++}
++
++static void pushh_u32_i(void)
++{
++      unsigned short count = get_u16_oprnd();
++      unsigned long offset = rpnpop();
++      byte_t *handle = (byte_t *)rpnpop();
++      unsigned long blk_size;
++      
++      /* validate the handle */
++      if (!heap_validate_handle(handle, &blk_size)) {
++              gen_ex(EX_HEAP_INVALID_HANDLE, (unsigned long)handle, offset);
++              return;
++      }
++      while (count) {
++              /* validate the offset */
++              if (offset + 4 > blk_size) {
++                      gen_ex(EX_HEAP_INVALID_OFFSET, (unsigned long)handle, 
++                                      offset);
++                      return;
++              }
++              rpnpush((unsigned long)(*((u32 *)(handle + offset))));
++              offset += 4;
++              count--;
++      }
++}
++
++static void pushh_u64_i(void)
++{
++      unsigned short count = get_u16_oprnd();
++      unsigned long offset = rpnpop();
++      byte_t *handle = (byte_t *)rpnpop();
++      unsigned long blk_size;
++      
++      /* validate the handle */
++      if (!heap_validate_handle(handle, &blk_size)) {
++              gen_ex(EX_HEAP_INVALID_HANDLE, (unsigned long)handle, offset);
++              return;
++      }
++      while (count) {
++              /* validate the offset */
++              if (offset + 8 > blk_size) {
++                      gen_ex(EX_HEAP_INVALID_OFFSET, (unsigned long)handle, 
++                                      offset);
++                      return;
++              }
++              /* shouldn't this order depend on endianness ? */
++              rpnpush((unsigned long)(*((u64 *)(handle + offset))));
++              rpnpush((unsigned long)(*((u64 *)(handle + offset))));
++              offset += 8;
++              count--;
++      }
++}
++
++static void poph_u8_i(void)
++{
++      unsigned short count = get_u16_oprnd();
++      unsigned long offset = rpnpop();
++      byte_t *handle = (byte_t *)rpnpop();
++      unsigned long blk_size;
++      
++      /* validate the handle */
++      if (!heap_validate_handle(handle, &blk_size)) {
++              gen_ex(EX_HEAP_INVALID_HANDLE, (unsigned long)handle, offset);
++              return;
++      }
++      while (count) {
++              /* validate the offset */
++              if (offset > blk_size) {
++                      gen_ex(EX_HEAP_INVALID_OFFSET, (unsigned long)handle,
++                                      offset);
++                      return;
++              }
++              *((u8 *)(handle + offset)) = (u8)rpnpop();
++              offset++;
++              count--;
++      }
++}
++
++static void poph_u16_i(void)
++{
++      unsigned short count = get_u16_oprnd();
++      unsigned long offset = rpnpop();
++      byte_t *handle = (byte_t *)rpnpop();
++      unsigned long blk_size;
++      
++      /* validate the handle */
++      if (!heap_validate_handle(handle, &blk_size)) {
++              gen_ex(EX_HEAP_INVALID_HANDLE, (unsigned long)handle, offset);
++              return;
++      }
++      while (count) {
++              /* validate the offset */
++              if (offset + 2 > blk_size) {
++                      gen_ex(EX_HEAP_INVALID_OFFSET, (unsigned long)handle,
++                                      offset);
++                      return;
++              }
++              *((u16 *)(handle + offset)) = (u16)rpnpop();
++              offset += 2;
++              count--;
++      }
++}
++
++static void poph_u32_i(void)
++{
++      unsigned short count = get_u16_oprnd();
++      unsigned long offset = rpnpop();
++      byte_t *handle = (byte_t *)rpnpop();
++      unsigned long blk_size;
++      
++      /* validate the handle */
++      if (!heap_validate_handle(handle, &blk_size)) {
++              gen_ex(EX_HEAP_INVALID_HANDLE, (unsigned long)handle, offset);
++              return;
++      }
++      while (count) {
++              /* validate the offset */
++              if (offset + 4 > blk_size) {
++                      gen_ex(EX_HEAP_INVALID_OFFSET, (unsigned long)handle,
++                                      offset);
++                      return;
++              }
++              *((u32 *)(handle + offset)) = (u32)rpnpop();
++              offset += 4;
++              count--;
++      }
++}
++
++static void poph_u64_i(void)
++{
++      unsigned short count = get_u16_oprnd();
++      unsigned long offset = rpnpop();
++      byte_t *handle = (byte_t *)rpnpop();
++      unsigned long blk_size;
++      
++      /* validate the handle */
++      if (!heap_validate_handle(handle, &blk_size)) {
++              gen_ex(EX_HEAP_INVALID_HANDLE, (unsigned long)handle, offset);
++              return;
++      }
++      while (count) {
++              /* validate the offset */
++              if (offset + 8 > blk_size) {
++                      gen_ex(EX_HEAP_INVALID_OFFSET, (unsigned long)handle,
++                                      offset);
++                      return;
++              }
++              /* shouldn't this order depend on endianness ? */
++              *((u32 *)(handle + offset)) = (u32)rpnpop();
++              *((u32 *)(handle + offset + 4)) = (u32)rpnpop();
++              offset += 8;
++              count--;
++      }
++}
++
++static void malloc(void)
++{
++      unsigned long size = rpnpop();
++      byte_t *handle;
++
++      /* 
++       * Does this allocation exceed the maximum heapsize specified for
++       * this probe ?
++       */ 
++      if (size + dprobes.heap_size > dprobes.rec->point.heap_size) {
++              gen_ex(EX_HEAP_NOMEM, size, 0);
++              return;
++      }
++      handle = heap_alloc(size);
++      if (!handle) {
++              gen_ex(EX_HEAP_NOMEM, size, 0);
++              return;
++      }
++      dprobes.heap_size += size;
++      rpnpush((unsigned long)handle);
++}
++
++static void free(void)
++{
++      byte_t *handle = (byte_t *)rpnpop();
++      unsigned long size;
++
++      if (!(size = heap_free(handle))) {
++              gen_ex(EX_HEAP_INVALID_HANDLE, (unsigned long)handle, 0);
++              return;
++      }
++      dprobes.heap_size -= size;
++}
++
++static void push_wid(void)
++{
++      union wid {
++              short a;
++              char b[sizeof(short)];
++      } w;
++      w.a = 0x0102;
++      
++      if (sizeof(short) != 2) {
++              rpnpush(0);
++              return;
++      }
++      
++      if (w.b[0] == 0x01 && w.b[1] == 0x02) {
++              rpnpush(BITS_PER_LONG);
++      } else if (w.b[0] == 0x02 && w.b[1] == 0x01) {
++              rpnpush(-BITS_PER_LONG);
++      } else {
++              rpnpush(0);
++      }
++}
++
++/*
++ * Entry point for the dprobes interpreter(Probe handler).
++ */
++void dp_interpreter(void)
++{
++      struct dprobes_struct *dp = &dprobes;
++
++      dp->call_tos = CALL_STACK_SIZE - CALL_FRAME_SIZE;
++      dp->call_stack[dp->call_tos + OFFSET_EX_HANDLER] = EX_NO_HANDLER;
++      dp->rpn_tos = dp->rpn_sbp = RPN_STACK_SIZE;
++      dp->rpn_code = dp->rec->mod->pgm.rpn_code;
++      dp->rpn_ip = dp->rec->mod->pgm.rpn_code + dp->rec->point.rpn_offset;
++      dp->log_len = dp->rec->mod->hdr.len;
++      dp->ex_log_len = MIN_ST_SIZE;
++      dp->jmp_count = 0;
++      dp->ex_parm1 = dp->ex_parm2 = 0;
++      if (dp->rec->point.heap_size > 2*HEAP_HDR_SIZE) {
++              read_lock(&dp_heap_lock);
++              heap_init(dp_heap + dp->mod->pgm.heapmax * smp_processor_id());
++              dp->heap_size = 0;
++      }
++      
++      dp->status |= DP_STATUS_INTERPRETER;
++      while (dp->status & DP_STATUS_INTERPRETER) {
++              register u8 rpn_instr = *dp->rpn_ip++;
++              switch(rpn_instr) {
++                      case DP_NOP:            no_op(); break;         
++
++                      case DP_JMP:            jmp(); break;                   
++                      case DP_JLT:            jlt(); break;                   
++                      case DP_JLE:            jle(); break;                   
++                      case DP_JGT:            jgt(); break;           
++                      case DP_JGE:            jge(); break;                   
++                      case DP_JZ:             jz(); break;    
++                      case DP_JNZ:            jnz(); break;                   
++                      case DP_LOOP:           loop(); break;                  
++                      case DP_CALL:           call(); break;                  
++                      case DP_RET:            ret(); break;                   
++                      case DP_ABORT:          dp_abort(); break;              
++                      case DP_REM:            dp_remove(); break;             
++                      case DP_EXIT:           dp_exit(); break;               
++                      case DP_EXIT_N:         dp_exit_n(); break;             
++
++                      case DP_SETMIN_I:       setmin_i(); break;              
++                      case DP_SETMIN:         setmin(); break;                
++                      case DP_SETMAJ_I:       setmaj_i(); break;              
++                      case DP_SETMAJ:         setmaj(); break;                
++                      case DP_LOG_STR:        log_str(); break;               
++                      case DP_LOG_MRF:        log_mrf(); break;               
++                      case DP_LOG_I:          log_i(); break;         
++
++                      case DP_PUSH_LVI:       push_lvi(); break;      
++                      case DP_PUSH_LV:        push_lv(); break;               
++                      case DP_POP_LVI:        pop_lvi(); break;               
++                      case DP_POP_LV:         pop_lv(); break;                
++                      case DP_MOVE_LVI:       move_lvi(); break;              
++                      case DP_MOVE_LV:        move_lv(); break;               
++                      case DP_INC_LVI:        inc_lvi(); break;               
++                      case DP_INC_LV:         inc_lv(); break;                
++                      case DP_DEC_LVI:        dec_lvi(); break;               
++                      case DP_DEC_LV:         dec_lv(); break;                
++
++                      case DP_PUSH_GVI:       push_gvi(); break;
++                      case DP_PUSH_GV:        push_gv(); break;
++                      case DP_POP_GVI:        pop_gvi(); break;
++                      case DP_POP_GV:         pop_gv(); break;
++                      case DP_MOVE_GVI:       move_gvi(); break;              
++                      case DP_MOVE_GV:        move_gv(); break;               
++                      case DP_INC_GVI:        inc_gvi(); break;               
++                      case DP_INC_GV:         inc_gv(); break;                
++                      case DP_DEC_GVI:        dec_gvi(); break;               
++                      case DP_DEC_GV:         dec_gv(); break;                
++
++                      case DP_ADD:            add(); break;                   
++                      case DP_SUB:            sub(); break;                   
++                      case DP_MUL:            mul(); break;                   
++                      case DP_DIV:            div(); break;
++                      case DP_IDIV:           idiv(); break;
++
++                      case DP_NEG:            neg(); break;                   
++                      case DP_AND:            and(); break;                   
++                      case DP_OR:             or(); break;                    
++                      case DP_XOR:            xor(); break;                   
++                      case DP_ROL_I:          rol_i(); break;         
++                      case DP_ROL:            rol(); break;                   
++                      case DP_ROR_I:          ror_i(); break;         
++                      case DP_ROR:            ror(); break;                   
++                      case DP_SHL_I:          shl_i(); break;         
++                      case DP_SHL:            shl(); break;                   
++                      case DP_SHR_I:          shr_i(); break;         
++                      case DP_SHR:            shr(); break;                   
++                      case DP_PBL:            pbl(); break;
++                      case DP_PBR:            pbr(); break;
++                      case DP_PBL_I:          pbl_i(); break;
++                      case DP_PBR_I:          pbr_i(); break;
++                      case DP_PZL:            pzl(); break;
++                      case DP_PZR:            pzr(); break;
++                      case DP_PZL_I:          pzl_i(); break;
++                      case DP_PZR_I:          pzr_i(); break;
++#ifdef DPROBES_CALLK_HOOK
++                      case DP_CALLK:          callk(); break;
++#endif
++
++                      case DP_XCHG:           xchng(); break; 
++                      case DP_DUP_I:          dupn(); break;          
++                      case DP_DUP:            dup(); break;                   
++                      case DP_ROS:            ros(); break;           
++
++                      case DP_PUSH_R:         pushr(); break;         
++                      case DP_POP_R:          popr(); break;          
++                      case DP_PUSH_U:         pushu(); break;         
++                      case DP_POP_U:          popu(); break;          
++
++                      case DP_PUSH:           push_i(); break;                
++                      case DP_PUSH_MEM_U8:    push_mem_u8(); break;           
++                      case DP_PUSH_MEM_U16:   push_mem_u16(); break;          
++                      case DP_PUSH_MEM_U32:   push_mem_u32(); break;                          
++                      case DP_PUSH_MEM_U64:   push_mem_u64(); break;          
++                      case DP_POP_MEM_U8:     pop_mem_u8(); break;            
++                      case DP_POP_MEM_U16:    pop_mem_u16(); break;           
++                      case DP_POP_MEM_U32:    pop_mem_u32(); break;           
++                      case DP_POP_MEM_U64:    pop_mem_u64(); break;           
++
++                      case DP_PUSH_TASK:      push_task(); break;             
++                      case DP_PUSH_PID:       push_pid(); break;              
++                      case DP_PUSH_PROCID:    push_procid(); break;           
++
++                      case DP_VFY_R:          verify_access(0); break;
++                      case DP_VFY_RW:         verify_access(1); break;
++
++                      case DP_SX:             sx(); break;
++                      case DP_UX:             ux(); break;
++                      case DP_RX:             rx(); break;
++                      case DP_PUSH_X:         push_x(); break;
++                      case DP_PUSH_LP:        push_lp(); break;
++                      case DP_PUSH_PLP:       push_plp(); break;
++                      case DP_POP_LP:         pop_lp(); break;
++                      case DP_LOG_ST:         log_st(); break;
++                      case DP_PURGE_ST:       purge_st(); break;
++                      case DP_TRACE_LV:       trace_lv(); break;      
++                      case DP_TRACE_GV:       trace_gv(); break;      
++                      case DP_TRACE_PV:       trace_pv(); break;      
++
++                      case DP_PUSH_SBP:       push_sbp(); break;      
++                      case DP_POP_SBP:        pop_sbp(); break;       
++                      case DP_PUSH_TSP:       push_tsp(); break;      
++                      case DP_POP_TSP:        pop_tsp(); break;       
++                      case DP_COPY_SBP:       copy_sbp(); break;      
++                      case DP_COPY_TSP:       copy_tsp(); break;      
++                      case DP_PUSH_SBP_I:     push_sbp_i(); break;    
++                      case DP_POP_SBP_I:      pop_sbp_i(); break;     
++                      case DP_PUSH_TSP_I:     push_tsp_i(); break;    
++                      case DP_POP_TSP_I:      pop_tsp_i(); break;     
++                      case DP_COPY_SBP_I:     copy_sbp_i(); break;    
++                      case DP_COPY_TSP_I:     copy_tsp_i(); break;    
++                      case DP_PUSH_STP:       push_stp(); break;
++                      case DP_POP_STP:        pop_stp(); break;
++                      case DP_SAVE_SBP:       save_sbp(); break;
++                      case DP_RESTORE_SBP:    restore_sbp(); break;
++                      case DP_SAVE_TSP:       save_tsp(); break;
++                      case DP_RESTORE_TSP:    restore_tsp(); break;
++
++                      case DP_LOG:            log(); break;
++                      case DP_LOG_LV:         log_lv(); break;
++                      case DP_LOG_GV:         log_gv(); break;
++
++                      case DP_MALLOC:         malloc(); break;
++                      case DP_FREE:           free(); break;
++                      case DP_PUSH_WID:       push_wid(); break;
++                      case DP_PUSHH_U8_I:     pushh_u8_i(); break;
++                      case DP_PUSHH_U16_I:    pushh_u16_i(); break;
++                      case DP_PUSHH_U32_I:    pushh_u32_i(); break;
++                      case DP_PUSHH_U64_I:    pushh_u64_i(); break;
++                      case DP_POPH_U8_I:      poph_u8_i(); break;
++                      case DP_POPH_U16_I:     poph_u16_i(); break;
++                      case DP_POPH_U32_I:     poph_u32_i(); break;
++                      case DP_POPH_U64_I:     poph_u64_i(); break;
++
++                      default: dp_asm_interpreter(rpn_instr); break;
++              }
++      }
++      if (dp->rec->point.heap_size > 2*HEAP_HDR_SIZE)
++              read_unlock(&dp_heap_lock);
++      return;
++}
++
++void dprobes_interpreter_code_end(void) { }
+diff -urNp linux.orig/drivers/dprobes/i386/dprobes.c linux-2.6.0-test11/drivers/dprobes/i386/dprobes.c
+--- linux.orig/drivers/dprobes/i386/dprobes.c  1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.0-test11/drivers/dprobes/i386/dprobes.c  2003-12-15 15:51:48.000000000 +0530
+@@ -0,0 +1,808 @@
++/*
++ * IBM Dynamic Probes
++ * Copyright (c) International Business Machines Corp., 2000
++ *
++ * 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.
++ */
++
++#include <linux/dprobes.h>
++#include <linux/vmalloc.h>
++#include <linux/module.h>
++#include <linux/serial_reg.h>
++#include <linux/ctype.h>
++
++#include <asm/kwatch.h>
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include <asm/dprobes_exclude.h>
++#ifdef CONFIG_DEBUGREG
++#include <asm/debugreg.h>
++#endif
++
++void dprobes_asm_code_start(void) { }
++
++#ifdef CONFIG_MAGIC_SYSRQ
++extern unsigned long emergency_remove;
++#endif
++
++/*
++ * Format strings for printing out the log.
++ */
++#define DP_LOG_HDR_FMT                "dprobes(%d,%d) "
++#define DP_LOG_CPU_FMT                "cpu=%d "
++#define DP_LOG_PROCNAME_FMT   "name=%s "
++#define DP_LOG_PID_FMT                "pid=%d "
++#define DP_LOG_UID_FMT                "uid=%d "
++#define DP_LOG_CS_EIP_FMT     "cs=%x eip=%08lx "
++#define DP_LOG_SS_ESP_FMT     "ss=%x esp=%08lx "
++#define DP_LOG_TSC_FMT                "tsc=%08lx:%08lx "
++#define DP_LOG_NEWLINE_FMT    "\n"
++#define DP_LOG_DATA_FMT               "%x "
++#define DP_LOG_DATA_FT                "%x"
++
++static void log_stack_trace(struct dprobes_struct *dp)
++{
++      unsigned long i;
++      byte_t *ex_log;
++      unsigned char *tmp = dp->log_hdr;
++      unsigned long ex_log_len = dp->ex_log_len;
++
++      if (ex_log_len > MIN_ST_SIZE) {
++              tmp += sprintf(tmp, DP_LOG_HDR_FMT, 0, 0);
++
++#ifdef CONFIG_SMP
++              tmp += sprintf(tmp, DP_LOG_CPU_FMT, smp_processor_id());
++#endif
++              printk("%s ", dp->log_hdr);
++
++              ex_log_len -= MIN_ST_SIZE;
++              ex_log = dp->ex_log + MIN_ST_SIZE;
++              for (i = 0; i < ex_log_len; i++)
++                      printk(DP_LOG_DATA_FMT, ex_log[i]);
++              printk(DP_LOG_NEWLINE_FMT);
++      }
++}
++
++static void fmt_log_hdr(struct dprobes_struct *dp)
++{
++      unsigned char *tmp = dp->log_hdr;
++      unsigned long log_flags = dp->mod->pgm.flags & DP_LOG_MASK;
++
++      tmp += sprintf(tmp, DP_LOG_HDR_FMT, dp->major, dp->minor);
++
++#ifdef CONFIG_SMP
++      tmp += sprintf(tmp, DP_LOG_CPU_FMT, smp_processor_id());
++#endif
++      if (log_flags & DP_LOG_PID)
++              tmp += sprintf(tmp, DP_LOG_PID_FMT, current->pid);
++      if (log_flags & DP_LOG_UID)
++              tmp += sprintf(tmp, DP_LOG_UID_FMT, current->uid);
++      if (log_flags & DP_LOG_CS_EIP)
++              tmp += sprintf(tmp, DP_LOG_CS_EIP_FMT, dp->cs, dp->eip);
++      if (log_flags & DP_LOG_SS_ESP)
++              tmp += sprintf(tmp, DP_LOG_SS_ESP_FMT, dp->ss, dp->esp);
++      if (log_flags & DP_LOG_TSC) {
++              struct timeval ts;
++              do_gettimeofday(&ts);
++              tmp += sprintf(tmp, DP_LOG_TSC_FMT, ts.tv_sec, ts.tv_usec);
++      }
++      if (log_flags & DP_LOG_PROCNAME)
++              tmp += sprintf(tmp, DP_LOG_PROCNAME_FMT, current->comm);
++      tmp += sprintf(tmp, DP_LOG_NEWLINE_FMT);
++
++      tmp += sprintf(tmp, DP_LOG_HDR_FMT, dp->major, dp->minor);
++      *tmp = '\0';
++
++      return;
++}
++
++
++#define ROWS 16
++/*
++ * Saves (writes) the log to the standard kernel log.
++ */
++static void log_dumpformat(unsigned long log_len, byte_t *log)
++{
++      unsigned long i, start = 0, end = ROWS;
++      unsigned int  off=0x0;
++      char c;
++
++      while (start < log_len) {
++              printk("0x%8.8x : ", (unsigned int)off);
++              for( i = start; i < end; i++) {
++                      printk("%2.2x", 0xff & log[i]);
++                      if (((i + 1) % 4) == 0)
++                              printk(" ");
++              }
++
++              if ((end - start) < ROWS)
++                      for (i = 0; i < ((ROWS - (end - start)) * 2) + 4 - ((end - start) / 4); i++)
++                              printk(" ");
++
++              printk(": ");
++              for( i = start ; i < end ; i++ )       /* Now print the ASCII field. */
++               { 
++                      c = 0x7f & log[i];            /* mask out bit 7 */
++                      if (!(isprint(c)))              /* If not printable */
++                              printk(".");                    /* print a dot */
++                      else 
++                              printk("%c",c);
++           
++              }
++
++              printk(DP_LOG_NEWLINE_FMT);
++              if ( (log_len - end) > ROWS) 
++                      end += ROWS;
++              else 
++                      end = log_len;
++              start += ROWS;
++              off +=0x10;
++      }
++
++}     
++
++static void log_stack_trace_dump(struct dprobes_struct *dp)
++{
++      byte_t *ex_log;
++      unsigned char *tmp = dp->log_hdr;
++      unsigned long ex_log_len = dp->ex_log_len;
++      if (ex_log_len > MIN_ST_SIZE) {
++              tmp += sprintf(tmp, DP_LOG_HDR_FMT, 0, 0);
++
++#ifdef CONFIG_SMP
++              tmp += sprintf(tmp, DP_LOG_CPU_FMT, smp_processor_id());
++#endif
++              printk("%s \n", dp->log_hdr);
++
++              ex_log_len -= MIN_ST_SIZE;
++              ex_log = dp->ex_log + MIN_ST_SIZE;
++              log_dumpformat(ex_log_len, ex_log);
++
++      }
++}
++
++/*
++ * Saves (writes) the log to the standard kernel log.
++ */
++static int log_to_klog_dump(struct dprobes_struct *dp)
++{
++      byte_t *log = dp->log + dp->mod->hdr.len;
++      unsigned long log_len = dp->log_len - dp->mod->hdr.len;
++      
++      
++      fmt_log_hdr(dp);
++      printk("%s \n", dp->log_hdr);
++      log_dumpformat( log_len, log);
++      return 0;
++}     
++
++/*
++ * Saves (writes) the log to the standard kernel log.
++ */
++static int log_to_klog(struct dprobes_struct *dp)
++{
++      unsigned long i;
++      byte_t *log = dp->log + dp->mod->hdr.len;
++      unsigned long log_len = dp->log_len - dp->mod->hdr.len;
++
++      fmt_log_hdr(dp);
++      printk("%s ", dp->log_hdr);
++
++      for (i = 0; i < log_len; i++) {
++              if (log[i] < 0xf)
++                      printk(DP_LOG_DATA_FT, 0);
++              printk(DP_LOG_DATA_FMT, log[i]);
++      }
++      printk(DP_LOG_NEWLINE_FMT);
++      return 0;
++}     
++
++/*
++ * The order in which the optional header elements is written out has to be the
++ * same order in which the DP_HDR_* constants are defined in 
++ * include/linux/dprobes.h. The formatter is expected to look for the optional
++ * elements in the same order.
++ */
++static void fmt_log_hdr_raw(struct dprobes_struct *dp)
++{
++      unsigned char *tmp = dp->log;
++      unsigned long mask = dp->mod->hdr.mask;
++
++      dp->mod->hdr.major = dp->major;
++      dp->mod->hdr.minor = dp->minor;
++      *(struct dp_trace_hdr_struct *)tmp = dp->mod->hdr;      
++      tmp += sizeof(dp->mod->hdr);
++
++#ifdef CONFIG_SMP
++      *(unsigned int *)tmp = smp_processor_id();
++      tmp += sizeof(int);
++#endif
++      if (mask & DP_HDR_PID) {
++              *(pid_t *)tmp = current->pid;
++              tmp += sizeof(pid_t);
++      }
++      if (mask & DP_HDR_UID) {
++              *(uid_t *)tmp = current->uid;
++              tmp += sizeof(uid_t);
++      }
++      if (mask & DP_HDR_CS) {
++              *(unsigned short *)tmp = dp->cs;
++              tmp += sizeof(dp->cs);
++      }
++      if (mask & DP_HDR_EIP) {
++              *(unsigned long *)tmp = dp->eip;
++              tmp += sizeof(dp->eip);
++      }
++      if (mask & DP_HDR_SS) {
++              *(unsigned short *)tmp = dp->ss;
++              tmp += sizeof(dp->ss);
++      }
++      if (mask & DP_HDR_ESP) {
++              *(unsigned long *)tmp = dp->esp;
++              tmp += sizeof(dp->esp);
++      }
++      if (mask & DP_HDR_TSC) {
++              struct timeval ts;
++              do_gettimeofday(&ts);
++              *(struct timeval *)tmp = ts;
++              tmp += sizeof(ts);
++      }
++      if (mask & DP_HDR_PROCNAME) {
++              memcpy(tmp, current->comm, 16);
++              tmp += 16;
++      }
++      return;
++}
++
++/*
++ * dp->mod->hdr is changed here. Hence should be called only after
++ * fmt_log_hdr_raw().
++ */
++static void fmt_st_hdr_raw(struct dprobes_struct *dp)
++{
++      unsigned char *tmp = dp->ex_log;
++      dp->mod->hdr.mask = DP_HDR_MAJOR | DP_HDR_MINOR;
++      dp->mod->hdr.major = DP_ST_MAJOR;
++      dp->mod->hdr.minor = DP_ST_MINOR;
++      dp->mod->hdr.len = MIN_ST_SIZE;
++      *(struct dp_trace_hdr_struct *)tmp = dp->mod->hdr;      
++      tmp += sizeof(dp->mod->hdr);
++#ifdef CONFIG_SMP
++      dp->mod->hdr.mask |= DP_HDR_CPU;
++      *(unsigned int *)tmp = smp_processor_id();
++      tmp += sizeof(int);
++      dp->mod->hdr.len += sizeof(int);
++#endif
++}
++
++#if defined(CONFIG_TRACE) || defined(CONFIG_TRACE_MODULE)
++#include <linux/trace.h>
++
++static int log_to_ltt(struct dprobes_struct *dp)
++{
++      trace_raw_event(dp->mod->trace_id, dp->log_len, dp->log);       
++      return 0;
++}
++
++static int log_st_to_ltt(struct dprobes_struct *dp)
++{
++      trace_raw_event(dp->mod->trace_id, dp->ex_log_len, dp->ex_log);
++      return 0;
++}
++#else 
++static int log_to_ltt(struct dprobes_struct *dp)
++{
++      printk(KERN_WARNING "dprobes: Linux Trace Toolkit not available.\n");
++      return 0;
++}
++
++static int log_st_to_ltt(struct dprobes_struct *dp)
++{
++      printk(KERN_WARNING "dprobes: Linux Trace Toolkit not available.\n");
++      return 0;
++}
++#endif
++
++#ifdef CONFIG_EVLOG
++#include <linux/evl_log.h>
++static int log_to_evl(struct dprobes_struct *dp)
++{
++      /*
++       * We will need to modify this in future to create a DPROBES facility
++       * type and use dp->id instead of (major,minor) for event type. Even the
++       * priority ought to be something other than LOG_KERN.
++       */
++      posix_log_write(LOG_KERN, 
++                      (dp->major << 16) | dp->minor, /* dp->id */
++                      LOG_INFO,
++                      (dp->log + dp->mod->hdr.len),
++                      (dp->log_len - dp->mod->hdr.len),
++                      POSIX_LOG_BINARY,
++                      0);
++      return 0;
++}
++#else
++static int log_to_evl(struct dprobes_struct *dp)
++{
++      printk(KERN_WARNING "dprobes: POSIX Event Logging not available.\n");
++      return 0;
++}
++#endif
++
++#define BOTH_EMPTY_TR         (UART_LSR_TEMT | UART_LSR_THRE)
++#define COM1_ADDR     0x3f8
++#define COM2_ADDR     0x2f8
++
++/*
++ * Wait for the transmitter buffer to become empty.
++ */  
++static inline void wait_for_xmitr_empty(int port)
++{
++      int lsr;
++      unsigned int tmout = 1000000;
++      do {
++                      lsr = inb(port + UART_LSR);
++                      if (--tmout == 0) break;
++              } while ((lsr & BOTH_EMPTY_TR) != BOTH_EMPTY_TR);
++}
++
++/*
++ * This routine sends the raw binary data to com port. The receiving
++ * end should be capable of handling raw bytes.
++ */  
++static int log_to_com_port(struct dprobes_struct *dp, int port)
++{
++      int i, ier;
++      byte_t *log = dp->log;
++      byte_t *ex_log = dp->ex_log;
++      unsigned long log_len = dp->log_len;
++      unsigned long ex_log_len = dp->ex_log_len;
++      
++      /* store UART configuration and program it in polled mode */
++      ier = inb(port + UART_IER);     
++      outb(0x00, port + UART_IER);
++
++      /* send the log data to com port */
++      fmt_log_hdr_raw(dp);
++      for (i = 0; i < log_len; i++) {
++              wait_for_xmitr_empty(port);
++              outb(log[i], port + UART_TX);
++      }
++      
++      /* send CR and LF characters */
++      wait_for_xmitr_empty(port);
++      outb(0x0d, port + UART_TX);
++      wait_for_xmitr_empty(port);
++      outb(0x0a, port + UART_TX);
++
++      /* send the stack trace data(if present) to com port */
++      if (ex_log_len > MIN_ST_SIZE) {
++              fmt_st_hdr_raw(dp);
++              for (i = 0; i < ex_log_len; i++) {
++                      wait_for_xmitr_empty(port);
++                      outb(ex_log[i], port + UART_TX);
++              }
++
++              /* send CR and LF characters */
++              wait_for_xmitr_empty(port);
++              outb(0x0d, port + UART_TX);
++              wait_for_xmitr_empty(port);
++              outb(0x0a, port + UART_TX);
++      }       
++
++      /* restore the configuration of UART */
++      wait_for_xmitr_empty(port);
++      outb(ier, port + UART_IER);
++      return 0;
++}
++
++static void save_log(struct dprobes_struct *dp)
++{
++      switch(dp->mod->pgm.flags & DP_LOG_TARGET_MASK) {
++      case DP_LOG_TARGET_COM1:
++              log_to_com_port(dp, COM1_ADDR);
++              break;
++      case DP_LOG_TARGET_COM2:
++              log_to_com_port(dp, COM2_ADDR);
++              break;
++      case DP_LOG_TARGET_LTT:
++              fmt_log_hdr_raw(dp);
++              log_to_ltt(dp);
++              if (dp->ex_log_len > MIN_ST_SIZE) {
++                      fmt_st_hdr_raw(dp);
++                      log_st_to_ltt(dp);
++              }
++              break;
++      case DP_LOG_TARGET_EVL:
++              log_to_evl(dp);
++              break;
++      case DP_UNFORMATTED_OUTPUT:
++              log_to_klog(dp);
++              log_stack_trace(dp);
++              break;
++      default:
++              log_to_klog_dump(dp);
++              log_stack_trace_dump(dp);
++              break;
++      }
++      return;
++}
++
++#ifdef CONFIG_DEBUGREG
++static inline void set_rf(struct dp_record_struct *rec, struct pt_regs *regs)
++{
++      unsigned short wtype = rec->point.probe & DP_WATCHTYPE_MASK;
++      if (wtype == DP_WATCHTYPE_EXECUTE) {
++              regs->eflags |= EF_RF;
++      }
++      return;
++}
++
++inline void delete_watchpoint(unsigned int cond, struct pt_regs *regs, struct dp_record_struct *rec)
++{
++      int dbno = rec->dbregno;
++      unsigned long dr = read_dr(7);
++      RESET_DR7(dr, dbno);
++      dr_free(dbno);
++      write_dr(7, dr);
++}
++
++#else
++inline void delete_watchpoint(unsigned int cond, struct pt_regs *regs, struct dp_record_struct *rec) 
++{
++      return;
++}
++
++static inline void set_rf(struct dp_record_struct *rec, struct pt_regs *regs) 
++{
++      return; 
++}
++
++inline int dr_trap_type(unsigned int cond) 
++{
++      return 0;
++}
++#endif
++/*
++ * This routine save the registers during handling of kernel, userspace and 
++ * watchpoint probes and also updates the status in the dp_record_struct.
++ */
++void save_regs(struct dp_record_struct *rec, unsigned long addr,
++               struct pt_regs *regs)
++{
++      struct dprobes_struct *dp = &dprobes;
++
++      dp->rec = rec;
++      dp->probe_addr = addr;
++      dp->regs = regs;
++      dp->mod = rec->mod;
++      dp->major = rec->point.major;
++      dp->minor = rec->point.minor;
++      dp->status = 0UL;
++      dp->cs = regs->xcs;
++      dp->eip = regs->eip - sizeof(opcode_t);
++      dp->ss = regs->xss;
++      dp->esp = regs->esp;
++      if (regs->xcs & 3) {
++              dp->status |= DP_USER_PROBE;
++              dp->uregs = regs;
++      } else {
++              dp->status |= DP_KERNEL_PROBE;
++              dp->uregs = (struct pt_regs * )((unsigned long)(current) + 2 * PAGE_SIZE - sizeof(struct pt_regs));
++      }
++      dp->status |= DP_STATUS_FIRSTFPU;
++
++      /* rec->count > 0 for passcount */
++      if (rec->status & DP_REC_STATUS_ACTIVE && rec->count >= 0) {
++              dp_interpreter();
++              if (rec->status & (DP_REC_STATUS_DISABLED | DP_REC_STATUS_REMOVED)) {
++                      if (rec->status & DP_REC_STATUS_ACTIVE) {
++                              rec->status &= ~DP_REC_STATUS_ACTIVE;
++                              rec->status |= DP_REC_STATUS_DISABLED;
++                      }
++              }
++      } else {
++                      dp->status |= DP_STATUS_ABORT;
++      }
++}
++int dp_pre_handler(struct kprobe *kp, struct pt_regs *regs)
++{
++      struct dprobes_struct *dp = &dprobes;
++      struct dp_record_struct *rec = container_of(kp, typeof(*rec), kp);
++
++      if (rec->status & (DP_REC_STATUS_DISABLED | DP_REC_STATUS_REMOVED)) {
++              return 1;
++              }
++
++#ifdef CONFIG_MAGIC_SYSRQ
++      /* check if probes are marked for emergency removal */
++      if (test_bit(0, &emergency_remove)) 
++              return 1; 
++#endif
++      dp->rec = rec;
++      save_regs(rec, (unsigned long)rec->kp.addr, regs);
++      dp->status |= DP_STATUS_SS;
++      return 0;
++}
++
++void dp_post_handler(struct kprobe *kp, struct pt_regs *regs, unsigned long flags)
++{
++      struct dprobes_struct *dp = &dprobes;
++
++      dp->rec->count++;
++      if (dp->rec->count >= dp->rec->point.maxhits) {
++              dp->rec->status &= ~DP_REC_STATUS_ACTIVE;
++              dp->rec->status |= DP_REC_STATUS_DISABLED;
++      }
++      if (dp->status & DP_STATUS_ABORT)
++              return;
++      save_log(dp);
++}
++
++int dp_fault_handler(struct kprobe *kp, struct pt_regs *regs, int trapnr)
++{
++      struct dprobes_struct *dp = &dprobes;
++
++      if (trapnr != 13 && trapnr != 14)
++              return 0;
++      
++      if (dp->status & DP_STATUS_INTERPRETER) {
++              const struct exception_table_entry *fixup;
++              if ((fixup = search_exception_tables(regs->eip)) != 0) {
++                      regs->eip = fixup->fixup;
++                      return 1;
++              }
++      } else if (dp->status & DP_STATUS_SS) {
++              if (dp->rec->point.logonfault) {
++                      dp->rec->count++;
++                      save_log(dp);
++              }
++      }
++      return 0;
++}
++
++/*
++ * If there are multiple debug traps simultaneously, we handle the
++ * single step condition first (DR_STEP) as it is related to completing
++ * a previous debug trap. We then handle the debug register hits.
++ */
++int dp_do_debug(struct pt_regs * regs, unsigned long condition)
++{
++#ifdef CONFIG_DEBUGREG
++#if 0
++      /* assume that only one watchpoint possible on an address. */
++      if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
++              if (dp_trap(regs, DP_PROBE_WATCHPOINT, condition, dr_trap_addr(condition))) {
++                      return 1;
++              }
++      }
++#endif
++#endif
++      return 0;
++}
++
++#include <asm/desc.h>
++#include <asm/ldt.h>
++#ifndef GDT_ENTRIES
++#define GDT_ENTRIES     (__TSS(NR_CPUS))
++#endif
++static inline int is_fpu_instn(byte_t *addr)
++{
++      if (((*addr & 0xf8) == 0xd8) || (*addr == 0x9b)) 
++              return 1;
++      return 0;
++}
++/* Use this array to store the dp_record_struct during registration, and index
++ * using the debugreg number in the handler to get back, the dp_record_struct.
++ */
++static struct dp_record_struct *kwatch_rec[DP_MAX_WATCHPOINT];
++      
++/* 
++ * dp_kwatch_handler: Dprobes handler for watchpoint probes, registerd through
++ * kwatch interface. This routine is called by the watch point probe handler, 
++ * when the probe is hit.
++ */
++
++void dp_kwatch_handler(struct kwatch *kw, struct pt_regs *regs, int debugreg)
++{
++      struct dprobes_struct *dp = &dprobes;
++      struct dp_record_struct *rec = kwatch_rec[debugreg];
++      if ((!rec) || (rec->status & (DP_REC_STATUS_DISABLED | 
++                              DP_REC_STATUS_REMOVED))) {
++              return ;
++      }
++      rec->count++;
++      save_regs(rec, kw->addr, regs);
++      if (dp->status & DP_STATUS_ABORT)
++              return;
++      save_log(dp);
++      dp->status &= ~DP_STATUS_DONE;
++      return;
++}
++
++/* 
++ * Unregister watchpoint probes.
++ */
++
++static inline int remove_wp(byte_t *addr, struct dp_record_struct *rec)
++{
++      kwatch_rec[rec->dbregno] = NULL;
++      unregister_kwatch(rec->dbregno);
++      return 0;
++}
++
++/* Check the range for debug register watchpoint */
++static inline int invalid_range(unsigned long len)
++{
++      return (len > 3 ) ? 1 : 0;
++}
++
++/*
++ * Insert watchpoint probes, using the kwatch interface.
++ */
++static inline int insert_wp(byte_t *addr, struct dp_record_struct *rec,
++      struct dp_module_struct *m, struct page * page)
++{
++      int ret;
++
++      if (invalid_range(rec->point.len)) {
++              rec->status |= DP_REC_STATUS_WATCHPOINT_LEN_INVALID;
++              return -1;
++      }
++      ret = register_kwatch((unsigned long)addr, (u8)(rec->point.len + 1),
++               (u8)(rec->point.probe & DP_WATCHTYPE_MASK), dp_kwatch_handler);
++
++      if (ret < 0) {
++              rec->status |= DP_REC_STATUS_KPROBE_ERR;
++              return -1;
++      }
++
++      kwatch_rec[ret] = rec;
++      rec->status |= DP_REC_STATUS_ACTIVE;
++      rec->dbregno = ret;
++      return 0;
++}
++
++/* 
++ * Writing the breakpoint instruction should be the last thing done
++ * in this function to ensure that all the structures that
++ * are needed to locate the probe are in place before a probe can
++ * be hit.
++ */
++static inline int insert_bp(byte_t *addr, struct dp_record_struct *rec,
++      struct dp_module_struct *m, struct page * page)
++{
++      if (dprobes_excluded((unsigned long)addr)) {
++              rec->status |= DP_REC_STATUS_EXCLUDED;
++              return -1;
++      }
++
++      if (!(m->pgm.flags & DP_MODTYPE_USER) &&
++              !(((unsigned long)addr) >= m->base && 
++              ((unsigned long)addr) < (m->end + m->base))) {
++              rec->status |= DP_REC_STATUS_INVALID_OFFSET;
++              return -1;
++      }
++      if (*addr != rec->point.opcode)  {
++              if (m->pgm.flags & DP_DONT_VERIFY_OPCODES) {
++                      rec->point.opcode = *addr;
++              } else {
++                      if (!(m->pgm.flags & DP_MODTYPE_USER) || 
++                          !IS_COW_PAGE(page, m->inode)) {
++                              rec->point.actual_opcode = *addr;
++                              rec->status |= DP_REC_STATUS_MISMATCH;
++                      }
++                      return -1;
++              }
++      }
++
++      /* all okay, register the probe */
++      rec->kp.addr = addr;
++      rec->kp.pre_handler = dp_pre_handler;
++      rec->kp.post_handler = dp_post_handler;
++      rec->kp.fault_handler = dp_fault_handler;
++      
++      if (register_kprobe(&rec->kp)) {
++              rec->status |= DP_REC_STATUS_KPROBE_ERR;
++              return -1;
++      }
++      rec->status |= DP_REC_STATUS_ACTIVE;
++      return 0;
++}
++
++int __insert_probe(byte_t *addr, struct dp_record_struct *rec, 
++      struct dp_module_struct *m, struct page * page)
++{
++      if (rec->point.probe & DP_PROBE_BREAKPOINT)
++              return insert_bp(addr, rec, m, page);
++      else 
++              return insert_wp(addr, rec, m, page);
++}
++
++static inline void remove_bp(byte_t *addr, struct dp_record_struct *rec)
++{
++      unregister_kprobe(&rec->kp);
++}
++
++int __remove_probe(byte_t * addr, struct dp_record_struct *rec)
++{
++      if (rec->point.probe & DP_PROBE_BREAKPOINT)
++              remove_bp(addr, rec);
++      else 
++              remove_wp(addr, rec);
++      return 0;
++}
++/*
++ * Insert breakpoints in the user space at the given address.
++ * Need to specify address, page and vma in kprobe structure.
++ */
++inline int insert_probe_userspace(byte_t *addr, struct dp_record_struct *rec, 
++      struct page *page, struct vm_area_struct *vma)
++{
++      rec->kp.user->addr = addr;
++      rec->kp.user->page = page;
++      rec->kp.user->vma = vma;
++      if (insert_kprobe_user(&rec->kp)) {
++              rec->status |= DP_REC_STATUS_KPROBE_ERR;
++              return -1;
++      }
++      rec->status |= DP_REC_STATUS_ACTIVE;
++      return 0;
++}
++
++/*
++ * Remove breakpoints in the user space previously inserted at the given
++ * address. Need to specify address, page and vma in kprobe structure.
++ */
++inline int remove_probe_userspace(byte_t *addr, struct dp_record_struct *rec, 
++      struct page *page, struct vm_area_struct *vma)
++{
++      rec->kp.user->addr = addr;
++      rec->kp.user->page = page;
++      rec->kp.user->vma = vma;
++      return remove_kprobe_user(&rec->kp);
++              
++}
++
++
++/*
++ * register user space probes before actually inserting the probes.
++ */
++int register_userspace_probes(struct dp_record_struct *rec)
++{
++      rec->kp.pre_handler = dp_pre_handler;
++      rec->kp.post_handler = dp_post_handler;
++      rec->kp.fault_handler = dp_fault_handler;
++      rec->up.offset = rec->point.offset;
++      rec->up.inode = rec->mod->inode;
++      rec->kp.user = &(rec->up);
++      if (register_kprobe_user(&rec->kp)) {
++              rec->status |= DP_REC_STATUS_KPROBE_ERR;
++              return -1;
++      }
++      rec->status |= DP_REC_STATUS_ACTIVE;
++      return 0;
++}
++
++/*
++ * Unregister the user space probes previously registered.
++ * Make sure all the probes for a pair of inode and offset are removed
++ * before unregistering. 
++ */
++void unregister_userspace_probes(struct dp_record_struct *rec)
++{
++      unregister_kprobe_user(&rec->kp);
++}
++void dprobes_asm_code_end(void) { }
+diff -urNp linux.orig/drivers/dprobes/i386/dprobes_in.c linux-2.6.0-test11/drivers/dprobes/i386/dprobes_in.c
+--- linux.orig/drivers/dprobes/i386/dprobes_in.c       1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.0-test11/drivers/dprobes/i386/dprobes_in.c       2003-12-15 15:51:48.000000000 +0530
+@@ -0,0 +1,903 @@
++/*
++ * IBM Dynamic Probes
++ * Copyright (c) International Business Machines Corp., 2000
++ *
++ * 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.  
++ */
++
++/*
++ * This is a special file, part of the dprobes interpreter that contains
++ * architecture-specific functions. It is not compiled as a seperate unit.
++ * It is #included into the arch-independent dprobes_in.c at a specific
++ * location.
++ */
++#include <linux/binfmts.h>
++#ifdef CONFIG_DUMP
++#include <linux/dump.h>
++#endif
++#ifdef CONFIG_KDB
++#include <linux/kdb.h>
++#endif
++#include <asm/desc.h>
++#include <asm/ldt.h>
++#ifndef GDT_ENTRIES
++#define GDT_ENTRIES     (__TSS(NR_CPUS))
++#endif
++
++/*
++ * Convert segmented address (selector : offset) to flat linear address.
++ */
++static int dp_seg_to_flat(unsigned long sel, unsigned long off, void **faddr)
++{
++      struct Xgt_desc_struct g;
++      unsigned long ldt_desc, ldt_base, ldtr, seg_desc, seg_base;
++      unsigned long gdt_index = (sel & ~7);
++      mm_context_t *x = &current->mm->context;
++
++      __asm__ __volatile__ ("sgdt (%0)" : : "r"((unsigned long) &g));
++
++      if (sel & 4) {
++              if (!(x->ldt && ((sel >> 3) < x->size)))
++                      return 1;
++
++              __asm__ __volatile__ ("sldt %0" :"=r"(ldtr));
++              ldt_desc = g.address + ((ldtr & ~7));
++              ldt_base = _get_base ((char *)ldt_desc);
++              seg_desc = ldt_base + (gdt_index);
++              seg_base = _get_base ((char *)seg_desc);
++      }
++      else {
++              if ((sel >> 3) > GDT_ENTRIES)
++                      return 1;
++              seg_desc = g.address + gdt_index;
++              seg_base = _get_base ((char *)seg_desc);
++      }
++      *faddr = (void *)(seg_base + off);
++      return 0;
++}
++
++static void seg2lin(void)
++{
++      void *faddr;
++        unsigned long off = rpnpop();
++        unsigned long sel = rpnpop();
++
++      if (dp_seg_to_flat(sel, off, &faddr)) {
++              gen_ex(EX_SEG_FAULT, sel, 0);
++              return;
++      }
++      rpnpush((unsigned long) faddr);
++}
++
++#ifdef CONFIG_KDB
++/* 
++ * Temporarily restore the orignal opcode befor calling the kdb 
++ * so that kdb shows correct disassembly.
++ */
++static inline void restore_opcode(void)
++{
++      if (dprobes.rec->point.probe & DP_PROBE_BREAKPOINT) {
++              dprobes.reset_addr = dprobes.probe_addr;
++              *((byte_t *)dprobes.reset_addr) = dprobes.opcode;
++              flush_page_to_ram(dprobes.reset_addr);
++      }
++}
++
++/*
++ * After kdb terminates, restore the breakpoint.
++ */
++static inline void restore_int3(void)
++{     
++      if (dprobes.rec->point.probe & DP_PROBE_BREAKPOINT) {
++              dprobes.reset_addr = dprobes.probe_addr;
++              *((byte_t *)dprobes.reset_addr) = DP_INSTR_BREAKPOINT;
++              flush_page_to_ram(dprobes.reset_addr);
++      }
++}
++      
++void call_kdb(void)
++{
++      unsigned long eip = dprobes.regs->eip - 1;
++      if (dprobes.status & DP_KERNEL_PROBE) {
++              if (dprobes.rec->point.probe & DP_PROBE_BREAKPOINT)
++                      dprobes.regs->eip--;
++              restore_opcode();
++              kdb(KDB_REASON_CALL, 0, dprobes.regs);
++              restore_int3();
++              if (eip == dprobes.regs->eip)
++                      dprobes.regs->eip++;
++      }
++}
++#else
++
++void call_kdb(void)
++{
++      printk("Dprobes: Kernel Debugger is not present.\n");
++      return;
++}
++#endif
++/*
++ * Exiting the interpreter through the registered facility n.
++ */
++static void dp_exit_n(void)
++{
++      u8 facility = get_u8_oprnd();
++      switch(facility) {
++      case DP_EXIT_TO_SGI_KDB:
++              call_kdb();     
++              break;
++
++      case DP_EXIT_TO_SGI_VMDUMP:
++#ifdef CONFIG_DUMP
++              if (dprobes.status & DP_KERNEL_PROBE)
++                      dump("Dumping due to dprobes", dprobes.regs);
++#else
++              printk("dprobes: Crash dump facility is not present.\n");
++#endif
++              break;
++      case DP_EXIT_TO_CORE_DUMP:
++              if (dprobes.status & DP_USER_PROBE) {
++                      if (do_coredump(SIGINT, SIGINT, dprobes.regs)) {        
++                              current->mm->dumpable = 1;
++                              printk("dprobes(%d,%d) process %s dumped core\n", dprobes.major, dprobes.minor, current->comm);
++                      }
++                      else
++                              printk("dprobes(%d,%d) exit to core dump failed\n", dprobes.major, dprobes.minor);
++              }
++              break;
++      default: gen_ex(EX_INVALID_OPERAND, 4, facility); return;
++      
++      }
++      dprobes.status &= ~DP_STATUS_INTERPRETER;
++}
++
++/*
++ * Interpreter's version of copy_xxx_user functions. These need to save
++ * and restore cr2 contents to be able to correctly handle probes in
++ * page fault handler.
++ */
++static int dp_intr_copy_from_user(void *to, void *from, int len) 
++{
++      unsigned long address;
++      int retval;
++      __asm__("movl %%cr2,%0":"=r" (address)); /* save cr2 contents */
++      retval = __copy_from_user(to, from, len);
++      __asm__("movl %0,%%cr2": :"r" (address)); /* restore cr2 contents */
++      return retval;
++}
++
++static int dp_intr_copy_to_user(void *to, void *from, int len) 
++{
++      unsigned long address;
++      int retval;
++      __asm__("movl %%cr2,%0":"=r" (address)); /* save cr2 contents */
++      retval = __copy_to_user(to, from, len);
++      __asm__("movl %0,%%cr2": :"r" (address)); /* restore cr2 contents */
++      return retval;
++}
++
++#define BITS_IN_UL    32
++
++#define PROPAGATE_BIT(name, OPERATOR) \
++static void name(void) \
++{ \
++      unsigned long index, num, pos, val; \
++      index = rpnpop(); \
++      if (!index || index > BITS_IN_UL) { \
++              gen_ex(EX_INVALID_OPERAND, 3, index); \
++              return; \
++      } \
++      num = rpnpop(); \
++      pos = 1UL << (index - 1); \
++      val = num & pos; \
++      for (; pos; pos OPERATOR 1, val OPERATOR 1) \
++              num &= ~pos, num |= val; \
++      rpnpush(num); \
++}     
++
++PROPAGATE_BIT(pbl, <<=)
++PROPAGATE_BIT(pbr, >>=)
++
++#define PROPAGATE_BIT_IMM(name, OPERATOR) \
++static void name(void) \
++{ \
++      unsigned long index, num, pos, val; \
++      index = (unsigned long)get_u8_oprnd(); \
++      if (!index || index > BITS_IN_UL) { \
++              dprobes.status &= ~DP_STATUS_INTERPRETER; \
++              return; \
++      } \
++      num = rpnpop(); \
++      pos = 1UL << (index - 1); \
++      val = num & pos; \
++      for (; pos; pos OPERATOR 1, val OPERATOR 1) \
++              num &= ~pos, num |= val; \
++      rpnpush(num); \
++}
++
++PROPAGATE_BIT_IMM(pbl_i, <<=)
++PROPAGATE_BIT_IMM(pbr_i, >>=)
++
++static void pzl(void) 
++{ 
++      unsigned long index, num, pos;
++      index = rpnpop(); 
++      if (!index || index > BITS_IN_UL) {
++              gen_ex(EX_INVALID_OPERAND, 3, index); \
++              return;
++      }
++      num = rpnpop();
++      pos = 1UL << index;
++      for (; pos; pos <<= 1)
++              num &= ~pos;
++      rpnpush(num);
++}
++      
++static void pzl_i(void) 
++{ 
++      unsigned long index, num, pos;
++      index = (unsigned long)get_u8_oprnd();
++      if (!index || index > BITS_IN_UL) {
++              gen_ex(EX_INVALID_OPERAND, 3, index);
++              return;
++      }
++      num = rpnpop();
++      pos = 1UL << index;
++      for (; pos; pos <<= 1)
++              num &= ~pos;
++      rpnpush(num);
++}
++
++static void pzr(void)
++{
++      unsigned long index, num, pos;
++      index = rpnpop();
++      if (!index || index > BITS_IN_UL) {
++              gen_ex(EX_INVALID_OPERAND, 3, index);
++              return;
++      }
++      if (index == 1)
++              return;
++      num = rpnpop();
++      pos = 1UL << (index - 2);
++      for (; pos; pos >>= 1)
++              num &= ~pos;
++      rpnpush(num);
++}
++
++static void pzr_i(void)
++{
++      unsigned long index, num, pos;
++      index = (unsigned long)get_u8_oprnd();
++      if (!index || index > BITS_IN_UL) {
++              gen_ex(EX_INVALID_OPERAND, 3, index);
++              return;
++      }
++      if (index == 1)
++              return;
++      num = rpnpop();
++      pos = 1UL << (index - 2);
++      for (; pos; pos >>= 1)
++              num &= ~pos;
++      rpnpush(num);
++}
++
++static void ror_i(void)
++{
++      byte_t count = get_u8_oprnd();
++      __asm__ __volatile__("rorl %%cl, %0" 
++                              :"=m"(dprobes.rpn_stack[dprobes.rpn_tos])
++                              :"c"((unsigned long) count));
++}
++
++static void rol_i(void)
++{
++      byte_t count = get_u8_oprnd();
++      __asm__ __volatile__("roll %%cl, %0" 
++                              :"=m"(dprobes.rpn_stack[dprobes.rpn_tos])
++                              :"c"((unsigned long) count));
++}
++
++static void ror(void)
++{
++      unsigned long oprnd = rpnpop();
++      unsigned long count = rpnpop();
++      __asm__ __volatile__("rorl %%cl, %0" : "=m"(oprnd)
++                              :"c"(count) );
++      rpnpush(oprnd);
++}
++
++static void rol(void)
++{
++      unsigned long oprnd = rpnpop();
++      unsigned long count = rpnpop();
++      __asm__ __volatile__("roll %%cl, %0" : "=m"(oprnd)
++                              :"c"(count));
++      rpnpush(oprnd);
++}
++
++/*
++ * IO group
++ */
++static void push_io_u8(void)
++{
++      rpnpush(inb(rpnpop()));
++}
++static void push_io_u16(void)
++{
++        rpnpush(inw(rpnpop()));
++}
++
++static void push_io_u32(void)
++{
++        rpnpush(inl(rpnpop()));
++}
++
++static void pop_io_u8(void)
++{
++      u8 b = (u8)rpnpop();
++      outb(b, rpnpop());
++}
++
++static void pop_io_u16(void)
++{
++        u16 w = (u16)rpnpop();
++      outw(w, rpnpop());
++}
++
++static void pop_io_u32(void)
++{
++        u32 d = (u32)rpnpop();
++      outl(d, rpnpop());
++}
++
++/*
++ * Register push and pop, current and user registers.
++ */
++
++/*
++ * y -- allowed and implemented, n -- not allowed and not implemented.
++ *
++ * Index      Register        push u  push r  pop u   pop r   
++ *
++ * 0          cs              y       y       n       n
++ * 1          ds              y       y       y       y
++ * 2          es              y       y       y       y
++ * 3          fs              y       y       y       y
++ * 4          gs              y       y       y       y                       
++ * 5          ss              y       y       n       n
++ * 6          eax             y       y       y       y
++ * 7          ebx             y       y       y       y
++ * 8          ecx             y       y       y       y
++ * 9          edx             y       y       y       y
++ * a          edi             y       y       y       y
++ * b          esi             y       y       y       y       
++ * c          eflags          y       y       n       n
++ * d          eip             y       y       n       n
++ * e          esp             y       y       n       n
++ * f          ebp             y       y       y       y
++ * 20         tr              n       y       n       n
++ * 21         ldtr            n       y       n       n
++ * 22         gdtr            n       y       n       n
++ * 23         idtr            n       y       n       n
++ * 24         cr0             n       y       n       n
++ * 25         cr1                     RESERVED                        
++ * 26         cr2             n       y       n       n
++ * 27         cr3             n       y       n       n
++ * 28         cr4             n       y       n       n
++ * 29         cr5                     RESERVED
++ * 2a         cr6                     RESERVED
++ * 2b         cr7                     RESERVED
++ * 2c         dr0             n       y       n       n
++ * 2d         dr1             n       y       n       n
++ * 2e         dr2             n       y       n       n
++ * 2f         dr3             n       y       n       n
++ * 30         dr4                     RESERVED        
++ * 31         dr5                     RESERVED
++ * 32         dr6             n       y       n       n
++ * 33         dr7             n       y       n       n
++ * 34         tr0                     RESERVED
++ * 35         tr1                     RESERVED
++ * 36         tr2                     RESERVED
++ * 37         tr3                     RESERVED        
++ * 38         tr4                     RESERVED
++ * 39         tr5                     RESERVED
++ * 3a         tr6                     RESERVED
++ * 3b         tr7                     RESERVED
++ * 3c         cpuid           y       y       n       n
++ * 3d         msr             y       y       n       n
++ * 3e         fr0             y       n       n       n
++ * 3f         fr1             y       n       n       n
++ * 40         fr2             y       n       n       n
++ * 41         fr3             y       n       n       n
++ * 42         fr4             y       n       n       n
++ * 43         fr5             y       n       n       n
++ * 44         fr6             y       n       n       n
++ * 45         fr7             y       n       n       n
++ * 46         fcw             y       n       n       n
++ * 47         fsw             y       n       n       n
++ * 48         ftw             y       n       n       n
++ * 49         fip             y       n       n       n
++ * 4a         fcs             y       n       n       n
++ * 4b         fdp             y       n       n       n
++ * 4c         fds             y       n       n       n
++ * 4d         xmm0            y       n       n       n
++ * 4e         xmm1            y       n       n       n
++ * 4f         xmm2            y       n       n       n
++ * 50         xmm3            y       n       n       n
++ * 51         xmm4            y       n       n       n
++ * 52         xmm5            y       n       n       n
++ * 53         xmm6            y       n       n       n
++ * 54         xmm7            y       n       n       n
++ * 55         mxcsr           y       n       n       n
++ */
++
++static void dp_save_fpu(void)
++{
++      dprobes.status &= ~DP_STATUS_FIRSTFPU;
++      if (HAVE_HWFP) {
++              if (!current->used_math) {
++                      memset(&dprobes.fpu_save_area,0, sizeof(dprobes.fpu_save_area));
++                      return;
++              }
++
++              if ((read_cr0()) & CR0_TS) {
++                      dprobes.fpu_save_area = current->thread.i387;
++              }
++              else {
++                      if (cpu_has_fxsr) {
++                              __asm__ __volatile__ (
++                                      "fxsave %0\n"   
++                                      "fxrstor %0" :"=m" (dprobes.fpu_save_area));
++                      } else {
++                              __asm__ __volatile__ (
++                                      "fsave %0\n"    
++                                      "frstor %0" :"=m" (dprobes.fpu_save_area));
++              
++                      }
++              }
++      }
++      else
++              memset(&dprobes.fpu_save_area,0, sizeof(dprobes.fpu_save_area));
++
++}
++
++/*
++ * Define Floating Point Control Registers' push functions.
++ */
++
++#define DEFINE_PUSHFP(REG) \
++static void pushfp_##REG(void) \
++{ \
++      if (dprobes.status & DP_STATUS_FIRSTFPU) \
++              dp_save_fpu(); \
++      if (cpu_has_fxsr) \
++              rpnpush(dprobes.fpu_save_area.fxsave.REG); \
++      else \
++              rpnpush(dprobes.fpu_save_area.fsave.REG); \
++}
++
++DEFINE_PUSHFP(cwd)
++DEFINE_PUSHFP(swd)
++DEFINE_PUSHFP(twd)
++DEFINE_PUSHFP(fip)
++DEFINE_PUSHFP(fcs)
++DEFINE_PUSHFP(foo)
++DEFINE_PUSHFP(fos)
++
++static void pushfp_mxcsr(void)
++{
++      if (dprobes.status & DP_STATUS_FIRSTFPU)
++              dp_save_fpu();
++      if (cpu_has_xmm)
++              rpnpush(dprobes.fpu_save_area.fxsave.mxcsr);
++      else
++              rpnpush(0); /* could we return 0x1f80 ? */
++}
++
++/*
++ * Floating Point Data Registers' push function.
++ */
++static void pushfp_st(int offset)
++{
++      unsigned long st_0, st_4, st_8;
++      if (dprobes.status & DP_STATUS_FIRSTFPU)
++              dp_save_fpu();
++      if (cpu_has_fxsr) {
++              offset = (offset - 0x3e) * 16;
++              st_0 = *(unsigned long *) ((unsigned char *)
++                      (dprobes.fpu_save_area.fxsave.st_space) + offset);
++              st_4 = *(unsigned long *) ((unsigned char *)
++                      (dprobes.fpu_save_area.fxsave.st_space) + offset + 4);
++              st_8 = *(unsigned long *) ((unsigned char *)
++                      (dprobes.fpu_save_area.fxsave.st_space) + offset + 8);
++      }
++      else {
++              offset = (offset - 0x3e) * 10;
++              st_0 = *(unsigned long *) ((unsigned char *)
++                      (dprobes.fpu_save_area.fsave.st_space) + offset);
++              st_4 = *(unsigned long *) ((unsigned char *)
++                      (dprobes.fpu_save_area.fsave.st_space) + offset + 4);
++              st_8 = *(unsigned short *) ((unsigned char *)
++                      (dprobes.fpu_save_area.fsave.st_space) + offset + 8);
++      }
++      rpnpush(st_8);
++      rpnpush(st_4);
++      rpnpush(st_0);
++}
++
++static void push_xmm(int offset)
++{
++      unsigned long xmm_0 = 0, xmm_4 = 0, xmm_8 = 0, xmm_12 = 0;
++      if (dprobes.status & DP_STATUS_FIRSTFPU)
++              dp_save_fpu();
++      if (cpu_has_xmm) {
++              offset = (offset - 0x4d) * 16;
++              xmm_0 = *(unsigned long *) ((unsigned char *)
++                      (dprobes.fpu_save_area.fxsave.xmm_space) + offset);
++              xmm_4 = *(unsigned long *) ((unsigned char *)
++                      (dprobes.fpu_save_area.fxsave.xmm_space) + offset + 4);
++              xmm_8 = *(unsigned long *) ((unsigned char *)
++                      (dprobes.fpu_save_area.fxsave.xmm_space) + offset + 8);
++              xmm_12 = *(unsigned long *) ((unsigned char *)
++                      (dprobes.fpu_save_area.fxsave.xmm_space) + offset + 12);
++      }
++      rpnpush(xmm_12);
++      rpnpush(xmm_8);
++      rpnpush(xmm_4);
++      rpnpush(xmm_0);
++}
++
++/*
++ * push r, ss.
++ */
++static unsigned long getr_ss(void)
++{
++      unsigned long reg;
++      if (dprobes.status & DP_KERNEL_PROBE)
++              __asm__ __volatile__("movw %%ss, %%ax\n\t"
++                                    :"=a"(reg)
++                                   );
++      else 
++              reg = dprobes.regs->xss;
++      return reg;
++}
++
++/*
++ * push r, esp
++ */
++static unsigned long getr_esp(void)
++{
++      if (dprobes.status & DP_KERNEL_PROBE)
++              return (unsigned long)&dprobes.regs->esp;
++      else 
++              return dprobes.regs->esp;
++}
++
++/*
++ * Push GDTR
++ */
++static void push_gdtr(void)
++{
++      struct Xgt_desc_struct gdtr;
++      __asm__ __volatile__("sgdt (%0)" : : "r"((unsigned long) &gdtr));
++
++      rpnpush(gdtr.address);
++      rpnpush((unsigned long) gdtr.size);
++}
++
++/*
++ * Push LDTR
++ */
++static void push_ldtr(void)
++{
++      unsigned long ldtr = 0; 
++      __asm__ __volatile__("sldt %0" : "=r"(ldtr));
++      rpnpush(ldtr);
++}
++
++/*
++ * Push IDTR
++ */
++static void push_idtr(void)
++{
++      struct Xgt_desc_struct idtr;
++      __asm__ __volatile__("sidt (%0)" : : "r"((unsigned long) &idtr));
++
++      rpnpush(idtr.address);
++      rpnpush((unsigned long)idtr.size);
++}
++
++/*
++ * Push TR
++ */
++static void push_tr(void)
++{
++      unsigned long tr;
++      __asm__ __volatile__("str %%ax" : "=a"(tr));
++      rpnpush(tr);
++}
++
++/*
++ * Push cpuid.
++ */
++static void push_cpuid(void)
++{
++      int op, cpuid_eax = 0, cpuid_ebx = 0, cpuid_ecx = 0, cpuid_edx = 0;
++      op = (int) rpnpop();
++      if ((boot_cpu_data.x86 >= 5) && (op <= boot_cpu_data.cpuid_level)) 
++              cpuid(op, &cpuid_eax, &cpuid_ebx, &cpuid_ecx, &cpuid_edx);
++      rpnpush(cpuid_edx);
++      rpnpush(cpuid_ecx);
++      rpnpush(cpuid_ebx);
++      rpnpush(cpuid_eax);
++}
++      
++/*
++ * push msr. 
++ */
++static void push_msr(void)
++{
++      unsigned long msr, val1 =0, val2 = 0;
++      msr = rpnpop();
++      if (boot_cpu_data.x86 >= 5) 
++              __asm__ __volatile__ (
++                      "0:     rdmsr\n"
++                      "1:\n"
++                      ".section .fixup,\"ax\"\n"
++                      "2:     jmp 1b\n"
++                      ".previous\n"
++                      ".section __ex_table,\"a\"\n"
++                      "       .align 4\n"
++                      "       .long 0b,2b\n"
++                      ".previous"
++                      :"=a"(val1), "=d"(val2)
++                      :"c"(msr));
++      rpnpush(val2);
++      rpnpush(val1);
++}
++
++/*    
++ * Prototype for control registers'(CR0 TO CR4) and debug registers'(DR0 TO DR7)
++ * push functions.
++ */
++#define DEFINE_PUSHCRDB(REG) \
++static void push_##REG(void) \
++{ \
++      unsigned long reg; \
++      __asm__ __volatile__ ("movl %%" #REG ", %0" : "=r"(reg)); \
++      rpnpush(reg); \
++}
++
++/*
++ * Define control and debug registers' push functions.
++ */
++DEFINE_PUSHCRDB(cr0)
++DEFINE_PUSHCRDB(cr2)
++DEFINE_PUSHCRDB(cr3)
++DEFINE_PUSHCRDB(cr4)
++DEFINE_PUSHCRDB(dr0)
++DEFINE_PUSHCRDB(dr1)
++DEFINE_PUSHCRDB(dr2)
++DEFINE_PUSHCRDB(dr3)
++DEFINE_PUSHCRDB(dr6)
++DEFINE_PUSHCRDB(dr7)
++
++/*
++ * Since fs and gs are not in pt_regs, these
++ * are directly taken from the processor.
++ */
++static unsigned long read_fs(void)
++{
++      unsigned long val;
++      __asm__ __volatile__("movw %%fs, %%ax" :"=a"(val));
++      return val;
++}
++
++static unsigned long read_gs(void)
++{
++      unsigned long val;
++      __asm__ __volatile__("movw %%gs, %%ax" :"=a"(val));
++      return val;
++}
++
++static void write_fs(unsigned long val)
++{
++      __asm__ __volatile__("movw %%ax, %%fs" : : "a"(val));
++}
++
++static void write_gs(unsigned long val)
++{
++      __asm__ __volatile__("movw %%ax, %%gs" : :"a"(val));
++}
++
++/*
++ * Current register main push function.
++ */
++static void pushr(void)
++{
++      struct dprobes_struct *dp = &dprobes;
++      unsigned short index = get_u16_oprnd();
++      unsigned long val;
++      switch(index) {
++              case DP_CS:     val = dp->regs->xcs; break;
++              case DP_DS:     val = dp->regs->xds; break;
++              case DP_ES:     val = dp->regs->xes; break;
++              case DP_FS:     val = read_fs(); break;
++              case DP_GS:     val = read_gs(); break;
++              case DP_SS:     val = getr_ss(); break;
++              case DP_EAX:    val = dp->regs->eax; break;
++              case DP_EBX:    val = dp->regs->ebx; break;
++              case DP_ECX:    val = dp->regs->ecx; break;
++              case DP_EDX:    val = dp->regs->edx; break;
++              case DP_EDI:    val = dp->regs->edi; break;
++              case DP_ESI:    val = dp->regs->esi; break;
++              case DP_EFLAGS: val = dp->regs->eflags; break;
++              case DP_EIP:    val = dp->regs->eip; break;
++              case DP_ESP:    val = getr_esp(); break;
++              case DP_EBP:    val = dp->regs->ebp; break;
++
++              /* special registers */
++              case DP_TR:     push_tr(); return;
++              case DP_LDTR:   push_ldtr(); return;
++              case DP_GDTR:   push_gdtr(); return;
++              case DP_IDTR:   push_idtr(); return;
++              case DP_CR0:    push_cr0(); return;
++              case DP_CR2:    push_cr2(); return;
++              case DP_CR3:    push_cr3(); return;
++              case DP_CR4:    push_cr4(); return;
++              case DP_DR0:    push_dr0(); return;
++              case DP_DR1:    push_dr1(); return;
++              case DP_DR2:    push_dr2(); return;
++              case DP_DR3:    push_dr3(); return;
++              case DP_DR6:    push_dr6(); return;
++              case DP_DR7:    push_dr7(); return;
++              case DP_CPUID:  push_cpuid(); return;
++              case DP_MSR:    push_msr(); return;
++              default:        val = 0; break;
++      }
++      rpnpush(val);
++      return;
++}
++
++/*
++ * User register main push function.
++ */
++static void pushu(void)
++{
++      struct dprobes_struct *dp = &dprobes;
++      unsigned short index = get_u16_oprnd();
++      unsigned long val;
++      switch(index) {
++              case DP_CS:     val = dp->uregs->xcs; break;
++              case DP_DS:     val = dp->uregs->xds; break;
++              case DP_ES:     val = dp->uregs->xes; break;
++              case DP_FS:     val = read_fs(); break;
++              case DP_GS:     val = read_gs(); break;
++              case DP_SS:     val = dp->uregs->xss; break;
++              case DP_EAX:    val = dp->uregs->eax; break;
++              case DP_EBX:    val = dp->uregs->ebx; break;
++              case DP_ECX:    val = dp->uregs->ecx; break;
++              case DP_EDX:    val = dp->uregs->edx; break;
++              case DP_EDI:    val = dp->uregs->edi; break;
++              case DP_ESI:    val = dp->uregs->esi; break;
++              case DP_EFLAGS: val = dp->uregs->eflags; break;
++              case DP_EIP:    val = dp->uregs->eip; break;
++              case DP_ESP:    val = dp->uregs->esp; break;
++              case DP_EBP:    val = dp->uregs->ebp; break;
++              case DP_CPUID:  push_cpuid(); return;
++              case DP_MSR:    push_msr(); return;
++              case DP_FR0:    pushfp_st(0x3e); return;
++              case DP_FR1:    pushfp_st(0x3f); return;
++              case DP_FR2:    pushfp_st(0x40); return;
++              case DP_FR3:    pushfp_st(0x41); return;
++              case DP_FR4:    pushfp_st(0x42); return;
++              case DP_FR5:    pushfp_st(0x43); return;
++              case DP_FR6:    pushfp_st(0x44); return;
++              case DP_FR7:    pushfp_st(0x45); return;
++              case DP_FCW:    pushfp_cwd(); return;
++              case DP_FSW:    pushfp_swd(); return;
++              case DP_FTW:    pushfp_twd(); return;
++              case DP_FIP:    pushfp_fip(); return;
++              case DP_FCS:    pushfp_fcs(); return;
++              case DP_FDP:    pushfp_foo(); return;
++              case DP_FDS:    pushfp_fos(); return;
++              
++              case DP_XMM0:   push_xmm(0x4d); return;
++              case DP_XMM1:   push_xmm(0x4e); return;
++              case DP_XMM2:   push_xmm(0x4f); return;
++              case DP_XMM3:   push_xmm(0x50); return;
++              case DP_XMM4:   push_xmm(0x51); return;
++              case DP_XMM5:   push_xmm(0x52); return;
++              case DP_XMM6:   push_xmm(0x53); return;
++              case DP_XMM7:   push_xmm(0x54); return;
++              case DP_MXCSR:  pushfp_mxcsr(); return;
++
++              default:        val = 0; break;
++      }
++      rpnpush(val);
++      return;
++}
++
++/*
++ * Current register main pop function.
++ */
++static void popr(void)
++{
++      struct dprobes_struct *dp = &dprobes;
++      unsigned short index = get_u16_oprnd();
++      unsigned long val = rpnpop();
++      switch(index) {
++              case DP_DS:     dp->regs->xds = val; break;
++              case DP_ES:     dp->regs->xes = val; break;
++              case DP_FS:     write_fs(val); break;
++              case DP_GS:     write_gs(val); break;
++              case DP_EAX:    dp->regs->eax = val; break;
++              case DP_EBX:    dp->regs->ebx = val; break;
++              case DP_ECX:    dp->regs->ecx = val; break;
++              case DP_EDX:    dp->regs->edx = val; break;
++              case DP_EDI:    dp->regs->edi = val; break;
++              case DP_ESI:    dp->regs->esi = val; break;
++              case DP_EBP:    dp->regs->ebp = val; break;
++              default:        break;
++      }
++}
++
++/*
++ * User register main pop function.
++ */
++static void popu(void)
++{
++      struct dprobes_struct *dp = &dprobes;
++      unsigned short index = get_u16_oprnd();
++      unsigned long val = rpnpop();
++      switch(index) {
++              case DP_DS:     dp->uregs->xds = val; break;
++              case DP_ES:     dp->uregs->xes = val; break;
++              case DP_FS:     write_fs(val); break;
++              case DP_GS:     write_gs(val); break;
++              case DP_EAX:    dp->uregs->eax = val; break;
++              case DP_EBX:    dp->uregs->ebx = val; break;
++              case DP_ECX:    dp->uregs->ecx = val; break;
++              case DP_EDX:    dp->uregs->edx = val; break;
++              case DP_EDI:    dp->uregs->edi = val; break;
++              case DP_ESI:    dp->uregs->esi = val; break;
++              case DP_EBP:    dp->uregs->ebp = val; break;
++              default:        break;
++      }
++}
++
++/*
++ * Entry point for the dprobes interpreter(Probe handler).
++ */
++static void dp_asm_interpreter(byte_t rpn_instr)
++{
++      struct dprobes_struct *dp = &dprobes;
++
++              switch(rpn_instr) {
++
++                      case DP_SEG2LIN:        seg2lin(); break;               
++
++                      case DP_PUSH_IO_U8:     push_io_u8(); break;            
++                      case DP_PUSH_IO_U16:    push_io_u16(); break;           
++                      case DP_PUSH_IO_U32:    push_io_u32(); break;           
++                      case DP_POP_IO_U8:      pop_io_u8(); break;             
++                      case DP_POP_IO_U16:     pop_io_u16(); break;
++                      case DP_POP_IO_U32:     pop_io_u32(); break;
++
++                      default: gen_ex(EX_INVALID_OPCODE, *(dp->rpn_ip - 1),
++                      (unsigned long)(dp->rpn_ip -dp->rpn_code - 1)); break;          }
++      return;
++}
+diff -urNp linux.orig/drivers/dprobes/Makefile linux-2.6.0-test11/drivers/dprobes/Makefile
+--- linux.orig/drivers/dprobes/Makefile        1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.0-test11/drivers/dprobes/Makefile        2003-12-15 15:51:48.000000000 +0530
+@@ -0,0 +1,13 @@
++#
++# Makefile for IBM Dynamic Probes
++#
++
++# Multipart objects.
++dp-objs               := dprobes.o dprobes_in.o
++
++# Optional parts of multipart objects.
++ifeq ($(CONFIG_X86),y)
++      dp-objs += i386/dprobes.o
++endif
++
++obj-$(CONFIG_DPROBES) += dp.o
+diff -urNp linux.orig/drivers/Makefile linux-2.6.0-test11/drivers/Makefile
+--- linux.orig/drivers/Makefile        2003-11-27 02:15:19.000000000 +0530
++++ linux-2.6.0-test11/drivers/Makefile        2003-12-15 15:51:48.000000000 +0530
+@@ -49,3 +49,4 @@ obj-$(CONFIG_ISDN_BOOL)              += isdn/
+ obj-$(CONFIG_MCA)             += mca/
+ obj-$(CONFIG_EISA)            += eisa/
+ obj-$(CONFIG_CPU_FREQ)                += cpufreq/
++obj-$(CONFIG_DPROBES)         += dprobes/
+diff -urNp linux.orig/fs/exec.c linux-2.6.0-test11/fs/exec.c
+--- linux.orig/fs/exec.c       2003-11-27 02:13:36.000000000 +0530
++++ linux-2.6.0-test11/fs/exec.c       2003-12-15 15:51:48.000000000 +0530
+@@ -1391,3 +1391,4 @@ fail:
+       unlock_kernel();
+       return retval;
+ }
++EXPORT_SYMBOL(do_coredump);
+diff -urNp linux.orig/fs/namei.c linux-2.6.0-test11/fs/namei.c
+--- linux.orig/fs/namei.c      2003-11-27 02:13:34.000000000 +0530
++++ linux-2.6.0-test11/fs/namei.c      2003-12-15 15:51:48.000000000 +0530
+@@ -264,6 +264,18 @@ int deny_write_access(struct file * file
+       return 0;
+ }
++int deny_write_access_to_inode(struct inode * inode)
++{
++      spin_lock(&arbitration_lock);
++      if (atomic_read(&inode->i_writecount) > 0) {
++              spin_unlock(&arbitration_lock);
++              return -ETXTBSY;
++      }
++      atomic_dec(&inode->i_writecount);
++      spin_unlock(&arbitration_lock);
++      return 0;
++}
++
+ void path_release(struct nameidata *nd)
+ {
+       dput(nd->dentry);
+@@ -2307,3 +2319,8 @@ EXPORT_SYMBOL(vfs_rename);
+ EXPORT_SYMBOL(vfs_rmdir);
+ EXPORT_SYMBOL(vfs_symlink);
+ EXPORT_SYMBOL(vfs_unlink);
++#ifdef CONFIG_DPROBES_MODULE
++extern int deny_write_access_to_inode(struct inode *);
++EXPORT_SYMBOL(deny_write_access_to_inode);
++#endif
++
+diff -urNp linux.orig/include/asm-i386/debugreg.h linux-2.6.0-test11/include/asm-i386/debugreg.h
+--- linux.orig/include/asm-i386/debugreg.h     2003-11-27 02:15:08.000000000 +0530
++++ linux-2.6.0-test11/include/asm-i386/debugreg.h     2003-12-15 15:51:48.000000000 +0530
+@@ -61,4 +61,166 @@
+ #define DR_LOCAL_SLOWDOWN (0x100)   /* Local slow the pipeline */
+ #define DR_GLOBAL_SLOWDOWN (0x200)  /* Global slow the pipeline */
++struct debugreg {
++      unsigned long flag;
++      unsigned long use_count;
++};
++
++/* debugreg flags */
++#define DR_UNUSED     0
++#define DR_LOCAL      1
++#define DR_GLOBAL     2
++      
++#define DR_MAX        4
++#define DR_ANY        DR_MAX + 1
++
++/* global or local allocation requests */
++#define DR_ALLOC_GLOBAL               0
++#define DR_ALLOC_LOCAL                1
++
++#define DR7_RW_SET(dr, regnum, rw) do {       \
++              (dr) &= ~(0x3 << (16 + (4 * (regnum)))); \
++              (dr) |= (((rw) & 0x3) << (16 + (4 * (regnum)))); \
++      } while (0)
++
++#define DR7_RW_VAL(dr, regnum) \
++      (((dr) >> (16 + (4 * (regnum)))) & 0x3)
++
++#define DR7_LEN_SET(dr, regnum, len) do { \
++              (dr) &= ~(0x3 << (18 + (4 * (regnum)))); \
++              (dr) |= (((len-1) & 0x3) << (18 + (4 * (regnum)))); \
++      } while (0)
++
++#define DR7_LEN_VAL(dr, regnum) \
++      (((dr) >> (18 + (4 * (regnum)))) & 0x3)
++
++#define DR7_L0(dr)    (((dr))&0x1)
++#define DR7_L1(dr)    (((dr)>>2)&0x1)
++#define DR7_L2(dr)    (((dr)>>4)&0x1)
++#define DR7_L3(dr)    (((dr)>>6)&0x1)
++
++#define DR_IS_LOCAL(dr, num) ((dr) & (1UL << (num <<1)))
++
++/* Set the rw, len and global flag in dr7 for a debug register */
++#define SET_DR7(dr, regnum, access, len) do { \
++              DR7_RW_SET(dr, regnum, access); \
++              DR7_LEN_SET(dr, regnum, len); \
++              dr |= (2UL << regnum*2); \
++      } while (0)
++
++/* Disable a debug register by clearing the global/local flag in dr7 */
++#define RESET_DR7(dr, regnum) dr &= ~(3UL << regnum*2)
++
++#define DR7_DR0_BITS          0x000F0003
++#define DR7_DR1_BITS          0x00F0000C
++#define DR7_DR2_BITS          0x0F000030
++#define DR7_DR3_BITS          0xF00000C0
++
++#define DR_TRAP_MASK          0xF
++
++#define DR_TYPE_EXECUTE               0x0
++#define DR_TYPE_WRITE         0x1
++#define DR_TYPE_IO            0x2
++#define DR_TYPE_RW            0x3
++
++#define get_dr(regnum, val) \
++              __asm__("movl %%db" #regnum ", %0"  \
++                      :"=r" (val))
++static inline unsigned long read_dr(int regnum)
++{
++      unsigned long val = 0;
++      switch (regnum) {
++              case 0: get_dr(0, val); break;
++              case 1: get_dr(1, val); break;
++              case 2: get_dr(2, val); break;
++              case 3: get_dr(3, val); break;
++              case 6: get_dr(6, val); break;
++              case 7: get_dr(7, val); break;
++      }
++      return val;
++}
++#undef get_dr
++      
++#define set_dr(regnum, val) \
++              __asm__("movl %0,%%db" #regnum  \
++                      : /* no output */ \
++                      :"r" (val))
++static inline void write_dr(int regnum, unsigned long val)
++{
++      switch (regnum) {
++              case 0: set_dr(0, val); break;
++              case 1: set_dr(1, val); break;
++              case 2: set_dr(2, val); break;
++              case 3: set_dr(3, val); break;
++              case 7: set_dr(7, val); break;
++      }
++      return;
++}
++#undef set_dr
++
++#ifdef CONFIG_DEBUGREG
++/*
++ * Given the debug status register, returns the debug register number
++ * which caused the debug trap.
++ */
++static inline int dr_trap(unsigned int condition)
++{
++      int i, reg_shift = 1UL;
++      for (i = 0; i < DR_MAX; i++, reg_shift <<= 1)
++              if ((condition & reg_shift))
++                      return i;       
++      return -1;
++}
++
++/*
++ * Given the debug status register, returns the address due to which
++ * the debug trap occured.
++ */
++static inline unsigned long dr_trap_addr(unsigned int condition)
++{
++      int regnum = dr_trap(condition);
++
++      if (regnum == -1)
++              return -1;
++      return read_dr(regnum);
++}
++
++/*
++ * Given the debug status register, returns the type of debug trap:
++ * execute, read/write, write or io.
++ */
++static inline int dr_trap_type(unsigned int condition)
++{
++      int regnum = dr_trap(condition);
++
++      if (regnum == -1)
++              return -1;
++      return DR7_RW_VAL(read_dr(7), regnum);
++}
++
++/* Function declarations */
++
++extern int dr_alloc(int regnum, int flag);
++extern int dr_free(int regnum);
++extern void dr_inc_use_count(unsigned long mask);
++extern void dr_dec_use_count(unsigned long mask);
++extern struct debugreg dr_list[DR_MAX];
++extern unsigned long dr7_global_mask;
++extern int enable_debugreg(unsigned long old_dr7, unsigned long new_dr7);
++
++static inline void load_process_dr7(unsigned long curr_dr7)
++{
++      write_dr(7, (read_dr(7) & dr7_global_mask) | curr_dr7);
++}
++#else
++static inline int enable_debugreg(unsigned long old_dr7, unsigned long new_dr7) { return 0; }
++static inline void load_process_dr7(unsigned long curr_dr7)
++{
++      write_dr(7, curr_dr7);
++}
++
++static void dr_inc_use_count(unsigned long mask) { }
++static void dr_dec_use_count(unsigned long mask) { }
++
++#endif /* CONFIG_DEBUGREG */
+ #endif
+diff -urNp linux.orig/include/asm-i386/dprobes_exclude.h linux-2.6.0-test11/include/asm-i386/dprobes_exclude.h
+--- linux.orig/include/asm-i386/dprobes_exclude.h      1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.0-test11/include/asm-i386/dprobes_exclude.h      2003-12-15 15:51:48.000000000 +0530
+@@ -0,0 +1,84 @@
++#ifndef __ASM_I386_DPROBES_EXCLUDE_H__
++#define __ASM_I386_DPROBES_EXCLUDE_H__
++
++/*
++ * IBM Dynamic Probes
++ * Copyright (c) International Business Machines Corp., 2000
++ *
++ * 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.  
++ */
++
++/*
++ * Exclude regions markers: We do not allow probes to be placed in these
++ * code areas to _prevent_ recursion into dp_trap3. Note that this does
++ * not eliminate the possibility of recursion completely. dp_trap3 handles
++ * recursion by silently and permanently removing the recursed probe point.
++ */
++#include <linux/kprobes.h>
++#include <asm/kwatch.h>
++
++extern void kprobes_code_start(void);
++extern void kprobes_code_end(void);
++extern void kprobes_asm_code_start(void);
++extern void kprobes_asm_code_end(void);
++extern void dprobes_code_start(void);
++extern void dprobes_code_end(void);
++extern void dprobes_asm_code_start(void);
++extern void dprobes_asm_code_end(void);
++extern void dprobes_interpreter_code_start(void);
++extern void dprobes_interpreter_code_end(void);
++
++#ifdef CONFIG_DR_ALLOC
++extern void kwatch_asm_start(void);
++extern void kwatch_asm_end(void);
++#endif
++
++struct region {
++      unsigned long start;
++      unsigned long end;
++};
++
++#define NR_EXCLUDED_REGIONS 6
++static struct region exclude[] = {
++#ifdef CONFIG_DR_ALLOC
++      {(unsigned long)kwatch_asm_start,
++              (unsigned long)kwatch_asm_end},
++#else 
++      {0, 0},
++#endif
++      {(unsigned long)kprobes_code_start,
++              (unsigned long)kprobes_code_end},
++      {(unsigned long)kprobes_asm_code_start,
++              (unsigned long)kprobes_asm_code_end},
++      {(unsigned long)dprobes_code_start,
++              (unsigned long)dprobes_code_end},
++      {(unsigned long)dprobes_asm_code_start,
++              (unsigned long)dprobes_asm_code_end},
++      {(unsigned long)dprobes_interpreter_code_start,
++              (unsigned long)dprobes_interpreter_code_end}
++};
++
++static inline int dprobes_excluded(unsigned long addr)
++{
++      int i;
++      for (i = 0; i < NR_EXCLUDED_REGIONS; i++) {
++              if (addr >= exclude[i].start && addr <= exclude[i].end) {
++                      return 1;
++              }
++      }
++      return 0;
++}
++
++#endif /* __ASM_I386_DPROBES_EXCLUDE_H__ */
+diff -urNp linux.orig/include/asm-i386/dprobes.h linux-2.6.0-test11/include/asm-i386/dprobes.h
+--- linux.orig/include/asm-i386/dprobes.h      1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.0-test11/include/asm-i386/dprobes.h      2003-12-15 15:51:48.000000000 +0530
+@@ -0,0 +1,202 @@
++#ifndef __ASM_I386_DPROBES_H__
++#define __ASM_I386_DPROBES_H__
++
++/*
++ * IBM Dynamic Probes
++ * Copyright (c) International Business Machines Corp., 2000
++ *
++ * 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.  
++ */
++
++/*
++ * RPN stack width will always be equal to the machine register width.
++ */
++#define RPN_STACK_SIZE        1024
++#define CALL_FRAME_SIZE               10
++#define NR_NESTED_CALLS               32
++/* 1st is a dummy frame, not used by call instruction */
++#define CALL_STACK_SIZE               (NR_NESTED_CALLS+1)*CALL_FRAME_SIZE 
++#define FMT_LOG_HDR_SIZE      256
++
++/* Offsets of different items on call stack */
++#define OFFSET_SBP            0
++#define OFFSET_GV_RANGE               1
++#define OFFSET_LV_RANGE               3
++#define OFFSET_RPN_STACK_RANGE        5
++#define OFFSET_EX_HANDLER     7
++#define OFFSET_CALLED_ADDR    8
++#define OFFSET_RETURN_ADDR    9
++
++/* 
++ * offsets of different repitition entries (3 byte prefix) in the 
++ * exception stacktrace buffer.
++ */
++struct ex_buffer_offset {
++      unsigned long st;       /* ex stack traces */
++      unsigned long sf;       /* ex stack frames */
++      unsigned long rpn;      /* rpn stack entries */
++      unsigned long lv;       /* lv entries */
++      unsigned long gv;       /* gv entries */
++};
++
++/* Token bytes of all available 3 byte prefixes */
++#define TOKEN_SEG_FAULT               -2
++#define TOKEN_MEMORY_FAULT    -1
++#define TOKEN_MEMORY_LOG      0
++#define TOKEN_ASCII_LOG               1
++#define TOKEN_STACK_TRACE     2
++#define TOKEN_STACK_FRAME     3
++#define TOKEN_RPN_ENTRY               4
++#define TOKEN_LV_ENTRY                5
++#define TOKEN_GV_ENTRY                6
++#define TOKEN_LOG             7
++
++#define PREFIX_SIZE           3
++
++struct dprobes_struct {
++      unsigned long status;   /* status */
++      /*
++       * details about the probe that is hit, kept here for quick access at
++       * trap1 time.
++       */
++      unsigned long probe_addr;
++      struct pt_regs *regs;
++      struct pt_regs *uregs;
++      struct dp_module_struct *mod;
++      struct dp_record_struct *rec;
++
++      /* fpu registers are saved here */
++      union i387_union fpu_save_area;
++
++      /*
++       * Optional data to store with the log record. This data is collected
++       * in the interpreter and used in the trap1 handler when writing the
++       * log to the specified log target.
++       */
++      unsigned long eip;
++      unsigned short cs;
++      unsigned long esp;
++      unsigned short ss;
++      unsigned short major, minor;
++
++      /*
++       * per-processor data used by the interpreter.
++       */
++      unsigned long rpn_tos, call_tos, log_len, prev_log_len, ex_log_len;
++      byte_t * rpn_code;
++      byte_t * rpn_ip;
++      unsigned short jmp_count;
++      byte_t opcode;
++      byte_t reserved;
++      byte_t ex_pending;
++      unsigned long ex_code;
++      unsigned long ex_parm1, ex_parm2, ex_hand;
++      struct ex_buffer_offset ex_off;
++      unsigned long rpn_sbp;
++      unsigned long heap_size;
++
++      /*
++       * locks used to handle recursion.
++       */
++      spinlock_t lock;
++      long sem;
++
++      unsigned long rpn_stack[RPN_STACK_SIZE];
++      unsigned long call_stack[CALL_STACK_SIZE];
++      unsigned char log[LOG_SIZE];
++      unsigned char ex_log[EX_LOG_SIZE];
++      unsigned char log_hdr[FMT_LOG_HDR_SIZE];
++};
++
++/*
++ * status
++ *
++ * DP_KENREL_PROBE: When this is set, we will not use the pte* fields in the
++ * alias structure at trap1 time, we can write directly to the probe_addr.
++ *
++ * DP_STATUS_ERROR: Contains all the bits to check for error conditions.
++ *
++ * DP_STATUS_DONE: Contains all the per-probe hit bits that need to be turned
++ * off after a probe handler is executed.
++ *
++ * DP_STATUS_ABORT: Indicates that the designated exit facility should not
++ * be called after the original instruction is successfully single-stepped.
++ */
++#define DP_STATUS_INACTIVE      0x00000000
++#define DP_STATUS_ACTIVE      0x00000001
++
++#define DP_STATUS_ERROR               0x00ff0000
++#define DP_STATUS_GPF         0x00010000
++#define DP_STATUS_PF          0x00020000
++#define DP_STATUS_LOG_OVERFLOW        0x00040000
++
++#define DP_STATUS_INTERPRETER   0x01000000
++#define DP_STATUS_SS          0x02000000
++#define DP_KERNEL_PROBE               0x04000000
++#define DP_USER_PROBE         0x08000000
++#define DP_STATUS_ABORT               0x10000000
++#define DP_STATUS_FIRSTFPU    0x20000000
++#define DP_STATUS_DONE                0xffff0000
++
++#define DP_INSTR_BREAKPOINT   0xcc
++
++/* arch-specific rec flags */
++#define DP_REC_OPCODE_EMULATED                0x01000000
++#define DP_REC_OPCODE_IF_MODIFIER     0x02000000
++
++#ifndef EF_CF
++#define EF_CF 0x00000001
++#endif
++#ifndef EF_TF
++#define EF_TF 0x00000100
++#endif
++#ifndef EF_IE
++#define EF_IE 0x00000200
++#endif
++#ifndef EF_DF
++#define EF_DF 0x00000400
++#endif
++#ifndef EF_RF
++#define EF_RF 0x00010000
++#endif
++
++#define CR0_TS  0x00000008
++
++#ifndef HAVE_HWFP
++#ifdef CONFIG_MATH_EMULATION
++#define HAVE_HWFP (boot_cpu_data.hard_math)
++#else
++#define HAVE_HWFP 1
++#endif
++#endif
++
++/*
++ *  Function declarations
++ */
++extern void dp_interpreter(void);
++extern int dp_gpf(struct pt_regs *);
++extern int dp_pf(struct pt_regs *);
++extern int dp_handle_fault(struct pt_regs *);
++extern int dp_do_debug(struct pt_regs *, unsigned long);
++extern int dp_trap1(struct pt_regs *);
++extern int dp_trap(struct pt_regs *, int, unsigned int, unsigned long);
++extern int __remove_probe(byte_t *, struct dp_record_struct *);
++extern int __insert_probe(byte_t *, struct dp_record_struct *, struct dp_module_struct *, struct page *);
++extern int register_userspace_probes(struct dp_record_struct *);
++extern void unregister_userspace_probes(struct dp_record_struct *);
++extern inline int insert_probe_userspace(byte_t *, struct dp_record_struct *, struct page *, struct vm_area_struct *);
++extern inline int remove_probe_userspace(byte_t *, struct dp_record_struct *, struct page *, struct vm_area_struct *);
++
++#endif
+diff -urNp linux.orig/include/asm-i386/dprobes_in.h linux-2.6.0-test11/include/asm-i386/dprobes_in.h
+--- linux.orig/include/asm-i386/dprobes_in.h   1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.0-test11/include/asm-i386/dprobes_in.h   2003-12-15 15:51:48.000000000 +0530
+@@ -0,0 +1,120 @@
++#ifndef __ASM_I386_DPROBES_IN_H__
++#define __ASM_I386_DPROBES_IN_H__
++
++/*
++ * IBM Dynamic Probes
++ * Copyright (c) International Business Machines Corp., 2000
++ *
++ * 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.  
++ */
++
++/*
++ * This header file defines the opcodes for the RPN instructions
++ *
++ * Opcodes 0x00 to 0xAF are for common, arch-independent instructions.
++ * Opcodes 0xB0 to 0xDF are for arch-dependent instructions.
++ * Opcodes 0xF1 to 0xFF are for two byte instructions.
++ */
++
++/*
++ * Misc
++ */
++#define DP_SEG2LIN            0xB0
++
++/*
++ * IO Group.
++ */
++#define DP_PUSH_IO_U8         0xB1
++#define DP_PUSH_IO_U16                0xB2
++#define DP_PUSH_IO_U32                0xB3
++#define DP_POP_IO_U8          0xB4
++#define DP_POP_IO_U16         0xB5
++#define DP_POP_IO_U32         0xB6
++
++/*
++ * Intel32 Register Assignments.
++ */
++#define DP_CS                 0x0000
++#define DP_DS                 0x0001
++#define DP_ES                 0x0002
++#define DP_FS                 0x0003
++#define DP_GS                 0x0004
++#define DP_SS                 0x0005
++#define DP_EAX                        0x0006
++#define DP_EBX                        0x0007
++#define DP_ECX                        0x0008
++#define DP_EDX                        0x0009
++#define DP_EDI                        0x000a
++#define DP_ESI                        0x000b
++#define DP_EFLAGS             0x000c
++#define DP_EIP                        0x000d
++#define DP_ESP                        0x000e
++#define DP_EBP                        0x000f
++
++#define DP_TR                 0x0020
++#define DP_LDTR                       0x0021
++#define DP_GDTR                       0x0022
++#define DP_IDTR                       0x0023
++#define DP_CR0                        0x0024
++#define DP_CR1                        0x0025
++#define DP_CR2                        0x0026
++#define DP_CR3                        0x0027
++#define DP_CR4                        0x0028
++
++#define DP_DR0                        0x002c
++#define DP_DR1                        0x002d
++#define DP_DR2                        0x002e
++#define DP_DR3                        0x002f
++#define DP_DR4                        0x0030
++#define DP_DR5                        0x0031
++#define DP_DR6                        0x0032
++#define DP_DR7                        0x0033
++
++#define DP_CPUID              0x003c
++#define DP_MSR                        0x003d
++
++#define DP_FR0                        0x003e
++#define DP_FR1                        0x003f
++#define DP_FR2                        0x0040
++#define DP_FR3                        0x0041
++#define DP_FR4                        0x0042
++#define DP_FR5                        0x0043
++#define DP_FR6                        0x0044
++#define DP_FR7                        0x0045
++#define DP_FCW                        0x0046
++#define DP_FSW                        0x0047
++#define DP_FTW                        0x0048
++#define DP_FIP                        0x0049
++#define DP_FCS                        0x004a
++#define DP_FDP                        0x004b
++#define DP_FDS                        0x004c
++
++#define DP_XMM0                       0x004d
++#define DP_XMM1                       0x004e
++#define DP_XMM2                       0x004f
++#define DP_XMM3                       0x0050
++#define DP_XMM4                       0x0051
++#define DP_XMM5                       0x0052
++#define DP_XMM6                       0x0053
++#define DP_XMM7                       0x0054
++#define DP_MXCSR              0x0055
++
++#ifndef __KERNEL__
++#ifndef PAGE_OFFSET
++#define PAGE_OFFSET           0xc0000000
++#endif
++#endif /* !__KERNEL__ */
++
++#endif
+diff -urNp linux.orig/include/asm-i386/kprobes.h linux-2.6.0-test11/include/asm-i386/kprobes.h
+--- linux.orig/include/asm-i386/kprobes.h      1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.0-test11/include/asm-i386/kprobes.h      2003-12-15 15:51:48.000000000 +0530
+@@ -0,0 +1,38 @@
++#ifndef _ASM_KPROBES_H
++#define _ASM_KPROBES_H
++/*
++ *  Dynamic Probes (kprobes) support
++ *    Vamsi Krishna S <vamsi_krishna@in.ibm.com>, July, 2002
++ *    Mailing list: dprobes@www-124.ibm.com
++ */
++#include <linux/types.h>
++#include <linux/ptrace.h>
++
++struct pt_regs;
++
++typedef u8 kprobe_opcode_t;
++#define BREAKPOINT_INSTRUCTION        0xcc
++#define MAX_INSN_SIZE 16
++
++/* trap3/1 are intr gates for kprobes.  So, restore the status of IF,
++ * if necessary, before executing the original int3/1 (trap) handler.
++ */
++static inline void restore_interrupts(struct pt_regs *regs)
++{
++      if (regs->eflags & IF_MASK)
++              __asm__ __volatile__ ("sti");
++}
++
++void kprobes_asm_code_start(void);
++void kprobes_asm_code_end(void);
++
++#ifdef CONFIG_KPROBES
++extern int kprobe_fault_handler(struct pt_regs *regs, int trapnr);
++extern int post_kprobe_handler(struct pt_regs *regs);
++extern int kprobe_handler(struct pt_regs *regs);
++#else /* !CONFIG_KPROBES */
++static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr) { return 0; }
++static inline int post_kprobe_handler(struct pt_regs *regs) { return 0; }
++static inline int kprobe_handler(struct pt_regs *regs) { return 0; }
++#endif
++#endif /* _ASM_KPROBES_H */
+diff -urNp linux.orig/include/asm-i386/kwatch.h linux-2.6.0-test11/include/asm-i386/kwatch.h
+--- linux.orig/include/asm-i386/kwatch.h       1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.0-test11/include/asm-i386/kwatch.h       2003-12-15 15:51:48.000000000 +0530
+@@ -0,0 +1,31 @@
++#ifndef _ASM_KWATCH_H
++#define _ASM_KWATCH_H
++/*
++ * Dynamic Probes (kwatch points) support
++ *    Vamsi Krishna S <vamsi_krishna@in.ibm.com>, Oct, 2002
++ */
++#include <linux/types.h>
++#include <linux/ptrace.h>
++
++struct kwatch;
++typedef void (*kwatch_handler_t)(struct kwatch *, struct pt_regs *, int );
++
++struct kwatch {
++      unsigned long addr;     /* location of watchpoint */
++      u8 length;      /* range of address */
++      u8 type;        /* type of watchpoint */
++      kwatch_handler_t handler;
++};
++
++#define RF_MASK       0x00010000
++
++#ifdef CONFIG_KWATCH
++extern int register_kwatch(unsigned long addr, u8 length, u8 type, kwatch_handler_t handler);
++extern void unregister_kwatch(int debugreg);
++extern int kwatch_handler(unsigned long condition, struct pt_regs *regs);
++#else
++static inline int register_kwatch(unsigned long addr, u8 length, u8 type, kwatch_handler_t handler) { return -ENOSYS; }
++static inline void unregister_kwatch(int debugreg) { }
++static inline int kwatch_handler(unsigned long condition, struct pt_regs *regs) { return 0; }
++#endif
++#endif /* _ASM_KWATCH_H */
+diff -urNp linux.orig/include/linux/dprobes.h linux-2.6.0-test11/include/linux/dprobes.h
+--- linux.orig/include/linux/dprobes.h 1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.0-test11/include/linux/dprobes.h 2003-12-15 15:51:48.000000000 +0530
+@@ -0,0 +1,450 @@
++#ifndef _LINUX_DPROBES_H
++#define _LINUX_DPROBES_H
++
++/*
++ * IBM Dynamic Probes
++ * Copyright (c) International Business Machines Corp., 2000
++ *
++ */
++
++#ifdef __KERNEL__
++#include <linux/types.h>
++#else
++#include <sys/types.h>
++#endif
++
++#define DP_MAJOR_VER  5
++#define DP_MINOR_VER  0
++#define DP_PATCH_VER  0
++
++/* main command codes */
++#define DP_CMD_MASK           0x000000ff
++#define DP_INSERT             0x00000001
++#define DP_REMOVE             0x00000002
++#define DP_GETVARS            0x00000004
++#define DP_QUERY              0x00000008
++#define DP_HELP                       0x00000010
++#define DP_VERSION            0x00000020
++#define DP_BUILDPPDF          0x00000040
++#define DP_APPLYPPDF          0x00000080
++
++/* command modifiers */
++#define DP_FLAGS_MASK         0xff000000
++#define DP_ALL                        0x80000000
++
++/* insert cmd modifiers */
++#define DP_MERGE              0x01000000
++#define DP_REPLACE            0x02000000
++#define DP_STOP_CPUS          0x04000000
++#define DP_DONT_VERIFY_OPCODES        0x08000000
++#define DP_AUTOSTACKTRACE     0x10000000
++
++/* getvars cmd modifiers */
++#define DP_GETVARS_INDEX      0x01000000
++#define DP_GETVARS_RESET      0x02000000
++#define DP_GETVARS_LOCAL      0x04000000
++#define DP_GETVARS_GLOBAL     0x08000000
++
++/* query cmd modifiers */
++#define DP_QUERY_EXTENDED     0x01000000
++
++/* pgm->flags: default data that will be part of each log record */
++#define DP_LOG_MASK           0x0000ff00
++#define DP_LOG_PROCNAME               0x00000100
++#define DP_LOG_PID            0x00000200
++#define DP_LOG_UID            0x00000400
++#define DP_LOG_NIP             0x00000800
++#define DP_LOG_PSW             0x00000800
++#define DP_LOG_UPSW            0x00001000
++#define DP_LOG_SS_ESP         0x00000800
++#define DP_LOG_CS_EIP         0x00001000
++#define DP_LOG_TSC            0x00002000
++#define DP_LOG_CPU            0x00004000
++#define DP_LOG_ALL            0x0000ff00
++
++/* pgm->flags: default log target */
++#define DP_LOG_TARGET_MASK    0x00ff0000
++#define DP_LOG_TARGET_KLOG    0x00010000
++#define DP_LOG_TARGET_LTT     0x00020000
++#define DP_LOG_TARGET_COM1    0x00040000
++#define DP_LOG_TARGET_COM2    0x00080000
++#define DP_LOG_TARGET_EVL     0x00100000
++#define DP_UNFORMATTED_OUTPUT 0x00200000
++
++/* exit facilities for use with "exit_to" instruction */
++#define DP_EXIT_TO_SGI_KDB    0x01
++#define DP_EXIT_TO_SGI_VMDUMP 0x02
++#define DP_EXIT_TO_CORE_DUMP  0x03
++
++/* bit flags to indicate elements present in the trace buffer header. */
++#define DP_HDR_MAJOR          0x00000001
++#define DP_HDR_MINOR          0x00000002
++#define DP_HDR_CPU            0x00000004
++#define DP_HDR_PID            0x00000008
++#define DP_HDR_UID            0x00000010
++#define DP_HDR_CS             0x00000020
++#define DP_HDR_EIP            0x00000040
++#define DP_HDR_SS             0x00000080
++#define DP_HDR_ESP            0x00000100
++#define DP_HDR_TSC            0x00000200
++#define DP_HDR_PROCNAME               0x00000400
++
++typedef unsigned char byte_t;
++/* FIXME: Well, we're working on getting this in arch headers */
++#if defined(CONFIG_X86) || defined(CONFIG_IA64)
++typedef byte_t opcode_t;
++#endif
++
++/*
++ * This captures the header information of each probe point. It also contains
++ * links to the rpn code of this dprobe handler.
++ *
++ * maxhits: This field indicates the number of times this probe will be
++ * executed before being disabled. A negative value here means that the
++ * probe will not be disabled automatically.
++ *
++ * count: This field keeps track of number of times this probe is hit,
++ * and executed successfully. There is a reason this is "long" and not
++ * "unsigned long". We would implement "pass-count" feature that specifies
++ * the number of times we pass over this probe with actually executing the
++ * probe handler, using the fact that count is a signed value.
++ */
++struct dp_point_struct {
++      loff_t offset;  /* file offset or absolute address */
++      unsigned short address_flag;
++      opcode_t opcode;
++      opcode_t actual_opcode; /* in case of opcode mismatch */
++      unsigned short major;
++      unsigned short minor;
++      unsigned short group;
++      unsigned short type;
++      unsigned long rpn_offset; /* offset into rpn_code of dp_pgm_struct */
++      unsigned long rpn_end;
++      unsigned short probe; /* watchpoint info, probe and access types */
++      unsigned long len;      /* range of the watchpoint probe */
++      int dbregno;    /* the debug reg used for this watchpoint */
++      long maxhits;
++      long passcount;
++      unsigned char logonfault;
++      unsigned short ex_mask;
++      unsigned long heap_size; /* no of heap elements specified by this probe */
++};
++
++#define DP_ADDRESS_ABSOLUTE   0x0001
++
++/*
++ * Flags related to watchpoint probes.
++ */
++#define DP_PROBE_BREAKPOINT   0x8000
++#define DP_PROBE_WATCHPOINT   0x4000
++#define DP_PROBE_MASK         0xc000
++#define DP_MAX_WATCHPOINT     0x4 /* maximum number of watchpoint probes */
++
++#define DP_WATCHTYPE_EXECUTE  0x0000
++#define DP_WATCHTYPE_WRITE    0x0001
++#define DP_WATCHTYPE_IO               0x0002
++#define DP_WATCHTYPE_RDWR     0x0003
++#define DP_WATCHTYPE_MASK     0x0003
++
++/*
++ * This captures the information specified in the dprobe program file header.
++ *
++ * User application passes the details of the pgm header to the system call in
++ * this structure. It is also used in the kernel as part of dp_module_struct.
++ */
++struct dp_pgm_struct {
++      unsigned char *name; /* module for which the probe program is written */
++      unsigned long flags;
++      unsigned short major;
++      unsigned long id;
++      unsigned short jmpmax;
++      unsigned short logmax;
++      unsigned short ex_logmax; /* length of exception stack trace buffer */ 
++      unsigned short num_lv;  /* num of local variables */
++      unsigned short num_gv;  /* num of global variables */
++      unsigned long heapmax; /* num of heap elements required 
++                                 by this probe program */
++
++      unsigned short rpn_length; /* rpn code */
++      unsigned char autostacktrace;
++      byte_t *rpn_code;
++
++      unsigned short align; /* kernel module alignment */
++      unsigned short num_points;
++      struct dp_point_struct *point;
++};
++
++/* pgm flags */
++#define DP_MODTYPE_MASK               0x000f
++#define DP_MODTYPE_USER               0x0001
++#define DP_MODTYPE_KERNEL     0x0002
++#define DP_MODTYPE_KMOD               0x0004
++
++#define LOG_SIZE              1024
++#define EX_LOG_SIZE           1024
++#define JMP_MAX                       65535
++#define MAX_MAXHITS           0x7fffffff
++#define HEAPMAX                       16*1024
++
++#define DEFAULT_LOGMAX                LOG_SIZE
++#define DEFAULT_EX_LOG_MAX    EX_LOG_SIZE
++#define DEFAULT_JMPMAX                JMP_MAX
++#define DEFAULT_MAXHITS               MAX_MAXHITS
++#define DEFAULT_HEAPMAX               HEAPMAX
++
++/* compiled in limits */
++#define DP_MAX_LVARS          256
++#define DP_MAX_GVARS          256
++
++/* exception codes */
++#define EX_INVALID_ADDR         0x0001
++#define EX_SEG_FAULT            0x0002
++#define EX_MAX_JMPS             0x0004
++#define EX_CALL_STACK_OVERFLOW  0x0010
++#define EX_DIV_BY_ZERO          0x0020
++#define EX_INVALID_OPERAND      0x0040
++#define EX_INVALID_OPCODE       0x0080
++#define EX_HEAP_NOMEM         0x0100
++#define EX_HEAP_INVALID_HANDLE        0x0200
++#define EX_HEAP_INVALID_OFFSET        0x0400
++#define EX_LOG_OVERFLOW         0x1000
++#define EX_RPN_STACK_WRAP       0x2000
++#define EX_USER                 0x8000
++#define DEFAULT_EX_MASK         0x0fff
++
++/* If a non-maskable ex is masked out, the interpreter will be terminated. */
++#define EX_NON_MASKABLE_EX      0x0fff
++
++#define EX_NO_HANDLER         0xffffffff
++
++/*
++ * This defines the Dynamic Probe getvars Request Packet, passed in from
++ * the user for subfunction DP_GETVARS.
++ */
++struct  dp_getvars_in_struct  {
++      unsigned char *name;    /* loadable module name */
++      unsigned short from;
++      unsigned short to;
++      unsigned long allocated; /* Allocated size of result pkt */
++      unsigned long returned; /* Returned size of result pkt */
++};
++
++/*
++ * The output from getvars command is returned in this format. First all
++ * global variables will be there as dp_getvars_global_out_struct followed
++ * by local variables for each module in form of dp_getvars_local_out_struct.
++ */
++struct  dp_getvars_global_out_struct  {
++      unsigned long num_vars; /* number of the variables to follow */
++      /* variables */
++};
++
++struct dp_getvars_local_out_struct {
++      unsigned long length;  /* length of this element */
++      unsigned long num_vars; /* number of the variables to follow */
++      /* variables followed by the name of loadable module*/
++};
++
++/*
++ * This defines the Dynamic Probe query Request Packet passed in
++ * from the user for subfunction DP_QUERY.
++ */
++struct dp_query_in_struct {
++      unsigned char *name; /* loadable module name */
++      unsigned long allocated; /* Allocated size of result pkt */
++      unsigned long returned; /* Returned size of result pkt */
++};
++
++struct dp_outrec_struct {
++      unsigned long status;
++      long count;
++      int dbregno;    /* the debug reg used for this watchpoint */
++      struct dp_point_struct point;
++};
++
++/*
++ * flags
++ *
++ * Initially a probe record starts out with zero flags.
++ *
++ * DP_REC_STATUS_COMPILED: A probe record is compiled, after successfully
++ * validating the rpn code.
++ *
++ * DP_REC_STATUS_ACTIVE: A probe record becomes valid after it is verified
++ * that the opcode as specified in the probe program matches with the one
++ * at the specified location. We would probably do this verification the
++ * first time this probe is inserted.
++ *
++ * DP_REC_STATUS_MISMATCH: This means the opcode specified by the probe
++ * does not match with the one present when we try to insert it.
++ *
++ * DP_REC_STATUS_DISABLED: A probe will be disabled after being executed
++ * for max-hit number of times automatically.
++ *
++ * DP_REC_STATUS_REMOVED: The status of a probe will be removed if user
++ * explicitly removes it using dprobe --remove --major-minor command.
++ * Note that if a specific probe is removed by its major-minor, we
++ * don't remove the dp_record_struct from memory as it is too much
++ * work. We simply note that fact in the status flags and leave the
++ * dp_record_struct alone. But, if an entire probe program is removed,
++ * all its structures will be removed permanently.
++ *
++ * DP_REC_STATUS_INVALID_OFFSET: Set if the address specified for probe insertion
++ * is out of bounds for that executable module. 
++ *
++ * DP_REC_STATUS_DEBUGREG_UNAVAIL: Set if the probe is of type watchpoint and
++ * no free debug registers are free for use.
++ * 
++ * DP_REC_STATUS_WATCHPOINT_LEN_INVALID: Set if the probe is of type watchpoint
++ * and the range of address specified is not valid.
++ */
++#define DP_REC_STATUS_COMPILED                0x00000001
++#define DP_REC_STATUS_ACTIVE                  0x00000002
++#define DP_REC_STATUS_MISMATCH                        0x00000004
++#define DP_REC_STATUS_DISABLED                0x00000008
++#define DP_REC_STATUS_REMOVED                 0x00000010
++#define DP_REC_STATUS_INVALID_OFFSET          0x00000020
++#define DP_REC_STATUS_DEBUGREG_UNAVAIL                0x00000040
++#define DP_REC_STATUS_WATCHPOINT_LEN_INVALID  0x00000080
++#define DP_REC_STATUS_DEBUGREG_PATCH_NEEDED   0x00000100
++#define DP_REC_STATUS_KPROBE_ERR              0x00000200
++#define DP_REC_STATUS_EXCLUDED                        0x00000400
++#define DP_REC_ARCH_FLAGS                     0xff000000
++
++struct dp_outmod_struct {
++      struct dp_outmod_struct *next;  /* link */
++      unsigned long flags;    /* cmdline switches */
++      struct dp_outrec_struct * rec;  /* array of dp_outrec_structs. */
++      unsigned long * lv;     /* local variables */
++      struct dp_pgm_struct pgm;
++      unsigned long base;
++      unsigned long end;
++};
++
++struct dp_ioctl_arg {
++      void * input;
++      void * output;
++      unsigned long cmd;
++};
++
++/* 
++ * This should ideally be 2*HEAP_HDR_SIZE, but the latter is 
++ *  __KERNEL__  specific. Hence hardcoded here.
++ */
++#define MIN_HEAP_SIZE 40
++
++#ifdef __KERNEL__
++
++#include <linux/sched.h>
++#include <linux/dcache.h>
++#include <linux/namei.h>
++#include <linux/mm.h>
++#include <linux/kprobes.h>
++#include <asm/page.h>
++#include <asm/pgtable.h>
++#include <asm/ptrace.h>
++
++struct dp_record_struct {
++      struct kprobe kp;
++      struct uprobe up;
++      struct dp_module_struct *mod;
++      spinlock_t lock;
++      unsigned long status;
++      long count;
++      int dbregno;    /* the debug reg used for this watchpoint */
++      struct dp_point_struct point;
++};
++
++/* 
++ * When Dprobes stores it's log in a trace buffer, the log data is preceded
++ * by the header information as in this structure, followed by optional 
++ * header elements.
++ */
++#define DP_TRACE_HDR_ID 1
++struct dp_trace_hdr_struct {
++      unsigned short facility_id;
++      unsigned short len;
++      unsigned long mask;
++      unsigned short major;
++      unsigned short minor;
++};
++
++#ifdef CONFIG_SMP
++#define MIN_ST_SIZE   sizeof(struct dp_trace_hdr_struct) + sizeof(int)
++#else
++#define MIN_ST_SIZE   sizeof(struct dp_trace_hdr_struct)
++#endif
++
++/* Major number 0 is reserved for stack trace log record */
++#define DP_ST_MAJOR   0x0000
++#define DP_ST_MINOR   0x0000
++
++/*
++ * This is the data structure that we maintain in kernel for each module
++ * that has any probes applied on it.
++ */
++struct dp_module_struct {
++      struct dp_module_struct *next;  /* link */
++      unsigned long flags;
++      struct dp_record_struct * rec;  /* array of dp_record_structs. */
++      unsigned long * lv;     /* local variables */
++      struct inode * inode;   /* for quicker access to inode */
++      int trace_id;           /* ltt trace event id */
++      struct dp_trace_hdr_struct hdr;
++      struct dp_pgm_struct pgm;
++      unsigned long base; /* used to store kmod base address */
++      unsigned long end; /* used to store kmod base address */
++      struct nameidata nd; /* to hold path/dentry etc. */
++      struct address_space_operations * ori_a_ops;
++      struct address_space_operations dp_a_ops;
++};
++
++/* flags used to keep track of allocations */
++#define DP_MOD_FLAGS_LARGE_REC        0x01
++
++#ifdef CONFIG_SMP
++extern struct dprobes_struct dprobes_set[];
++#define dprobes dprobes_set[smp_processor_id()]
++#else 
++extern struct dprobes_struct dprobes;
++#define dprobes_set (&dprobes)
++#endif /* CONFIG_SMP */
++
++/*extern char _stext, _etext;  kernel start and end */
++
++/*
++ * global variables stuff
++ */
++extern unsigned long *dp_gv;
++extern unsigned long dp_num_gv;
++extern rwlock_t dp_gv_lock;
++
++extern byte_t *dp_heap;
++extern unsigned long dp_num_heap;
++extern rwlock_t dp_heap_lock;
++
++extern int dp_insmod(struct module *kmod);
++extern int dp_remmod(struct module *kmod);
++extern int dp_readpage(struct file *, struct page *);
++extern int dp_writepage(struct page *page);
++
++#define IS_COW_PAGE(page, inode) (!(page->mapping) || \
++      (page->mapping->host != (void *)inode)) 
++
++#include <linux/list.h>
++struct heap_hdr {
++      byte_t *addr;
++      unsigned char flags;
++      unsigned long size;
++      struct list_head list;
++};
++
++#define HEAP_HDR_SIZE sizeof(struct heap_hdr)
++#define HEAP_FREE     1
++#define       HEAP_ALLOCATED  2
++
++#include <asm/dprobes.h>
++
++#endif /* __KERNEL__ */
++
++#endif
+diff -urNp linux.orig/include/linux/dprobes_in.h linux-2.6.0-test11/include/linux/dprobes_in.h
+--- linux.orig/include/linux/dprobes_in.h      1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.0-test11/include/linux/dprobes_in.h      2003-12-15 15:51:48.000000000 +0530
+@@ -0,0 +1,218 @@
++#ifndef _LINUX_DPROBES_IN_H
++#define _LINUX_DPROBES_IN_H
++
++/*
++ * IBM Dynamic Probes
++ * Copyright (c) International Business Machines Corp., 2000
++ */
++
++/*
++ * This header file defines the opcodes for the RPN instructions.
++ *
++ * Opcodes 0x00 to 0xAF are for common, arch-independent instructions.
++ * Opcodes 0xB0 to 0xDF are for arch-dependent instructions.
++ * Opcodes 0xF1 to 0xFF are for two byte instructions.
++ */
++
++#define DP_NOP                        0x00                                    
++
++/*
++ * RPN execution group.
++ */
++#define DP_JMP                        0x01
++#define DP_JLT                        0x02
++#define DP_JLE                        0x03
++#define DP_JGT                        0x04
++#define DP_JGE                        0x05
++#define DP_JZ                 0x06
++#define DP_JNZ                        0x07
++#define DP_LOOP                       0x08
++#define DP_CALL                       0x09
++#define DP_RET                        0x0a
++#define DP_ABORT              0x0b
++#define DP_REM                        0x0c
++#define DP_EXIT                       0x0d
++#define DP_EXIT_N             0x0e
++#define DP_SUSPEND            0x0f
++
++/*
++ * Logging Group.
++ */
++#define DP_RESUME             0x10
++#define DP_SETMIN_I           0x11
++#define DP_SETMIN             0x12
++#define DP_SETMAJ_I           0x13
++#define DP_SETMAJ             0x14
++#define DP_LOG_STR            0x15
++#define DP_LOG_MRF            0x17
++#define DP_LOG_I              0x1b
++
++/*
++ * Global Variable Group.
++ */
++#define DP_ALLOC_GV           0x1c
++#define DP_FREE_GV            0x1d
++#define DP_FREE_GVI           0x1e
++#define DP_PUSH_GVI           0x1f
++#define DP_PUSH_GV            0x20
++#define DP_POP_GVI            0x21
++#define DP_POP_GV             0x22
++#define DP_MOVE_GVI           0x23
++#define DP_MOVE_GV            0x24
++#define DP_INC_GVI            0x25
++#define DP_INC_GV             0x26
++#define DP_DEC_GVI            0x27
++#define DP_DEC_GV             0x28
++
++/*
++ * Local Variable Group.
++ */
++#define DP_PUSH_LVI           0x29
++#define DP_PUSH_LV            0x2a
++#define DP_POP_LVI            0x2b
++#define DP_POP_LV             0x2c
++#define DP_MOVE_LVI           0x2d
++#define DP_MOVE_LV            0x2e
++#define DP_INC_LVI            0x2f
++#define DP_INC_LV             0x30
++#define DP_DEC_LVI            0x31
++#define DP_DEC_LV             0x32
++
++/*
++ * Arithmetic Group.
++ */
++#define DP_ADD                        0x33
++#define DP_SUB                        0x34
++#define DP_MUL                        0x35
++
++/*
++ * Logic Group.
++ */
++#define DP_NEG                        0x36
++#define DP_AND                        0x37
++#define DP_OR                 0x38
++#define DP_XOR                        0x39
++#define DP_ROL_I              0x3a
++#define DP_ROL                        0x3b
++#define DP_ROR_I              0x3c
++#define DP_ROR                        0x3d
++#define DP_SHL_I              0x3e
++#define DP_SHL                        0x3f
++#define DP_SHR_I              0x40
++#define DP_SHR                        0x41
++
++/*
++ * RPN Stack Group.
++ */
++#define DP_XCHG                       0x42
++#define DP_DUP_I              0x43
++#define DP_DUP                        0x44
++#define DP_ROS                        0x45
++
++/*
++ * Register Group.
++ */
++#define DP_PUSH_R             0x46
++#define DP_POP_R              0x47
++#define DP_PUSH_U             0x48
++#define DP_POP_U              0x49
++
++/* 
++ * Data Group.
++ */
++#define DP_PUSH                       0x4c
++#define DP_PUSH_MEM_U8                0x4d
++#define DP_PUSH_MEM_U16               0x4e
++#define DP_PUSH_MEM_U32               0x4f
++#define DP_PUSH_MEM_U64               0x50
++#define DP_POP_MEM_U8         0x51
++#define DP_POP_MEM_U16                0x52
++#define DP_POP_MEM_U32                0x53
++#define DP_POP_MEM_U64                0x54
++
++/*
++ * System Variable Group.
++ */
++#define DP_PUSH_TASK          0x5d
++#define DP_PUSH_PID           0x5e
++#define DP_PUSH_PROCID                0x5f
++
++/*
++ * Address Verification.
++ */
++#define DP_VFY_R              0x60
++#define DP_VFY_RW             0x61
++
++/*
++ * Some more arithmetic/logic instructions.
++ */
++#define DP_DIV                        0x62
++#define DP_IDIV                       0x63
++#define DP_PBL                        0x64
++#define DP_PBR                        0x65
++#define DP_PBL_I              0x66
++#define DP_PBR_I              0x67
++#define DP_PZL                        0x68
++#define DP_PZR                        0x69
++#define DP_PZL_I              0x6a
++#define DP_PZR_I              0x6b
++
++/*
++ * Exception handling/Stacktrace instructions.
++ */
++#define DP_SX                 0x6c
++#define DP_UX                 0x6d
++#define DP_RX                 0x6e
++#define DP_PUSH_X             0x6f
++#define DP_PUSH_LP            0x70
++#define DP_PUSH_PLP           0x71
++#define DP_POP_LP             0x72
++#define DP_LOG_ST             0x73
++#define DP_PURGE_ST           0x74
++#define DP_TRACE_LV           0x75
++#define DP_TRACE_GV           0x76
++#define DP_TRACE_PV           0x77
++
++#define DP_PUSH_SBP           0x78
++#define DP_POP_SBP            0x79
++#define DP_PUSH_TSP           0x7a
++#define DP_POP_TSP            0x7b
++#define DP_PUSH_SBP_I         0x7c
++#define DP_POP_SBP_I          0x7d
++#define DP_PUSH_TSP_I         0x7e
++#define DP_POP_TSP_I          0x7f
++#define DP_COPY_SBP_I         0x80
++#define DP_COPY_TSP_I         0x81
++#define DP_PUSH_STP           0x82
++#define DP_POP_STP            0x83
++
++#define DP_SAVE_SBP           0x84
++#define DP_RESTORE_SBP                0x85
++#define DP_SAVE_TSP           0x86
++#define DP_RESTORE_TSP                0x87
++#define DP_COPY_SBP           0x88
++#define DP_COPY_TSP           0x89
++
++/* stack based log instructions */
++#define DP_LOG                        0x8a
++#define DP_LOG_LV             0x8b
++#define DP_LOG_GV             0x8c
++
++#define DP_CALLK              0x8d
++
++/* byte heap instructions */
++#define DP_MALLOC             0x8e
++#define DP_FREE                       0x8f
++#define DP_PUSH_WID           0x90
++#define DP_PUSHH_U8_I         0x91
++#define DP_PUSHH_U16_I                0x92
++#define DP_PUSHH_U32_I                0x93
++#define DP_PUSHH_U64_I                0x94
++#define DP_POPH_U8_I          0x95
++#define DP_POPH_U16_I         0x96
++#define DP_POPH_U32_I         0x97
++#define DP_POPH_U64_I         0x98
++
++#include <asm/dprobes_in.h>
++
++#endif
+diff -urNp linux.orig/include/linux/kprobes.h linux-2.6.0-test11/include/linux/kprobes.h
+--- linux.orig/include/linux/kprobes.h 1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.0-test11/include/linux/kprobes.h 2003-12-15 15:51:48.000000000 +0530
+@@ -0,0 +1,88 @@
++#ifndef _LINUX_KPROBES_H
++#define _LINUX_KPROBES_H
++#include <linux/config.h>
++#include <linux/list.h>
++#include <linux/fs.h>
++#include <linux/notifier.h>
++#include <linux/smp.h>
++#include <asm/kprobes.h>
++
++struct kprobe;
++struct pt_regs;
++
++typedef int (*kprobe_pre_handler_t)(struct kprobe *, struct pt_regs *);
++typedef void (*kprobe_post_handler_t)(struct kprobe *, struct pt_regs *,
++                                    unsigned long flags);
++typedef int (*kprobe_fault_handler_t)(struct kprobe *, struct pt_regs *,
++                                    int trapnr);
++struct kprobe {
++      struct list_head list;
++
++      /* location of the probe point */
++      kprobe_opcode_t *addr;
++
++      /* user space probe info */
++      struct uprobe *user;
++ 
++       /* Called before addr is executed. */
++      kprobe_pre_handler_t pre_handler;
++
++      /* Called after addr is executed, unless... */
++      kprobe_post_handler_t post_handler;
++
++       /* ... called if executing addr causes a fault (eg. page fault).
++        * Return 1 if it handled fault, otherwise kernel will see it. */
++      kprobe_fault_handler_t fault_handler;
++
++      /* Saved opcode (which has been replaced with breakpoint) */
++      kprobe_opcode_t opcode;
++
++      /* copy of the original instruction */
++      kprobe_opcode_t insn[MAX_INSN_SIZE];
++};
++
++struct uprobe {
++      struct inode *inode;
++      unsigned long offset;
++      kprobe_opcode_t *addr;
++
++      /* for kprobes internal use */
++      struct vm_area_struct *vma;
++      struct page *page;
++};
++
++#ifdef CONFIG_KPROBES
++/* Locks kprobe: irq must be disabled */
++void lock_kprobes(void);
++void unlock_kprobes(void);
++
++/* kprobe running now on this CPU? */
++static inline int kprobe_running(void)
++{
++      extern unsigned int kprobe_cpu;
++      return kprobe_cpu == smp_processor_id();
++}
++
++extern void arch_prepare_kprobe(struct kprobe *p);
++
++/* Get the kprobe at this addr (if any).  Must have called lock_kprobes */
++extern struct kprobe *get_kprobe(void *addr);
++extern void put_kprobe(struct kprobe *p);
++extern void set_opcode(struct kprobe *p, kprobe_opcode_t opcode);
++
++extern int register_kprobe(struct kprobe *p);
++extern void unregister_kprobe(struct kprobe *p);
++extern int register_kprobe_user(struct kprobe *p);
++extern void unregister_kprobe_user(struct kprobe *p);
++extern int insert_kprobe_user(struct kprobe *p);
++extern int remove_kprobe_user(struct kprobe *p);
++#else
++static inline int kprobe_running(void) { return 0; }
++static inline int register_kprobe(struct kprobe *p) { return -ENOSYS; }
++static inline void unregister_kprobe(struct kprobe *p) { }
++static inline int register_kprobe_user(struct kprobe *p) { return -ENOSYS; }
++static inline void unregister_kprobe_user(struct kprobe *p) { }
++static inline int insert_kprobe_user(struct kprobe *p) { return -ENOSYS; }
++static inline int remove_kprobe_user(struct kprobe *p) { }
++#endif
++#endif /* _LINUX_KPROBES_H */
+diff -urNp linux.orig/kernel/extable.c linux-2.6.0-test11/kernel/extable.c
+--- linux.orig/kernel/extable.c        2003-11-27 02:13:32.000000000 +0530
++++ linux-2.6.0-test11/kernel/extable.c        2003-12-15 15:51:48.000000000 +0530
+@@ -32,6 +32,7 @@ const struct exception_table_entry *sear
+               e = search_module_extables(addr);
+       return e;
+ }
++EXPORT_SYMBOL(search_exception_tables);
+ int kernel_text_address(unsigned long addr)
+ {
+diff -urNp linux.orig/kernel/fork.c linux-2.6.0-test11/kernel/fork.c
+--- linux.orig/kernel/fork.c   2003-11-27 02:12:58.000000000 +0530
++++ linux-2.6.0-test11/kernel/fork.c   2003-12-15 15:51:48.000000000 +0530
+@@ -1229,3 +1229,7 @@ void __init proc_caches_init(void)
+       if(!mm_cachep)
+               panic("vma_init: Cannot alloc mm_struct SLAB cache");
+ }
++#ifdef CONFIG_DPROBES_MODULE
++EXPORT_SYMBOL(mmput);
++#endif
++
+diff -urNp linux.orig/kernel/kprobes.c linux-2.6.0-test11/kernel/kprobes.c
+--- linux.orig/kernel/kprobes.c        1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.0-test11/kernel/kprobes.c        2003-12-15 15:51:48.000000000 +0530
+@@ -0,0 +1,379 @@
++/* Support for kernel probes.
++   (C) 2002 Vamsi Krishna S <vamsi_krishna@in.ibm.com>.
++   Support for user space probes.
++   (C) 2003 Prasanna S Panchamukhi <prasanna@in.ibm.com>.
++*/
++#include <linux/kprobes.h>
++#include <linux/sysrq.h>
++#include <linux/kallsyms.h>
++#include <linux/spinlock.h>
++#include <linux/hash.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/highmem.h>
++#include <linux/pagemap.h>
++#include <asm/cacheflush.h>
++#include <asm/errno.h>
++
++#define KPROBE_HASH_BITS 6
++#define KPROBE_TABLE_SIZE (1 << KPROBE_HASH_BITS)
++
++static struct list_head kprobe_table[KPROBE_TABLE_SIZE];
++
++unsigned int kprobe_cpu = NR_CPUS;
++static spinlock_t kprobe_lock = SPIN_LOCK_UNLOCKED;
++
++void kprobes_code_start(void){}
++
++/* Locks kprobe: irqs must be disabled */
++void lock_kprobes(void)
++{
++      spin_lock(&kprobe_lock);
++      kprobe_cpu = smp_processor_id();
++}
++
++void unlock_kprobes(void)
++{
++      kprobe_cpu = NR_CPUS;
++      spin_unlock(&kprobe_lock);
++}
++
++static struct kprobe *get_uprobe_at(struct inode *inode, unsigned long offset)
++{
++      struct list_head *head;
++      struct kprobe *p;
++      
++      head = &kprobe_table[hash_long((unsigned long)inode*offset, 
++                                      KPROBE_HASH_BITS)];
++      list_for_each_entry(p, head, list) {
++              if (p->user->inode == inode && p->user->offset == offset)
++                      return p;
++      }
++      return NULL;
++}
++
++/*
++ * This leaves with page, and kmap held. They will be released in 
++ * put_kprobe_user. Not sure if holding page_table_lock is also 
++ * needed, it is a very small, probably can't happen, race where 
++ * vma could be gone by the time we complete the single-step.
++ */
++static void get_kprobe_user(struct uprobe *u)
++{
++      kprobe_opcode_t *addr;
++      u->page = find_get_page(u->inode->i_mapping, u->offset >> PAGE_CACHE_SHIFT);
++      addr = (kprobe_opcode_t *)kmap_atomic(u->page, KM_USER0);
++      u->addr = (kprobe_opcode_t *) ((unsigned long) addr + (unsigned long) ( u->offset & ~PAGE_MASK));
++
++}
++
++static void put_kprobe_user(struct uprobe *u)
++{
++      kunmap_atomic(u->addr, KM_USER0);       
++      page_cache_release(u->page);
++}
++
++/*
++ * We need to look up the inode and offset from the vma. We can't depend on
++ * the page->(mapping, index) as that would be incorrect if we ever swap this
++ * page out (possible for pages which are dirtied by GDB breakpoints etc)
++ * 
++ * We acquire page_table_lock here to ensure that:
++ *    - current page doesn't go away from under us (kswapd)
++ *    - mm->mmap consistancy (vma are always added under this lock)
++ *
++ * We will never deadlock on page_table_lock, we always come here due to a
++ * probe in user space, no kernel code could have executed to take the
++ * page_table_lock.
++ */
++static struct kprobe *get_uprobe(void *addr)
++{
++      struct mm_struct *mm = current->mm;
++      struct vm_area_struct *vma;
++      struct inode *inode;
++      unsigned long offset;
++      struct kprobe *p;
++
++      spin_lock(&mm->page_table_lock); 
++      vma = find_vma(mm, (unsigned long)addr);
++      offset = (unsigned long)addr - vma->vm_start + (vma->vm_pgoff << PAGE_SHIFT);
++      if (!vma->vm_file) {
++              spin_unlock(&mm->page_table_lock);
++              return NULL;
++      }
++      inode = vma->vm_file->f_dentry->d_inode;
++      spin_unlock(&mm->page_table_lock);
++
++      p = get_uprobe_at(inode, offset);
++      if (p) {
++              get_kprobe_user(p->user);
++              p->addr = addr;
++              p->user->vma = vma;
++      }
++      return p;
++}
++
++/* You have to be holding the kprobe_lock */
++struct kprobe *get_kprobe(void *addr)
++{
++      struct list_head *head, *tmp;
++
++      if ((unsigned long)addr < PAGE_OFFSET)
++              return get_uprobe(addr);
++
++      head = &kprobe_table[hash_ptr(addr, KPROBE_HASH_BITS)];
++      list_for_each(tmp, head) {
++              struct kprobe *p = list_entry(tmp, struct kprobe, list);
++              if (p->addr == addr)
++                      return p;
++      }
++      return NULL;
++}
++
++void put_kprobe(struct kprobe *p)
++{
++      if (p->user)
++              put_kprobe_user(p->user);
++}
++
++static void set_opcode_user(struct kprobe *p, kprobe_opcode_t opcode)
++{
++      *p->user->addr = opcode;
++      flush_icache_user_range(p->user->vma, p->user->page, addr, sizeof(kprobe_opcode_t));
++}
++
++static void set_opcode_k(struct kprobe *p, kprobe_opcode_t opcode)
++{
++      kprobe_opcode_t *addr = p->addr;
++      *addr = opcode;
++      flush_icache_range(addr, addr + sizeof(kprobe_opcode_t));
++}
++
++void set_opcode(struct kprobe *p, kprobe_opcode_t opcode)
++{
++      if ((unsigned long)p->addr > PAGE_OFFSET)
++              set_opcode_k(p, opcode);
++      else
++              set_opcode_user(p, opcode);
++}
++
++int register_kprobe(struct kprobe *p)
++{
++      int ret = 0;
++      kprobe_opcode_t *addr = p->addr;
++
++      spin_lock_irq(&kprobe_lock);
++      if (get_kprobe(addr)) {
++              ret = -EEXIST;
++              goto out;
++      }
++      list_add(&p->list, &kprobe_table[hash_ptr(addr, 
++                                       KPROBE_HASH_BITS)]);
++      arch_prepare_kprobe(p);
++      p->opcode = *addr;
++      set_opcode_k(p, BREAKPOINT_INSTRUCTION);
++ out:
++      spin_unlock_irq(&kprobe_lock);
++      return ret;
++}
++
++void unregister_kprobe(struct kprobe *p)
++{
++      spin_lock_irq(&kprobe_lock);
++      set_opcode_k(p, p->opcode);
++      list_del(&p->list);
++      spin_unlock_irq(&kprobe_lock);
++}
++
++/* 
++ * User space probes defines four simple and lightweight interfaces :
++ *
++ * register_kprobe_user :
++ *    Registration of user space probes is defined for a pair of inode and
++ *    offset within the executable where the probes need to be inserted.
++ *    Similar to kernel space probes registration, the user space 
++ *    registration provides three callback functions. 
++ *    User space registration requires a kprobes structure as an argument 
++ *    with the following fields initialized:
++ *
++ * pre_handler - pointer to the function that will be called when the 
++ *    probed instruction is about to execute.
++ * post_handler - pointer to the function that will be called after the 
++ *    successful execution of the instruction.
++ * fault_handler - pointer to the function that will be called if a 
++ *    software exception occurs, while executing inside the probe_handler
++ *    or while single stepping.
++ * user - pointer to the struct uprobe. The following fields within this 
++ *    structure must be initialized:
++ * 
++ *    inode -  pointer to the inode of the executable.
++ *    offset - offset within the executable, where probes are 
++ *            inserted/removed. Each unique pair of inode and offset is 
++ *            used as a hashing function.
++ *
++ * User is required to retain this structure until the probes are unregistered.
++ * This routine should be called only once for a given pair of inode and 
++ * offset. Only after the user space probes are registered, the user
++ * can insert and remove probes at the given address.
++ */
++
++int register_kprobe_user(struct kprobe *p)
++{
++      int ret = 0;
++      spin_lock_irq(&kprobe_lock);
++      if (get_uprobe_at(p->user->inode, p->user->offset)) {
++              ret = -EEXIST;
++              goto out;
++      } 
++      list_add(&p->list, &kprobe_table[hash_long(
++              (unsigned long)p->user->inode * p->user->offset,
++              KPROBE_HASH_BITS)]);
++      p->opcode = BREAKPOINT_INSTRUCTION;
++ out :
++      spin_unlock_irq(&kprobe_lock);
++      return ret;
++
++}
++
++/* 
++ * unregister_kprobe_user:
++ *    Every registered user space probe must be unregistered.
++ *    For unregistering, kprobes structure must be passed with
++ *    the following fields initialized:
++ *
++ * user->inode -  pointer to the inode of the executable.
++ * user->offset - offset within the executable, where the probe was registered.
++ *
++ * This routine must be called after all the probes for a given 
++ * pair of inode and offset are removed.
++ */
++
++void unregister_kprobe_user(struct kprobe *p)
++{
++      spin_lock_irq(&kprobe_lock);
++      if (get_uprobe_at(p->user->inode, p->user->offset)) 
++              list_del(&p->list);
++      spin_unlock_irq(&kprobe_lock);
++}
++
++/* 
++ * insert_kprobe_userspace:
++ *    To insert a user space probe within a page at a given address,
++ *    this routine must be called with the following fields initialized:
++ *
++ * user->inode -  pointer to the inode of the executable.
++ * user->offset - offset within the executable, where we need to insert a probe.
++ * user->addr - address in the user address space where probes need to inserted.
++ * user->page - pointer to the page containing the address.
++ * user->vma - pointer to the vma containing the address.
++ *
++ * The user space probes can be inserted into the pages existing in the memory or 
++ * pages read via readpage routine of the inode's address space operations or 
++ * swapping in of the process private page. 
++ * User has to ensure that the page containing the specified address 
++ * (user->addr) must be present in the memory before calling.
++ * User has to first register user space probes for a given pair of 
++ * of inode and offset before calling this routine to insert probes.
++ * 
++ */
++
++int insert_kprobe_user(struct kprobe *p)
++{
++      int ret = 0;
++      spin_lock_irq(&kprobe_lock);
++      if (!get_uprobe_at(p->user->inode, p->user->offset)) {
++              ret = -ENODATA;
++              goto out;
++      }
++
++      if (*p->user->addr == BREAKPOINT_INSTRUCTION) {
++              ret = -EEXIST;
++              goto out;
++      }
++              
++      p->opcode = *p->user->addr;
++      set_opcode_user(p, BREAKPOINT_INSTRUCTION);
++ out :
++      spin_unlock_irq(&kprobe_lock);
++      return ret;
++}
++
++/*
++ * remove_kprobe_user:
++ * For removing user space probe from a page at the given address, this routine must be
++ * called with the following fields initialized:
++ *
++ * user->inode -  pointer to the inode of the executable.
++ * user->offset - offset within the executable,where we need to remove a probe.
++ * user->addr - address in user address space where probes need to removed.
++ * user->page - pointer to the page containing the address.
++ * user->vma - pointer to the vma containing the address.
++ * 
++ * User has to ensure that the page containing the specified address 
++ * (user->addr) must be present in the memory before calling this routine.
++ * Before unregistering, all the probes inserted at a given inode and offset
++ * must be removed. 
++ */
++
++int remove_kprobe_user(struct kprobe *p)
++{
++      int ret = 0;
++      spin_lock_irq(&kprobe_lock);
++      if (!get_uprobe_at(p->user->inode, p->user->offset)) {
++              ret = -ENODATA;
++              goto out;
++      }
++      set_opcode_user(p, p->opcode);
++ out:
++      spin_unlock_irq(&kprobe_lock);
++      return ret;
++}
++
++static void show_kprobes(int key, struct pt_regs *pt_regs, struct tty_struct *tty)
++{
++      int i;
++      struct kprobe *p;
++      
++      /* unsafe: kprobe_lock ought to be taken here */
++      for(i = 0; i < KPROBE_TABLE_SIZE; i++) {
++              if (!list_empty(&kprobe_table[i])) {
++                      list_for_each_entry(p, &kprobe_table[i], list) {
++                              printk("[<%p>] ", p->addr);
++                              print_symbol("%s\t", (unsigned long)p->addr);
++                              print_symbol("%s\n", (unsigned long)p->pre_handler);
++                      }
++              }
++      }
++}
++
++static struct sysrq_key_op sysrq_show_kprobes = {
++      .handler        = show_kprobes,
++      .help_msg       = "shoWkprobes",
++      .action_msg     = "Show kprobes\n"
++};
++
++static int __init init_kprobes(void)
++{
++      int i;
++
++      register_sysrq_key('w', &sysrq_show_kprobes);
++      /* FIXME allocate the probe table, currently defined statically */
++      /* initialize all list heads */
++      for (i = 0; i < KPROBE_TABLE_SIZE; i++)
++              INIT_LIST_HEAD(&kprobe_table[i]);
++      return 0;
++}
++
++void kprobes_code_end(void) {}
++__initcall(init_kprobes);
++
++EXPORT_SYMBOL_GPL(register_kprobe);
++EXPORT_SYMBOL_GPL(unregister_kprobe);
++EXPORT_SYMBOL_GPL(register_kprobe_user);
++EXPORT_SYMBOL_GPL(unregister_kprobe_user);
++EXPORT_SYMBOL_GPL(insert_kprobe_user);
++EXPORT_SYMBOL_GPL(remove_kprobe_user);
++EXPORT_SYMBOL_GPL(kprobes_code_start);
++EXPORT_SYMBOL_GPL(kprobes_code_end);
++EXPORT_SYMBOL_GPL(kprobes_asm_code_start);
++EXPORT_SYMBOL_GPL(kprobes_asm_code_end);
+diff -urNp linux.orig/kernel/Makefile linux-2.6.0-test11/kernel/Makefile
+--- linux.orig/kernel/Makefile 2003-11-27 02:13:24.000000000 +0530
++++ linux-2.6.0-test11/kernel/Makefile 2003-12-15 15:51:48.000000000 +0530
+@@ -19,6 +19,7 @@ obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
+ obj-$(CONFIG_COMPAT) += compat.o
+ obj-$(CONFIG_IKCONFIG) += configs.o
+ obj-$(CONFIG_IKCONFIG_PROC) += configs.o
++obj-$(CONFIG_KPROBES) += kprobes.o
+ ifneq ($(CONFIG_IA64),y)
+ # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
+diff -urNp linux.orig/mm/memory.c linux-2.6.0-test11/mm/memory.c
+--- linux.orig/mm/memory.c     2003-11-27 02:13:52.000000000 +0530
++++ linux-2.6.0-test11/mm/memory.c     2003-12-15 15:51:48.000000000 +0530
+@@ -1699,3 +1699,7 @@ struct page * vmalloc_to_page(void * vma
+ }
+ EXPORT_SYMBOL(vmalloc_to_page);
++#ifdef CONFIG_DPROBES_MODULE
++EXPORT_SYMBOL(handle_mm_fault);
++#endif
++
+diff -urNp linux.orig/mm/swap.c linux-2.6.0-test11/mm/swap.c
+--- linux.orig/mm/swap.c       2003-11-27 02:13:37.000000000 +0530
++++ linux-2.6.0-test11/mm/swap.c       2003-12-15 15:51:48.000000000 +0530
+@@ -419,3 +419,8 @@ void __init swap_setup(void)
+        * _really_ don't want to cluster much more
+        */
+ }
++#ifdef CONFIG_DPROBES_MODULE
++EXPORT_SYMBOL(swapper_space);
++EXPORT_SYMBOL(delete_from_swap_cache);
++#endif
++
This page took 0.364963 seconds and 5 git commands to generate.