diff -rN -wup old-gnumach/ddb/db_probes.c new-gnumach/ddb/db_probes.c
--- old-gnumach/ddb/db_probes.c	1969-12-31 19:00:00.000000000 -0500
+++ new-gnumach/ddb/db_probes.c	2008-08-18 04:49:23.000000000 -0400
@@ -0,0 +1,506 @@
+/*-
+ * Copyright (c) 2008 Andrei Barbu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/db_probes.h>
+#include <mach/mach_types.h>	/* vm_address_t */
+#include <mach/std_types.h>	/* pointer_t */
+#include <kern/host.h>
+#include <kern/task.h>
+#include <ddb/db_break.h>
+#include <ddb/db_task_thread.h>
+#include <ddb/db_sym.h>
+#include <ddb/db_output.h>
+
+static struct db_probe* db_probe_list;
+
+
+struct pt_regs i386_regs_to_db_reg(struct i386_saved_state* s)
+{
+  struct pt_regs r;
+
+  r.ebx = s->ebx;
+  r.ecx = s->ecx;
+  r.edx = s->edx;
+  r.esi = s->esi;
+  r.edi = s->edi;
+  r.ebp = s->ebp;
+  r.eax = s->eax;
+  r.xds = s->ds;
+  r.xes = s->es;
+  r.xfs = s->fs;
+  r.gs  = s->gs;
+  r.orig_eax = s->eax;
+  r.eip = s->eip;
+  r.xcs = s->cs;
+  r.eflags = s->efl;
+  r.esp = s->uesp;
+  r.xss = s->ss;
+
+  return r;
+}
+
+int init_db_probes()
+{
+  db_probe_list = NULL;
+
+  int i;
+  for(i = 0; i < DB_PROBE_MAX_PROBES; ++i)
+    probe_storage[i].valid = 0;
+
+  return 0;
+}
+
+int armed_probe(struct db_probe* p)
+{
+  return p->breakpoint;
+}
+
+int arm_probe(struct db_probe* p)
+{
+  if(!p->addr)
+    return -1;
+
+  db_breakpoint_t bkpt = db_find_breakpoint(db_target_space(THREAD_NULL, FALSE)
+					    , p->addr);
+  if(bkpt)
+  {
+    p->breakpoint = bkpt;
+  } else {
+    p->breakpoint = db_set_breakpoint(db_target_space(THREAD_NULL, FALSE)
+				      , (db_addr_t) p->addr, 1, THREAD_NULL, FALSE);
+    if(!p->breakpoint)
+      return -2;
+  }
+
+  p->breakpoint->flags |= BKPT_EXTERNAL;
+  p->exec_num = 0;
+  p->pre_hook_handled = FALSE;
+  p->next = NULL;
+  p->ready_to_run = 0;
+
+  struct db_probe* curr = db_probe_list;
+  if(!curr) db_probe_list = p;
+  else {
+    while(curr->next) curr = curr->next;
+    curr->next = p;
+  }
+
+  clear_queue(p);
+
+  db_clear_breakpoints();
+  db_set_breakpoints();
+  return 0;
+}
+
+struct db_probe* next_db_probe(struct db_probe* p)
+{
+  if(!p)
+    return db_probe_list;
+  return p->next;
+}
+
+struct db_probe* next_db_probe_by_breakpoint(struct db_probe* p, db_breakpoint_t breakpoint)
+{
+  if(!p)
+    p = db_probe_list;
+  else
+    p = p->next;
+
+  while(p != NULL) {
+    if(p->breakpoint == breakpoint)
+      return p;
+    p = p->next;
+  }
+
+  return NULL;  
+}
+
+struct db_probe* db_probe_by_breakpoint(db_breakpoint_t b)
+{
+  return next_db_probe_by_breakpoint(NULL, b);
+}
+
+
+int disarm_probe(struct db_probe* p)
+{
+  struct db_probe* curr = db_probe_list;
+
+  if(!curr)
+    return 0;
+
+  if(curr == p)
+  {
+    db_clear_breakpoints();
+    db_probe_list = curr->next;
+    if(!db_probe_by_breakpoint(p->breakpoint))
+      db_delete_breakpoint(p->breakpoint->task, p->breakpoint->address
+			   , p->breakpoint->threads->tb_task_thd, FALSE);
+    db_set_breakpoints();
+    return 1;
+  }
+
+  else do {
+      if(curr->next == p) {
+	curr->next = p->next;
+	db_clear_breakpoints();
+	if(!db_probe_by_breakpoint(p->breakpoint))
+	  db_delete_breakpoint(p->breakpoint->task, p->breakpoint->address
+			       , p->breakpoint->threads->tb_task_thd, FALSE);
+	db_set_breakpoints();
+	return 1; 
+      }
+    } while(curr);
+
+  clear_queue(p);
+
+  return 0;
+}
+
+vm_offset_t kallsyms_lookup_name(const char *name)
+{
+  char* name_;
+  db_expr_t location;
+  db_sym_t s = db_lookup(name);
+
+  if(s == NULL)
+    return 0;
+
+  db_symbol_values(0, s, &name_, &location);
+  db_free_symbol(s);
+  return location;
+}
+
+struct db_probe* add_probe(struct db_probe probe)
+{
+  int i;
+  for(i = 0; i < DB_PROBE_MAX_PROBES; ++i)
+    if(!probe_storage[i].valid)
+    {
+      probe_storage[i].valid = TRUE;
+      probe_storage[i].probe = probe;
+      return &probe_storage[i].probe;
+    }
+  
+  return NULL;
+}
+
+int remove_probe(struct db_probe* p)
+{
+  int i;
+  for(i = 0; i < DB_PROBE_MAX_PROBES; ++i)
+    if(&probe_storage[i].probe == p)
+    {
+      probe_storage[i].valid = FALSE;
+      return 0;
+    }
+  
+  return -1;
+}
+
+void probe_wakeup_threads(struct db_probe *probe)
+{
+  if(!empty_queue(probe))
+  {
+    if(probe->waiting != THREAD_NULL)
+    {
+      thread_wakeup((event_t)&probe->ready_to_run);
+    }
+  }
+  
+  return;
+}
+
+int userland_probe_pre(struct db_probe *probe, struct pt_regs *regs)
+{
+  probe->exec_num++;
+
+  struct db_probe_exec exec;
+  exec.status = PROBE_STATUS_PRE;
+  exec.exec_num = probe->exec_num;
+  exec.regs = *regs;
+  exec.valid = TRUE;
+
+  if(full_queue(probe))
+    clear_queue(probe);
+
+  int q;
+  if((q = push_queue(probe, exec)) >= 0)
+    memcpy(probe->queue[q].mem, (void*)probe->mem_addr, probe->mem_size);
+
+  probe_wakeup_threads(probe);
+
+  return 0;
+}
+
+void userland_probe_post(struct db_probe *probe, struct pt_regs *regs, unsigned long flags)
+{
+  probe->exec_num++;
+
+  struct db_probe_exec exec;
+  exec.status = PROBE_STATUS_POST;
+  exec.exec_num = probe->exec_num;
+  exec.regs = *regs;
+  exec.valid = TRUE;
+
+  if(full_queue(probe))
+    clear_queue(probe);
+
+  int q;
+  if((q = push_queue(probe, exec)) >= 0)
+    memcpy(probe->queue[q].mem, (void*)probe->mem_addr, probe->mem_size);
+
+  probe_wakeup_threads(probe);
+
+  return;
+}
+
+void zero_probe(struct db_probe* p)
+{
+  p->next = 0;
+  p->pre_hook_handled = 0;
+  p->nmissed = 0;
+  p->addr = 0;
+  p->symbol_name = 0;
+  p->offset = 0;
+  p->pre_handler = 0;
+  p->post_handler = 0;
+  p->fault_handler = 0;
+  p->break_handler = 0;
+  p->mem_size = 0;
+
+  int i;
+  for(i = 0; i < DB_PROBE_MAX_QUEUE; ++i)
+  {
+    p->queue[i].status = 0;
+    p->queue[i].mem = NULL;
+  }
+
+  p->waiting = THREAD_NULL;
+}
+
+boolean_t valid_probe(struct db_probe* probe)
+{
+  if(!probe)
+    return FALSE;
+
+  struct db_probe* curr = db_probe_list;
+  while(curr)
+  {
+    if(curr == probe)
+      return TRUE;
+
+    curr = curr->next;
+  }
+
+  return FALSE;
+}
+
+int push_queue(struct db_probe* p, struct db_probe_exec exec)
+{
+  int i;
+  for(i = 0; i < DB_PROBE_MAX_QUEUE; ++i)
+  {
+    if(!p->queue[i].valid)
+    {
+      char* mem = p->queue[i].mem;
+      p->queue[i] = exec;
+      p->queue[i].valid = TRUE;
+      p->queue[i].mem = mem;
+
+      return i;
+    }
+  }
+
+  return -1;
+}
+
+struct db_probe_exec pop_queue(struct db_probe* p)
+{
+  struct db_probe_exec ret;
+  ret.valid = FALSE;
+
+  int i, ret_off = 0;
+  unsigned int min_exec = p->exec_num;
+  for(i = 0; i < DB_PROBE_MAX_QUEUE; ++i)
+  {
+    if(p->queue[i].valid && p->queue[i].exec_num <= min_exec)
+    {
+      min_exec = p->queue[i].exec_num;
+      ret = p->queue[i];
+      ret_off = i;
+    }
+  }
+
+  p->queue[ret_off].valid = FALSE;
+
+  return ret;
+}
+
+void clear_queue(struct db_probe* p)
+{
+  int i;
+  for(i = 0; i < DB_PROBE_MAX_QUEUE; ++i)
+    p->queue[i].valid = FALSE;
+}
+
+boolean_t empty_queue(struct db_probe* p)
+{
+  int i;
+  for(i = 0; i < DB_PROBE_MAX_QUEUE; ++i)
+    if(p->queue[i].valid)
+      return FALSE;
+
+  return TRUE;
+}
+
+boolean_t full_queue(struct db_probe* p)
+{
+  int i;
+  for(i = 0; i < DB_PROBE_MAX_QUEUE; ++i)
+    if(!p->queue[i].valid)
+      return FALSE;
+
+  return TRUE;
+}
+
+kern_return_t mach_arm_probe(host_t host
+			     , vm_address_t addr
+			     , char* name
+			     , vm_address_t mem_addr
+			     , natural_t mem_size
+			     , vm_address_t *out_probe
+			     , natural_t *status)
+{
+  *out_probe = NULL;
+
+  struct db_probe p;
+  zero_probe(&p);
+
+  if(name)
+    addr = kallsyms_lookup_name(name);
+
+  if(!addr)
+    return KERN_FAILURE;
+
+  p.addr = addr;
+  p.symbol_name = name;
+  p.pre_handler = userland_probe_pre;
+  p.post_handler = userland_probe_post;
+
+  p.mem_addr = mem_addr;
+  p.mem_size = mem_size;
+
+  struct db_probe* probe = add_probe(p);
+  if(!probe)
+    return KERN_NO_SPACE;
+
+
+  if(!alloc_queue_buffers(probe))
+  {
+    free_queue_buffers(probe);
+    return KERN_NO_SPACE;
+  }
+  
+  if(arm_probe(probe))
+  {
+    free_queue_buffers(probe);
+    remove_probe(probe);
+    return KERN_FAILURE;
+  }
+
+  *out_probe = (vm_address_t)probe;
+  return KERN_SUCCESS;
+}
+
+boolean_t alloc_queue_buffers(struct db_probe* probe)
+{
+  if(probe->mem_size)
+  {
+    int i;
+    for(i = 0; i < DB_PROBE_MAX_QUEUE; ++i)
+      if(!(probe->queue[i].mem = kalloc(probe->mem_size)))
+	return FALSE;
+  }
+
+  return TRUE;
+}
+
+void free_queue_buffers(struct db_probe* probe)
+{
+  int i;
+  if(probe->mem_size)
+    for(i = 0; i < DB_PROBE_MAX_QUEUE; ++i)
+      kfree(probe->queue[i].mem, probe->mem_size);
+}
+
+kern_return_t mach_wait_probe(host_t host, vm_address_t in_probe
+			      , mach_probe_mem_t memory
+			      , mach_msg_type_number_t *memoryCnt
+			      , natural_t *status)
+{
+  struct db_probe* probe = in_probe;
+  if(!valid_probe(probe))
+    return KERN_INVALID_ARGUMENT;
+
+  if(probe->waiting != THREAD_NULL)
+    return KERN_FAILURE;
+
+  probe->waiting = current_thread();
+
+  if(empty_queue(probe))
+    thread_sleep((event_t) &probe->ready_to_run
+		 , simple_lock_addr(current_thread()->lock), FALSE);
+
+  probe->waiting = THREAD_NULL;
+  struct db_probe_exec exec = pop_queue(probe);
+
+  *status = exec.status;
+
+  if(*memoryCnt > probe->mem_size)
+    *memoryCnt = probe->mem_size;
+
+  memcpy((char*)memory, exec.mem, *memoryCnt);
+
+  return KERN_SUCCESS;
+}
+
+kern_return_t mach_disarm_probe(host_t host, vm_address_t probe)
+{
+  if(!valid_probe((struct db_probe*)probe))
+    return KERN_INVALID_ARGUMENT;
+
+  disarm_probe((struct db_probe*)probe);
+
+  free_queue_buffers(probe);
+
+  int rp = remove_probe((struct db_probe*)probe);
+
+  if(!rp)
+    return KERN_SUCCESS;
+  else
+    return KERN_FAILURE;
+}
+
diff -rN -wup old-gnumach/ddb/db_probes.h new-gnumach/ddb/db_probes.h
--- old-gnumach/ddb/db_probes.h	1969-12-31 19:00:00.000000000 -0500
+++ new-gnumach/ddb/db_probes.h	2008-08-18 04:49:23.000000000 -0400
@@ -0,0 +1,120 @@
+/*-
+ * Copyright (c) 2008 Andrei Barbu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef	_DDB_DB_DB_PROBE_H_
+#define	_DDB_DB_DB_PROBE_H_
+
+#include <ddb/db_break.h>
+#include <ddb/db_task_thread.h>
+#include <kern/thread.h>
+#include <machine/db_probes.h>
+#include <mach/mach_types.h>
+
+struct db_probe;
+struct pt_regs;
+
+typedef vm_offset_t db_probe_opcode_t;
+
+typedef int (*db_probe_pre_handler_t) (struct db_probe *, struct pt_regs *);
+typedef int (*db_probe_break_handler_t) (struct db_probe *, struct pt_regs *);
+typedef void (*db_probe_post_handler_t) (struct db_probe *, struct pt_regs *,
+                                       unsigned long flags);
+typedef int (*db_probe_fault_handler_t) (struct db_probe *, struct pt_regs *,
+                                       int trapnr);
+
+
+#define PROBE_STATUS_PRE      2
+#define PROBE_STATUS_POST     3
+
+struct db_probe_exec {
+  boolean_t valid;
+  int status;
+  unsigned int exec_num;
+  char* mem;
+  struct pt_regs regs;
+};
+
+#define DB_PROBE_MAX_QUEUE 10
+
+struct db_probe {
+  struct db_probe *next;
+  int pre_hook_handled;
+
+  /* count the number of times this probe was temporarily disarmed */
+  unsigned long nmissed;
+
+  /* location of the probe point */
+  db_probe_opcode_t *addr;
+
+  const char *symbol_name;
+  unsigned int offset;
+
+  /* Handlers */
+  db_probe_pre_handler_t pre_handler;
+  db_probe_post_handler_t post_handler;
+  db_probe_fault_handler_t fault_handler;
+  db_probe_break_handler_t break_handler;
+
+  struct db_probe_exec queue[DB_PROBE_MAX_QUEUE];
+  unsigned int exec_num;
+
+  db_breakpoint_t breakpoint;
+  natural_t ready_to_run;
+
+  vm_address_t mem_addr;
+  natural_t mem_size;
+
+  thread_t waiting;
+};
+
+struct db_probe_storage {
+  boolean_t valid;
+  struct db_probe probe;
+};
+
+#define DB_PROBE_MAX_PROBES 100
+struct db_probe_storage probe_storage[DB_PROBE_MAX_PROBES];
+
+struct db_probe* add_probe(struct db_probe);
+int remove_probe(struct db_probe*);
+void zero_probe(struct db_probe* p);
+
+int push_queue(struct db_probe*, struct db_probe_exec);
+struct db_probe_exec pop_queue(struct db_probe* p);
+void clear_queue(struct db_probe* p);
+boolean_t empty_queue(struct db_probe* p);
+
+vm_offset_t kallsyms_lookup_name(const char *name);
+int init_db_probes();
+int armed_probe(struct db_probe* p);
+int arm_probe(struct db_probe* p);
+struct db_probe* next_db_probe(struct db_probe* p);
+struct db_probe* next_db_probe_by_breakpoint(struct db_probe* p, db_breakpoint_t breakpoint);
+struct db_probe* db_probe_by_breakpoint(db_breakpoint_t b);
+int disarm_probe(struct db_probe* p);
+
+
+#endif
diff -rN -wup old-gnumach/ddb/db_trap.c new-gnumach/ddb/db_trap.c
--- old-gnumach/ddb/db_trap.c	2008-08-18 04:49:23.000000000 -0400
+++ new-gnumach/ddb/db_trap.c	2008-08-18 04:49:23.000000000 -0400
@@ -42,6 +42,7 @@
 #include <ddb/db_output.h>
 #include <ddb/db_task_thread.h>
 #include <ddb/db_trap.h>
