Add utrace(2)-based tracing (--enable-utrace).
diff --git a/INSTALL b/INSTALL
index c0ae106..8a825df 100644
--- a/INSTALL
+++ b/INSTALL
@@ -119,6 +119,10 @@
 --disable-experimental
     Disable support for the experimental API (*allocm()).
 
+--enable-utrace
+    Enable utrace(2)-based allocation tracing.  This feature is not broadly
+    portable (FreeBSD has it, but Linux and OS X do not).
+
 --enable-xmalloc
     Enable support for optional immediate termination due to out-of-memory
     errors, as is commonly implemented by "xmalloc" wrapper function for malloc.
diff --git a/configure.ac b/configure.ac
index 16f0378..8e94b5c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -699,6 +699,34 @@
 fi
 AC_SUBST([enable_fill])
 
+dnl Disable utrace(2)-based tracing by default.
+AC_ARG_ENABLE([utrace],
+  [AS_HELP_STRING([--enable-utrace], [Enable utrace(2)-based tracing])],
+[if test "x$enable_utrace" = "xno" ; then
+  enable_utrace="0"
+else
+  enable_utrace="1"
+fi
+],
+[enable_utrace="0"]
+)
+JE_COMPILABLE([utrace(2)], [
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <sys/ktrace.h>
+], [
+	utrace((void *)0, 0);
+], [je_cv_utrace])
+if test "x${je_cv_utrace}" = "xno" ; then
+  enable_utrace="0"
+fi
+if test "x$enable_utrace" = "x1" ; then
+  AC_DEFINE([JEMALLOC_UTRACE], [ ])
+fi
+AC_SUBST([enable_utrace])
+
 dnl Do not support the xmalloc option by default.
 AC_ARG_ENABLE([xmalloc],
   [AS_HELP_STRING([--enable-xmalloc], [Support xmalloc option])],
@@ -1061,6 +1089,7 @@
 AC_MSG_RESULT([tcache             : ${enable_tcache}])
 AC_MSG_RESULT([fill               : ${enable_fill}])
 AC_MSG_RESULT([xmalloc            : ${enable_xmalloc}])
+AC_MSG_RESULT([utrace             : ${enable_utrace}])
 AC_MSG_RESULT([dss                : ${enable_dss}])
 AC_MSG_RESULT([lazy_lock          : ${enable_lazy_lock}])
 AC_MSG_RESULT([tls                : ${enable_tls}])
diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in
index 7a2d033..8ae8262 100644
--- a/doc/jemalloc.xml.in
+++ b/doc/jemalloc.xml.in
@@ -712,6 +712,16 @@
 
       <varlistentry>
         <term>
+          <mallctl>config.utrace</mallctl>
+          (<type>bool</type>)
+          <literal>r-</literal>
+        </term>
+        <listitem><para><option>--enable-utrace</option> was specified during
+        build configuration.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
           <mallctl>config.xmalloc</mallctl>
           (<type>bool</type>)
           <literal>r-</literal>
@@ -826,6 +836,19 @@
         </para></listitem>
       </varlistentry>
 
+      <varlistentry id="opt.utrace">
+        <term>
+          <mallctl>opt.utrace</mallctl>
+          (<type>bool</type>)
+          <literal>r-</literal>
+          [<option>--enable-utrace</option>]
+        </term>
+        <listitem><para>Allocation tracing based on
+        <citerefentry><refentrytitle>utrace</refentrytitle>
+        <manvolnum>2</manvolnum></citerefentry> enabled/disabled.  This option
+        is disabled by default.</para></listitem>
+      </varlistentry>
+
       <varlistentry id="opt.xmalloc">
         <term>
           <mallctl>opt.xmalloc</mallctl>
@@ -1958,6 +1981,8 @@
     <manvolnum>2</manvolnum></citerefentry>,
     <citerefentry><refentrytitle>sbrk</refentrytitle>
     <manvolnum>2</manvolnum></citerefentry>,
+    <citerefentry><refentrytitle>utrace</refentrytitle>
+    <manvolnum>2</manvolnum></citerefentry>,
     <citerefentry><refentrytitle>alloca</refentrytitle>
     <manvolnum>3</manvolnum></citerefentry>,
     <citerefentry><refentrytitle>atexit</refentrytitle>
diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in
index c8e4019..66dd357 100644
--- a/include/jemalloc/internal/jemalloc_internal.h.in
+++ b/include/jemalloc/internal/jemalloc_internal.h.in
@@ -36,6 +36,10 @@
 #define	JEMALLOC_NO_DEMANGLE
 #include "../jemalloc@install_suffix@.h"
 
+#ifdef JEMALLOC_UTRACE
+#include <sys/ktrace.h>
+#endif
+
 #include "jemalloc/internal/private_namespace.h"
 
 #ifdef JEMALLOC_CC_SILENCE
@@ -114,6 +118,13 @@
     false
 #endif
     ;
+static const bool config_utrace =
+#ifdef JEMALLOC_UTRACE
+    true
+#else
+    false
+#endif
+    ;
 static const bool config_xmalloc =
 #ifdef JEMALLOC_XMALLOC
     true
@@ -332,6 +343,7 @@
 
 extern bool	opt_abort;
 extern bool	opt_junk;
+extern bool	opt_utrace;
 extern bool	opt_xmalloc;
 extern bool	opt_zero;
 extern size_t	opt_narenas;
diff --git a/include/jemalloc/internal/private_namespace.h b/include/jemalloc/internal/private_namespace.h
index ed34e32..de3042e 100644
--- a/include/jemalloc/internal/private_namespace.h
+++ b/include/jemalloc/internal/private_namespace.h
@@ -173,6 +173,7 @@
 #define	opt_prof_leak JEMALLOC_N(opt_prof_leak)
 #define	opt_stats_print JEMALLOC_N(opt_stats_print)
 #define	opt_tcache JEMALLOC_N(opt_tcache)
+#define	opt_utrace JEMALLOC_N(opt_utrace)
 #define	opt_xmalloc JEMALLOC_N(opt_xmalloc)
 #define	opt_zero JEMALLOC_N(opt_zero)
 #define	pow2_ceil JEMALLOC_N(pow2_ceil)
diff --git a/include/jemalloc/jemalloc_defs.h.in b/include/jemalloc/jemalloc_defs.h.in
index 040753a..8e7442d 100644
--- a/include/jemalloc/jemalloc_defs.h.in
+++ b/include/jemalloc/jemalloc_defs.h.in
@@ -154,6 +154,9 @@
 /* Support the experimental API. */
 #undef JEMALLOC_EXPERIMENTAL
 
+/* Support utrace(2)-based tracing. */
+#undef JEMALLOC_UTRACE
+
 /* Support optional abort() on OOM. */
 #undef JEMALLOC_XMALLOC
 
diff --git a/src/ctl.c b/src/ctl.c
index df7affd..1aaf197 100644
--- a/src/ctl.c
+++ b/src/ctl.c
@@ -56,6 +56,7 @@
 CTL_PROTO(config_stats)
 CTL_PROTO(config_tcache)
 CTL_PROTO(config_tls)
+CTL_PROTO(config_utrace)
 CTL_PROTO(config_xmalloc)
 CTL_PROTO(opt_abort)
 CTL_PROTO(opt_lg_chunk)
@@ -64,6 +65,7 @@
 CTL_PROTO(opt_stats_print)
 CTL_PROTO(opt_junk)
 CTL_PROTO(opt_zero)
+CTL_PROTO(opt_utrace)
 CTL_PROTO(opt_xmalloc)
 CTL_PROTO(opt_tcache)
 CTL_PROTO(opt_lg_tcache_max)
@@ -176,6 +178,7 @@
 	{NAME("stats"),			CTL(config_stats)},
 	{NAME("tcache"),		CTL(config_tcache)},
 	{NAME("tls"),			CTL(config_tls)},
+	{NAME("utrace"),		CTL(config_utrace)},
 	{NAME("xmalloc"),		CTL(config_xmalloc)}
 };
 
