Index: trunk/src/VBox/Runtime/Makefile.kmk
===================================================================
--- trunk/src/VBox/Runtime/Makefile.kmk	(revision 36596)
+++ trunk/src/VBox/Runtime/Makefile.kmk	(revision 36597)
@@ -251,4 +251,5 @@
 	common/alloc/heapoffset.cpp \
 	common/alloc/memcache.cpp \
+	common/alloc/memtracker.cpp \
 	common/checksum/adler32.cpp \
 	common/checksum/crc32.cpp \
@@ -2258,5 +2259,5 @@
 	do \
 		if $(SED) -ne '/\# *define '"$${fn}"' /q 1' $(PATH_ROOT)/include/iprt/mangling.h; then \
-			echo "mangling.h: Missing '"$${fn}"'"; \
+			echo "mangling.h: Missing # define "$${fn}"               RT_MANGLER("$${fn}")"; \
 			rcExit=1;\
 		fi \
@@ -2289,5 +2290,5 @@
 	do \
 		if $(SED) -ne '/\# *define '"$${fn}"' /q 1' $(PATH_ROOT)/include/iprt/mangling.h; then \
-			echo "mangling.h: Missing '"$${fn}"'"; \
+			echo "mangling.h: Missing # define "$${fn}"               RT_MANGLER("$${fn}")""; \
 			rcExit=1;\
 		fi \
Index: trunk/src/VBox/Runtime/common/alloc/memtracker.cpp
===================================================================
--- trunk/src/VBox/Runtime/common/alloc/memtracker.cpp	(revision 36596)
+++ trunk/src/VBox/Runtime/common/alloc/memtracker.cpp	(revision 36597)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-2011 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -29,11 +29,1305 @@
 *   Header Files                                                               *
 *******************************************************************************/
-#include <iprt/memcache.h>
+#include <iprt/memtracker.h>
 #include "internal/iprt.h"
 
+#include <iprt/asm.h>
 #include <iprt/assert.h>
+#include <iprt/avl.h>
+#include <iprt/critsect.h>
+#ifdef IN_RING3
+# include <iprt/file.h>
+#endif
+#include <iprt/err.h>
+#include <iprt/list.h>
+#include <iprt/log.h>
 #include <iprt/mem.h>
-#include <iprt/param.h>
-
+#include <iprt/semaphore.h>
+#include <iprt/string.h>
+#include <iprt/thread.h>
+
+#include "internal/file.h"
 #include "internal/magics.h"