+#include <machine/db_probes.h>
 
 
 extern jmp_buf_t *db_recover;
@@ -53,49 +54,122 @@ extern int		db_inst_count;
 extern int		db_load_count;
 extern int		db_store_count;
 
+#ifdef	SOFTWARE_SSTEP
+#error "post-probes don't work in software single step mode"
+#endif
+
+extern db_breakpoint_t	db_not_taken_bkpt;
+extern db_breakpoint_t	db_taken_bkpt;
+
+void db_enter_loop(type, code, user_space, set_jump, task_space)
+     int       type, code, set_jump;
+     boolean_t user_space;
+     task_t    task_space;
+{
+  jmp_buf_t *prev;
+
+  if (db_inst_count) {
+    db_printf("After %d instructions (%d loads, %d stores),\n",
+    	      db_inst_count, db_load_count, db_store_count);
+  }
+  if (IS_BREAKPOINT_TRAP(type, code))
+    db_printf("Breakpoint at  ");
+  else if (IS_WATCHPOINT_TRAP(type, code))
+    db_printf("Watchpoint at  ");
+  else
+    db_printf("Stopped at  ");
+
+  prev = db_recover;
+
+  if (set_jump == 0)
+    db_print_loc_and_inst(PC_REGS(DDB_REGS), task_space);
+  else
+    db_printf("Trouble printing location %#X.\n", PC_REGS(DDB_REGS));
+
+  db_recover = prev;
+
+  db_command_loop();  
+}
+
 void
 db_task_trap(type, code, user_space)
 	int	  type, code;
 	boolean_t user_space;
 {
 	jmp_buf_t db_jmpbuf;
-	jmp_buf_t *prev;
 	boolean_t	bkpt;
 	boolean_t	watchpt;
 	void		db_init_default_thread();
 	void		db_check_breakpoint_valid();
 	task_t		task_space;
 
+	thread_t thread = current_thread();
 	task_space = db_target_space(current_thread(), user_space);
 	bkpt = IS_BREAKPOINT_TRAP(type, code);
-	watchpt = IS_WATCHPOINT_TRAP(type, code);
 
 	db_init_default_thread();
 	db_check_breakpoint_valid();
 	if (db_stop_at_pc(&bkpt, task_space)) {
-	    if (db_inst_count) {
-		db_printf("After %d instructions (%d loads, %d stores),\n",
-			  db_inst_count, db_load_count, db_store_count);
-	    }
+	    int set_jump = _setjmp(db_recover = &db_jmpbuf);
+
 	    if (bkpt)
-		db_printf("Breakpoint at  ");
-	    else if (watchpt)
-		db_printf("Watchpoint at  ");
-	    else
-		db_printf("Stopped at  ");
-	    db_dot = PC_REGS(DDB_REGS);
+	    {
+	      db_breakpoint_t bpoint = db_find_breakpoint(task_space
+							  , PC_REGS(DDB_REGS));
+	      if(bpoint->flags & BKPT_EXTERNAL)
+	      {
+		struct db_probe* probe = next_db_probe_by_breakpoint(NULL, bpoint);
 
-	    prev = db_recover;
-	    if (_setjmp(db_recover = &db_jmpbuf) == 0)
-		db_print_loc_and_inst(db_dot, task_space);
-	    else
-		db_printf("Trouble printing location %#X.\n", db_dot);
-	    db_recover = prev;
+		while(probe)
+		{
+		  struct pt_regs reg = DB_PROBE_REGS(DDB_REGS);
+		  if(probe->pre_handler)
+		    probe->pre_handler(probe, &reg);
+		  probe->pre_hook_handled = TRUE;
+		  probe = next_db_probe_by_breakpoint(probe, bpoint);
+		}
 
-	    db_command_loop();
+		db_single_step_cmd(0, 0, 0, " ");
+	      } else {
+		db_enter_loop(type, code, user_space, set_jump);
+	      }
+	    } else {
+	      boolean_t probe_exec = FALSE;
+	      struct db_probe* probe = next_db_probe(NULL);
+	      while(probe)
+	      {
+		if(probe->pre_hook_handled 
+		   && task_space == probe->breakpoint->task)
+		{
+		  db_thread_breakpoint_t bthread = probe->breakpoint->threads;
+		  while(bthread)
+		  {
+		    if(!bthread->tb_is_task
+		       &&
+		       (!bthread->tb_task_thd
+			|| thread == (thread_t)bthread->tb_task_thd))
+		    {
+		      struct pt_regs reg = DB_PROBE_REGS(DDB_REGS);
+		      if(probe->post_handler)
+			probe->post_handler(probe, &reg, 0);
+		      probe_exec = TRUE;
+		      break;
+		      }
+		    bthread = bthread->tb_next;
+		  }
+		}
+		
+		probe = next_db_probe(probe);
+	      }
+
+	      if(probe_exec)
+		db_continue_cmd(0, 0, 0, " ");
+	      else
+		db_enter_loop(type, code, user_space, set_jump);
+	    }
 	}
 
-	db_restart_at_pc(watchpt, task_space);
+	db_restart_at_pc(IS_WATCHPOINT_TRAP(type, code), task_space);
 }
 
 void
