Index: configure.in
===================================================================
--- configure.in	(revision 5983)
+++ configure.in	(working copy)
@@ -738,6 +738,9 @@
    none/tests/ppc64/Makefile
    none/tests/x86/Makefile
    none/docs/Makefile
+   refdbg/Makefile
+   refdbg/tests/Makefile
+   refdbg/docs/Makefile
 ) 
 
 cat<<EOF
Index: refdbg/refdbg.h
===================================================================
--- refdbg/refdbg.h	(revision 0)
+++ refdbg/refdbg.h	(revision 0)
@@ -0,0 +1,143 @@
+/*
+   ----------------------------------------------------------------
+
+   Notice that the following BSD-style license applies to this one
+   file (refdbg.h) only.  The rest of Valgrind is licensed under the
+   terms of the GNU General Public License, version 2, unless
+   otherwise indicated.  See the COPYING file in the source
+   distribution for details.
+
+   ----------------------------------------------------------------
+
+   This file is part of refdbg, a lightweight Valgrind tool for
+   detecting reference leaks.
+
+   Copyright (C) 2006 Chris Wilson.  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. The origin of this software must not be misrepresented; you must
+      not claim that you wrote the original software.  If you use this
+      software in a product, an acknowledgment in the product
+      documentation would be appreciated but is not required.
+
+   3. Altered source versions must be plainly marked as such, and must
+      not be misrepresented as being the original software.
+
+   4. The name of the author may not be used to endorse or promote
+      products derived from this software without specific prior written
+      permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+
+   ----------------------------------------------------------------
+
+   Notice that the above BSD-style license applies to this one file
+   (refdbg.h) only.  The entire rest of Valgrind is licensed under
+   the terms of the GNU General Public License, version 2.  See the
+   COPYING file in the source distribution for details.
+
+   ----------------------------------------------------------------
+*/
+
+#ifndef __refdbg_h
+#define __refdbg_h
+
+#include "valgrind.h"
+
+/*
+** Setup client request calls so we can track reference counts
+*/
+typedef
+enum {
+  VG_USERREQ__NEW_TYPE = VG_USERREQ_TOOL_BASE('R','F'),
+
+  VG_USERREQ__GET_CTX,
+  VG_USERREQ__MOVE_CTX,
+
+  VG_USERREQ__NEW_REF,
+  VG_USERREQ__INC_REF,
+  VG_USERREQ__DEC_REF,
+  VG_USERREQ__DEL_REF
+
+} Vg_RefDbgClientRequest;
+
+#define REFDBG_NEW_TYPE(type, name, size) {\
+	unsigned int _qzz_res;                                       \
+	VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                      \
+			VG_USERREQ__NEW_TYPE,           \
+			type, name, size, 0, 0);\
+}
+
+#define REFDBG_GET_CTX(ptr, ctx, create) {\
+	unsigned int _qzz_res;                                       \
+	VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                      \
+			VG_USERREQ__GET_CTX,           \
+			ptr, ctx, create, 0, 0);\
+}
+#define REFDBG_MOVE_CTX(ptr, old, now) {\
+	unsigned int _qzz_res;                                       \
+	VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                      \
+			VG_USERREQ__MOVE_CTX,           \
+			ptr, old, now, 0, 0);\
+}
+
+#define REFDBG_NEW_REF(ptr, type) {\
+	unsigned int _qzz_res;                                       \
+	VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                      \
+			VG_USERREQ__NEW_REF,           \
+			ptr, type, 0, 0, 0);\
+}
+#define REFDBG_NEW_REF_WITH_CTX(ptr, type, ctx) {\
+	unsigned int _qzz_res;                                       \
+	VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                      \
+			VG_USERREQ__NEW_REF,           \
+			ptr, type, ctx, 0, 0);\
+}
+#define REFDBG_INC_REF(ptr) {\
+	unsigned int _qzz_res;                                       \
+	VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                      \
+			VG_USERREQ__INC_REF,           \
+			ptr, 0, 0, 0, 0); \
+}
+#define REFDBG_INC_REF_WITH_CTX(ptr, ctx) {\
+	unsigned int _qzz_res;                                       \
+	VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                      \
+			VG_USERREQ__INC_REF,           \
+			ptr, ctx, 0, 0, 0); \
+}
+#define REFDBG_DEC_REF(ptr) {\
+	unsigned int _qzz_res;                                       \
+	VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                      \
+			VG_USERREQ__DEC_REF,           \
+			ptr, 0, 0, 0, 0);                      \
+}
+#define REFDBG_DEC_REF_WITH_CTX(ptr, ctx) {\
+	unsigned int _qzz_res;                                       \
+	VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                      \
+			VG_USERREQ__DEC_REF,           \
+			ptr, ctx, 0, 0, 0);                      \
+}
+#define REFDBG_DEL_REF(ptr) {\
+	unsigned int _qzz_res;                                       \
+	VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                      \
+			VG_USERREQ__DEL_REF,           \
+			ptr, 0, 0, 0, 0);                      \
+}
+
+#endif
Index: refdbg/rf_include.h
===================================================================
--- refdbg/rf_include.h	(revision 0)
+++ refdbg/rf_include.h	(revision 0)
@@ -0,0 +1,98 @@
+/*
+   This file is part of refdbg, a lighweight Valgrind tool for
+   detecting reference leaks.
+
+   Copyright (C) 2006 Chris Wilson
+
+   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.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+#ifndef __RF_INCLUDE_H
+#define __RF_INCLUDE_H
+
+#define RF_(str)    VGAPPEND(vgRefDebg_, str)
+
+typedef enum {
+	ST_None,
+	ST_Leaked,
+	ST_Allocated,
+	ST_All,
+}ShowTypesMode;
+
+extern Bool RF_(clo_show_objects);
+extern Bool RF_(clo_show_references);
+extern ShowTypesMode RF_(clo_show_types);
+
+void RF_(print_types)(ShowTypesMode mode);
+void RF_(print_leaked_objects)(void);
+void RF_(print_object)(Addr p);
+
+
+typedef struct _RF_Type{
+	VgHashNode	node;
+	Char *name;
+	SizeT size;
+	SizeT allocated;
+	SizeT freed;
+	SizeT peak;
+	UInt average_age;
+}RF_Type;
+
+typedef struct _RF_Object{
+	VgHashNode	node;
+	RF_Type     *type;
+	ExeContext  *where;
+	Int         ref;
+	UInt        ninc, nsinc;
+	UInt        ndec, nsdec;
+	VgHashTable inc;
+	VgHashTable dec;
+	struct _RF_Context *contexts;
+	struct _RF_Context *context;
+}RF_Object;
+
+typedef struct _RF_Count{
+	VgHashNode node;
+	UInt       count;
+}RF_Count;
+
+typedef struct _RF_Context{
+	struct _RF_Context *prev, *next;
+	Addr ctx;
+	RF_Object *obj;
+	RF_Count *inc, *dec;
+}RF_Context;
+
+typedef struct _RF_Error{
+	UInt type;
+	Addr addr;
+} RF_Error;
+enum{
+	TypeErr,
+	ObjectErr,
+	ContextErr,
+	LeakErr
+};
+enum{
+	TypeSupp,
+	ObjectSupp,
+	ContextSupp,
+	LeakSupp
+};
+
+#endif /* __RF_INCLUDE_H */
Index: refdbg/tests/Makefile.am
===================================================================
--- refdbg/tests/Makefile.am	(revision 0)
+++ refdbg/tests/Makefile.am	(revision 0)
@@ -0,0 +1,3 @@
+# For AM_FLAG_M3264_PRI
+include $(top_srcdir)/Makefile.flags.am
+
Index: refdbg/docs/rf-manual.xml
===================================================================
--- refdbg/docs/rf-manual.xml	(revision 0)
+++ refdbg/docs/rf-manual.xml	(revision 0)
@@ -0,0 +1,14 @@
+<?xml version="1.0"?> <!-- -*- sgml -*- -->
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+
+
+<chapter id="rf-manual" xreflabel="Refdbg">
+
+<title>Refdbg: the reference debugger</title>
+<subtitle>A tool tracks references.</subtitle>
+
+<para>Refdbg is a minimalistic tool for Valgrind, as it depends upon
+client request to keep track of reference counting.</para>
+</chapter>
+
Index: refdbg/docs/Makefile.am
===================================================================
--- refdbg/docs/Makefile.am	(revision 0)
+++ refdbg/docs/Makefile.am	(revision 0)
@@ -0,0 +1 @@
+EXTRA_DIST = rf-manual.xml
Index: refdbg/Makefile.am
===================================================================
--- refdbg/Makefile.am	(revision 0)
+++ refdbg/Makefile.am	(revision 0)
@@ -0,0 +1,64 @@
+include $(top_srcdir)/Makefile.tool.am
+
+noinst_PROGRAMS = 
+if VG_X86_LINUX
+noinst_PROGRAMS += refdbg-x86-linux
+endif
+if VG_AMD64_LINUX
+noinst_PROGRAMS += refdbg-amd64-linux
+endif
+if VG_PPC32_LINUX
+noinst_PROGRAMS += refdbg-ppc32-linux
+endif
+if VG_PPC64_LINUX
+noinst_PROGRAMS += refdbg-ppc64-linux
+endif
+
+rfincludedir = $(includedir)/valgrind
+
+rfinclude_HEADERS = \
+	refdbg.h
+
+noinst_HEADERS =	\
+	rf_include.h
+
+
+VGPRELOAD_REFDBG_SOURCES_COMMON = rf_wrappers.c
+
+vgpreload_refdbg_x86_linux_so_SOURCES      = $(VGPRELOAD_REFDBG_SOURCES_COMMON)
+vgpreload_refdbg_x86_linux_so_CPPFLAGS     = $(AM_CPPFLAGS_X86_LINUX) -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include
+vgpreload_refdbg_x86_linux_so_CFLAGS       = $(AM_CFLAGS_X86_LINUX) $(AM_CFLAGS_PIC) -O2
+vgpreload_refdbg_x86_linux_so_CCASFLAGS    = $(AM_CCASFLAGS_X86_LINUX)
+vgpreload_refdbg_x86_linux_so_LDFLAGS      = \
+	$(PRELOAD_LDFLAGS_X86_LINUX)
+
+
+REFDBG_SOURCES_COMMON = rf_main.c
+
+refdbg_x86_linux_SOURCES      = $(REFDBG_SOURCES_COMMON)
+refdbg_x86_linux_CPPFLAGS     = $(AM_CPPFLAGS_X86_LINUX)
+refdbg_x86_linux_CFLAGS       = $(AM_CFLAGS_X86_LINUX)
+refdbg_x86_linux_DEPENDENCIES = $(COREGRIND_LIBS_X86_LINUX)
+refdbg_x86_linux_LDADD        = $(TOOL_LDADD_X86_LINUX)
+refdbg_x86_linux_LDFLAGS      = $(TOOL_LDFLAGS_X86_LINUX)
+
+refdbg_amd64_linux_SOURCES      = $(REFDBG_SOURCES_COMMON)
+refdbg_amd64_linux_CPPFLAGS     = $(AM_CPPFLAGS_AMD64_LINUX)
+refdbg_amd64_linux_CFLAGS       = $(AM_CFLAGS_AMD64_LINUX)
+refdbg_amd64_linux_DEPENDENCIES = $(COREGRIND_LIBS_AMD64_LINUX)
+refdbg_amd64_linux_LDADD        = $(TOOL_LDADD_AMD64_LINUX)
+refdbg_amd64_linux_LDFLAGS      = $(TOOL_LDFLAGS_AMD64_LINUX)
+
+refdbg_ppc32_linux_SOURCES      = $(REFDBG_SOURCES_COMMON)
+refdbg_ppc32_linux_CPPFLAGS     = $(AM_CPPFLAGS_PPC32_LINUX)
+refdbg_ppc32_linux_CFLAGS       = $(AM_CFLAGS_PPC32_LINUX)
+refdbg_ppc32_linux_DEPENDENCIES = $(COREGRIND_LIBS_PPC32_LINUX)
+refdbg_ppc32_linux_LDADD        = $(TOOL_LDADD_PPC32_LINUX)
+refdbg_ppc32_linux_LDFLAGS      = $(TOOL_LDFLAGS_PPC32_LINUX)
+
+refdbg_ppc64_linux_SOURCES      = $(REFDBG_SOURCES_COMMON)
+refdbg_ppc64_linux_CPPFLAGS     = $(AM_CPPFLAGS_PPC64_LINUX)
+refdbg_ppc64_linux_CFLAGS       = $(AM_CFLAGS_PPC64_LINUX)
+refdbg_ppc64_linux_DEPENDENCIES = $(COREGRIND_LIBS_PPC64_LINUX)
+refdbg_ppc64_linux_LDADD        = $(TOOL_LDADD_PPC64_LINUX)
+refdbg_ppc64_linux_LDFLAGS      = $(TOOL_LDFLAGS_PPC64_LINUX)
Index: refdbg/rf_wrappers.c
===================================================================
--- refdbg/rf_wrappers.c	(revision 0)
+++ refdbg/rf_wrappers.c	(revision 0)
@@ -0,0 +1,90 @@
+#include"pub_tool_basics.h"
+
+#include"refdbg.h"
+
+#include<glib.h>
+#include<glib-object.h>
+
+gpointer I_WRAP_SONAME_FNNAME_ZZ(libgobjectZa, gZutypeZucreateZuinstance)(GType type);
+gpointer I_WRAP_SONAME_FNNAME_ZZ(libgobjectZa, gZutypeZucreateZuinstance)(GType type)
+{
+	gpointer ptr;
+	OrigFn fn;
+
+	VALGRIND_GET_ORIG_FN(fn);
+
+	CALL_FN_W_W(ptr, fn, type);
+	if(ptr){
+		GTypeQuery query;
+		g_type_query(type, &query);
+		if(query.type==type){
+			SizeT size=query.instance_size;
+			const Char *name=query.type_name;
+			REFDBG_NEW_TYPE(type, name, size);
+		}
+		REFDBG_NEW_REF(ptr, type);
+	}
+
+	return ptr;
+}
+
+gpointer I_WRAP_SONAME_FNNAME_ZZ(libgobjectZa, gZuobjectZuref)(gpointer obj);
+gpointer I_WRAP_SONAME_FNNAME_ZZ(libgobjectZa, gZuobjectZuref)(gpointer obj)
+{
+	OrigFn fn;
+
+	VALGRIND_GET_ORIG_FN(fn);
+
+	REFDBG_INC_REF(obj);
+	CALL_FN_W_W(obj, fn, obj);
+
+	return obj;
+}
+
+void I_WRAP_SONAME_FNNAME_ZZ(libgobjectZa, gZuobjectZuunref)(gpointer obj);
+void I_WRAP_SONAME_FNNAME_ZZ(libgobjectZa, gZuobjectZuunref)(gpointer obj)
+{
+	OrigFn fn;
+
+	VALGRIND_GET_ORIG_FN(fn);
+
+	REFDBG_DEC_REF(obj);
+	CALL_FN_v_W(fn, obj);
+}
+
+
+GParamSpec *I_WRAP_SONAME_FNNAME_ZZ(libgobjectZa, gZuparamZuspecZuref)(GParamSpec *);
+GParamSpec *I_WRAP_SONAME_FNNAME_ZZ(libgobjectZa, gZuparamZuspecZuref)(GParamSpec *pspec)
+{
+	OrigFn fn;
+
+	VALGRIND_GET_ORIG_FN(fn);
+
+	REFDBG_INC_REF(pspec);
+	CALL_FN_W_W(pspec, fn, pspec);
+
+	return pspec;
+}
+
+void I_WRAP_SONAME_FNNAME_ZZ(libgobjectZa, gZuparamZuspecZuunref)(GParamSpec *);
+void I_WRAP_SONAME_FNNAME_ZZ(libgobjectZa, gZuparamZuspecZuunref)(GParamSpec *pspec)
+{
+	OrigFn fn;
+
+	VALGRIND_GET_ORIG_FN(fn);
+
+	REFDBG_DEC_REF(pspec);
+	CALL_FN_v_W(fn, pspec);
+}
+
+
+void I_WRAP_SONAME_FNNAME_ZZ(libgobjectZa, gZutypeZufreeZuinstance)(gpointer ptr);
+void I_WRAP_SONAME_FNNAME_ZZ(libgobjectZa, gZutypeZufreeZuinstance)(gpointer ptr)
+{
+	OrigFn fn;
+
+	VALGRIND_GET_ORIG_FN(fn);
+
+	REFDBG_DEL_REF(ptr);
+	CALL_FN_v_W(fn, ptr);
+}
Index: refdbg/rf_main.c
===================================================================
--- refdbg/rf_main.c	(revision 0)
+++ refdbg/rf_main.c	(revision 0)
@@ -0,0 +1,681 @@
+/*
+   This file is part of refdbg, a lightweight Valgrind tool for
+   detecting reference leaks.
+
+   Copyright (C) 2006 Chris Wilson
+
+   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.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+/* TODO
+ * - user suppressions for leaked types/objects
+ * - sorting output leaks/allocated/alphabetically
+ */
+
+#include"pub_tool_basics.h"
+#include"pub_tool_debuginfo.h"
+#include"pub_tool_hashtable.h"
+#include"pub_tool_libcbase.h"
+#include"pub_tool_libcassert.h"
+#include"pub_tool_libcprint.h"
+#include"pub_tool_libcbase.h"
+#include"pub_tool_options.h"
+#include"pub_tool_machine.h"     // VG_(fnptr_to_fnentry)
+#include"pub_tool_mallocfree.h"     // VG_(malloc)
+#include"pub_tool_threadstate.h" // VG_N_THREADS
+#include"pub_tool_tooliface.h"
+
+#include "rf_include.h"
+#include "refdbg.h"
+
+Bool RF_(clo_show_objects) = False;
+Bool RF_(clo_show_references) = False;
+ShowTypesMode RF_(clo_show_types) = ST_Leaked;
+
+/* Record objects. */
+static VgHashTable types;
+static VgHashTable objects;
+
+void RF_(print_types)(ShowTypesMode mode)
+{
+	RF_Type   *rt;
+	SizeT nbytes=0, allbytes=0;
+	SizeT nblocks=0, allblocks=0;
+
+	VG_(HT_ResetIter)(types);
+	while((rt=VG_(HT_Next)(types))){
+		SizeT n=rt->allocated - rt->freed;
+		nbytes+=rt->size*n;
+		nblocks+=n;
+
+		allblocks+=rt->allocated;
+		allbytes+=rt->size*rt->allocated;
+	}
+	VG_(message)(Vg_UserMsg,
+			"Allocated %,lu objects, %,lu bytes",
+			allblocks, allbytes);
+	VG_(message)(Vg_UserMsg,
+			"Objects in use at exit: %,lu objects, %,lu bytes.",
+			nblocks, nbytes);
+
+	VG_(HT_ResetIter)(types);
+	while((rt=VG_(HT_Next)(types))){
+		Bool show=False;
+		SizeT n=rt->allocated - rt->freed;
+		if(mode==ST_All)
+			show=True;
+		else if(mode==ST_Allocated)
+			show=rt->allocated!=0;
+		else if(mode==ST_Leaked)
+			show=n!=0;
+		if(show)
+			VG_(message)(Vg_UserMsg,
+					"%s: allocated %,lu, freed %,lu [peak %,lu], leaked %,lu bytes.",
+					rt->name, rt->allocated, rt->freed, rt->peak, n*rt->size);
+	}
+}
+
+void RF_(print_leaked_objects)(void)
+{
+	RF_Object *rf;
+
+	VG_(message)(Vg_UserMsg, "---");
+
+	VG_(HT_ResetIter)(objects);
+	while((rf=VG_(HT_Next)(objects))){
+		const Char *name=rf->type->name;
+		if(VG_(strncmp)(name, "GParam", 6)
+				&& VG_(strncmp)(name, "Pango", 5))
+			RF_(print_object)((Addr)rf->node.key);
+	}
+}
+
+void RF_(print_object)(Addr p)
+{
+	RF_Object *rf=VG_(HT_lookup)(objects, p);
+	RF_Count *rc;
+	if(rf){
+		if(rf->type){
+			VG_(message)(Vg_UserMsg,
+					"Object at %p [%s, size %d], references %d [++%d, %d--].",
+					p, rf->type->name, rf->type->size, rf->ref, rf->ninc, rf->ndec);
+		}else{
+			VG_(message)(Vg_UserMsg,
+					"Object at %p [no type], references %d [++%d, %d--].",
+					p, rf->ref, rf->ninc, rf->ndec);
+		}
+
+		if(RF_(clo_show_references)){
+			VG_(message)(Vg_UserMsg, "Referenced %d times, suppressed %d ...",
+					rf->ninc, rf->nsinc);
+		}
+		VG_(message)(Vg_UserMsg, "Created at:");
+		VG_(pp_ExeContext)(rf->where);
+		VG_(message)(Vg_UserMsg, "---");
+
+		if(RF_(clo_show_references)){
+			if(rf->ninc){
+				VG_(HT_ResetIter)(rf->inc);
+				while((rc=VG_(HT_Next)(rf->inc))){
+					VG_(message)(Vg_UserMsg, "Referenced %dx:", rc->count);
+					VG_(pp_ExeContext)((ExeContext *)rc->node.key);
+					VG_(message)(Vg_UserMsg, "---");
+				}
+			}
+
+			if(rf->ndec){
+				VG_(message)(Vg_UserMsg, "Unreferenced %d times, suppressed %d ...",
+						rf->ndec, rf->nsdec);
+				VG_(HT_ResetIter)(rf->dec);
+				while((rc=VG_(HT_Next)(rf->dec))){
+					VG_(message)(Vg_UserMsg, "Unreferenced %dx:", rc->count);
+					VG_(pp_ExeContext)((ExeContext *)rc->node.key);
+					VG_(message)(Vg_UserMsg, "---");
+				}
+			}
+		}
+	}
+}
+
+
+static void rf_post_clo_init(void)
+{
+}
+
+static IRBB *rf_instrument(VgCallbackClosure *closure,
+		IRBB *bbIn,
+		VexGuestLayout *layout,
+		VexGuestExtents *vge,
+		IRType gWordTy, IRType hWordTy)
+{
+	return bbIn;
+}
+
+static void rf_fini(Int exitcode)
+{
+	RF_(print_types)(RF_(clo_show_types));
+	if(RF_(clo_show_objects))
+		RF_(print_leaked_objects)();
+}
+
+/*------------------------------------------------------------*/
+/*--- Client Request Handling                              ---*/
+/*------------------------------------------------------------*/
+static RF_Context *get_context(ThreadId tid, Addr p, Addr ctx, Bool create)
+{
+	RF_Object *rf;
+	RF_Context *c;
+
+	rf=VG_(HT_lookup)(objects, p);
+	if(!rf){
+		VG_(maybe_record_error)(tid, ObjectErr, p,
+				"get_context: unknown object", NULL);
+		return NULL;
+	}
+
+	for(c=rf->contexts; c; c=c->next){
+		if(c->ctx==ctx){
+			rf->context=c;
+			return c;
+		}
+	}
+
+	if(create){
+		c=VG_(malloc)(sizeof(RF_Context));
+		c->ctx=ctx;
+		c->inc=c->dec=NULL;
+		c->obj=rf;
+
+		c->next=rf->contexts;
+		if(rf->contexts)
+			rf->contexts->prev=c;
+		c->prev=NULL;
+		rf->contexts=c;
+		rf->context=c;
+	}else{
+		VG_(maybe_record_error)(tid, ContextErr, ctx,
+				"get_context: unknown context", NULL);
+		c=NULL;
+	}
+
+	return c;
+}
+
+static RF_Context *move_context(ThreadId tid, Addr p, Addr old, Addr ctx)
+{
+	RF_Object *rf;
+	RF_Context *c;
+
+	rf=VG_(HT_lookup)(objects, p);
+	if(!rf){
+		VG_(maybe_record_error)(tid, ObjectErr, p,
+				"move_context: unknown object", NULL);
+		return NULL;
+	}
+
+
+	c=rf->context;
+	if(c && c->ctx==old){
+		c->ctx=ctx;
+	}else for(c=rf->contexts; c; c=c->next){
+		if(c->ctx==old){
+			c->ctx=ctx;
+			break;
+		}
+	}
+
+	if(!c)
+		VG_(maybe_record_error)(tid, ContextErr, ctx,
+				"move_context: unknown context", NULL);
+
+	return c;
+}
+
+static void pop_context(RF_Context *c)
+{
+	if(c->inc && c->dec){
+		if(!--c->inc->count){
+			VG_(HT_remove)(c->obj->inc, c->inc->node.key);
+			VG_(free)(c->inc);
+		}
+		if(!--c->dec->count){
+			VG_(HT_remove)(c->obj->dec, c->dec->node.key);
+			VG_(free)(c->dec);
+		}
+		c->obj->ninc--, c->obj->nsinc++;
+		c->obj->ndec--, c->obj->nsdec++;
+	}
+
+	if(c->prev)
+		c->prev->next=c->next;
+	else
+		c->obj->contexts=c->next;
+	if(c->next)
+		c->next->prev=c->prev;
+
+	VG_(free)(c);
+}
+
+static RF_Type *new_RF_Type(UInt id, const Char *name, SizeT size)
+{
+	RF_Type *rt=VG_(HT_lookup)(types, id);
+	if(!rt){
+		rt=VG_(malloc)(sizeof(RF_Type));
+		rt->node.key=id;
+		rt->name=VG_(strdup)(name);
+		rt->size=size;
+		rt->allocated=0;
+		rt->freed=0;
+		rt->peak=0;
+		rt->average_age=0;
+		VG_(HT_add_node)(types, rt);
+	}else{
+		rt->size=size;
+		VG_(free)(rt->name);
+		rt->name=VG_(strdup)(name);
+	}
+	return rt;
+}
+
+static RF_Type *add_RF_Type(UInt id)
+{
+	RF_Type *rt;
+
+	rt=VG_(HT_lookup)(types, id);
+	if(!rt)
+		rt=new_RF_Type(id, "<unknown>", 1);
+	rt->allocated++;
+	if(rt->allocated - rt->freed>rt->peak)
+		rt->peak=rt->allocated - rt->freed;
+
+	return rt;
+}
+
+static RF_Object *new_RF_Object(ThreadId tid, Addr p, UInt id)
+{
+	RF_Object *rf = VG_(malloc)(sizeof(RF_Object));
+	rf->node.key  = p;
+	rf->type      = add_RF_Type(id);
+	rf->where     = VG_(record_ExeContext)(tid);
+	rf->ref       = 0;
+	rf->ninc      = 0;
+	rf->nsinc     = 0;
+	rf->ndec      = 0;
+	rf->nsdec     = 0;
+	rf->inc       = VG_(HT_construct)(127);
+	rf->dec       = VG_(HT_construct)(127);
+	rf->contexts  = NULL;
+	rf->context   = NULL;
+	VG_(HT_add_node)(objects, rf);
+
+	return rf;
+}
+
+static RF_Count *increment_RF_Count(ThreadId tid, VgHashTable table)
+{
+	ExeContext *where=VG_(record_ExeContext)(tid);
+	RF_Count *rc=table?VG_(HT_lookup)(table, (Addr)where):NULL;
+	if(!rc){
+		rc=VG_(malloc)(sizeof(RF_Count));
+		rc->node.key=(UWord)where;
+		rc->count=0;
+		if(table)
+			VG_(HT_add_node)(table, rc);
+	}
+	rc->count++;
+	return rc;
+}
+
+static void track_new(ThreadId tid, Addr p, UInt id, Addr ctx)
+{
+	RF_Object *rf=new_RF_Object(tid, p, id);
+	RF_Context *c=get_context(tid, p, ctx?ctx:p, True);
+	RF_Count *rc=increment_RF_Count(tid, NULL);
+	rf->where=(ExeContext *)rc->node.key;
+	c->inc=rc;
+	rf->context=NULL;
+	rf->ninc++;
+	rf->ref++;
+}
+
+
+static void track_ref(ThreadId tid, Addr p, Addr ctx)
+{
+	RF_Object *rf=VG_(HT_lookup)(objects, p);
+	if(rf){
+		RF_Count *rc=increment_RF_Count(tid, rf->inc);
+		RF_Context *c=ctx?get_context(tid, p, ctx, True):rf->context;
+		if(c){
+			c->inc=rc;
+			rf->context=NULL;
+		}
+		rf->ninc++;
+		rf->ref++;
+	}else
+		VG_(maybe_record_error)(tid, ObjectErr, p,
+				"invalid ref: unknown object", NULL);
+}
+
+
+static void track_unref(ThreadId tid, Addr p, Addr ctx)
+{
+	RF_Object *rf=VG_(HT_lookup)(objects, p);
+	if(rf){
+		RF_Count *rc=increment_RF_Count(tid, rf->dec);
+		RF_Context *c=ctx?get_context(tid, p, ctx, False):rf->context;
+		if(c){
+			c->dec=rc;
+			pop_context(c);
+			rf->context=NULL;
+		}
+		rf->ndec++;
+		--rf->ref;
+	}else
+		VG_(maybe_record_error)(tid, ObjectErr, p,
+				"invalid unref: unknown object", NULL);
+}
+
+
+static void free_RF_Counts(VgHashTable table)
+{
+	RF_Count *rc;
+	VG_(HT_ResetIter)(table);
+	while((rc=VG_(HT_Next)(table))){
+		VG_(HT_remove) (table, rc->node.key);
+		VG_(free)(rc);
+		VG_(HT_ResetIter)(table);
+	}
+	VG_(HT_destruct)(table);
+}
+
+static void free_RF_Contexts(RF_Context *contexts)
+{
+	while(contexts){
+		RF_Context *next=contexts->next;
+		VG_(free)(contexts);
+		contexts=next;
+	}
+}
+
+static void track_del(ThreadId tid, Addr p)
+{
+	RF_Object *rf=VG_(HT_lookup)(objects, p);
+	if(rf){
+		VG_(HT_remove)(objects, rf->node.key);
+
+		//rf->ref==0;
+		free_RF_Contexts(rf->contexts);
+
+		free_RF_Counts(rf->inc);
+		free_RF_Counts(rf->dec);
+
+		rf->type->freed++;
+		VG_(free)(rf);
+	}else
+		VG_(maybe_record_error)(tid, ObjectErr, p,
+				"invalid delete: unknown object", NULL);
+}
+
+
+static Bool rf_handle_client_request(ThreadId tid, UWord *arg, UWord *ret)
+{
+	if(!VG_IS_TOOL_USERREQ('R','F',arg[0]))
+		return False;
+
+	switch(arg[0]){
+		case VG_USERREQ__NEW_TYPE:
+			new_RF_Type(arg[1], (const Char *)arg[2], arg[3]);
+			break;
+
+		case VG_USERREQ__GET_CTX:
+			get_context(tid, arg[1], arg[2], arg[3]);
+			break;
+		case VG_USERREQ__MOVE_CTX:
+			move_context(tid, arg[1], arg[2], arg[3]);
+			break;
+
+		case VG_USERREQ__NEW_REF:
+			track_new(tid, arg[1], arg[2], arg[3]);
+			break;
+		case VG_USERREQ__INC_REF:
+			track_ref(tid, arg[1], arg[2]);
+			break;
+		case VG_USERREQ__DEC_REF:
+			track_unref(tid, arg[1], arg[2]);
+			break;
+		case VG_USERREQ__DEL_REF:
+			track_del(tid, arg[1]);
+			break;
+
+		default:
+			return False;
+	}
+
+	return True;
+}
+
+
+/* errors and suppressions */
+static Bool rf_eq_Error(VgRes res, Error *e1, Error *e2)
+{
+	RF_Error *e1_extra=VG_(get_error_extra)(e1);
+	RF_Error *e2_extra=VG_(get_error_extra)(e2);
+
+	switch(VG_(get_error_kind)(e1)){
+		case TypeErr:
+			return e1_extra->type==e2_extra->type;
+		case ObjectErr:
+		case ContextErr:
+			//return VG_(get_error_address)(e1)==VG_(get_error_address)(e2);
+			return True;
+	}
+
+	return False;
+}
+
+static void rf_pp_Error(Error *err)
+{
+	RF_Error *err_extra=VG_(get_error_extra)(err);
+
+	switch(VG_(get_error_kind)(err)){
+		case TypeErr:
+			VG_(message)(Vg_UserMsg, "%s",
+					VG_(get_error_string)(err));
+			break;
+		case ObjectErr:
+			VG_(message)(Vg_UserMsg, "%s %p",
+					VG_(get_error_string)(err), VG_(get_error_address)(err));
+			VG_(pp_ExeContext)(VG_(get_error_where)(err));
+			break;
+		case ContextErr:
+			VG_(message)(Vg_UserMsg, "%s %p",
+					VG_(get_error_string)(err), VG_(get_error_address)(err));
+			VG_(pp_ExeContext)(VG_(get_error_where)(err));
+			break;
+	}
+}
+
+
+static UInt rf_update_extra(Error *err)
+{
+	switch(VG_(get_error_kind)(err)){
+		case TypeErr:
+		case ObjectErr:
+		case ContextErr:
+			return sizeof(RF_Error);
+		default:
+			VG_(tool_panic)("rf_update_extra: bad error_kind");
+	}
+}
+
+
+static Bool rf_recognised_suppression(Char *name, Supp *su)
+{
+	SuppKind skind;
+
+	if     (VG_STREQ(name, "Type")) skind=TypeSupp;
+	else if(VG_STREQ(name, "Leak")) skind=LeakSupp;
+	else
+		return False;
+
+	VG_(set_supp_kind)(su, skind);
+	return True;
+}
+
+
+static Bool rf_read_extra_suppression_info(Int fd, Char *buf, Int nbuf, Supp *su)
+{
+	Bool eof;
+
+	if(VG_(get_supp_kind)(su)==TypeSupp){
+		eof=VG_(get_line)(fd, buf, nbuf);
+		if(eof) return False;
+		VG_(set_supp_string)(su, VG_(strdup)(buf));
+	}
+
+	return True;
+}
+
+
+static Bool rf_error_matches_suppression(Error *err, Supp *su)
+{
+	RF_Error *err_extra=VG_(get_error_extra)(err);
+	ErrorKind ekind=VG_(get_error_kind)(err);
+
+	switch(VG_(get_supp_kind)(su)){
+		case TypeSupp:
+			return ekind==TypeErr
+				&& VG_STREQ(VG_(get_error_string)(err),
+						VG_(get_supp_string)(su));
+
+		case ContextSupp:
+			return ekind==ContextErr
+				&& VG_STREQ(VG_(get_error_string)(err),
+						VG_(get_supp_string)(su));
+
+		case ObjectSupp:
+			return ekind==ObjectErr
+				&& VG_STREQ(VG_(get_error_string)(err),
+						VG_(get_supp_string)(su));
+
+		case LeakSupp:
+			return ekind==LeakErr
+				&& VG_STREQ(VG_(get_error_string)(err),
+						VG_(get_supp_string)(su));
+
+		default:
+			VG_(printf)("Error:\n"
+					" unknown suppression type %d\n",
+					VG_(get_supp_kind)(su));
+			VG_(tool_panic)("unknown suppression type in rf_error_matches_suppression");
+	}
+}
+
+
+static Char *rf_get_error_name(Error *err)
+{
+	Char *s;
+	switch(VG_(get_error_kind)(err)){
+		case TypeErr: return "Type";
+		case ObjectErr: return "Object";
+		case ContextErr: return "Context";
+		default: VG_(tool_panic)("rf_get_error_name: unexpexted type");
+	}
+	VG_(printf)(s);
+}
+
+
+static void rf_print_extra_suppression_info(Error *err)
+{
+	switch(VG_(get_error_kind)(err)){
+		case TypeErr:
+			VG_(printf)("    %s\n", VG_(get_error_string)(err));
+			break;
+	}
+}
+
+
+/* command line options */
+static Bool rf_process_cmd_line_options(Char* arg)
+{
+	VG_BOOL_CLO(arg, "--show-objects",      RF_(clo_show_objects))
+	else VG_BOOL_CLO(arg, "--show-references",      RF_(clo_show_references))
+	else if(VG_CLO_STREQ(arg, "--show-types")
+			|| VG_CLO_STREQ(arg, "--show-types=all"))
+		RF_(clo_show_types)=ST_All;
+	else if(VG_CLO_STREQ(arg, "--show-types=allocated"))
+		RF_(clo_show_types)=ST_Allocated;
+	else if(VG_CLO_STREQ(arg, "--show-types=leaked"))
+		RF_(clo_show_types)=ST_Leaked;
+	else if(VG_CLO_STREQ(arg, "--show-types=no")
+			|| VG_CLO_STREQ(arg, "--show-types=none"))
+		RF_(clo_show_types)=ST_None;
+	else
+		return False;
+
+	return True;
+}
+
+
+static void rf_print_usage(void)
+{
+   VG_(printf)(
+"    --show-types=no|leaked|allocated|all   Print out allocations per type\n"
+"    --show-objects=no|yes                  Display leaked objects\n"
+"    --show-references=no|yes               Display leaked references\n"
+   );
+}
+
+
+static void rf_print_debug_usage(void)
+{
+}
+
+
+static void rf_pre_clo_init(void)
+{
+	VG_(details_name)            ("refdbg");
+	VG_(details_version)         (NULL);
+	VG_(details_description)     ("Reference debugger");
+	VG_(details_copyright_author)(
+			"Copyright (C) 2006, and GNU GPL'd, by Chris Wilson.");
+	VG_(details_bug_reports_to)  ("chris@chris-wilson.co.uk");
+
+	VG_(basic_tool_funcs)(rf_post_clo_init,
+			rf_instrument,
+			rf_fini);
+	VG_(needs_core_errors)       ();
+	VG_(needs_command_line_options)(
+			rf_process_cmd_line_options,
+			rf_print_usage,
+			rf_print_debug_usage);
+	VG_(needs_client_requests)   (rf_handle_client_request);
+	VG_(needs_tool_errors)       (rf_eq_Error,
+			                          rf_pp_Error,
+																rf_update_extra,
+																rf_recognised_suppression,
+																rf_read_extra_suppression_info,
+																rf_error_matches_suppression,
+																rf_get_error_name,
+																rf_print_extra_suppression_info);
+
+	types=VG_(HT_construct)(1009);  // prime, not so big
+	objects=VG_(HT_construct)(80021);  // prime, big
+}
+
+VG_DETERMINE_INTERFACE_VERSION(rf_pre_clo_init)
Index: Makefile.am
===================================================================
--- Makefile.am	(revision 5983)
+++ Makefile.am	(working copy)
@@ -8,7 +8,8 @@
 		callgrind \
 		massif \
 		lackey \
-		none
+		none \
+		refdbg
 
 # Temporary: we want to compile Helgrind, but not regtest it.
 # Put docs last because building the HTML is slow and we want to get