-
+#include "internal/strhash.h"
+
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+/** Pointer to a memory tracker instance */
+typedef struct RTMEMTRACKERINT *PRTMEMTRACKERINT;
+
+/**
+ * Memory tracker statistics.
+ */
+typedef struct RTMEMTRACKERSTATS
+{
+    /** Array of method calls. */
+    uint64_t volatile   acMethodCalls[RTMEMTRACKERMETHOD_END];
+    /** The number of times this user freed or reallocated a memory block
+     * orignally allocated by someone else. */
+    uint64_t volatile   cUserChanges;
+    /** The total number of bytes allocated ever. */
+    uint64_t volatile   cbTotalAllocated;
+    /** The total number of blocks allocated ever. */
+    uint64_t volatile   cTotalAllocatedBlocks;
+    /** The number of bytes currently allocated. */
+    size_t volatile     cbAllocated;
+    /** The number of blocks currently allocated. */
+    size_t volatile     cAllocatedBlocks;
+} RTMEMTRACKERSTATS;
+/** Pointer to memory tracker statistics. */
+typedef RTMEMTRACKERSTATS *PRTMEMTRACKERSTATS;
+
+
+/**
+ * Memory tracker user data.
+ */
+typedef struct RTMEMTRACKERUSER
+{
+    /** Entry in the user list (RTMEMTRACKERINT::UserList). */
+    RTLISTNODE          ListEntry;
+    /** Pointer to the tracker. */
+    PRTMEMTRACKERINT    pTracker;
+    /** Critical section protecting the memory list. */
+    RTCRITSECT          CritSect;
+    /** The list of memory allocated by this user. */
+    RTLISTNODE          MemoryList;
+    /** Positive numbers indicates recursion.
+     * Negative numbers are used for the global user since that is shared by
+     * more than one thread. */
+    int32_t volatile    cInTracker;
+    /** The user identifier. */
+    uint32_t            idUser;
+    /** The statistics for this user. */
+    RTMEMTRACKERSTATS   Stats;
+    /** The user (thread) name. */
+    char                szName[32];
+} RTMEMTRACKERUSER;
+/** Pointer to memory tracker per user data. */
+typedef RTMEMTRACKERUSER *PRTMEMTRACKERUSER;
+
+
+/**
+ * Memory tracker per tag statistics.
+ */
+typedef struct RTMEMTRACKERTAG
+{
+    /** AVL node core for lookup by hash.  */
+    AVLU32NODECORE      Core;
+    /** Tag list entry for flat traversal while dumping. */
+    RTLISTNODE          ListEntry;
+    /** Pointer to the next tag with the same hash (collisions). */
+    PRTMEMTRACKERTAG    pNext;
+    /** The tag statistics. */
+    RTMEMTRACKERSTATS   Stats;
+    /** The tag name length.  */
+    size_t              cchTag;
+    /** The tag string. */
+    char                szTag[1];
+} RTMEMTRACKERTAG;
+
+
+/**
+ * The memory tracker instance.
+ */
+typedef struct RTMEMTRACKERINT
+{
+    /** Cross roads semaphore separating dumping and normal operation.
+     *  - NS - normal tracking.
+     *  - EW - dumping tracking data. */
+    RTSEMXROADS         hXRoads;
+
+    /** Critical section protecting the user list and tag database. */
+    RTCRITSECT          CritSect;
+    /** List of RTMEMTRACKERUSER records. */
+    RTLISTNODE          UserList;
+    /** The next user identifier number.  */
+    uint32_t            idUserNext;
+    /** The TLS index used for the per thread user records. */
+    RTTLS               iTls;
+    /** Cross roads semaphore used to protect the tag database.
+     *  - NS - lookup.
+     *  - EW + critsect - insertion.
+     * @todo Replaced this by a read-write semaphore. */
+    RTSEMXROADS         hXRoadsTagDb;
+    /** The root of the tag lookup database. */
+    AVLU32TREE          TagDbRoot;
+    /** List of RTMEMTRACKERTAG records. */
+    RTLISTNODE          TagList;
+    /** The global user record (fallback). */
+    RTMEMTRACKERUSER    FallbackUser;
+    /** The global statistics. */
+    RTMEMTRACKERSTATS   GlobalStats;
+    /** The number of busy (recursive) allocations. */
+    uint64_t volatile   cBusyAllocs;
+    /** The number of busy (recursive) frees. */
+    uint64_t volatile   cBusyFrees;
+    /** The number of tags. */
+    uint32_t            cTags;
+    /** The number of users. */
+    uint32_t            cUsers;
+} RTMEMTRACKERINT;
+AssertCompileMemberAlignment(RTMEMTRACKERINT, FallbackUser, 8);
+
+
+/**
+ * Output callback structure.
+ */
+typedef struct RTMEMTRACKEROUTPUT
+{
+    /** The printf like callback. */
+    DECLCALLBACKMEMBER(void, pfnPrintf)(struct RTMEMTRACKEROUTPUT *pThis, const char *pszFormat, ...);
+
+    /** The data. */
+    union
+    {
+        RTFILE  hFile;
+    } uData;
+} RTMEMTRACKEROUTPUT;
+/** Pointer to a memory tracker output callback structure. */
+typedef RTMEMTRACKEROUTPUT *PRTMEMTRACKEROUTPUT;
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+/** Pointer to the default memory tracker. */
+static PRTMEMTRACKERINT g_pDefaultTracker = NULL;
+
+
+/**
+ * Creates a memory tracker.
+ *
+ * @returns IRPT status code.
+ * @param   ppTracker           Where to return the tracker instance.
+ */
+static int rtMemTrackerCreate(PRTMEMTRACKERINT *ppTracker)
+{
+    PRTMEMTRACKERINT pTracker = (PRTMEMTRACKERINT)RTMemAllocZ(sizeof(*pTracker));
+    if (!pTracker)
+        return VERR_NO_MEMORY;
+
+    /*
+     * Create locks and stuff.
+     */
+    int rc = RTCritSectInitEx(&pTracker->CritSect,
+                              RTCRITSECT_FLAGS_NO_LOCK_VAL | RTCRITSECT_FLAGS_NO_NESTING | RTCRITSECT_FLAGS_BOOTSTRAP_HACK,
+                              NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, NULL);
+    if (RT_SUCCESS(rc))
+    {
+        rc = RTSemXRoadsCreate(&pTracker->hXRoads);
+        if (RT_SUCCESS(rc))
+        {
+            rc = RTSemXRoadsCreate(&pTracker->hXRoadsTagDb);
+            if (RT_SUCCESS(rc))
+            {
+                rc = RTTlsAllocEx(&pTracker->iTls, NULL);
+                if (RT_SUCCESS(rc))
+                {
+                    rc = RTCritSectInitEx(&pTracker->FallbackUser.CritSect,
+                                          RTCRITSECT_FLAGS_NO_LOCK_VAL | RTCRITSECT_FLAGS_NO_NESTING | RTCRITSECT_FLAGS_BOOTSTRAP_HACK,
+                                          NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, NULL);
+                    if (RT_SUCCESS(rc))
+                    {
+                        /*
+                         * Initialize the rest of the structure.
+                         */
+                        RTListInit(&pTracker->UserList);
+                        RTListInit(&pTracker->TagList);
+                        RTListInit(&pTracker->FallbackUser.ListEntry);
+                        RTListInit(&pTracker->FallbackUser.MemoryList);
+                        pTracker->FallbackUser.pTracker   = pTracker;
+                        pTracker->FallbackUser.cInTracker = INT32_MIN / 2;
+                        pTracker->FallbackUser.idUser     = pTracker->idUserNext++;
+                        strcpy(pTracker->FallbackUser.szName, "fallback");
+
+                        *ppTracker = pTracker;
+                        return VINF_SUCCESS;
+                    }
+
+                    RTTlsFree(pTracker->iTls);
+                }
+                RTSemXRoadsDestroy(pTracker->hXRoadsTagDb);
+            }
+            RTSemXRoadsDestroy(pTracker->hXRoads);
+        }
+        RTCritSectDelete(&pTracker->CritSect);
+    }
+    return rc;
+}
+
+
+/**
+ * Gets the user record to use.
+ *
+ * @returns Pointer to a user record.
+ * @param   pTracker            The tracker instance.
+ */
+static PRTMEMTRACKERUSER rtMemTrackerGetUser(PRTMEMTRACKERINT pTracker)
+{
+    /* ASSUMES that RTTlsGet and RTTlsSet will not reenter. */
+    PRTMEMTRACKERUSER pUser = (PRTMEMTRACKERUSER)RTTlsGet(pTracker->iTls);
+    if (RT_UNLIKELY(!pUser))
+    {
+        /*
+         * Is the thread currently initializing or terminating?
+         * If so, don't try add any user record for it as RTThread may barf or
+         * we might not get the thread name.
+         */
+        if (!RTThreadIsSelfAlive())
+            return &pTracker->FallbackUser;
+
+        /*
+         * Allocate and initialize a new user record for this thread.
+         *
+         * We install the fallback user record while doing the allocation and
+         * locking so that we can deal with recursions.
+         */
+        int rc = RTTlsSet(pTracker->iTls, &pTracker->FallbackUser);
+        if (RT_SUCCESS(rc))
+        {
+            pUser = (PRTMEMTRACKERUSER)RTMemAllocZ(sizeof(*pUser));
+            if (pUser)
+            {
+                rc = RTCritSectInitEx(&pUser->CritSect,
+                                      RTCRITSECT_FLAGS_NO_LOCK_VAL | RTCRITSECT_FLAGS_NO_NESTING | RTCRITSECT_FLAGS_BOOTSTRAP_HACK,
+                                      NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, NULL);
+                if (RT_SUCCESS(rc))
+                {
+                    RTListInit(&pUser->ListEntry);
+                    RTListInit(&pUser->MemoryList);
+                    pUser->pTracker   = pTracker;
+                    pUser->cInTracker = 1;
+
+                    const char *pszName = RTThreadSelfName();
+                    if (pszName)
+                        RTStrCopy(pUser->szName, sizeof(pUser->szName), pszName);
+
+                    /*
+                     * Register the new user record.
+                     */
+                    rc = RTTlsSet(pTracker->iTls, pUser);
+                    if (RT_SUCCESS(rc))
+                    {
+                        RTCritSectEnter(&pTracker->CritSect);
+
+                        pUser->idUser = pTracker->idUserNext++;
+                        RTListAppend(&pTracker->UserList, &pUser->ListEntry);
+                        pTracker->cUsers++;
+
+                        RTCritSectLeave(&pTracker->CritSect);
+                        return pUser;
+                    }
+
+                    RTCritSectDelete(&pUser->CritSect);
+                }
+                RTMemFree(pUser);
+            }
+            else
+                rc = VERR_NO_MEMORY;
+        }
+
+        /* Failed, user the fallback. */
+        pUser = &pTracker->FallbackUser;
+    }
+
+    ASMAtomicIncS32(&pUser->cInTracker);
+    return pUser;
+}
+
+
+/**
+ * Counterpart to rtMemTrackerGetUser.
+ *
+ * @param   pUser               The user record to 'put' back.
+ */
+DECLINLINE(void) rtMemTrackerPutUser(PRTMEMTRACKERUSER pUser)
+{
+    ASMAtomicDecS32(&pUser->cInTracker);
+}
+
+
+/**
+ * Get the tag record corresponding to @a pszTag.
+ *
+ * @returns The tag record.  This may be NULL if we're out of memory or
+ *          if something goes wrong.
+ *
+ * @param   pTracker            The tracker instance.
+ * @param   pUser               The user record of the caller.  Must NOT be
+ *                              NULL.  This is used to prevent infinite
+ *                              recursions when allocating a new tag record.
+ * @param   pszTag              The tag string.  Can be NULL.
+ */
+DECLINLINE(PRTMEMTRACKERTAG) rtMemTrackerGetTag(PRTMEMTRACKERINT pTracker, PRTMEMTRACKERUSER pUser, const char *pszTag)
+{
+    AssertPtr(pTracker);
+    AssertPtr(pUser);
+    if (pUser->cInTracker <= 0)
+        return NULL;
+
+    /*
+     * Hash tag string.
+     */
+    size_t   cchTag;
+    uint32_t uHash;
+    if (pszTag)
+        uHash = sdbmN(pszTag, 260, &cchTag);
+    else
+    {
+        pszTag = "";
+        cchTag = 0;
+        uHash  = 0;
+    }
+
+    /*
+     * Look up the tag.
+     */
+    RTSemXRoadsNSEnter(pTracker->hXRoadsTagDb);
+    PRTMEMTRACKERTAG pTag = (PRTMEMTRACKERTAG)RTAvlU32Get(&pTracker->TagDbRoot, uHash);
+    while (   pTag
+           && (   pTag->cchTag != cchTag
+               || memcmp(pTag->szTag, pszTag, cchTag)) )
+        pTag = pTag->pNext;
+    RTSemXRoadsNSLeave(pTracker->hXRoadsTagDb);
+
+    /*
+     * Create a new tag record if not found.
+     */
+    if (RT_UNLIKELY(!pTag))
+    {
+        pTag = (PRTMEMTRACKERTAG)RTMemAllocZVar(RT_OFFSETOF(RTMEMTRACKERTAG, szTag[cchTag + 1]));
+        if (pTag)
+        {
+            pTag->Core.Key = uHash;
+            pTag->cchTag   = cchTag;
+            memcpy(pTag->szTag, pszTag, cchTag + 1);
+
+            RTSemXRoadsEWEnter(pTracker->hXRoadsTagDb);
+            RTCritSectEnter(&pTracker->CritSect);
+
+            void *pvFreeMe = NULL;
+            PRTMEMTRACKERTAG pHeadTag = (PRTMEMTRACKERTAG)RTAvlU32Get(&pTracker->TagDbRoot, uHash);
+            if (!pHeadTag)
+            {
+                RTAvlU32Insert(&pTracker->TagDbRoot, &pTag->Core);
+                RTListAppend(&pTracker->TagList, &pTag->ListEntry);
+                pTracker->cTags++;
+            }
+            else
+            {
+                PRTMEMTRACKERTAG pTag2 = pHeadTag;
+                while (   pTag2
+                       && (   pTag2->cchTag != cchTag
+                           || memcmp(pTag2->szTag, pszTag, cchTag)) )
+                    pTag2 = pTag2->pNext;
+                if (RT_LIKELY(!pTag2))
+                {
+                    pTag->pNext     = pHeadTag->pNext;
+                    pHeadTag->pNext = pTag;
+                    RTListAppend(&pTracker->TagList, &pTag->ListEntry);
+                    pTracker->cTags++;
+                }
+                else
+                {
+                    pvFreeMe = pTag;
+                    pTag = pTag2;
+                }
+            }
+
+            RTCritSectLeave(&pTracker->CritSect);
+            RTSemXRoadsEWLeave(pTracker->hXRoadsTagDb);
+
+            if (RT_LIKELY(pvFreeMe))
+                RTMemFree(pvFreeMe);
+        }
+    }
+
+    return pTag;
+}
+
+
+/**
+ * Counterpart to rtMemTrackerGetTag.
+ *
+ * @param   pTag                The tag record to 'put' back.
+ */
+DECLINLINE(void) rtMemTrackerPutTag(PRTMEMTRACKERTAG pTag)
+{
+    NOREF(pTag);
+}
+
+
+/**
+ * Record an allocation call.
+ *
+ * @param   pStats              The statistics record.
+ * @param   cbUser              The size of the allocation.
+ * @param   enmMethod           The allocation method.
+ */
+DECLINLINE(void) rtMemTrackerStateRecordAlloc(PRTMEMTRACKERSTATS pStats, size_t cbUser, RTMEMTRACKERMETHOD enmMethod)
+{
+    ASMAtomicAddU64(&pStats->cbTotalAllocated, cbUser);
+    ASMAtomicIncU64(&pStats->cTotalAllocatedBlocks);
+    ASMAtomicAddZ(&pStats->cbAllocated, cbUser);
+    ASMAtomicIncZ(&pStats->cAllocatedBlocks);
+    ASMAtomicIncU64(&pStats->acMethodCalls[enmMethod]);
+}
+
+
+/**
+ * Record a free call.
+ *
+ * @param   pStats              The statistics record.
+ * @param   cbUser              The size of the allocation.
+ * @param   enmMethod           The free method.
+ */
+DECLINLINE(void) rtMemTrackerStateRecordFree(PRTMEMTRACKERSTATS pStats, size_t cbUser, RTMEMTRACKERMETHOD enmMethod)
+{
+    ASMAtomicSubZ(&pStats->cbAllocated, cbUser);
+    ASMAtomicDecZ(&pStats->cAllocatedBlocks);
+    ASMAtomicIncU64(&pStats->acMethodCalls[enmMethod]);
+}
+
+
+/**
+ * Internal RTMemTrackerHdrAlloc and RTMemTrackerHdrAllocEx worker.
+ *
+ * @returns Pointer to the user data allocation.
+ * @param   pTracker            The tracker instance.  Can be NULL.
+ * @param   pv                  The pointer to the allocated memory. This
+ *                              includes room for the header.
+ * @param   cbUser              The size requested by the user.
+ * @param   pszTag              The tag string.
+ * @param   enmMethod           The allocation method.
+ */
+static void *rtMemTrackerHdrAllocEx(PRTMEMTRACKERINT pTracker, void *pv, size_t cbUser,
+                                    const char *pszTag, RTMEMTRACKERMETHOD enmMethod)
+{
+    /*
+     * Check input.
+     */
+    if (!pv)
+        return NULL;
+    AssertReturn(enmMethod > RTMEMTRACKERMETHOD_INVALID && enmMethod < RTMEMTRACKERMETHOD_END, NULL);
+
+    /*
+     * Initialize the header.
+     */
+    PRTMEMTRACKERHDR pHdr = (PRTMEMTRACKERHDR)pv;
+
+    pHdr->uMagic            = RTMEMTRACKERHDR_MAGIC;
+    pHdr->cbUser            = cbUser;
+    RTListInit(&pHdr->ListEntry);
+    pHdr->pUser             = NULL;
+    pHdr->pszTag            = pszTag;
+    pHdr->pTag              = NULL;
+    pHdr->pvUser            = pHdr + 1;
+
+    /*
+     * Add it to the tracker if we've got one.
+     */
+    if (pTracker)
+    {
+        PRTMEMTRACKERUSER pUser = rtMemTrackerGetUser(pTracker);
+        if (pUser->cInTracker == 1)
+        {
+            RTSemXRoadsNSEnter(pTracker->hXRoads);
+
+            /* Get the tag and update it's statistics.  */
+            PRTMEMTRACKERTAG pTag = rtMemTrackerGetTag(pTracker, pUser, pszTag);
+            if (pTag)
+            {
+                pHdr->pTag = pTag;
+                rtMemTrackerStateRecordAlloc(&pTag->Stats, cbUser, enmMethod);
+                rtMemTrackerPutTag(pTag);
+            }
+
+            /* Link the header and update the user statistics. */
+            RTCritSectEnter(&pUser->CritSect);
+            RTListAppend(&pUser->MemoryList, &pHdr->ListEntry);
+            RTCritSectLeave(&pUser->CritSect);
+
+            pHdr->pUser = pUser;
+            rtMemTrackerStateRecordAlloc(&pUser->Stats, cbUser, enmMethod);
+
+            /* Update the global statistics. */
+            rtMemTrackerStateRecordAlloc(&pTracker->GlobalStats, cbUser, enmMethod);
+
+            RTSemXRoadsNSLeave(pTracker->hXRoads);
+        }
+        else
+            ASMAtomicIncU64(&pTracker->cBusyAllocs);
+        rtMemTrackerPutUser(pUser);
+    }
+
+    return pHdr + 1;
+}
+
+
+/**
+ * Internal worker for rtMemTrackerHdrFreeEx and rtMemTrackerHdrReallocPrep.
+ *
+ * @returns Pointer to the original block.
+ * @param   pTracker            The tracker instance.  Can be NULL.
+ * @param   pvUser              Pointer to the user memory.
+ * @param   cbUser              The size of the user memory or 0.
+ * @param   pszTag              The tag to associate the free with.
+ * @param   enmMethod           The free method.
+ * @param   uDeadMagic          The dead magic value to use.
+ */
+static void *rtMemTrackerHdrFreeCommon(PRTMEMTRACKERINT pTracker, void *pvUser, size_t cbUser,
+                                       const char *pszTag, RTMEMTRACKERMETHOD enmMethod,
+                                       size_t uDeadMagic)
+{
+    PRTMEMTRACKERHDR pHdr = (PRTMEMTRACKERHDR)pvUser - 1;
+    AssertReturn(pHdr->uMagic == RTMEMTRACKERHDR_MAGIC, NULL);
+    Assert(pHdr->cbUser == cbUser || !cbUser); NOREF(cbUser);
+    Assert(pHdr->pvUser == pvUser);
+
+    AssertReturn(enmMethod > RTMEMTRACKERMETHOD_INVALID && enmMethod < RTMEMTRACKERMETHOD_END, NULL);
+
+    /*
+     * First mark it as free.
+     */
+    pHdr->uMagic = uDeadMagic;
+
+    /*
+     * If there is a association with a user, we need to unlink it and update
+     * the statistics.
+     *
+     * A note on the locking here.  We don't take the crossroads semaphore when
+     * reentering the memory tracker on the same thread because we may be
+     * holding it in a different direction and would therefore deadlock.
+     */
+    PRTMEMTRACKERUSER pMemUser = pHdr->pUser;
+    if (pMemUser)
+    {
+        Assert(pMemUser->pTracker == pTracker); Assert(pTracker);
+        PRTMEMTRACKERUSER   pCallingUser    = rtMemTrackerGetUser(pTracker);
+        bool const          fTakeXRoadsLock = pCallingUser->cInTracker <= 1;
+        if (fTakeXRoadsLock)
+            RTSemXRoadsNSEnter(pTracker->hXRoads);
+
+        RTCritSectEnter(&pMemUser->CritSect);
+        RTListNodeRemove(&pHdr->ListEntry);
+        RTCritSectLeave(&pMemUser->CritSect);
+
+        if (pCallingUser == pMemUser)
+            rtMemTrackerStateRecordFree(&pCallingUser->Stats, pHdr->cbUser, enmMethod);
+        else
+        {
+            ASMAtomicIncU64(&pCallingUser->Stats.cUserChanges);
+            ASMAtomicIncU64(&pCallingUser->Stats.acMethodCalls[enmMethod]);
+
+            ASMAtomicSubU64(&pMemUser->Stats.cbTotalAllocated, cbUser);
+            ASMAtomicSubZ(&pMemUser->Stats.cbAllocated, cbUser);
+        }
+
+        rtMemTrackerStateRecordFree(&pTracker->GlobalStats, pHdr->cbUser, enmMethod);
+
+        /** @todo we're currently ignoring pszTag, consider how to correctly
+         *        attribute the free operation if the tags differ - it
+         *        makes sense at all... */
+        if (pHdr->pTag)
+            rtMemTrackerStateRecordFree(&pHdr->pTag->Stats, pHdr->cbUser, enmMethod);
+
+
+        if (fTakeXRoadsLock)
+            RTSemXRoadsNSLeave(pTracker->hXRoads);
+        rtMemTrackerPutUser(pCallingUser);
+    }
+    else
+    {
+        /*
+         * No tracked.  This may happen even when pTracker != NULL when the same
+         * thread reenters the tracker when allocating tracker structures or memory
+         * in some subroutine like threading and locking.
+         */
+        Assert(!pHdr->pTag);
+        if (pTracker)
+            ASMAtomicIncU64(&pTracker->cBusyFrees);
+    }
+
+    return pHdr;
+}
+
+
+/**
+ * Internal worker for RTMemTrackerHdrReallocPrep and
+ * RTMemTrackerHdrReallocPrepEx.
+ *
+ * @returns Pointer to the actual allocation.
+ * @param   pTracker            The tracker instance.  Can be NULL.
+ * @param   pvOldUser           The user memory.
+ * @param   cbOldUser           The size of the user memory, 0 if unknown.
+ * @param   pszTag              The tag string.
+ */
+static void *rtMemTrackerHdrReallocPrepEx(PRTMEMTRACKERINT pTracker, void *pvOldUser, size_t cbOldUser, const char *pszTag)
+{
+    if (!pvOldUser)
+        return NULL;
+    return rtMemTrackerHdrFreeCommon(pTracker, pvOldUser, cbOldUser, pszTag,
+                                     RTMEMTRACKERMETHOD_REALLOC_PREP, RTMEMTRACKERHDR_MAGIC_REALLOC);
+}
+
+
+/**
+ * Internal worker for RTMemTrackerHdrReallocDone and
+ * RTMemTrackerHdrReallocDoneEx.
+ *
+ * @returns Pointer to the actual allocation.
+ * @param   pTracker            The tracker instance.  Can be NULL.
+ * @param   pvNew               The new memory chunk.  Can be NULL.
+ * @param   cbNewUser           The size of the new memory chunk.
+ * @param   pvOldUser           Pointer to the old user memory.
+ * @param   pszTag              The tag string.
+ */
+static void *rtMemTrackerHdrReallocDoneEx(PRTMEMTRACKERINT pTracker, void *pvNew, size_t cbNewUser,
+                                          void *pvOldUser, const char *pszTag)
+{
+    /* Succeeded? */
+    if (pvNew)
+        return rtMemTrackerHdrAllocEx(pTracker, pvNew, cbNewUser, pszTag, RTMEMTRACKERMETHOD_REALLOC_DONE);
+
+    /* Failed or just realloc to zero? */
+    if (cbNewUser)
+    {
+        PRTMEMTRACKERHDR pHdr = (PRTMEMTRACKERHDR)pvOldUser - 1;
+        AssertReturn(pHdr->uMagic == RTMEMTRACKERHDR_MAGIC_REALLOC, NULL);
+
+        return rtMemTrackerHdrAllocEx(pTracker, pHdr, pHdr->cbUser, pszTag, RTMEMTRACKERMETHOD_REALLOC_FAILED);
+    }
+
+    /* Tealloc to zero bytes, i.e. free. */
+    return NULL;
+}
+
+
+/**
+ * Internal worker for RTMemTrackerHdrFree and RTMemTrackerHdrFreeEx.
+ *
+ * @returns Pointer to the actual allocation.
+ * @param   pTracker            The tracker instance.  Can be NULL.
+ * @param   pvUser              The user memory.
+ * @param   cbUser              The size of the user memory, 0 if unknown.
+ * @param   pszTag              The tag string.
+ * @param   enmMethod           The free method.
+ */
+static void *rtMemTrackerHdrFreeEx(PRTMEMTRACKERINT pTracker, void *pvUser, size_t cbUser,
+                                   const char *pszTag, RTMEMTRACKERMETHOD enmMethod)
+{
+    if (!pvUser)
+        return NULL;
+    return rtMemTrackerHdrFreeCommon(pTracker, pvUser, cbUser, pszTag, enmMethod, RTMEMTRACKERHDR_MAGIC_FREE);
+}
+
+
+/**
+ * Prints a statistics record.
+ *
+ * @param   pStats              The record.
+ * @param   pOutput             The output callback table.
+ * @param   fVerbose            Whether to print in terse or verbose form.
+ */
+DECLINLINE(void) rtMemTrackerDumpOneStatRecord(PRTMEMTRACKERSTATS pStats, PRTMEMTRACKEROUTPUT pOutput, bool fVerbose)
+{
+    if (fVerbose)
+    {
+        pOutput->pfnPrintf(pOutput,
+                           "     Currently allocated: %7zu blocks, %8zu bytes\n"
+                           "    Total allocation sum: %7RU64 blocks, %8RU64 bytes\n"
+                           ,
+                           pStats->cAllocatedBlocks,
+                           pStats->cbAllocated,
+                           pStats->cTotalAllocatedBlocks,
+                           pStats->cbTotalAllocated);
+        pOutput->pfnPrintf(pOutput,
+                           "  Alloc: %7RU64  AllocZ: %7RU64    Free: %7RU64  User Chg: %7RU64\n"
+                           "  RPrep: %7RU64   RDone: %7RU64   RFail: %7RU64\n"
+                           "    New: %7RU64   New[]: %7RU64  Delete: %7RU64  Delete[]: %7RU64\n"
+                           ,
+                           pStats->acMethodCalls[RTMEMTRACKERMETHOD_ALLOC],
+                           pStats->acMethodCalls[RTMEMTRACKERMETHOD_ALLOCZ],
+                           pStats->acMethodCalls[RTMEMTRACKERMETHOD_FREE],
+                           pStats->cUserChanges,
+                           pStats->acMethodCalls[RTMEMTRACKERMETHOD_REALLOC_PREP],
+                           pStats->acMethodCalls[RTMEMTRACKERMETHOD_REALLOC_DONE],
+                           pStats->acMethodCalls[RTMEMTRACKERMETHOD_REALLOC_FAILED],
+                           pStats->acMethodCalls[RTMEMTRACKERMETHOD_NEW],
+                           pStats->acMethodCalls[RTMEMTRACKERMETHOD_NEW_ARRAY],
+                           pStats->acMethodCalls[RTMEMTRACKERMETHOD_DELETE],
+                           pStats->acMethodCalls[RTMEMTRACKERMETHOD_DELETE_ARRAY]);
+    }
+    else
+    {
+        pOutput->pfnPrintf(pOutput, "  %zu bytes in %zu blocks\n",
+                           pStats->cbAllocated, pStats->cAllocatedBlocks);
+    }
+}
+
+
+/**
+ * Internal worker that dumps all the memory tracking data.
+ *
+ * @param   pTracker            The tracker instance.  Can be NULL.
+ * @param   pOutput             The output callback table.
+ */
+static void rtMemTrackerDumpAllWorker(PRTMEMTRACKERINT pTracker, PRTMEMTRACKEROUTPUT pOutput)
+{
+    if (!pTracker)
+        return;
+
+    /*
+     * We use the EW direction to make sure the lists, trees and statistics
+     * does not change while we're working.
+     */
+    PRTMEMTRACKERUSER pUser = rtMemTrackerGetUser(pTracker);
+    RTSemXRoadsEWEnter(pTracker->hXRoads);
+
+    /* Global statistics.*/
+    pOutput->pfnPrintf(pOutput, "*** Global statistics ***\n");
+    rtMemTrackerDumpOneStatRecord(&pTracker->GlobalStats, pOutput, true);
+    pOutput->pfnPrintf(pOutput, "  Busy Allocs: %4RU64  Busy Frees: %4RU64  Tags: %3u  Users: %3u\n",
+                       pTracker->cBusyAllocs, pTracker->cBusyFrees, pTracker->cTags, pTracker->cUsers);
+
+    /* Per tag statistics. */
+    pOutput->pfnPrintf(pOutput, "\n*** Tag statistics ***\n");
+    PRTMEMTRACKERTAG pTag, pNextTag;
+    RTListForEachSafe(&pTracker->TagList, pTag, pNextTag, RTMEMTRACKERTAG, ListEntry)
+    {
+        pOutput->pfnPrintf(pOutput, "Tag: %s\n", pTag->szTag);
+        rtMemTrackerDumpOneStatRecord(&pTag->Stats, pOutput, true);
+        pOutput->pfnPrintf(pOutput, "\n", pTag->szTag);
+    }
+
+    /* Per user statistics & blocks. */
+    pOutput->pfnPrintf(pOutput, "\n*** User statistics ***\n");
+    PRTMEMTRACKERUSER pCurUser, pNextUser;
+    RTListForEachSafe(&pTracker->UserList, pCurUser, pNextUser, RTMEMTRACKERUSER, ListEntry)
+    {
+        pOutput->pfnPrintf(pOutput, "User #%u: %s%s (cInTracker=%d)\n",
+                           pCurUser->idUser,
+                           pCurUser->szName,
+                           pUser == pCurUser ? " (me)" : "",
+                           pCurUser->cInTracker);
+        rtMemTrackerDumpOneStatRecord(&pCurUser->Stats, pOutput, true);
+
+        PRTMEMTRACKERHDR pCurHdr, pNextHdr;
+        RTListForEachSafe(&pCurUser->MemoryList, pCurHdr, pNextHdr, RTMEMTRACKERHDR, ListEntry)
+        {
+            if (pCurHdr->pTag)
+                pOutput->pfnPrintf(pOutput,
+                                   "    %zu bytes at %p with tag %s\n"
+                                   "    %.*Rhxd\n"
+                                   "\n",
+                                   pCurHdr->cbUser, pCurHdr->pvUser, pCurHdr->pTag->szTag,
+                                   RT_MIN(pCurHdr->cbUser, 16*3), pCurHdr->pvUser);
+            else
+                pOutput->pfnPrintf(pOutput,
+                                   "    %zu bytes at %p without a tag\n"
+                                   "    %.*Rhxd\n"
+                                   "\n",
+                                   pCurHdr->cbUser, pCurHdr->pvUser,
+                                   RT_MIN(pCurHdr->cbUser, 16*3), pCurHdr->pvUser);
+        }
+        pOutput->pfnPrintf(pOutput, "\n", pTag->szTag);
+    }
+
+    /* Repeat the global statistics. */
+    pOutput->pfnPrintf(pOutput, "*** Global statistics (reprise) ***\n");
+    rtMemTrackerDumpOneStatRecord(&pTracker->GlobalStats, pOutput, true);
+    pOutput->pfnPrintf(pOutput, "  Busy Allocs: %4RU64  Busy Frees: %4RU64  Tags: %3u  Users: %3u\n",
+                       pTracker->cBusyAllocs, pTracker->cBusyFrees, pTracker->cTags, pTracker->cUsers);
+
+    RTSemXRoadsEWLeave(pTracker->hXRoads);
+    rtMemTrackerPutUser(pUser);
+}
+
+
+/**
+ * Internal worker that dumps the memory tracking statistics.
+ *
+ * @param   pTracker            The tracker instance.  Can be NULL.
+ * @param   pOutput             The output callback table.
+ * @param   fVerbose            Whether to the verbose or quiet.
+ */
+static void rtMemTrackerDumpStatsWorker(PRTMEMTRACKERINT pTracker, PRTMEMTRACKEROUTPUT pOutput, bool fVerbose)
+{
+    if (!pTracker)
+        return;
+
+    /*
+     * We use the EW direction to make sure the lists, trees and statistics
+     * does not change while we're working.
+     */
+    PRTMEMTRACKERUSER pUser = rtMemTrackerGetUser(pTracker);
+    RTSemXRoadsEWEnter(pTracker->hXRoads);
+
+    /* Global statistics.*/
+    pOutput->pfnPrintf(pOutput, "*** Global statistics ***\n");
+    rtMemTrackerDumpOneStatRecord(&pTracker->GlobalStats, pOutput, fVerbose);
+    if (fVerbose)
+        pOutput->pfnPrintf(pOutput, "  Busy Allocs: %4RU64  Busy Frees: %4RU64  Tags: %3u  Users: %3u\n",
+                           pTracker->cBusyAllocs, pTracker->cBusyFrees, pTracker->cTags, pTracker->cUsers);
+
+    /* Per tag statistics. */
+    pOutput->pfnPrintf(pOutput, "\n*** Tag statistics ***\n");
+    PRTMEMTRACKERTAG pTag, pNextTag;
+    RTListForEachSafe(&pTracker->TagList, pTag, pNextTag, RTMEMTRACKERTAG, ListEntry)
+    {
+        if (   fVerbose
+            || pTag->Stats.cbAllocated)
+        {
+            pOutput->pfnPrintf(pOutput, "Tag: %s\n", pTag->szTag);
+            rtMemTrackerDumpOneStatRecord(&pTag->Stats, pOutput, fVerbose);
+            if (fVerbose)
+                pOutput->pfnPrintf(pOutput, "\n", pTag->szTag);
+        }
+    }
+
+    /* Per user statistics. */
+    pOutput->pfnPrintf(pOutput, "\n*** User statistics ***\n");
+    PRTMEMTRACKERUSER pCurUser, pNextUser;
+    RTListForEachSafe(&pTracker->UserList, pCurUser, pNextUser, RTMEMTRACKERUSER, ListEntry)
+    {
+        if (   fVerbose
+            || pCurUser->Stats.cbAllocated
+            || pCurUser == pUser)
+        {
+            pOutput->pfnPrintf(pOutput, "User #%u: %s%s (cInTracker=%d)\n",
+                               pCurUser->idUser,
+                               pCurUser->szName,
+                               pUser == pCurUser ? " (me)" : "",
+                               pCurUser->cInTracker);
+            rtMemTrackerDumpOneStatRecord(&pCurUser->Stats, pOutput, fVerbose);
+            if (fVerbose)
+                pOutput->pfnPrintf(pOutput, "\n", pTag->szTag);
+        }
+    }
+
+    if (fVerbose)
+    {
+        /* Repeat the global statistics. */
+        pOutput->pfnPrintf(pOutput, "*** Global statistics (reprise) ***\n");
+        rtMemTrackerDumpOneStatRecord(&pTracker->GlobalStats, pOutput, fVerbose);
+        pOutput->pfnPrintf(pOutput, "  Busy Allocs: %4RU64  Busy Frees: %4RU64  Tags: %3u  Users: %3u\n",
+                           pTracker->cBusyAllocs, pTracker->cBusyFrees, pTracker->cTags, pTracker->cUsers);
+    }
+
+    RTSemXRoadsEWLeave(pTracker->hXRoads);
+    rtMemTrackerPutUser(pUser);
+}
+
+
+/**
+ * @callback_method_impl{RTMEMTRACKEROUTPUT::pfnPrintf, Outputting to the release log}
+ */
+static DECLCALLBACK(void) rtMemTrackerDumpLogOutput(PRTMEMTRACKEROUTPUT pThis, const char *pszFormat, ...)
+{
+    va_list va;
+    va_start(va, pszFormat);
+    RTLogPrintfV(pszFormat, va);
+    va_end(va);
+}
+
+
+/**
+ * Internal worker for RTMemTrackerDumpAllToLog and RTMemTrackerDumpAllToLogEx.
+ *
+ * @param   pTracker            The tracker instance.  Can be NULL.
+ */
+static void rtMemTrackerDumpAllToLogEx(PRTMEMTRACKERINT pTracker)
+{
+    RTMEMTRACKEROUTPUT Output;
+    Output.pfnPrintf = rtMemTrackerDumpLogOutput;
+    rtMemTrackerDumpAllWorker(pTracker, &Output);
+}
+
+
+/**
+ * Internal worker for RTMemTrackerDumpStatsToLog and
+ * RTMemTrackerDumpStatsToLogEx.
+ *
+ * @param   pTracker            The tracker instance.  Can be NULL.
+ * @param   fVerbose            Whether to print all the stats or just the ones
+ *                              relevant to hunting leaks.
+ */
+static void rtMemTrackerDumpStatsToLogEx(PRTMEMTRACKERINT pTracker, bool fVerbose)
+{
+    RTMEMTRACKEROUTPUT Output;
+    Output.pfnPrintf = rtMemTrackerDumpLogOutput;
+    rtMemTrackerDumpStatsWorker(pTracker, &Output, fVerbose);
+}
+
+
+/**
+ * @callback_method_impl{RTMEMTRACKEROUTPUT::pfnPrintf, Outputting to the release log}
+ */
+static DECLCALLBACK(void) rtMemTrackerDumpLogRelOutput(PRTMEMTRACKEROUTPUT pThis, const char *pszFormat, ...)
+{
+    va_list va;
+    va_start(va, pszFormat);
+    RTLogRelPrintfV(pszFormat, va);
+    va_end(va);
+}
+
+
+/**
+ * Internal worker for RTMemTrackerDumpStatsToLog and
+ * RTMemTrackerDumpStatsToLogEx.
+ *
+ * @param   pTracker            The tracker instance.  Can be NULL.
+ */
+static void rtMemTrackerDumpAllToLogRelEx(PRTMEMTRACKERINT pTracker)
+{
+    RTMEMTRACKEROUTPUT Output;
+    Output.pfnPrintf = rtMemTrackerDumpLogRelOutput;
+    rtMemTrackerDumpAllWorker(pTracker, &Output);
+}
+
+
+/**
+ * Internal worker for RTMemTrackerDumpStatsToLogRel and
+ * RTMemTrackerDumpStatsToLogRelEx.
+ *
+ * @param   pTracker            The tracker instance.  Can be NULL.
+ * @param   fVerbose            Whether to print all the stats or just the ones
+ *                              relevant to hunting leaks.
+ */
+static void rtMemTrackerDumpStatsToLogRelEx(PRTMEMTRACKERINT pTracker, bool fVerbose)
+{
+    RTMEMTRACKEROUTPUT Output;
+    Output.pfnPrintf = rtMemTrackerDumpLogRelOutput;
+    rtMemTrackerDumpStatsWorker(pTracker, &Output, fVerbose);
+}
+
+#ifdef IN_RING3
+
+/**
+ * @callback_method_impl{RTMEMTRACKEROUTPUT::pfnPrintf, Outputting to file}
+ */
+static DECLCALLBACK(void) rtMemTrackerDumpFileOutput(PRTMEMTRACKEROUTPUT pThis, const char *pszFormat, ...)
+{
+    va_list va;
+    va_start(va, pszFormat);
+    char szOutput[_4K];
+    size_t cchOutput = RTStrPrintfV(szOutput, sizeof(szOutput), pszFormat, va);
+    va_end(va);
+    RTFileWrite(pThis->uData.hFile, szOutput, cchOutput, NULL);
+}
+
+
+/**
+ * Internal work that dumps the memory tracking statistics to a file handle.
+ *
+ * @param   pTracker        The tracker instance.  Can be NULL.
+ * @param   fVerbose        Whether to print all the stats or just the ones
+ *                          relevant to hunting leaks.
+ * @param   hFile           The file handle.  Can be NIL_RTFILE.
+ */
+static void rtMemTrackerDumpStatsToFileHandle(PRTMEMTRACKERINT pTracker, bool fVerbose, RTFILE hFile)
+{
+    if (hFile == NIL_RTFILE)
+        return;
+    RTMEMTRACKEROUTPUT Output;
+    Output.pfnPrintf   = rtMemTrackerDumpFileOutput;
+    Output.uData.hFile = hFile;
+    rtMemTrackerDumpStatsWorker(pTracker, &Output, fVerbose);
+}
+
+
+/**
+ * Internal work that dumps all the memory tracking information to a file
+ * handle.
+ *
+ * @param   pTracker        The tracker instance.  Can be NULL.
+ * @param   hFile           The file handle.  Can be NIL_RTFILE.
+ */
+static void rtMemTrackerDumpAllToFileHandle(PRTMEMTRACKERINT pTracker, RTFILE hFile)
+{
+    if (hFile == NIL_RTFILE)
+        return;
+    RTMEMTRACKEROUTPUT Output;
+    Output.pfnPrintf   = rtMemTrackerDumpFileOutput;
+    Output.uData.hFile = hFile;
+    rtMemTrackerDumpAllWorker(pTracker, &Output);
+}
+
+
+/**
+ * Internal worker for RTMemTrackerDumpStatsToStdOut and
+ * RTMemTrackerDumpStatsToStdOutEx.
+ *
+ * @param   pTracker            The tracker instance.  Can be NULL.
+ * @param   fVerbose            Whether to print all the stats or just the ones
+ *                              relevant to hunting leaks.
+ */
+static void rtMemTrackerDumpStatsToStdOutEx(PRTMEMTRACKERINT pTracker, bool fVerbose)
+{
+    rtMemTrackerDumpStatsToFileHandle(pTracker, fVerbose, rtFileGetStandard(RTHANDLESTD_OUTPUT));
+}
+
+
+/**
+ * Internal worker for RTMemTrackerDumpAllToStdOut and
+ * RTMemTrackerDumpAllToStdOutEx.
+ *
+ * @param   pTracker            The tracker instance.  Can be NULL.
+ */
+static void rtMemTrackerDumpAllToStdOutEx(PRTMEMTRACKERINT pTracker)
+{
+    rtMemTrackerDumpAllToFileHandle(pTracker, rtFileGetStandard(RTHANDLESTD_OUTPUT));
+}
+
+
+/**
+ * Internal worker for RTMemTrackerDumpStatsToStdErr and
+ * RTMemTrackerDumpStatsToStdErrEx.
+ *
+ * @param   pTracker            The tracker instance.  Can be NULL.
+ * @param   fVerbose            Whether to print all the stats or just the ones
+ *                              relevant to hunting leaks.
+ */
+static void rtMemTrackerDumpStatsToStdErrEx(PRTMEMTRACKERINT pTracker, bool fVerbose)
+{
+    rtMemTrackerDumpStatsToFileHandle(pTracker, fVerbose, rtFileGetStandard(RTHANDLESTD_ERROR));
+}
+
+
+/**
+ * Internal worker for RTMemTrackerDumpAllToStdErr and
+ * RTMemTrackerDumpAllToStdErrEx.
+ *
+ * @param   pTracker            The tracker instance.  Can be NULL.
+ */
+static void rtMemTrackerDumpAllToStdErrEx(PRTMEMTRACKERINT pTracker)
+{
+    rtMemTrackerDumpAllToFileHandle(pTracker, rtFileGetStandard(RTHANDLESTD_ERROR));
+}
+
+
+/**
+ * Internal worker for RTMemTrackerDumpStatsToFile and
+ * RTMemTrackerDumpStatsToFileEx.
+ *
+ * @param   pTracker            The tracker instance.  Can be NULL.
+ * @param   fVerbose            Whether to print all the stats or just the ones
+ *                              relevant to hunting leaks.
+ * @param   pszFilename         The name of the output file.
+ */
+static void rtMemTrackerDumpStatsToFileEx(PRTMEMTRACKERINT pTracker, bool fVerbose, const char *pszFilename)
+{
+    if (!pTracker)
+        return;
+
+    /** @todo this is borked. */
+    RTFILE hFile;
+    int rc = RTFileOpen(&hFile, pszFilename,
+                        RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_NONE
+                        | (0600 << RTFILE_O_CREATE_MODE_SHIFT));
+    if (RT_FAILURE(rc))
+        return;
+    rtMemTrackerDumpStatsToFileHandle(pTracker, fVerbose, hFile);
+    RTFileClose(hFile);
+}
+
+
+/**
+ * Internal worker for RTMemTrackerDumpAllToFile and
+ * RTMemTrackerDumpAllToFileEx.
+ *
+ * @param   pTracker            The tracker instance.  Can be NULL.
+ * @param   pszFilename         The name of the output file.
+ */
+static void rtMemTrackerDumpAllToFileEx(PRTMEMTRACKERINT pTracker, const char *pszFilename)
+{
+    if (!pTracker)
+        return;
+
+    RTFILE hFile;
+    int rc = RTFileOpen(&hFile, pszFilename,
+                        RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_NONE
+                        | (0600 << RTFILE_O_CREATE_MODE_SHIFT));
+    if (RT_FAILURE(rc))
+        return;
+    rtMemTrackerDumpAllToFileHandle(pTracker, hFile);
+    RTFileClose(hFile);
+}
+
+#endif /* IN_RING3 */
+
+
+
+/*
+ *
+ *
+ * Default tracker.
+ * Default tracker.
+ * Default tracker.
+ * Default tracker.
+ * Default tracker.
+ *
+ *
+ */
+
+
+/**
+ * Handles the lazy initialization when g_pDefaultTracker is NULL.
+ *
+ * @returns The newly created default tracker or NULL.
+ */
+static PRTMEMTRACKERINT rtMemTrackerLazyInitDefaultTracker(void)
+{
+    /*
+     * Don't attempt initialize before RTThread has been initialized.
+     */
+    if (!RTThreadIsInitialized())
+        return NULL;
+
+    /*
+     * Only one initialization at a time.  For now we'll ASSUME that there
+     * won't be thread ending up here at the same time, only the same
+     * reentering from the allocator when creating the tracker.
+     */
+    static volatile bool s_fInitialized = false;
+    if (ASMAtomicXchgBool(&s_fInitialized, true))
+        return g_pDefaultTracker;
+
+    PRTMEMTRACKERINT pTracker;
+    int rc = rtMemTrackerCreate(&pTracker);
+    if (RT_FAILURE(rc))
+        return NULL;
+
+    g_pDefaultTracker = pTracker;
+    return pTracker;
+}
+
+
+
+RTDECL(void *) RTMemTrackerHdrAlloc(void *pv, size_t cb, const char *pszTag, RTMEMTRACKERMETHOD enmMethod)
+{
+    PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
+    if (RT_UNLIKELY(!pTracker))
+        pTracker = rtMemTrackerLazyInitDefaultTracker();
+    return rtMemTrackerHdrAllocEx(pTracker, pv, cb, pszTag, enmMethod);
+}
+
+
+RTDECL(void *) RTMemTrackerHdrReallocPrep(void *pvOldUser, size_t cbOldUser, const char *pszTag)
+{
+    PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
+    if (RT_UNLIKELY(!pTracker))
+        pTracker = rtMemTrackerLazyInitDefaultTracker();
+    return rtMemTrackerHdrReallocPrepEx(pTracker, pvOldUser, cbOldUser, pszTag);
+}
+
+
+RTDECL(void *) RTMemTrackerHdrReallocDone(void *pvNew, size_t cbNewUser, void *pvOld, const char *pszTag)
+{
+    PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
+    if (RT_UNLIKELY(!pTracker))
+        pTracker = rtMemTrackerLazyInitDefaultTracker();
+    return rtMemTrackerHdrReallocDoneEx(pTracker, pvNew, cbNewUser, pvOld, pszTag);
+}
+
+
+RTDECL(void *) RTMemTrackerHdrFree(void *pvUser, size_t cbUser, const char *pszTag, RTMEMTRACKERMETHOD enmMethod)
+{
+    PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
+    if (RT_UNLIKELY(!pTracker))
+        pTracker = rtMemTrackerLazyInitDefaultTracker();
+    return rtMemTrackerHdrFreeEx(pTracker, pvUser, cbUser, pszTag, enmMethod);
+}
+
+
+RTDECL(void) RTMemTrackerDumpAllToLog(void)
+{
+    PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
+    if (RT_UNLIKELY(!pTracker))
+        pTracker = rtMemTrackerLazyInitDefaultTracker();
+    return rtMemTrackerDumpAllToLogEx(pTracker);
+}
+
+
+RTDECL(void) RTMemTrackerDumpAllToLogRel(void)
+{
+    PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
+    if (RT_UNLIKELY(!pTracker))
+        pTracker = rtMemTrackerLazyInitDefaultTracker();
+    return rtMemTrackerDumpAllToLogRelEx(pTracker);
+}
+
+
+RTDECL(void) RTMemTrackerDumpAllToStdOut(void)
+{
+    PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
+    if (RT_UNLIKELY(!pTracker))
+        pTracker = rtMemTrackerLazyInitDefaultTracker();
+    return rtMemTrackerDumpAllToStdOutEx(pTracker);
+}
+
+
+RTDECL(void) RTMemTrackerDumpAllToStdErr(void)
+{
+    PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
+    if (RT_UNLIKELY(!pTracker))
+        pTracker = rtMemTrackerLazyInitDefaultTracker();
+    return rtMemTrackerDumpAllToStdErrEx(pTracker);
+}
+
+
+RTDECL(void) RTMemTrackerDumpAllToFile(const char *pszFilename)
+{
+    PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
+    if (RT_UNLIKELY(!pTracker))
+        pTracker = rtMemTrackerLazyInitDefaultTracker();
+    return rtMemTrackerDumpAllToFileEx(pTracker, pszFilename);
+}
+
+
+RTDECL(void) RTMemTrackerDumpStatsToLog(bool fVerbose)
+{
+    PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
+    if (RT_UNLIKELY(!pTracker))
+        pTracker = rtMemTrackerLazyInitDefaultTracker();
+    return rtMemTrackerDumpStatsToLogEx(pTracker, fVerbose);
+}
+
+
+RTDECL(void) RTMemTrackerDumpStatsToLogRel(bool fVerbose)
+{
+    PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
+    if (RT_UNLIKELY(!pTracker))
+        pTracker = rtMemTrackerLazyInitDefaultTracker();
+    return rtMemTrackerDumpStatsToLogRelEx(pTracker, fVerbose);
+}
+
+
+RTDECL(void) RTMemTrackerDumpStatsToStdOut(bool fVerbose)
+{
+    PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
+    if (RT_UNLIKELY(!pTracker))
+        pTracker = rtMemTrackerLazyInitDefaultTracker();
+    return rtMemTrackerDumpStatsToStdOutEx(pTracker, fVerbose);
+}
+
+
+RTDECL(void) RTMemTrackerDumpStatsToStdErr(bool fVerbose)
+{
+    PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
+    if (RT_UNLIKELY(!pTracker))
+        pTracker = rtMemTrackerLazyInitDefaultTracker();
+    return rtMemTrackerDumpStatsToStdErrEx(pTracker, fVerbose);
+}
+
+
+RTDECL(void) RTMemTrackerDumpStatsToFile(bool fVerbose, const char *pszFilename)
+{
+    PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
+    if (RT_UNLIKELY(!pTracker))
+        pTracker = rtMemTrackerLazyInitDefaultTracker();
+    return rtMemTrackerDumpStatsToFileEx(pTracker, fVerbose, pszFilename);
+}
+
Index: trunk/src/VBox/Runtime/common/misc/lockvalidator.cpp
===================================================================
--- trunk/src/VBox/Runtime/common/misc/lockvalidator.cpp	(revision 36596)
+++ trunk/src/VBox/Runtime/common/misc/lockvalidator.cpp	(revision 36597)
@@ -43,4 +43,5 @@
 #include "internal/lockvalidator.h"
 #include "internal/magics.h"