@@ -187,6 +190,7 @@
 	{NAME("stats_print"),		CTL(opt_stats_print)},
 	{NAME("junk"),			CTL(opt_junk)},
 	{NAME("zero"),			CTL(opt_zero)},
+	{NAME("utrace"),		CTL(opt_utrace)},
 	{NAME("xmalloc"),		CTL(opt_xmalloc)},
 	{NAME("tcache"),		CTL(opt_tcache)},
 	{NAME("lg_tcache_max"),		CTL(opt_lg_tcache_max)},
@@ -1080,6 +1084,7 @@
 CTL_RO_BOOL_CONFIG_GEN(config_stats)
 CTL_RO_BOOL_CONFIG_GEN(config_tcache)
 CTL_RO_BOOL_CONFIG_GEN(config_tls)
+CTL_RO_BOOL_CONFIG_GEN(config_utrace)
 CTL_RO_BOOL_CONFIG_GEN(config_xmalloc)
 
 /******************************************************************************/
@@ -1091,6 +1096,7 @@
 CTL_RO_NL_GEN(opt_stats_print, opt_stats_print, bool)
 CTL_RO_NL_CGEN(config_fill, opt_junk, opt_junk, bool)
 CTL_RO_NL_CGEN(config_fill, opt_zero, opt_zero, bool)
+CTL_RO_NL_CGEN(config_utrace, opt_utrace, opt_utrace, bool)
 CTL_RO_NL_CGEN(config_xmalloc, opt_xmalloc, opt_xmalloc, bool)
 CTL_RO_NL_CGEN(config_tcache, opt_tcache, opt_tcache, bool)
 CTL_RO_NL_CGEN(config_tcache, opt_lg_tcache_max, opt_lg_tcache_max, ssize_t)