diff -rN -wup old-gnumach/i386/i386/db_probes.h new-gnumach/i386/i386/db_probes.h
--- old-gnumach/i386/i386/db_probes.h	1969-12-31 19:00:00.000000000 -0500
+++ new-gnumach/i386/i386/db_probes.h	2008-08-18 04:49:23.000000000 -0400
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 2008 Andrei Barbu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef	_I386AT_DB_PROBE_H_
+#define	_I386AT_DB_PROBE_H_
+
+#include <machine/thread.h>
+
+struct db_probe;
+
+struct pt_regs {
+  long ebx;
+  long ecx;
+  long edx;
+  long esi;
+  long edi;
+  long ebp;
+  long eax;
+  int  xds;
+  int  xes;
+  int  xfs;
+  int  gs;
+  long orig_eax;
+  long eip;
+  int  xcs;
+  long eflags;
+  long esp;
+  int  xss;
+};
+
+typedef struct ptregs* pt_regs_t;
+
+#define DB_PROBE_REGS(x) i386_regs_to_db_reg(x)
+struct pt_regs i386_regs_to_db_reg(struct i386_saved_state*);
+
+#include <ddb/db_probes.h>
+
+#endif
diff -rN -wup old-gnumach/i386/i386/trap.c new-gnumach/i386/i386/trap.c
--- old-gnumach/i386/i386/trap.c	2008-08-18 04:49:23.000000000 -0400
+++ new-gnumach/i386/i386/trap.c	2008-08-18 04:49:23.000000000 -0400
@@ -335,12 +335,6 @@ dump_ss(regs);
 
 	    default:
 	    badtrap:
-	    	printf("Kernel ");
-		if (type < TRAP_TYPES)
-			printf("%s trap", trap_type[type]);
-		else
-			printf("trap %d", type);
-		printf(", eip 0x%x\n", regs->eip);
 #if	MACH_TTD
 		if (kttd_enabled && kttd_trap(type, code, regs))
 			return;
diff -rN -wup old-gnumach/include/mach/mach_host.defs new-gnumach/include/mach/mach_host.defs
--- old-gnumach/include/mach/mach_host.defs	2008-08-18 04:49:23.000000000 -0400
+++ new-gnumach/include/mach/mach_host.defs	2008-08-18 04:49:23.000000000 -0400
@@ -377,3 +377,32 @@ routine processor_control(
 routine host_get_boot_info(
 		host_priv	: host_priv_t;
 	out	boot_info	: kernel_boot_info_t);
+
+
+#if	!defined(MACH_KDB) || MACH_KDB
+
+routine mach_arm_probe (
+		host		: host_priv_t;
+		addr            : vm_address_t;
+		name		: kernel_version_t;
+		mem_addr	: vm_address_t;
+		mem_size	: natural_t;
+	out	probe		: vm_address_t;
+	out	status		: natural_t);
+
+routine mach_wait_probe (
+		host		: host_priv_t;
+		probe		: vm_address_t;
+	out 	memory		: mach_probe_mem_t, CountInOut;
+	out	status		: natural_t);
+
+routine mach_disarm_probe (
+		host		: host_priv_t;
+		probe		: vm_address_t);
+
+#else	/* !defined(MACH_KDB) || MACH_KDB */
+
+skip; /* mach_arm_wait_probe */
+skip; /* mach_disarm_probe */
+
+#endif
diff -rN -wup old-gnumach/include/mach/mach_types.defs new-gnumach/include/mach/mach_types.defs
--- old-gnumach/include/mach/mach_types.defs	2008-08-18 04:49:23.000000000 -0400
+++ new-gnumach/include/mach/mach_types.defs	2008-08-18 04:49:23.000000000 -0400
@@ -234,6 +234,8 @@ type xxx_emulation_vector_t	= array[*:10
 
 type rpc_signature_info_t	= array[*:1024] of int;
 
+type mach_probe_mem_t 		= array[*:1024] of char;
+
 #if	KERNEL_SERVER
 simport <kern/ipc_kobject.h>;	/* for null conversion */
 simport <kern/ipc_tt.h>;	/* for task/thread conversion */
diff -rN -wup old-gnumach/include/mach/mach_types.h new-gnumach/include/mach/mach_types.h
--- old-gnumach/include/mach/mach_types.h	2008-08-18 04:49:23.000000000 -0400
+++ new-gnumach/include/mach/mach_types.h	2008-08-18 04:49:23.000000000 -0400
@@ -85,4 +85,6 @@ typedef vm_offset_t	*emulation_vector_t;
  */
 #include <mach/std_types.h>
 
+typedef char* mach_probe_mem_t;
+
 #endif	/* _MACH_MACH_TYPES_H_ */
diff -rN -wup old-gnumach/include/mach_debug/mach_debug.defs new-gnumach/include/mach_debug/mach_debug.defs
--- old-gnumach/include/mach_debug/mach_debug.defs	2008-08-18 04:49:23.000000000 -0400
+++ new-gnumach/include/mach_debug/mach_debug.defs	2008-08-18 04:49:23.000000000 -0400
@@ -233,3 +233,4 @@ skip;	/* mach_vm_region_info */
 skip;	/* mach_vm_object_info */
 skip;	/* mach_vm_object_pages */
 #endif	/* !defined(MACH_VM_DEBUG) || MACH_VM_DEBUG */
+
diff -rN -wup old-gnumach/include/mach_debug/mach_debug_types.defs new-gnumach/include/mach_debug/mach_debug_types.defs
--- old-gnumach/include/mach_debug/mach_debug_types.defs	2008-08-18 04:49:23.000000000 -0400
+++ new-gnumach/include/mach_debug/mach_debug_types.defs	2008-08-18 04:49:23.000000000 -0400
@@ -60,6 +60,8 @@ type vm_page_info_array_t = array[] of v
 
 type symtab_name_t = (MACH_MSG_TYPE_STRING_C, 8*32);
 
+type pt_regs = struct[28] of natural_t;
+
 import <mach_debug/mach_debug_types.h>;
 
 #endif	/* _MACH_DEBUG_MACH_DEBUG_TYPES_DEFS_ */
diff -rN -wup old-gnumach/kern/startup.c new-gnumach/kern/startup.c
--- old-gnumach/kern/startup.c	2008-08-18 04:49:22.000000000 -0400
+++ new-gnumach/kern/startup.c	2008-08-18 04:49:23.000000000 -0400
@@ -54,7 +54,7 @@
 #include <machine/pmap.h>
 #include <machine/model_dep.h>
 #include <mach/version.h>
-
+#include <machine/db_probes.h>
 
 
 extern void	vm_mem_init();
@@ -82,6 +82,7 @@ extern void	action_thread();
 /* XX */
 extern vm_offset_t phys_first_addr, phys_last_addr;
 
+
 /*
  *	Running in virtual memory, on the interrupt stack.
  *	Does not return.  Dispatches initial thread.
@@ -92,6 +93,8 @@ void setup_main()
 {
 	thread_t		startup_thread;
 
+	init_db_probes();
+
 	panic_init();
 	printf_init();
 
diff -rN -wup old-gnumach/Makefrag.am new-gnumach/Makefrag.am
--- old-gnumach/Makefrag.am	2008-08-18 04:49:23.000000000 -0400
+++ new-gnumach/Makefrag.am	2008-08-18 04:49:23.000000000 -0400
@@ -40,6 +40,8 @@ libkernel_a_SOURCES += \
 	ddb/db_mp.c \
 	ddb/db_output.c \
 	ddb/db_output.h \
+	ddb/db_probes.c \
+	ddb/db_probes.h \
 	ddb/db_print.c \
 	ddb/db_print.h \
 	ddb/db_run.c \