+#include "internal/strhash.h"
 #include "internal/thread.h"
 
@@ -851,27 +852,4 @@
 
 
-/* sdbm:
-   This algorithm was created for sdbm (a public-domain reimplementation of
-   ndbm) database library. it was found to do well in scrambling bits,
-   causing better distribution of the keys and fewer splits. it also happens
-   to be a good general hashing function with good distribution. the actual
-   function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below
-   is the faster version used in gawk. [there is even a faster, duff-device
-   version] the magic constant 65599 was picked out of thin air while
-   experimenting with different constants, and turns out to be a prime.
-   this is one of the algorithms used in berkeley db (see sleepycat) and
-   elsewhere. */
-DECL_FORCE_INLINE(uint32_t) sdbm(const char *str, uint32_t hash)
-{
-    uint8_t *pu8 = (uint8_t *)str;
-    int c;
-
-    while ((c = *pu8++))
-        hash = c + (hash << 6) + (hash << 16) - hash;
-
-    return hash;
-}
-
-
 /**
  * Hashes the specified source position.
@@ -889,7 +867,7 @@
         uHash = 0;
         if (pSrcPos->pszFile)
-            uHash = sdbm(pSrcPos->pszFile, uHash);
+            uHash = sdbmInc(pSrcPos->pszFile, uHash);
         if (pSrcPos->pszFunction)
-            uHash = sdbm(pSrcPos->pszFunction, uHash);
+            uHash = sdbmInc(pSrcPos->pszFunction, uHash);
         uHash += pSrcPos->uLine;
     }
Index: trunk/src/VBox/Runtime/common/string/strspace.cpp
===================================================================
--- trunk/src/VBox/Runtime/common/string/strspace.cpp	(revision 36596)
+++ trunk/src/VBox/Runtime/common/string/strspace.cpp	(revision 36597)
@@ -33,4 +33,5 @@
 
 #include <iprt/assert.h>
+#include "internal/strhash.h"
 
 
@@ -72,42 +73,4 @@
 #include "../table/avl_Destroy.cpp.h"
 
-
-
-/* sdbm:
-   This algorithm was created for sdbm (a public-domain reimplementation of
-   ndbm) database library. it was found to do well in scrambling bits,
-   causing better distribution of the keys and fewer splits. it also happens
-   to be a good general hashing function with good distribution. the actual
-   function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below
-   is the faster version used in gawk. [there is even a faster, duff-device
-   version] the magic constant 65599 was picked out of thin air while
-   experimenting with different constants, and turns out to be a prime.
-   this is one of the algorithms used in berkeley db (see sleepycat) and
-   elsewhere. */
-DECLINLINE(uint32_t) sdbm(const char *str, size_t *pcch)
-{
-    uint8_t *pu8 = (uint8_t *)str;
-    uint32_t hash = 0;
-    int c;
-
-    while ((c = *pu8++))
-        hash = c + (hash << 6) + (hash << 16) - hash;
-
-    *pcch = (uintptr_t)pu8 - (uintptr_t)str - 1;
-    return hash;
-}
-
-DECLINLINE(uint32_t) sdbmN(const char *str, size_t cchMax, size_t *pcch)
-{
-    uint8_t *pu8 = (uint8_t *)str;
-    uint32_t hash = 0;
-    int c;
-
-    while ((c = *pu8++) && cchMax-- > 0)
-        hash = c + (hash << 6) + (hash << 16) - hash;
-
-    *pcch = (uintptr_t)pu8 - (uintptr_t)str - 1;
-    return hash;
-}
 
 
Index: trunk/src/VBox/Runtime/include/internal/file.h
===================================================================
--- trunk/src/VBox/Runtime/include/internal/file.h	(revision 36596)
+++ trunk/src/VBox/Runtime/include/internal/file.h	(revision 36597)
@@ -44,4 +44,16 @@
 int rtFileRecalcAndValidateFlags(uint32_t *pfOpen);
 