diff --git a/src/jemalloc.c b/src/jemalloc.c
index a531a21..e051020 100644
--- a/src/jemalloc.c
+++ b/src/jemalloc.c
@@ -21,6 +21,7 @@
 bool	opt_abort = false;
 bool	opt_junk = false;
 #endif
+bool	opt_utrace = false;
 bool	opt_xmalloc = false;
 bool	opt_zero = false;
 size_t	opt_narenas = 0;
@@ -50,6 +51,26 @@
 /* Used to avoid initialization races. */
 static malloc_mutex_t	init_lock = MALLOC_MUTEX_INITIALIZER;
 
+typedef struct {
+	void	*p;	/* Input pointer (as in realloc(p, s)). */
+	size_t	s;	/* Request size. */
+	void	*r;	/* Result pointer. */
+} malloc_utrace_t;
+
+#ifdef JEMALLOC_UTRACE
+#  define UTRACE(a, b, c) do {						\
+	if (opt_utrace) {						\
+		malloc_utrace_t ut;					\
+		ut.p = (a);						\
+		ut.s = (b);						\
+		ut.r = (c);						\
+		utrace(&ut, sizeof(ut));				\
+	}								\
+} while (0)
+#else
+#  define UTRACE(a, b, c)
+#endif
+
 /******************************************************************************/
 /* Function prototypes for non-inline static functions. */
 
@@ -483,6 +504,9 @@
 				CONF_HANDLE_BOOL(opt_junk, junk)
 				CONF_HANDLE_BOOL(opt_zero, zero)
 			}
+			if (config_utrace) {
+				CONF_HANDLE_BOOL(opt_utrace, utrace)
+			}
 			if (config_xmalloc) {
 				CONF_HANDLE_BOOL(opt_xmalloc, xmalloc)
 			}
@@ -759,6 +783,7 @@
 		assert(usize == isalloc(ret));
 		thread_allocated_tsd_get()->allocated += usize;
 	}
+	UTRACE(0, size, ret);
 	return (ret);
 }
 
@@ -852,6 +877,7 @@
 	}
 	if (config_prof && opt_prof && result != NULL)
 		prof_malloc(result, usize, cnt);
+	UTRACE(0, size, result);
 	return (ret);
 }
 
@@ -951,6 +977,7 @@
 		assert(usize == isalloc(ret));
 		thread_allocated_tsd_get()->allocated += usize;
 	}
+	UTRACE(0, num_size, ret);
 	return (ret);
 }
 
@@ -1075,6 +1102,7 @@
 		ta->allocated += usize;
 		ta->deallocated += old_size;
 	}
+	UTRACE(ptr, size, ret);
 	return (ret);
 }
 
@@ -1083,6 +1111,7 @@
 je_free(void *ptr)
 {
 
+	UTRACE(ptr, 0, 0);
 	if (ptr != NULL) {
 		size_t usize;
 
@@ -1310,6 +1339,7 @@
 		assert(usize == isalloc(p));
 		thread_allocated_tsd_get()->allocated += usize;
 	}
+	UTRACE(0, size, p);
 	return (ALLOCM_SUCCESS);
 OOM:
 	if (config_xmalloc && opt_xmalloc) {
@@ -1318,6 +1348,7 @@
 		abort();
 	}
 	*ptr = NULL;
+	UTRACE(0, size, 0);
 	return (ALLOCM_ERR_OOM);
 }
 
@@ -1404,16 +1435,20 @@
 		ta->allocated += usize;
 		ta->deallocated += old_size;
 	}
+	UTRACE(p, size, q);
 	return (ALLOCM_SUCCESS);
 ERR:
-	if (no_move)
+	if (no_move) {
+		UTRACE(p, size, q);
 		return (ALLOCM_ERR_NOT_MOVED);
+	}
 OOM:
 	if (config_xmalloc && opt_xmalloc) {
 		malloc_write("<jemalloc>: Error in rallocm(): "
 		    "out of memory\n");
 		abort();
 	}
+	UTRACE(p, size, 0);
 	return (ALLOCM_ERR_OOM);
 }
 
@@ -1448,6 +1483,7 @@
 	assert(ptr != NULL);
 	assert(malloc_initialized || IS_INITIALIZER);
 
+	UTRACE(ptr, 0, 0);
 	if (config_stats)
 		usize = isalloc(ptr);
 	if (config_prof && opt_prof) {
diff --git a/src/stats.c b/src/stats.c
index 83baf56..0cd70b0 100644
--- a/src/stats.c
+++ b/src/stats.c
@@ -383,6 +383,7 @@
 		OPT_WRITE_BOOL(stats_print)
 		OPT_WRITE_BOOL(junk)
 		OPT_WRITE_BOOL(zero)
+		OPT_WRITE_BOOL(utrace)
 		OPT_WRITE_BOOL(xmalloc)
 		OPT_WRITE_BOOL(tcache)
 		OPT_WRITE_SSIZE_T(lg_tcache_max)