diff --git a/src/builtin_functions.c b/src/builtin_functions.c
index 13c263b1428541fa0358127755c92be63aeefab4..06c3da92ef5abb0f51de7fcfcf824465bb98200f 100644
--- a/src/builtin_functions.c
+++ b/src/builtin_functions.c
@@ -5,7 +5,7 @@
 \*/
 /**/
 #include "global.h"
-RCSID("$Id: builtin_functions.c,v 1.390 2001/07/02 20:09:16 mast Exp $");
+RCSID("$Id: builtin_functions.c,v 1.391 2001/07/05 00:09:41 mast Exp $");
 #include "interpret.h"
 #include "svalue.h"
 #include "pike_macros.h"
@@ -6245,12 +6245,26 @@ PMOD_EXPORT void f__describe(INT32 args)
   struct svalue *s;
 
   CHECK_SECURITY_OR_ERROR(SECURITY_BIT_SECURITY,
-			  ("_optimizer_debug: permission denied.\n"));
+			  ("_describe: permission denied.\n"));
   get_all_args("_describe", args, "%*", &s);
   debug_describe_svalue(debug_malloc_pass(s));
   pop_n_elems(args-1);
 }
 
+/*! @decl void _gc_set_watch(array|multiset|mapping|object|function|program|string x)
+ */
+PMOD_EXPORT void f__gc_set_watch(INT32 args)
+{
+  CHECK_SECURITY_OR_ERROR(SECURITY_BIT_SECURITY,
+			  ("_gc_set_watch: permission denied.\n"));
+  if (args < 1)
+    SIMPLE_TOO_FEW_ARGS_ERROR("_gc_set_watch", 1);
+  if (Pike_sp[-args].type > MAX_REF_TYPE)
+    SIMPLE_BAD_ARG_ERROR("_gc_set_watch", 1, "reference type");
+  gc_watch(Pike_sp[-args].u.refs);
+  pop_n_elems(args);
+}
+
 #endif
 
 /*! @decl array map_array(array arr, function fun, mixed ... args)
@@ -7799,6 +7813,8 @@ void init_builtin_efuns(void)
 	   tFunc(tSetvar(1,tMix),tVar(1)),OPT_SIDE_EFFECT);
   ADD_EFUN("_describe",f__describe,
 	   tFunc(tSetvar(1,tMix),tVar(1)),OPT_SIDE_EFFECT);
+  ADD_EFUN("_gc_set_watch", f__gc_set_watch,
+	   tFunc(tComplex,tVoid), OPT_SIDE_EFFECT);
 #endif
 
   ADD_EFUN("_gc_status",f__gc_status,
diff --git a/src/gc.c b/src/gc.c
index 530468187c43aa659fa13dfc83fe4e51da34a695..7c37df85d28e92981cb7346c5f8158f9d01ce919 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -30,7 +30,7 @@ struct callback *gc_evaluator_callback=0;
 
 #include "block_alloc.h"
 
-RCSID("$Id: gc.c,v 1.165 2001/07/02 01:02:56 mast Exp $");
+RCSID("$Id: gc.c,v 1.166 2001/07/05 00:09:41 mast Exp $");
 
 /* Run garbage collect approximately every time
  * 20 percent of all arrays, objects and programs is
@@ -198,6 +198,7 @@ struct callback *debug_add_gc_callback(callback_func call,
   return add_to_callback(&gc_callbacks, call, arg, free_func);
 }
 
+static void init_gc(void);
 static void gc_cycle_pop(void *a);
 
 
@@ -240,6 +241,8 @@ static unsigned gc_extra_refs = 0;
 static unsigned max_tot_gc_frames = 0;
 static unsigned tot_cycle_checked = 0, tot_live_rec = 0, tot_frame_rot = 0;
 
+static int gc_is_watching = 0;
+
 void dump_gc_info(void)
 {
   fprintf(stderr,"Current number of objects: %d\n",num_objects);
@@ -544,9 +547,9 @@ static void describe_gc_frame(struct gc_frame *l)
 static void describe_marker(struct marker *m)
 {
   if (m) {
-    fprintf(stderr, "marker at %p: flags=0x%04x, refs=%d, weak=%d, "
+    fprintf(stderr, "marker at %p: flags=0x%05lx, refs=%d, weak=%d, "
 	    "xrefs=%d, saved=%d, frame=%p",
-	    m, m->flags, m->refs, m->weak_refs,
+	    m, (long) m->flags, m->refs, m->weak_refs,
 	    m->xrefs, m->saved_refs, m->frame);
 #ifdef PIKE_DEBUG
     if (m->frame) {
@@ -957,15 +960,36 @@ void debug_describe_svalue(struct svalue *s)
   describe_something(s->u.refs,s->type,0,2,0);
 }
 
+void gc_watch(void *a)
+{
+  struct marker *m;
+  init_gc();
+  m = get_marker(a);
+  if (!(m->flags & GC_WATCHED)) {
+    m->flags |= GC_WATCHED;
+    fprintf(stderr, "## Watching thing %p.\n", a);
+    gc_is_watching++;
+  }
+  else
+    fprintf(stderr, "## Already watching thing %p.\n", a);
+}
+
 void debug_gc_touch(void *a)
 {
   struct marker *m;
+
+  if (gc_is_watching && (m = find_marker(a)) && m->flags & GC_WATCHED) {
+    /* This is useful to set breakpoints on. */
+    fprintf(stderr, "## Watched thing %p found in "
+	    "gc_touch() in pass %d.\n", a, Pike_in_gc);
+  }
+
   if (!a) fatal("Got null pointer.\n");
 
   switch (Pike_in_gc) {
     case GC_PASS_PRETOUCH:
       m = find_marker(a);
-      if (m && !(m->flags & GC_PRETOUCHED))
+      if (m && !(m->flags & (GC_PRETOUCHED|GC_WATCHED)))
 	gc_fatal(a, 1, "Thing got an existing but untouched marker.\n");
       m = get_marker(a);
       m->flags |= GC_PRETOUCHED;
@@ -1076,6 +1100,11 @@ PMOD_EXPORT INT32 real_gc_check(void *a)
   INT32 ret;
 
 #ifdef PIKE_DEBUG
+  if (gc_is_watching && (m = find_marker(a)) && m->flags & GC_WATCHED) {
+    /* This is useful to set breakpoints on. */
+    fprintf(stderr, "## Watched thing %p found in "
+	    "gc_check() in pass %d.\n", a, Pike_in_gc);
+  }
   if (!(m = gc_check_debug(a, 0))) return 0;
 #else
   m = get_marker(a);
@@ -1094,6 +1123,11 @@ INT32 real_gc_check_weak(void *a)
   INT32 ret;
 
 #ifdef PIKE_DEBUG
+  if (gc_is_watching && (m = find_marker(a)) && m->flags & GC_WATCHED) {
+    /* This is useful to set breakpoints on. */
+    fprintf(stderr, "## Watched thing %p found in "
+	    "gc_check_weak() in pass %d.\n", a, Pike_in_gc);
+  }
   if (!(m = gc_check_debug(a, 1))) return 0;
   if (m->weak_refs < 0)
     gc_fatal(a, 1, "Thing has already reached threshold for weak free.\n");
@@ -1119,8 +1153,14 @@ INT32 real_gc_check_weak(void *a)
 
 static void init_gc(void)
 {
-  init_marker_hash();
-  get_marker(rec_list.data);	/* Used to simplify fencepost conditions. */
+#ifdef PIKE_DEBUG
+  if (!gc_is_watching) {
+#endif
+    init_marker_hash();
+    get_marker(rec_list.data);	/* Used to simplify fencepost conditions. */
+#ifdef PIKE_DEBUG
+  }
+#endif
 }
 
 static void exit_gc(void)
@@ -1131,6 +1171,13 @@ static void exit_gc(void)
   for(e=0;e<marker_hash_table_size;e++)
     while(marker_hash_table[e])
       remove_marker(marker_hash_table[e]->data);
+#endif
+#ifdef PIKE_DEBUG
+  if (gc_is_watching) {
+    fprintf(stderr, "## Exiting gc and resetting watches for %d things.\n",
+	    gc_is_watching);
+    gc_is_watching = 0;
+  }
 #endif
   exit_marker_hash();
   free_all_gc_frame_blocks();
@@ -1214,6 +1261,12 @@ void debug_gc_add_extra_ref(void *a)
 {
   struct marker *m;
 
+  if (gc_is_watching && (m = find_marker(a)) && m->flags & GC_WATCHED) {
+    /* This is useful to set breakpoints on. */
+    fprintf(stderr, "## Watched thing %p found in "
+	    "gc_add_extra_ref() in pass %d.\n", a, Pike_in_gc);
+  }
+
   if (gc_debug) {
     m = find_marker(a);
     if ((!m || !(m->flags & GC_PRETOUCHED)) &&
@@ -1234,6 +1287,12 @@ void debug_gc_free_extra_ref(void *a)
 {
   struct marker *m;
 
+  if (gc_is_watching && (m = find_marker(a)) && m->flags & GC_WATCHED) {
+    /* This is useful to set breakpoints on. */
+    fprintf(stderr, "## Watched thing %p found in "
+	    "gc_free_extra_ref() in pass %d.\n", a, Pike_in_gc);
+  }
+
   if (gc_debug) {
     m = find_marker(a);
     if ((!m || !(m->flags & GC_PRETOUCHED)) &&
@@ -1253,6 +1312,13 @@ void debug_gc_free_extra_ref(void *a)
 int debug_gc_is_referenced(void *a)
 {
   struct marker *m;
+
+  if (gc_is_watching && (m = find_marker(a)) && m->flags & GC_WATCHED) {
+    /* This is useful to set breakpoints on. */
+    fprintf(stderr, "## Watched thing %p found in "
+	    "gc_is_referenced() in pass %d.\n", a, Pike_in_gc);
+  }
+
   if (!a) fatal("Got null pointer.\n");
   if (Pike_in_gc != GC_PASS_MARK)
     fatal("gc_is_referenced() called in invalid gc pass.\n");
@@ -1276,6 +1342,13 @@ int debug_gc_is_referenced(void *a)
 int gc_external_mark3(void *a, void *in, char *where)
 {
   struct marker *m;
+
+  if (gc_is_watching && (m = find_marker(a)) && m->flags & GC_WATCHED) {
+    /* This is useful to set breakpoints on. */
+    fprintf(stderr, "## Watched thing %p found in "
+	    "gc_external_mark3() in pass %d.\n", a, Pike_in_gc);
+  }
+
   if (!a) fatal("Got null pointer.\n");
 
   if(Pike_in_gc == GC_PASS_LOCATE)
@@ -1332,6 +1405,11 @@ int gc_do_weak_free(void *a)
   struct marker *m;
 
 #ifdef PIKE_DEBUG
+  if (gc_is_watching && (m = find_marker(a)) && m->flags & GC_WATCHED) {
+    /* This is useful to set breakpoints on. */
+    fprintf(stderr, "## Watched thing %p found in "
+	    "gc_do_weak_free() in pass %d.\n", a, Pike_in_gc);
+  }
   if (!a) fatal("Got null pointer.\n");
   if (Pike_in_gc != GC_PASS_MARK && Pike_in_gc != GC_PASS_ZAP_WEAK)
     fatal("gc_do_weak_free() called in invalid gc pass.\n");
@@ -1390,6 +1468,11 @@ void gc_delayed_free(void *a)
   struct marker *m;
 
 #ifdef PIKE_DEBUG
+  if (gc_is_watching && (m = find_marker(a)) && m->flags & GC_WATCHED) {
+    /* This is useful to set breakpoints on. */
+    fprintf(stderr, "## Watched thing %p found in "
+	    "gc_delayed_free() in pass %d.\n", a, Pike_in_gc);
+  }
   if (Pike_in_gc != GC_PASS_MARK && Pike_in_gc != GC_PASS_CYCLE &&
       Pike_in_gc != GC_PASS_ZAP_WEAK)
     fatal("gc_delayed_free() called in invalid gc pass.\n");
@@ -1412,11 +1495,29 @@ void gc_delayed_free(void *a)
   m->flags |= GC_GOT_DEAD_REF;
 }
 
+#ifdef PIKE_DEBUG
+void gc_mark_enqueue(queue_call call, void *data)
+{
+  struct marker *m;
+  if (gc_is_watching && (m = find_marker(data)) && m->flags & GC_WATCHED) {
+    /* This is useful to set breakpoints on. */
+    fprintf(stderr, "## Watched thing %p found in "
+	    "gc_mark_enqueue() in pass %d.\n", data, Pike_in_gc);
+  }
+  enqueue(&gc_mark_queue, call, data);
+}
+#endif
+
 int gc_mark(void *a)
 {
   struct marker *m = get_marker(debug_malloc_pass(a));
 
 #ifdef PIKE_DEBUG
+  if (gc_is_watching && m && m->flags & GC_WATCHED) {
+    /* This is useful to set breakpoints on. */
+    fprintf(stderr, "## Watched thing %p found in "
+	    "gc_mark() in pass %d.\n", a, Pike_in_gc);
+  }
   if (!a) fatal("Got null pointer.\n");
   if (Pike_in_gc != GC_PASS_MARK && Pike_in_gc != GC_PASS_ZAP_WEAK)
     fatal("gc mark attempted in invalid pass.\n");
@@ -1466,6 +1567,14 @@ PMOD_EXPORT void gc_cycle_enqueue(gc_cycle_check_cb *checkfn, void *data, int we
 {
   struct gc_frame *l = alloc_gc_frame();
 #ifdef PIKE_DEBUG
+  {
+    struct marker *m;
+    if (gc_is_watching && (m = find_marker(data)) && m->flags & GC_WATCHED) {
+      /* This is useful to set breakpoints on. */
+      fprintf(stderr, "## Watched thing %p found in "
+	      "gc_cycle_enqueue() in pass %d.\n", data, Pike_in_gc);
+    }
+  }
   if (Pike_in_gc != GC_PASS_CYCLE)
     gc_fatal(data, 0, "Use of the gc frame stack outside the cycle check pass.\n");
 #endif
@@ -1649,6 +1758,11 @@ int gc_cycle_push(void *x, struct marker *m, int weak)
   struct marker *last = find_marker(gc_rec_last->data);
 
 #ifdef PIKE_DEBUG
+  if (gc_is_watching && m && m->flags & GC_WATCHED) {
+    /* This is useful to set breakpoints on. */
+    fprintf(stderr, "## Watched thing %p found in "
+	    "gc_cycle_push() in pass %d.\n", x, Pike_in_gc);
+  }
 
   debug_malloc_touch(x);
 
@@ -1924,6 +2038,11 @@ static void gc_cycle_pop(void *a)
   struct gc_frame *here, *base, *p;
 
 #ifdef PIKE_DEBUG
+  if (gc_is_watching && m && m->flags & GC_WATCHED) {
+    /* This is useful to set breakpoints on. */
+    fprintf(stderr, "## Watched thing %p found in "
+	    "gc_cycle_pop() in pass %d.\n", a, Pike_in_gc);
+  }
   if (!a) fatal("Got null pointer.\n");
   if (Pike_in_gc != GC_PASS_CYCLE)
     fatal("GC cycle pop attempted in invalid pass.\n");
@@ -2034,6 +2153,11 @@ int gc_do_free(void *a)
 {
   struct marker *m;
 #ifdef PIKE_DEBUG
+  if (gc_is_watching && (m = find_marker(a)) && m->flags & GC_WATCHED) {
+    /* This is useful to set breakpoints on. */
+    fprintf(stderr, "## Watched thing %p found in "
+	    "gc_do_free() in pass %d.\n", a, Pike_in_gc);
+  }
   if (!a) fatal("Got null pointer.\n");
   if (Pike_in_gc != GC_PASS_FREE)
     fatal("gc free attempted in invalid pass.\n");
@@ -2141,6 +2265,8 @@ int do_gc(void)
 #ifdef PIKE_DEBUG
   gc_debug = d_flag;
   SET_ONERROR(uwp, fatal_on_error, "Shouldn't get an exception inside the gc.\n");
+  if (gc_is_watching)
+    fprintf(stderr, "## Doing gc while watching for %d things.\n", gc_is_watching);
 #endif
 
   destruct_objects_to_destruct();
diff --git a/src/gc.h b/src/gc.h
index 3864af918d2eaf6750e72b85bc5a3995f76fa86e..cf87666b25a6f1da3776d5160461278b10e663ed 100644
--- a/src/gc.h
+++ b/src/gc.h
@@ -1,5 +1,5 @@
 /*
- * $Id: gc.h,v 1.81 2001/07/01 23:07:55 mast Exp $
+ * $Id: gc.h,v 1.82 2001/07/05 00:09:41 mast Exp $
  */
 #ifndef GC_H
 #define GC_H
@@ -108,8 +108,10 @@ struct marker
   INT32 saved_refs;
   /* References at beginning of gc. Set by pretouch and check passes.
    * Decreased by gc_do_weak_free() as weak references are removed. */
-#endif
+  unsigned INT32 flags;
+#else
   unsigned INT16 flags;
+#endif
 };
 
 #define GC_MARKED		0x0001
@@ -164,6 +166,8 @@ struct marker
  * freed. Set in the mark and zap weak passes. */
 #define GC_CHECKED_AS_WEAK	0x8000
 /* The thing has been visited by gc_checked_as_weak(). */
+#define GC_WATCHED		0x10000
+/* The thing has been set under watch by gc_watch(). */
 #endif
 
 #ifdef PIKE_DEBUG
@@ -217,6 +221,7 @@ void low_describe_something(void *a,
 void describe_something(void *a, int t, int indent, int depth, int flags);
 PMOD_EXPORT void describe(void *x);
 void debug_describe_svalue(struct svalue *s);
+void gc_watch(void *a);
 void debug_gc_touch(void *a);
 PMOD_EXPORT INT32 real_gc_check(void *a);
 INT32 real_gc_check_weak(void *a);
@@ -228,6 +233,7 @@ int gc_external_mark3(void *a, void *in, char *where);
 void debug_really_free_gc_frame(struct gc_frame *l);
 int gc_do_weak_free(void *a);
 void gc_delayed_free(void *a);
+void debug_gc_mark_enqueue(queue_call call, void *data);
 int gc_mark(void *a);
 PMOD_EXPORT void gc_cycle_enqueue(gc_cycle_check_cb *checkfn, void *data, int weak);
 void gc_cycle_run_queue();