+
+/**
+ * Internal interface for getting the RTFILE handle of stdin, stdout or stderr.
+ *
+ * This interface will not be exposed and is purely for internal IPRT use.
+ *
+ * @returns Handle or NIL_RTFILE.
+ *
+ * @param   enmStdHandle    The standard handle.
+ */
+RTFILE rtFileGetStandard(RTHANDLESTD enmStdHandle);
+
 RT_C_DECLS_END
 
Index: trunk/src/VBox/Runtime/include/internal/strhash.h
===================================================================
--- trunk/src/VBox/Runtime/include/internal/strhash.h	(revision 36597)
+++ trunk/src/VBox/Runtime/include/internal/strhash.h	(revision 36597)
@@ -0,0 +1,94 @@
+/* $Id$ */
+/** @file
+ * IPRT - Internal header containing inline string hashing functions.
+ */
+
+/*
+ * Copyright (C) 2006-2011 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___internal_strhash_h
+#define ___internal_strhash_h
+
+#include <iprt/types.h>
+
+
+/* sdbm:
+   This algorithm was created for sdbm (a public-domain reimplementation of
+   ndbm) database library. it was found to do well in scrambling bits,
+   causing better distribution of the keys and fewer splits. it also happens
+   to be a good general hashing function with good distribution. the actual
+   function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below
+   is the faster version used in gawk. [there is even a faster, duff-device
+   version] the magic constant 65599 was picked out of thin air while
+   experimenting with different constants, and turns out to be a prime.
+   this is one of the algorithms used in berkeley db (see sleepycat) and
+   elsewhere. */
+
+/**
+ * Hash string, return hash + length.
+ */
+DECLINLINE(uint32_t) sdbm(const char *str, size_t *pcch)
+{
+    uint8_t *pu8 = (uint8_t *)str;
+    uint32_t hash = 0;
+    int c;
+
+    while ((c = *pu8++))
+        hash = c + (hash << 6) + (hash << 16) - hash;
+
+    *pcch = (uintptr_t)pu8 - (uintptr_t)str - 1;
+    return hash;
+}
+
+
+/**
+ * Hash up to N bytes, return hash + hashed length.
+ */
+DECLINLINE(uint32_t) sdbmN(const char *str, size_t cchMax, size_t *pcch)
+{
+    uint8_t *pu8 = (uint8_t *)str;
+    uint32_t hash = 0;
+    int c;
+
+    while ((c = *pu8++) && cchMax-- > 0)
+        hash = c + (hash << 6) + (hash << 16) - hash;
+
+    *pcch = (uintptr_t)pu8 - (uintptr_t)str - 1;
+    return hash;
+}
+
+/**
+ * Incremental hashing.
+ */
+DECLINLINE(uint32_t) sdbmInc(const char *str, uint32_t hash)
+{
+    uint8_t *pu8 = (uint8_t *)str;
+    int c;
+
+    while ((c = *pu8++))
+        hash = c + (hash << 6) + (hash << 16) - hash;
+
+    return hash;
+}
+
+
+#endif
+
Index: trunk/src/VBox/Runtime/r3/alloc.cpp
===================================================================
--- trunk/src/VBox/Runtime/r3/alloc.cpp	(revision 36596)
+++ trunk/src/VBox/Runtime/r3/alloc.cpp	(revision 36597)
@@ -34,4 +34,10 @@
 #endif
 
+/*#define RTMEMALLOC_USE_TRACKER*/
+/* Don't enable the tracker when building the minimal IPRT. */
+#ifdef RT_MINI
+# undef RTMEMALLOC_USE_TRACKER
+#endif
+
 
 /*******************************************************************************
@@ -73,4 +79,6 @@
 #undef RTMemDupExTag
 
+#undef RTALLOC_USE_EFENCE
+
 
 RTDECL(void *)  RTMemTmpAllocTag(size_t cb, const char *pszTag) RT_NO_THROW
@@ -178,20 +186,9 @@
 #else /* !RTALLOC_USE_EFENCE */
 
-# ifdef RTALLOC_USE_TRACKER
-    void *pv;
-    if (!pvOld)
-    {
-        if (cbNew)
-            pv = RTMemTrackerHdrAlloc(realloc(pvOld, cbNew + sizeof(RTMEMTRACKERHDR)), cbNew,
-                                      pszTag, RTMEMTRACKERMETHOD_REALLOC);
-        else
-            pv = NULL;
-    }
-    else
-    {
-        RTMemTrackerHdrReallocPrep(pvOld, 0, pszTag, RTMEMTRACKERMETHOD_REALLOC);
-        pv = RTMemTrackerHdrRealloc(realloc(pvOld, cbNew + sizeof(RTMEMTRACKERHDR)), cbNew, pvOld,
-                                    pszTag, RTMEMTRACKERMETHOD_REALLOC);
-    }
+# ifdef RTMEMALLOC_USE_TRACKER
+    void *pvRealOld  = RTMemTrackerHdrReallocPrep(pvOld, 0, pszTag);
+    size_t cbRealNew = cbNew || !pvRealOld ? cbNew + sizeof(RTMEMTRACKERHDR) : 0;
+    void *pvNew      = realloc(pvRealOld, cbRealNew);
+    void *pv         = RTMemTrackerHdrReallocDone(pvNew, cbNew, pvOld, pszTag);
 # else
     void *pv = realloc(pvOld, cbNew);
@@ -213,5 +210,5 @@
         rtR3MemFree("Free", RTMEMTYPE_RTMEMFREE, pv, ASMReturnAddress(), NULL, 0, NULL);
 #else
-# ifdef RTALLOC_USE_TRACKER
+# ifdef RTMEMALLOC_USE_TRACKER
         pv = RTMemTrackerHdrFree(pv, 0, NULL, RTMEMTRACKERMETHOD_FREE);
 # endif
Index: trunk/src/VBox/Runtime/r3/posix/fileio-posix.cpp
===================================================================
--- trunk/src/VBox/Runtime/r3/posix/fileio-posix.cpp	(revision 36596)
+++ trunk/src/VBox/Runtime/r3/posix/fileio-posix.cpp	(revision 36597)
@@ -376,4 +376,25 @@
 
 
+RTFILE rtFileGetStandard(RTHANDLESTD enmStdHandle)
+{
+    int fd;
+    switch (enmStdHandle)
+    {
+        case RTHANDLESTD_INPUT:  fd = 0; break;
+        case RTHANDLESTD_OUTPUT: fd = 1; break;
+        case RTHANDLESTD_ERROR:  fd = 2; break;
+            break;
+        default:
+            AssertFailedReturn(NIL_RTFILE);
+    }
+
+    struct stat st;
+    int rc = fstat(fd, &st);
+    if (rc == -1)
+        return NIL_RTFILE;
+    return (RTFILE)fd;
+}
+
+
 RTR3DECL(int)  RTFileDelete(const char *pszFilename)
 {
Index: trunk/src/VBox/Runtime/r3/win/fileio-win.cpp
===================================================================
--- trunk/src/VBox/Runtime/r3/win/fileio-win.cpp	(revision 36596)
+++ trunk/src/VBox/Runtime/r3/win/fileio-win.cpp	(revision 36597)
@@ -349,4 +349,27 @@
 
 
+RTFILE rtFileGetStandard(RTHANDLESTD enmStdHandle)
+{
+    DWORD dwStdHandle;
+    switch (enmStdHandle)
+    {
+        case RTHANDLESTD_INPUT:     dwStdHandle = STD_INPUT_HANDLE;  break;
+        case RTHANDLESTD_OUTPUT:    dwStdHandle = STD_OUTPUT_HANDLE; break;
+        case RTHANDLESTD_ERROR:     dwStdHandle = STD_ERROR_HANDLE;  break;
+            break;
+        default:
+            AssertFailedReturn(NIL_RTFILE);
+    }
+
+    HANDLE hHandle = GetStdHandle(dwStdHandle);
+    if (hNative == INVALID_HANDLE_VALUE)
+        return NIL_RTFILE;
+
+    RTFILE hFile = (RTFILE)(uintptr_t)hHandle;
+    AssertReturn((HANDLE)(uintptr_t)hFile == hHandle, NIL_RTFILE);
+    return hFile;
+}
+
+
 RTR3DECL(int)  RTFileSeek(RTFILE File, int64_t offSeek, unsigned uMethod, uint64_t *poffActual)
 {
@@ -405,7 +428,7 @@
     }
 
-    /* 
-     * If it's a console, we might bump into out of memory conditions in the 
-     * ReadConsole call.  
+    /*
+     * If it's a console, we might bump into out of memory conditions in the
+     * ReadConsole call.
      */
     DWORD dwErr = GetLastError();
@@ -450,5 +473,5 @@
         return VINF_SUCCESS;
     }
-    
+
     return RTErrConvertFromWin32(dwErr);
 }
@@ -491,7 +514,7 @@
     }
 
-    /* 
-     * If it's a console, we might bump into out of memory conditions in the 
-     * WriteConsole call.  
+    /*
+     * If it's a console, we might bump into out of memory conditions in the
+     * WriteConsole call.
      */
     DWORD dwErr = GetLastError();
