Index: /trunk/include/VBox/dbg.h
===================================================================
--- /trunk/include/VBox/dbg.h	(revision 55880)
+++ /trunk/include/VBox/dbg.h	(revision 55881)
@@ -8,5 +8,5 @@
 
 /*
- * Copyright (C) 2006-2013 Oracle Corporation
+ * Copyright (C) 2006-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -42,5 +42,10 @@
 RT_C_DECLS_BEGIN
 
+
 #ifdef IN_RING3 /* The debugger stuff is ring-3 only. */
+
+/** @defgroup grp_dbgc     The Debugger Console API
+ * @{
+ */
 
 /** @def VBOX_WITH_DEBUGGER
@@ -1096,55 +1101,8 @@
 DBGDECL(int)    DBGCTcpTerminate(PUVM pUVM, void *pvData);
 
-
-/** @defgroup grp_dbgc_plug_in      The DBGC Plug-in Interface
- * @{
- */
-
-/** The plug-in module name prefix. */
-#define DBGC_PLUG_IN_PREFIX         "DBGCPlugIn"
-
-/** The name of the plug-in entry point (FNDBGCPLUGIN) */
-#define DBGC_PLUG_IN_ENTRYPOINT     "DBGCPlugInEntry"
-
-/**
- * DBGC plug-in operations.
- */
-typedef enum DBGCPLUGINOP
-{
-    /** The usual invalid first value. */
-    DBGCPLUGINOP_INVALID,
-    /** Initialize the plug-in, register all the stuff.
-     * The plug-in will be unloaded on failure.
-     * uArg: The VirtualBox version (major+minor). */
-    DBGCPLUGINOP_INIT,
-    /** Terminate the plug-ing, deregister all the stuff.
-     * The plug-in will be unloaded after this call regardless of the return
-     * code. */
-    DBGCPLUGINOP_TERM,
-    /** The usual 32-bit hack. */
-    DBGCPLUGINOP_32BIT_HACK = 0x7fffffff
-} DBGCPLUGINOP;
-
-/**
- * DBGC plug-in main entry point.
- *
- * @returns VBox status code.
- *
- * @param   enmOperation    The operation.
- * @param   pUVM            The user mode VM handle. This may be NULL.
- * @param   uArg            Extra argument.
- */
-typedef DECLCALLBACK(int) FNDBGCPLUGIN(DBGCPLUGINOP enmOperation, PUVM pUVM, uintptr_t uArg);
-/** Pointer to a FNDBGCPLUGIN. */
-typedef FNDBGCPLUGIN *PFNDBGCPLUGIN;
-
-/** @copydoc FNDBGCPLUGIN */
-DECLEXPORT(int) DBGCPlugInEntry(DBGCPLUGINOP enmOperation, PUVM pUVM, uintptr_t uArg);
+/** @} */
 
 #endif /* IN_RING3 */
 
-/** @} */
-
-
 RT_C_DECLS_END
 
Index: /trunk/include/VBox/vmm/dbgf.h
===================================================================
--- /trunk/include/VBox/vmm/dbgf.h	(revision 55880)
+++ /trunk/include/VBox/vmm/dbgf.h	(revision 55881)
@@ -1733,5 +1733,61 @@
 VMMR3DECL(int)      DBGFR3CoreWrite(PUVM pUVM, const char *pszFilename, bool fReplaceFile);
 
+
+#ifdef IN_RING3
+/** @defgroup grp_dbgf_plug_in      The DBGF Plug-in Interface
+ * @{
+ */
+
+/** The plug-in module name prefix. */
+#define DBGF_PLUG_IN_PREFIX         "DbgPlugIn"
+
+/** The name of the plug-in entry point (FNDBGFPLUGIN) */
+#define DBGF_PLUG_IN_ENTRYPOINT     "DbgPlugInEntry"
+
+/**
+ * DBGF plug-in operations.
+ */
+typedef enum DBGFPLUGINOP
+{
+    /** The usual invalid first value. */
+    DBGFPLUGINOP_INVALID,
+    /** Initialize the plug-in for a VM, register all the stuff.
+     * The plug-in will be unloaded on failure.
+     * uArg: The full VirtualBox version, see VBox/version.h. */
+    DBGFPLUGINOP_INIT,
+    /** Terminate the plug-ing for a VM, deregister all the stuff.
+     * The plug-in will be unloaded after this call regardless of the return
+     * code. */
+    DBGFPLUGINOP_TERM,
+    /** The usual 32-bit hack. */
+    DBGFPLUGINOP_32BIT_HACK = 0x7fffffff
+} DBGFPLUGINOP;
+
+/**
+ * DBGF plug-in main entry point.
+ *
+ * @returns VBox status code.
+ *
+ * @param   enmOperation    The operation.
+ * @param   pUVM            The user mode VM handle. This may be NULL.
+ * @param   uArg            Extra argument.
+ */
+typedef DECLCALLBACK(int) FNDBGFPLUGIN(DBGFPLUGINOP enmOperation, PUVM pUVM, uintptr_t uArg);
+/** Pointer to a FNDBGFPLUGIN. */
+typedef FNDBGFPLUGIN *PFNDBGFPLUGIN;
+
+/** @copydoc FNDBGFPLUGIN */
+DECLEXPORT(int) DbgPlugInEntry(DBGFPLUGINOP enmOperation, PUVM pUVM, uintptr_t uArg);
+
+VMMR3DECL(int)  DBGFR3PlugInLoad(PUVM pUVM, const char *pszPlugIn, char *pszActual, size_t cbActual, PRTERRINFO pErrInfo);
+VMMR3DECL(int)  DBGFR3PlugInUnload(PUVM pUVM, const char *pszName);
+VMMR3DECL(void) DBGFR3PlugInLoadAll(PUVM pUVM);
+VMMR3DECL(void) DBGFR3PlugInUnloadAll(PUVM pUVM);
+
 /** @} */
+#endif /* IN_RING3 */
+
+
+/** @} */
 
 
Index: /trunk/src/VBox/Debugger/DBGCCommands.cpp
===================================================================
--- /trunk/src/VBox/Debugger/DBGCCommands.cpp	(revision 55880)
+++ /trunk/src/VBox/Debugger/DBGCCommands.cpp	(revision 55881)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2013 Oracle Corporation
+ * Copyright (C) 2006-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -70,5 +70,4 @@
 static FNDBGCCMD dbgcCmdLoadPlugIn;
 static FNDBGCCMD dbgcCmdUnloadPlugIn;
-static FNDBGCCMD dbgcCmdShowPlugIns;
 static FNDBGCCMD dbgcCmdHarakiri;
 static FNDBGCCMD dbgcCmdEcho;
@@ -267,5 +266,4 @@
                                                                                                                                         "(after removing blanks) are comment. blank lines are ignored. Stops on failure." },
     { "set",        2,        2,        &g_aArgSet[0],       RT_ELEMENTS(g_aArgSet),       0, dbgcCmdSet,       "<var> <value>",        "Sets a global variable." },
-    { "showplugins",0,        0,        NULL,                0,                            0, dbgcCmdShowPlugIns,"",                     "List loaded plugins." },
     { "showvars",   0,        0,        NULL,                0,                            0, dbgcCmdShowVars,  "",                     "List all the defined variables." },
     { "stop",       0,        0,        NULL,                0,                            0, dbgcCmdStop,      "",                     "Stop execution." },
@@ -1748,56 +1746,31 @@
 
 /**
- * Extracts the plugin name from a plugin specifier that may or may not include
- * path and/or suffix.
- *
- * @returns VBox status code.
- *
- * @param   pszDst      Where to return the name. At least DBGCPLUGIN_MAX_NAME
- *                      worth of buffer space.
- * @param   pszPlugIn   The plugin specifier to parse.
- */
-static int dbgcPlugInExtractName(char *pszDst, const char *pszPlugIn)
-{
-    /*
-     * Parse out the name stopping at the extension.
-     */
-    const char *pszName = RTPathFilename(pszPlugIn);
-    if (!pszName || !*pszName)
-        return VERR_INVALID_NAME;
-    if (!RTStrNICmp(pszName, DBGC_PLUG_IN_PREFIX, sizeof(DBGC_PLUG_IN_PREFIX) - 1))
-    {
-        pszName += sizeof(DBGC_PLUG_IN_PREFIX) - 1;
-        if (!*pszName)
-            return VERR_INVALID_NAME;
-    }
-
-    int         ch;
-    size_t      cchName = 0;
-    while (   (ch = pszName[cchName]) != '\0'
-           && ch != '.')
-    {
-        if (    !RT_C_IS_ALPHA(ch)
-            &&  (   !RT_C_IS_DIGIT(ch)
-                 || cchName == 0))
-            return VERR_INVALID_NAME;
-        cchName++;
-    }
-
-    if (cchName >= DBGCPLUGIN_MAX_NAME)
-        return VERR_OUT_OF_RANGE;
-
-    /*
-     * We're very picky about the extension if there is no path.
-     */
-    if (    ch == '.'
-        &&  !RTPathHavePath(pszPlugIn)
-        &&  RTStrICmp(&pszName[cchName], RTLdrGetSuff()))
-        return VERR_INVALID_NAME;
-
-    /*
-     * Copy it.
-     */
-    memcpy(pszDst, pszName, cchName);
-    pszDst[cchName] = '\0';
+ * @interface_method_impl{FNDBCCMD, The 'loadplugin' command.}
+ */
+static DECLCALLBACK(int) dbgcCmdLoadPlugIn(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
+{
+    PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
+
+    /*
+     * Loop thru the plugin names.
+     */
+    for (unsigned i = 0; i < cArgs; i++)
+    {
+        char            szPlugIn[128];
+        RTERRINFOSTATIC ErrInfo;
+        szPlugIn[0] = '\0';
+        int rc = DBGFR3PlugInLoad(pDbgc->pUVM, paArgs[i].u.pszString, szPlugIn, sizeof(szPlugIn), RTErrInfoInitStatic(&ErrInfo));
+        if (RT_SUCCESS(rc))
+            DBGCCmdHlpPrintf(pCmdHlp, "Loaded plug-in '%s' (%s)\n", szPlugIn, paArgs[i].u.pszString);
+        else if (rc == VERR_ALREADY_EXISTS)
+            DBGCCmdHlpPrintf(pCmdHlp, "A plug-in named '%s' is already loaded\n", szPlugIn);
+        else if (szPlugIn[0])
+            return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3PlugInLoad failed for '%s' ('%s'): %s",
+                                    szPlugIn, paArgs[i].u.pszString, ErrInfo.szMsg);
+        else
+            return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3PlugInLoad failed for '%s': %s",
+                                    paArgs[i].u.pszString, ErrInfo.szMsg);
+    }
+
     return VINF_SUCCESS;
 }
@@ -1805,369 +1778,26 @@
 
 /**
- * Locate a plug-in in list.
- *
- * @returns Pointer to the plug-in tracking structure.
- * @param   pDbgc               Pointer to the DBGC instance data.
- * @param   pszName             The name of the plug-in we're looking for.
- * @param   ppPrev              Where to optionally return the pointer to the
- *                              previous list member.
- */
-static PDBGCPLUGIN dbgcPlugInLocate(PDBGC pDbgc, const char *pszName, PDBGCPLUGIN *ppPrev)
-{
-    PDBGCPLUGIN pPrev = NULL;
-    PDBGCPLUGIN pCur  = pDbgc->pPlugInHead;
-    while (pCur)
-    {
-        if (!RTStrICmp(pCur->szName, pszName))
-        {
-            if (ppPrev)
-                *ppPrev = pPrev;
-            return pCur;
-        }
-
-        /* advance */
-        pPrev = pCur;
-        pCur  = pCur->pNext;
-    }
-    return NULL;
-}
-
-
-/**
- * Try load the specified plug-in module.
- *
- * @returns VINF_SUCCESS on success, path error or loader error on failure.
- *
- * @param   pPlugIn     The plugin tracing record.
- * @param   pszModule   Module name.
- */
-static int dbgcPlugInTryLoad(PDBGCPLUGIN pPlugIn, const char *pszModule)
-{
-    /*
-     * Load it and try resolve the entry point.
-     */
-    int rc = RTLdrLoad(pszModule, &pPlugIn->hLdrMod);
-    if (RT_SUCCESS(rc))
-    {
-        rc = RTLdrGetSymbol(pPlugIn->hLdrMod, DBGC_PLUG_IN_ENTRYPOINT, (void **)&pPlugIn->pfnEntry);
+ * @interface_method_impl{FNDBCCMD, The 'unload' command.}
+ */
+static DECLCALLBACK(int) dbgcCmdUnloadPlugIn(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
+{
+    PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
+
+    /*
+     * Loop thru the given plug-in names.
+     */
+    for (unsigned i = 0; i < cArgs; i++)
+    {
+        int rc = DBGFR3PlugInUnload(pDbgc->pUVM, paArgs[i].u.pszString);
         if (RT_SUCCESS(rc))
-            return VINF_SUCCESS;
-        LogRel(("DBGC: RTLdrGetSymbol('%s', '%s',) -> %Rrc\n", pszModule, DBGC_PLUG_IN_ENTRYPOINT, rc));
-
-        RTLdrClose(pPlugIn->hLdrMod);
-        pPlugIn->hLdrMod = NIL_RTLDRMOD;
-    }
-    return rc;
-}
-
-
-/**
- * RTPathTraverseList callback.
- *
- * @returns See FNRTPATHTRAVERSER.
- *
- * @param   pchPath     See FNRTPATHTRAVERSER.
- * @param   cchPath     See FNRTPATHTRAVERSER.
- * @param   pvUser1     The plug-in specifier.
- * @param   pvUser2     The plug-in tracking record.
- */
-static DECLCALLBACK(int) dbgcPlugInLoadCallback(const char *pchPath, size_t cchPath, void *pvUser1, void *pvUser2)
-{
-    PDBGCPLUGIN pPlugIn   = (PDBGCPLUGIN)pvUser2;
-    const char *pszPlugIn = (const char *)pvUser1;
-
-    /*
-     * Join the path and the specified plug-in module name, first with the
-     * prefix and then without it.
-     */
-    size_t      cchModule = cchPath + 1 + strlen(pszPlugIn) + sizeof(DBGC_PLUG_IN_PREFIX) + 8;
-    char       *pszModule = (char *)alloca(cchModule);
-    AssertReturn(pszModule, VERR_TRY_AGAIN);
-    memcpy(pszModule, pchPath, cchPath);
-    pszModule[cchPath] = '\0';
-
-    int rc = RTPathAppend(pszModule, cchModule, DBGC_PLUG_IN_PREFIX);
-    AssertRCReturn(rc, VERR_TRY_AGAIN);
-    strcat(pszModule, pszPlugIn);
-    rc = dbgcPlugInTryLoad(pPlugIn, pszModule);
-    if (RT_SUCCESS(rc))
-        return VINF_SUCCESS;
-
-    pszModule[cchPath] = '\0';
-    rc = RTPathAppend(pszModule, cchModule, pszPlugIn);
-    AssertRCReturn(rc, VERR_TRY_AGAIN);
-    rc = dbgcPlugInTryLoad(pPlugIn, pszModule);
-    if (RT_SUCCESS(rc))
-        return VINF_SUCCESS;
-
-    return VERR_TRY_AGAIN;
-}
-
-
-/**
- * Loads a plug-in.
- *
- * @returns VBox status code. If pCmd is specified, it's the return from
- *          DBGCCmdHlpFail.
- * @param   pDbgc               The DBGC instance data.
- * @param   pszName             The plug-in name.
- * @param   pszPlugIn           The plug-in module name.
- * @param   pCmd                The command pointer if invoked by the user, NULL
- *                              if invoked from elsewhere.
- */
-static int dbgcPlugInLoad(PDBGC pDbgc, const char *pszName, const char *pszPlugIn, PCDBGCCMD pCmd)
-{
-    PDBGCCMDHLP pCmdHlp = &pDbgc->CmdHlp;
-
-    /*
-     * Try load it.  If specified with a path, we're assuming the user
-     * wants to load a plug-in from some specific location.  Otherwise
-     * search for it.
-     */
-    PDBGCPLUGIN pPlugIn = (PDBGCPLUGIN)RTMemAllocZ(sizeof(*pPlugIn));
-    if (!pPlugIn)
-        return pCmd
-             ? DBGCCmdHlpFail(pCmdHlp, pCmd, "out of memory\n")
-             : VERR_NO_MEMORY;
-    strcpy(pPlugIn->szName, pszName);
-
-    int rc;
-    if (RTPathHavePath(pszPlugIn))
-        rc = dbgcPlugInTryLoad(pPlugIn, pszPlugIn);
-    else
-    {
-        /* 1. The private architecture directory. */
-        char szPath[4*_1K];
-        rc = RTPathAppPrivateArch(szPath, sizeof(szPath));
-        if (RT_SUCCESS(rc))
-            rc = RTPathTraverseList(szPath, '\0', dbgcPlugInLoadCallback, (void *)pszPlugIn, pPlugIn);
-        if (RT_FAILURE(rc))
-        {
-            /* 2. The DBGC PLUGIN_PATH variable. */
-            DBGCVAR PathVar;
-            int rc2 = DBGCCmdHlpEval(pCmdHlp, &PathVar, "$PLUGIN_PATH");
-            if (    RT_SUCCESS(rc2)
-                &&  PathVar.enmType == DBGCVAR_TYPE_STRING)
-                rc = RTPathTraverseList(PathVar.u.pszString, ';', dbgcPlugInLoadCallback, (void *)pszPlugIn, pPlugIn);
-            if (RT_FAILURE_NP(rc))
-            {
-                /* 3. The DBGC_PLUGIN_PATH environment variable. */
-                rc2 = RTEnvGetEx(RTENV_DEFAULT, "DBGC_PLUGIN_PATH", szPath, sizeof(szPath), NULL);
-                if (RT_SUCCESS(rc2))
-                    rc = RTPathTraverseList(szPath, ';', dbgcPlugInLoadCallback, (void *)pszPlugIn, pPlugIn);
-            }
-        }
-    }
-    if (RT_FAILURE(rc))
-    {
-        RTMemFree(pPlugIn);
-        return pCmd
-            ? DBGCCmdHlpFail(pCmdHlp, pCmd, "could not find/load '%s'\n", pszPlugIn)
-            : rc;
-    }
-
-    /*
-     * Try initialize it.
-     */
-    rc = pPlugIn->pfnEntry(DBGCPLUGINOP_INIT, pDbgc->pUVM, VBOX_VERSION);
-    if (RT_FAILURE(rc))
-    {
-        RTLdrClose(pPlugIn->hLdrMod);
-        RTMemFree(pPlugIn);
-        return pCmd
-            ? DBGCCmdHlpFail(pCmdHlp, pCmd, "initialization of plug-in '%s' failed with rc=%Rrc\n", pszPlugIn, rc)
-            : rc;
-    }
-
-    /*
-     * Link it and we're good.
-     */
-    pPlugIn->pNext = pDbgc->pPlugInHead;
-    pDbgc->pPlugInHead = pPlugIn;
-    DBGCCmdHlpPrintf(pCmdHlp, "Loaded plug-in '%s'.\n", pPlugIn->szName);
+            DBGCCmdHlpPrintf(pCmdHlp, "Unloaded plug-in '%s'\n", paArgs[i].u.pszString);
+        else if (rc == VERR_NOT_FOUND)
+            return DBGCCmdHlpFail(pCmdHlp, pCmd, "'%s' was not found\n", paArgs[i].u.pszString);
+        else
+            return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3PlugInUnload failed for '%s'", paArgs[i].u.pszString);
+    }
+
     return VINF_SUCCESS;
 }
-
-
-
-
-/**
- * Automatically load plug-ins from the architecture private directory of
- * VirtualBox.
- *
- * This is called during console init.
- *
- * @param   pDbgc       The DBGC instance data.
- */
-void dbgcPlugInAutoLoad(PDBGC pDbgc)
-{
-    /*
-     * Open the architecture specific directory with a filter on our prefix
-     * and names including a dot.
-     */
-    const char *pszSuff = RTLdrGetSuff();
-    size_t      cchSuff = strlen(pszSuff);
-
-    char szPath[RTPATH_MAX];
-    int rc = RTPathAppPrivateArch(szPath, sizeof(szPath) - cchSuff);
-    AssertRCReturnVoid(rc);
-    size_t offDir = strlen(szPath);
-
-    rc = RTPathAppend(szPath, sizeof(szPath) - cchSuff, DBGC_PLUG_IN_PREFIX "*");
-    AssertRCReturnVoid(rc);
-    strcat(szPath, pszSuff);
-
-    PRTDIR pDir;
-    rc = RTDirOpenFiltered(&pDir, szPath, RTDIRFILTER_WINNT, 0);
-    if (RT_SUCCESS(rc))
-    {
-        /*
-         * Now read it and try load each of the plug-in modules.
-         */
-        RTDIRENTRY DirEntry;
-        while (RT_SUCCESS(RTDirRead(pDir, &DirEntry, NULL)))
-        {
-            szPath[offDir] = '\0';
-            rc = RTPathAppend(szPath, sizeof(szPath), DirEntry.szName);
-            if (RT_SUCCESS(rc))
-            {
-                char szName[DBGCPLUGIN_MAX_NAME];
-                rc = dbgcPlugInExtractName(szName, DirEntry.szName);
-                if (RT_SUCCESS(rc))
-                    dbgcPlugInLoad(pDbgc, szName, szPath, NULL /*pCmd*/);
-            }
-        }
-
-        RTDirClose(pDir);
-    }
-}
-
-
-/**
- * @interface_method_impl{FNDBCCMD, The 'loadplugin' command.}
- */
-static DECLCALLBACK(int) dbgcCmdLoadPlugIn(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
-{
-    PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
-
-    /*
-     * Loop thru the plugin names.
-     */
-    for (unsigned i = 0; i < cArgs; i++)
-    {
-        const char *pszPlugIn = paArgs[i].u.pszString;
-
-        /* Extract the plug-in name. */
-        char szName[DBGCPLUGIN_MAX_NAME];
-        int rc = dbgcPlugInExtractName(szName, pszPlugIn);
-        if (RT_FAILURE(rc))
-            return DBGCCmdHlpFail(pCmdHlp, pCmd, "Malformed plug-in name: '%s'\n", pszPlugIn);
-
-        /* Loaded? */
-        PDBGCPLUGIN pPlugIn = dbgcPlugInLocate(pDbgc, szName, NULL);
-        if (pPlugIn)
-            return DBGCCmdHlpFail(pCmdHlp, pCmd, "'%s' is already loaded\n", szName);
-
-        /* Load it. */
-        rc = dbgcPlugInLoad(pDbgc, szName, pszPlugIn, pCmd);
-        if (RT_FAILURE(rc))
-            return rc;
-    }
-
-    return VINF_SUCCESS;
-}
-
-
-/**
- * Unload all plug-ins.
- *
- * @param   pDbgc       The DBGC instance data.
- */
-void dbgcPlugInUnloadAll(PDBGC pDbgc)
-{
-    while (pDbgc->pPlugInHead)
-    {
-        PDBGCPLUGIN pPlugIn = pDbgc->pPlugInHead;
-        pDbgc->pPlugInHead = pPlugIn->pNext;
-
-        if (    pDbgc->pVM /* prevents trouble during destruction. */
-            &&  pDbgc->pVM->enmVMState < VMSTATE_DESTROYING)
-        {
-            pPlugIn->pfnEntry(DBGCPLUGINOP_TERM, pDbgc->pUVM, 0);
-            RTLdrClose(pPlugIn->hLdrMod);
-        }
-        pPlugIn->hLdrMod = NIL_RTLDRMOD;
-
-        RTMemFree(pPlugIn);
-    }
-}
-
-
-/**
- * @interface_method_impl{FNDBCCMD, The 'unload' command.}
- */
-static DECLCALLBACK(int) dbgcCmdUnloadPlugIn(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
-{
-    PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
-
-    /*
-     * Loop thru the plugin names.
-     */
-    for (unsigned i = 0; i < cArgs; i++)
-    {
-        const char *pszPlugIn = paArgs[i].u.pszString;
-
-        /* Extract the plug-in name. */
-        char szName[DBGCPLUGIN_MAX_NAME];
-        int rc = dbgcPlugInExtractName(szName, pszPlugIn);
-        if (RT_FAILURE(rc))
-            return DBGCCmdHlpFail(pCmdHlp, pCmd, "Malformed plug-in name: '%s'\n", pszPlugIn);
-
-        /* Loaded? */
-        PDBGCPLUGIN pPrevPlugIn;
-        PDBGCPLUGIN pPlugIn = dbgcPlugInLocate(pDbgc, szName, &pPrevPlugIn);
-        if (!pPlugIn)
-            return DBGCCmdHlpFail(pCmdHlp, pCmd, "'%s' is not\n", szName);
-
-        /*
-         * Terminate and unload it.
-         */
-        pPlugIn->pfnEntry(DBGCPLUGINOP_TERM, pDbgc->pUVM, 0);
-        RTLdrClose(pPlugIn->hLdrMod);
-        pPlugIn->hLdrMod = NIL_RTLDRMOD;
-
-        if (pPrevPlugIn)
-            pPrevPlugIn->pNext = pPlugIn->pNext;
-        else
-            pDbgc->pPlugInHead = pPlugIn->pNext;
-        RTMemFree(pPlugIn->pNext);
-        DBGCCmdHlpPrintf(pCmdHlp, "Unloaded plug-in '%s'\n", szName);
-    }
-
-    return VINF_SUCCESS;
-}
-
-
-/**
- * @interface_method_impl{FNDBCCMD, The 'showplugins' command.}
- */
-static DECLCALLBACK(int) dbgcCmdShowPlugIns(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
-{
-    PDBGC       pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
-    PDBGCPLUGIN pPlugIn = pDbgc->pPlugInHead;
-    if (!pPlugIn)
-        return DBGCCmdHlpPrintf(pCmdHlp, "No plug-ins loaded\n");
-
-    DBGCCmdHlpPrintf(pCmdHlp, "Plug-ins: %s", pPlugIn->szName);
-    for (;;)
-    {
-        pPlugIn = pPlugIn->pNext;
-        if (!pPlugIn)
-            break;
-        DBGCCmdHlpPrintf(pCmdHlp, ", %s", pPlugIn->szName);
-    }
-    return DBGCCmdHlpPrintf(pCmdHlp, "\n");
-}
-
 
 
Index: /trunk/src/VBox/Debugger/DBGCInternal.h
===================================================================
--- /trunk/src/VBox/Debugger/DBGCInternal.h	(revision 55880)
+++ /trunk/src/VBox/Debugger/DBGCInternal.h	(revision 55881)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2013 Oracle Corporation
+ * Copyright (C) 2006-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -64,25 +64,4 @@
 /** Pointer to named variable. */
 typedef DBGCNAMEDVAR *PDBGCNAMEDVAR;
-
-
-/** The max length of a plug-in name, zero terminator included. */
-#define DBGCPLUGIN_MAX_NAME     32
-
-/**
- * Plug-in tracking record.
- */
-typedef struct DBGCPLUGIN
-{
-    /** Pointer to the next plug-in. */
-    struct DBGCPLUGIN  *pNext;
-    /** The loader handle.  */
-    RTLDRMOD            hLdrMod;
-    /** The plug-in entry point. */
-    PFNDBGCPLUGIN       pfnEntry;
-    /** The plug-in name (variable length).  */
-    char                szName[DBGCPLUGIN_MAX_NAME];
-} DBGCPLUGIN;
-/** Pointer to plug-in tracking record. */
-typedef DBGCPLUGIN *PDBGCPLUGIN;
 
 
@@ -158,7 +137,4 @@
      * and unset using command with those names. */
     PDBGCNAMEDVAR      *papVars;
-
-    /** The list of plug-in. (singly linked) */
-    PDBGCPLUGIN         pPlugInHead;
 
     /** The list of breakpoints. (singly linked) */
@@ -398,7 +374,4 @@
 void    dbgcInitCmdHlp(PDBGC pDbgc);
 
-void    dbgcPlugInAutoLoad(PDBGC pDbgc);
-void    dbgcPlugInUnloadAll(PDBGC pDbgc);
-
 /* For tstDBGCParser: */
 int     dbgcCreate(PDBGC *ppDbgc, PDBGCBACK pBack, unsigned fFlags);
Index: /trunk/src/VBox/Debugger/DBGConsole.cpp
===================================================================
--- /trunk/src/VBox/Debugger/DBGConsole.cpp	(revision 55880)
+++ /trunk/src/VBox/Debugger/DBGConsole.cpp	(revision 55881)
@@ -968,7 +968,4 @@
     }
 
-    /* Unload all plug-ins. */
-    dbgcPlugInUnloadAll(pDbgc);
-
     /* Detach from the VM. */
     if (pDbgc->pUVM)
@@ -1050,5 +1047,5 @@
     {
         if (pVM)
-            dbgcPlugInAutoLoad(pDbgc);
+            DBGFR3PlugInLoadAll(pDbgc->pUVM);
         rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
         if (RT_SUCCESS(rc))
Index: /trunk/src/VBox/Debugger/DBGPlugInDiggers.cpp
===================================================================
--- /trunk/src/VBox/Debugger/DBGPlugInDiggers.cpp	(revision 55880)
+++ /trunk/src/VBox/Debugger/DBGPlugInDiggers.cpp	(revision 55881)
@@ -1,9 +1,9 @@
 /* $Id$ */
 /** @file
- * DBGPlugInDiggers - Debugger and Guest OS Digger Plug-in.
+ * DbfPlugInDiggers - Debugger and Guest OS Digger Plug-in.
  */
 
 /*
- * Copyright (C) 2006-2013 Oracle Corporation
+ * Copyright (C) 2006-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -28,5 +28,5 @@
 
 
-DECLEXPORT(int) DBGCPlugInEntry(DBGCPLUGINOP enmOperation, PUVM pUVM, uintptr_t uArg)
+DECLEXPORT(int) DbgPlugInEntry(DBGFPLUGINOP enmOperation, PUVM pUVM, uintptr_t uArg)
 {
     static PCDBGFOSREG s_aPlugIns[] =
@@ -42,5 +42,5 @@
     switch (enmOperation)
     {
-        case DBGCPLUGINOP_INIT:
+        case DBGFPLUGINOP_INIT:
         {
             if (uArg != VBOX_VERSION)
@@ -61,5 +61,5 @@
         }
 
-        case DBGCPLUGINOP_TERM:
+        case DBGFPLUGINOP_TERM:
         {
             for (unsigned i = 0; i < RT_ELEMENTS(s_aPlugIns); i++)
Index: /trunk/src/VBox/Debugger/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Debugger/Makefile.kmk	(revision 55880)
+++ /trunk/src/VBox/Debugger/Makefile.kmk	(revision 55881)
@@ -54,7 +54,7 @@
 # The diggers plug-in.
 #
-DLLS += DBGCPlugInDiggers
-DBGCPlugInDiggers_TEMPLATE = VBOXR3
-DBGCPlugInDiggers_SOURCES = \
+DLLS += DbgPlugInDiggers
+DbgPlugInDiggers_TEMPLATE = VBOXR3
+DbgPlugInDiggers_SOURCES = \
 	DBGPlugInDiggers.cpp \
 	DBGPlugInDarwin.cpp \
@@ -64,9 +64,9 @@
 	DBGPlugInOS2.cpp \
 	DBGPlugInCommonELF.cpp
-DBGCPlugInDiggers_LIBS = \
+DbgPlugInDiggers_LIBS = \
 	$(if-expr "$(LIB_VMM)" == "$(VBOX_LIB_VMM_LAZY)",$(LIB_REM),) \
 	$(VBOX_LIB_VMM_LAZY) \
 	$(LIB_RUNTIME)
-$(call VBOX_SET_VER_INFO_DLL,DBGCPlugInDiggers,VirtualBox Debugger Guest OS Digger Plug-in)
+$(call VBOX_SET_VER_INFO_DLL,DbgPlugInDiggers,VirtualBox Debugger Guest OS Digger Plug-in)
 
 
Index: /trunk/src/VBox/Debugger/testcase/tstDBGCStubs.cpp
===================================================================
--- /trunk/src/VBox/Debugger/testcase/tstDBGCStubs.cpp	(revision 55880)
+++ /trunk/src/VBox/Debugger/testcase/tstDBGCStubs.cpp	(revision 55881)
@@ -322,4 +322,16 @@
 }
 
+VMMR3DECL(int)  DBGFR3PlugInLoad(PUVM pUVM, const char *pszPlugIn, char *pszActual, size_t cbActual, PRTERRINFO pErrInfo)
+{
+    return VERR_INTERNAL_ERROR;
+}
+VMMR3DECL(int)  DBGFR3PlugInUnload(PUVM pUVM, const char *pszName)
+{
+    return VERR_INTERNAL_ERROR;
+}
+VMMR3DECL(void) DBGFR3PlugInLoadAll(PUVM pUVM)
+{
+}
+
 
 //////////////////////////////////////////////////////////////////////////
Index: /trunk/src/VBox/VMM/Makefile.kmk
===================================================================
--- /trunk/src/VBox/VMM/Makefile.kmk	(revision 55880)
+++ /trunk/src/VBox/VMM/Makefile.kmk	(revision 55881)
@@ -144,4 +144,5 @@
 	VMMR3/DBGFMem.cpp \
 	VMMR3/DBGFOS.cpp \
+	VMMR3/DBGFR3PlugIn.cpp \
 	VMMR3/DBGFReg.cpp \
 	VMMR3/DBGFStack.cpp \
Index: /trunk/src/VBox/VMM/VMMR3/DBGF.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/DBGF.cpp	(revision 55880)
+++ /trunk/src/VBox/VMM/VMMR3/DBGF.cpp	(revision 55881)
@@ -141,15 +141,41 @@
     AssertCompile(sizeof(pUVM->aCpus[0].dbgf.s) <= sizeof(pUVM->aCpus[0].dbgf.padding));
 
-    int rc = dbgfR3InfoInit(pUVM);
+    /*
+     * The usual sideways mountain climbing style of init:
+     */
+    int rc = dbgfR3InfoInit(pUVM); /* (First, initalizes the shared critical section.) */
     if (RT_SUCCESS(rc))
+    {
         rc = dbgfR3TraceInit(pVM);
-    if (RT_SUCCESS(rc))
-        rc = dbgfR3RegInit(pUVM);
-    if (RT_SUCCESS(rc))
-        rc = dbgfR3AsInit(pUVM);
-    if (RT_SUCCESS(rc))
-        rc = dbgfR3BpInit(pVM);
-    if (RT_SUCCESS(rc))
-        rc = dbgfR3OSInit(pUVM);
+        if (RT_SUCCESS(rc))
+        {
+            rc = dbgfR3RegInit(pUVM);
+            if (RT_SUCCESS(rc))
+            {
+                rc = dbgfR3AsInit(pUVM);
+                if (RT_SUCCESS(rc))
+                {
+                    rc = dbgfR3BpInit(pVM);
+                    if (RT_SUCCESS(rc))
+                    {
+                        rc = dbgfR3OSInit(pUVM);
+                        if (RT_SUCCESS(rc))
+                        {
+                            rc = dbgfR3PlugInInit(pUVM);
+                            if (RT_SUCCESS(rc))
+                            {
+                                return VINF_SUCCESS;
+                            }
+                            dbgfR3OSTerm(pUVM);
+                        }
+                    }
+                    dbgfR3AsTerm(pUVM);
+                }
+                dbgfR3RegTerm(pUVM);
+            }
+            dbgfR3TraceTerm(pVM);
+        }
+        dbgfR3InfoTerm(pUVM);
+    }
     return rc;
 }
@@ -166,4 +192,5 @@
     PUVM pUVM = pVM->pUVM;
 
+    dbgfR3PlugInTerm(pUVM);
     dbgfR3OSTerm(pUVM);
     dbgfR3AsTerm(pUVM);
Index: /trunk/src/VBox/VMM/VMMR3/DBGFInfo.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/DBGFInfo.cpp	(revision 55880)
+++ /trunk/src/VBox/VMM/VMMR3/DBGFInfo.cpp	(revision 55881)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2013 Oracle Corporation
+ * Copyright (C) 2006-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -79,4 +79,7 @@
  * Initialize the info handlers.
  *
+ * This is called first during the DBGF init process and thus does the shared
+ * critsect init.
+ *
  * @returns VBox status code.
  * @param   pUVM        The user mode VM handle.
@@ -87,5 +90,5 @@
      * Make sure we already didn't initialized in the lazy manner.
      */
-    if (RTCritSectIsInitialized(&pUVM->dbgf.s.InfoCritSect))
+    if (RTCritSectRwIsInitialized(&pUVM->dbgf.s.CritSect))
         return VINF_SUCCESS;
 
@@ -93,5 +96,5 @@
      * Initialize the crit sect.
      */
-    int rc = RTCritSectInit(&pUVM->dbgf.s.InfoCritSect);
+    int rc = RTCritSectRwInit(&pUVM->dbgf.s.CritSect);
     AssertRCReturn(rc, rc);
 
@@ -117,5 +120,5 @@
      * Delete the crit sect.
      */
-    int rc = RTCritSectDelete(&pUVM->dbgf.s.InfoCritSect);
+    int rc = RTCritSectRwDelete(&pUVM->dbgf.s.CritSect);
     AssertRC(rc);
     return rc;
@@ -209,4 +212,5 @@
 /**
  * Handle registration worker.
+ *
  * This allocates the structure, initializes the common fields and inserts into the list.
  * Upon successful return the we're inside the crit sect and the caller must leave it.
@@ -245,5 +249,5 @@
         /* lazy init */
         rc = VINF_SUCCESS;
-        if (!RTCritSectIsInitialized(&pUVM->dbgf.s.InfoCritSect))
+        if (!RTCritSectRwIsInitialized(&pUVM->dbgf.s.CritSect))
             rc = dbgfR3InfoInit(pUVM);
         if (RT_SUCCESS(rc))
@@ -252,5 +256,5 @@
              * Insert in alphabetical order.
              */
-            rc = RTCritSectEnter(&pUVM->dbgf.s.InfoCritSect);
+            rc = RTCritSectRwEnterExcl(&pUVM->dbgf.s.CritSect);
             AssertRC(rc);
             PDBGFINFO pPrev = NULL;
@@ -308,5 +312,5 @@
         pInfo->u.Dev.pfnHandler = pfnHandler;
         pInfo->u.Dev.pDevIns = pDevIns;
-        RTCritSectLeave(&pVM->pUVM->dbgf.s.InfoCritSect);
+        RTCritSectRwLeaveExcl(&pVM->pUVM->dbgf.s.CritSect);
     }
 
@@ -346,5 +350,5 @@
         pInfo->u.Drv.pfnHandler = pfnHandler;
         pInfo->u.Drv.pDrvIns = pDrvIns;
-        RTCritSectLeave(&pVM->pUVM->dbgf.s.InfoCritSect);
+        RTCritSectRwLeaveExcl(&pVM->pUVM->dbgf.s.CritSect);
     }
 
@@ -398,5 +402,5 @@
         pInfo->enmType = DBGFINFOTYPE_INT;
         pInfo->u.Int.pfnHandler = pfnHandler;
-        RTCritSectLeave(&pVM->pUVM->dbgf.s.InfoCritSect);
+        RTCritSectRwLeaveExcl(&pVM->pUVM->dbgf.s.CritSect);
     }
 
@@ -437,5 +441,5 @@
         pInfo->u.Ext.pfnHandler = pfnHandler;
         pInfo->u.Ext.pvUser = pvUser;
-        RTCritSectLeave(&pUVM->dbgf.s.InfoCritSect);
+        RTCritSectRwLeaveExcl(&pUVM->dbgf.s.CritSect);
     }
 
@@ -467,5 +471,5 @@
      * Enumerate the info handlers and free the requested entries.
      */
-    int rc = RTCritSectEnter(&pUVM->dbgf.s.InfoCritSect); AssertRC(rc);
+    int rc = RTCritSectRwEnterExcl(&pUVM->dbgf.s.CritSect); AssertRC(rc);
     rc = VERR_FILE_NOT_FOUND;
     PDBGFINFO pPrev = NULL;
@@ -509,5 +513,5 @@
         rc = VINF_SUCCESS;
     }
-    int rc2 = RTCritSectLeave(&pUVM->dbgf.s.InfoCritSect);
+    int rc2 = RTCritSectRwLeaveExcl(&pUVM->dbgf.s.CritSect);
     AssertRC(rc2);
     AssertRC(rc);
@@ -539,5 +543,5 @@
      * Enumerate the info handlers and free the requested entries.
      */
-    int rc = RTCritSectEnter(&pUVM->dbgf.s.InfoCritSect); AssertRC(rc);
+    int rc = RTCritSectRwEnterExcl(&pUVM->dbgf.s.CritSect); AssertRC(rc);
     rc = VERR_FILE_NOT_FOUND;
     PDBGFINFO pPrev = NULL;
@@ -581,5 +585,5 @@
         rc = VINF_SUCCESS;
     }
-    int rc2 = RTCritSectLeave(&pUVM->dbgf.s.InfoCritSect);
+    int rc2 = RTCritSectRwLeaveExcl(&pUVM->dbgf.s.CritSect);
     AssertRC(rc2);
     AssertRC(rc);
@@ -608,5 +612,5 @@
      */
     size_t cchName = strlen(pszName);
-    int rc = RTCritSectEnter(&pUVM->dbgf.s.InfoCritSect);
+    int rc = RTCritSectRwEnterExcl(&pUVM->dbgf.s.CritSect);
     AssertRC(rc);
     rc = VERR_FILE_NOT_FOUND;
@@ -626,5 +630,5 @@
             break;
         }
-    int rc2 = RTCritSectLeave(&pUVM->dbgf.s.InfoCritSect);
+    int rc2 = RTCritSectRwLeaveExcl(&pUVM->dbgf.s.CritSect);
     AssertRC(rc2);
     AssertRC(rc);
@@ -694,5 +698,5 @@
      */
     size_t cchName = strlen(pszName);
-    int rc = RTCritSectEnter(&pUVM->dbgf.s.InfoCritSect);
+    int rc = RTCritSectRwEnterShared(&pUVM->dbgf.s.CritSect);
     AssertRC(rc);
     PDBGFINFO pInfo = pUVM->dbgf.s.pInfoFirst;
@@ -705,25 +709,20 @@
         /*
          * Found it.
-         *      Make a copy of it on the stack so we can leave the crit sect.
-         *      Switch on the type and invoke the handler.
          */
-        DBGFINFO Info = *pInfo;
-        rc = RTCritSectLeave(&pUVM->dbgf.s.InfoCritSect);
-        AssertRC(rc);
         rc = VINF_SUCCESS;
-        switch (Info.enmType)
+        switch (pInfo->enmType)
         {
             case DBGFINFOTYPE_DEV:
-                if (Info.fFlags & DBGFINFO_FLAGS_RUN_ON_EMT)
-                    rc = VMR3ReqCallVoidWaitU(pUVM, idCpu, (PFNRT)Info.u.Dev.pfnHandler, 3, Info.u.Dev.pDevIns, pHlp, pszArgs);
+                if (pInfo->fFlags & DBGFINFO_FLAGS_RUN_ON_EMT)
+                    rc = VMR3ReqCallVoidWaitU(pUVM, idCpu, (PFNRT)pInfo->u.Dev.pfnHandler, 3, pInfo->u.Dev.pDevIns, pHlp, pszArgs);
                 else
-                    Info.u.Dev.pfnHandler(Info.u.Dev.pDevIns, pHlp, pszArgs);
+                    pInfo->u.Dev.pfnHandler(pInfo->u.Dev.pDevIns, pHlp, pszArgs);
                 break;
 
             case DBGFINFOTYPE_DRV:
-                if (Info.fFlags & DBGFINFO_FLAGS_RUN_ON_EMT)
-                    rc = VMR3ReqCallVoidWaitU(pUVM, idCpu, (PFNRT)Info.u.Drv.pfnHandler, 3, Info.u.Drv.pDrvIns, pHlp, pszArgs);
+                if (pInfo->fFlags & DBGFINFO_FLAGS_RUN_ON_EMT)
+                    rc = VMR3ReqCallVoidWaitU(pUVM, idCpu, (PFNRT)pInfo->u.Drv.pfnHandler, 3, pInfo->u.Drv.pDrvIns, pHlp, pszArgs);
                 else
-                    Info.u.Drv.pfnHandler(Info.u.Drv.pDrvIns, pHlp, pszArgs);
+                    pInfo->u.Drv.pfnHandler(pInfo->u.Drv.pDrvIns, pHlp, pszArgs);
                 break;
 
@@ -731,8 +730,8 @@
                 if (RT_VALID_PTR(pUVM->pVM))
                 {
-                    if (Info.fFlags & DBGFINFO_FLAGS_RUN_ON_EMT)
-                        rc = VMR3ReqCallVoidWaitU(pUVM, idCpu, (PFNRT)Info.u.Int.pfnHandler, 3, pUVM->pVM, pHlp, pszArgs);
+                    if (pInfo->fFlags & DBGFINFO_FLAGS_RUN_ON_EMT)
+                        rc = VMR3ReqCallVoidWaitU(pUVM, idCpu, (PFNRT)pInfo->u.Int.pfnHandler, 3, pUVM->pVM, pHlp, pszArgs);
                     else
-                        Info.u.Int.pfnHandler(pUVM->pVM, pHlp, pszArgs);
+                        pInfo->u.Int.pfnHandler(pUVM->pVM, pHlp, pszArgs);
                 }
                 else
@@ -741,17 +740,19 @@
 
             case DBGFINFOTYPE_EXT:
-                if (Info.fFlags & DBGFINFO_FLAGS_RUN_ON_EMT)
-                    rc = VMR3ReqCallVoidWaitU(pUVM, idCpu, (PFNRT)Info.u.Ext.pfnHandler, 3, Info.u.Ext.pvUser, pHlp, pszArgs);
+                if (pInfo->fFlags & DBGFINFO_FLAGS_RUN_ON_EMT)
+                    rc = VMR3ReqCallVoidWaitU(pUVM, idCpu, (PFNRT)pInfo->u.Ext.pfnHandler, 3, pInfo->u.Ext.pvUser, pHlp, pszArgs);
                 else
-                    Info.u.Ext.pfnHandler(Info.u.Ext.pvUser, pHlp, pszArgs);
+                    pInfo->u.Ext.pfnHandler(pInfo->u.Ext.pvUser, pHlp, pszArgs);
                 break;
 
             default:
-                AssertMsgFailedReturn(("Invalid info type enmType=%d\n", Info.enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE);
+                AssertMsgFailedReturn(("Invalid info type enmType=%d\n", pInfo->enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE);
         }
+        int rc2 = RTCritSectRwLeaveShared(&pUVM->dbgf.s.CritSect);
+        AssertRC(rc2);
     }
     else
     {
-        rc = RTCritSectLeave(&pUVM->dbgf.s.InfoCritSect);
+        rc = RTCritSectRwLeaveShared(&pUVM->dbgf.s.CritSect);
         AssertRC(rc);
         rc = VERR_FILE_NOT_FOUND;
@@ -867,5 +868,5 @@
      * Note! We won't leave the critical section here...
      */
-    int rc = RTCritSectEnter(&pUVM->dbgf.s.InfoCritSect);
+    int rc = RTCritSectRwEnterShared(&pUVM->dbgf.s.CritSect);
     AssertRC(rc);
     rc = VWRN_NOT_FOUND;
@@ -915,5 +916,5 @@
         }
     }
-    int rc2 = RTCritSectLeave(&pUVM->dbgf.s.InfoCritSect);
+    int rc2 = RTCritSectRwLeaveShared(&pUVM->dbgf.s.CritSect);
     AssertRC(rc2);
 
@@ -947,5 +948,5 @@
      * Enter and enumerate.
      */
-    int rc = RTCritSectEnter(&pUVM->dbgf.s.InfoCritSect);
+    int rc = RTCritSectRwEnterShared(&pUVM->dbgf.s.CritSect);
     AssertRC(rc);
 
@@ -957,5 +958,5 @@
      * Leave and exit.
      */
-    int rc2 = RTCritSectLeave(&pUVM->dbgf.s.InfoCritSect);
+    int rc2 = RTCritSectRwLeaveShared(&pUVM->dbgf.s.CritSect);
     AssertRC(rc2);
 
@@ -980,5 +981,5 @@
      */
     PUVM pUVM = pVM->pUVM;
-    int rc = RTCritSectEnter(&pUVM->dbgf.s.InfoCritSect);
+    int rc = RTCritSectRwEnterShared(&pUVM->dbgf.s.CritSect);
     AssertRC(rc);
 
@@ -1007,5 +1008,5 @@
      * Leave and exit.
      */
-    rc = RTCritSectLeave(&pUVM->dbgf.s.InfoCritSect);
+    rc = RTCritSectRwLeaveShared(&pUVM->dbgf.s.CritSect);
     AssertRC(rc);
 }
Index: /trunk/src/VBox/VMM/VMMR3/DBGFOS.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/DBGFOS.cpp	(revision 55880)
+++ /trunk/src/VBox/VMM/VMMR3/DBGFOS.cpp	(revision 55881)
@@ -38,12 +38,12 @@
 
 #define DBGF_OS_READ_LOCK(pUVM) \
-    do { int rcLock = RTCritSectRwEnterShared(&pUVM->dbgf.s.OSCritSect); AssertRC(rcLock); } while (0)
+    do { int rcLock = RTCritSectRwEnterShared(&pUVM->dbgf.s.CritSect); AssertRC(rcLock); } while (0)
 #define DBGF_OS_READ_UNLOCK(pUVM) \
-    do { int rcLock = RTCritSectRwLeaveShared(&pUVM->dbgf.s.OSCritSect); AssertRC(rcLock); } while (0)
+    do { int rcLock = RTCritSectRwLeaveShared(&pUVM->dbgf.s.CritSect); AssertRC(rcLock); } while (0)
 
 #define DBGF_OS_WRITE_LOCK(pUVM) \
-    do { int rcLock = RTCritSectRwEnterExcl(&pUVM->dbgf.s.OSCritSect); AssertRC(rcLock); } while (0)
+    do { int rcLock = RTCritSectRwEnterExcl(&pUVM->dbgf.s.CritSect); AssertRC(rcLock); } while (0)
 #define DBGF_OS_WRITE_UNLOCK(pUVM) \
-    do { int rcLock = RTCritSectRwLeaveExcl(&pUVM->dbgf.s.OSCritSect); AssertRC(rcLock); } while (0)
+    do { int rcLock = RTCritSectRwLeaveExcl(&pUVM->dbgf.s.CritSect); AssertRC(rcLock); } while (0)
 
 
@@ -93,5 +93,5 @@
 int dbgfR3OSInit(PUVM pUVM)
 {
-    return RTCritSectRwInit(&pUVM->dbgf.s.OSCritSect);
+    return VINF_SUCCESS;
 }
 
@@ -104,5 +104,5 @@
 void dbgfR3OSTerm(PUVM pUVM)
 {
-    RTCritSectRwDelete(&pUVM->dbgf.s.OSCritSect);
+    DBGF_OS_WRITE_LOCK(pUVM);
 
     /*
@@ -135,4 +135,6 @@
         MMR3HeapFree(pOS);
     }
+
+    DBGF_OS_WRITE_UNLOCK(pUVM);
 }
 
Index: /trunk/src/VBox/VMM/VMMR3/DBGFR3PlugIn.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/DBGFR3PlugIn.cpp	(revision 55881)
+++ /trunk/src/VBox/VMM/VMMR3/DBGFR3PlugIn.cpp	(revision 55881)
@@ -0,0 +1,613 @@
+/* $Id$ */
+/** @file
+ * DBGF - Debugger Facility, Plug-In Support.
+ */
+
+/*
+ * Copyright (C) 2008-2015 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.
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#define LOG_GROUP LOG_GROUP_DBGF
+#include <VBox/vmm/dbgf.h>
+#include <VBox/vmm/mm.h>
+#include "DBGFInternal.h"
+#include <VBox/vmm/uvm.h>
+#include <VBox/vmm/vm.h>
+#include <VBox/err.h>
+#include <VBox/log.h>
+#include <VBox/version.h>
+
+#include <iprt/assert.h>
+#include <iprt/ctype.h>
+#include <iprt/env.h>
+#include <iprt/dir.h>
+#include <iprt/ldr.h>
+#include <iprt/param.h>
+#include <iprt/path.h>
+
+
+/*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+
+#define DBGF_PLUG_IN_READ_LOCK(pUVM) \
+    do { int rcLock = RTCritSectRwEnterShared(&pUVM->dbgf.s.CritSect); AssertRC(rcLock); } while (0)
+#define DBGF_PLUG_IN_READ_UNLOCK(pUVM) \
+    do { int rcLock = RTCritSectRwLeaveShared(&pUVM->dbgf.s.CritSect); AssertRC(rcLock); } while (0)
+
+#define DBGF_PLUG_IN_WRITE_LOCK(pUVM) \
+    do { int rcLock = RTCritSectRwEnterExcl(&pUVM->dbgf.s.CritSect); AssertRC(rcLock); } while (0)
+#define DBGF_PLUG_IN_WRITE_UNLOCK(pUVM) \
+    do { int rcLock = RTCritSectRwLeaveExcl(&pUVM->dbgf.s.CritSect); AssertRC(rcLock); } while (0)
+
+/** Max allowed length of a plug-in name (excludes the path and suffix). */
+#define DBGFPLUGIN_MAX_NAME     64
+
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+/**
+ * Plug-in tracking record.
+ */
+typedef struct DBGFPLUGIN
+{
+    /** Pointer to the next plug-in. */
+    struct DBGFPLUGIN  *pNext;
+    /** The loader handle.  */
+    RTLDRMOD            hLdrMod;
+    /** The plug-in entry point. */
+    PFNDBGFPLUGIN       pfnEntry;
+    /** The name length. */
+    uint8_t             cchName;
+    /** The plug-in name (variable length).  */
+    char                szName[1];
+} DBGFPLUGIN;
+/** Pointer to plug-in tracking record. */
+typedef DBGFPLUGIN *PDBGFPLUGIN;
+
+
+/*******************************************************************************
+*   Internal Functions                                                         *
+*******************************************************************************/
+static DECLCALLBACK(void) dbgfPlugInUnloadAll(PUVM pUVM);
+static FNDBGFHANDLERINT dbgfR3PlugInInfoList;
+
+
+/**
+ * Internal init routine called by DBGFR3Init().
+ *
+ * @returns VBox status code.
+ * @param   pUVM    The user mode VM handle.
+ */
+int dbgfR3PlugInInit(PUVM pUVM)
+{
+    return DBGFR3InfoRegisterInternal(pUVM->pVM, "plugins", "Lists the debugger plug-ins.", dbgfR3PlugInInfoList);
+}
+
+
+/**
+ * Internal cleanup routine called by DBGFR3Term().
+ *
+ * @param   pUVM    The user mode VM handle.
+ */
+void dbgfR3PlugInTerm(PUVM pUVM)
+{
+    dbgfPlugInUnloadAll(pUVM);
+}
+
+
+/**
+ * Extracts the plug-in name from a plug-in specifier that may or may not
+ * include path and/or suffix.
+ *
+ * @returns VBox status code.
+ *
+ * @param   pszDst      Where to return the name. At least DBGFPLUGIN_MAX_NAME
+ *                      worth of buffer space.
+ * @param   pszPlugIn   The plug-in module specifier to parse.
+ * @param   pErrInfo    Optional error information structure.
+ */
+static int dbgfPlugInExtractName(char *pszDst, const char *pszPlugIn, PRTERRINFO pErrInfo)
+{
+    /*
+     * Parse out the name stopping at the extension.
+     */
+    const char *pszName = RTPathFilename(pszPlugIn);
+    if (!pszName || !*pszName)
+        return VERR_INVALID_NAME;
+    if (!RTStrNICmp(pszName, RT_STR_TUPLE(DBGF_PLUG_IN_PREFIX)))
+    {
+        pszName += sizeof(DBGF_PLUG_IN_PREFIX) - 1;
+        if (!*pszName)
+            return RTErrInfoSetF(pErrInfo, VERR_INVALID_NAME, "Invalid plug-in name: nothing after the prefix");
+    }
+
+    int     ch;
+    size_t  cchName = 0;
+    while (   (ch = pszName[cchName]) != '\0'
+           && ch != '.')
+    {
+        if (   RT_C_IS_ALPHA(ch)
+            || (RT_C_IS_DIGIT(ch) && cchName != 0))
+            cchName++;
+        else
+        {
+            if (!RT_C_IS_DIGIT(ch))
+                return RTErrInfoSetF(pErrInfo, VERR_INVALID_NAME, "Invalid plug-in name: '%c' is not alphanumeric", ch);
+            return RTErrInfoSetF(pErrInfo, VERR_INVALID_NAME,
+                                 "Invalid plug-in name: Cannot start with a digit (after the prefix)");
+        }
+    }
+
+    if (cchName >= DBGFPLUGIN_MAX_NAME)
+        return RTErrInfoSetF(pErrInfo, VERR_INVALID_NAME, "Invalid plug-in name: too long (max %u)", DBGFPLUGIN_MAX_NAME);
+
+    /*
+     * We're very picky about the extension when present.
+     */
+    if (   ch == '.'
+        && RTStrICmp(&pszName[cchName], RTLdrGetSuff()))
+        return RTErrInfoSetF(pErrInfo, VERR_INVALID_NAME,
+                             "Invalid plug-in name: Suffix isn't the default dll/so/dylib one (%s): '%s'",
+                             RTLdrGetSuff(), &pszName[cchName]);
+
+    /*
+     * Copy it.
+     */
+    memcpy(pszDst, pszName, cchName);
+    pszDst[cchName] = '\0';
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Locate a loaded plug-in.
+ *
+ * @returns Pointer to the plug-in tracking structure.
+ * @param   pUVM                Pointer to the user-mode VM structure.
+ * @param   pszName             The name of the plug-in we're looking for.
+ * @param   ppPrev              Where to optionally return the pointer to the
+ *                              previous list member.
+ */
+static PDBGFPLUGIN dbgfR3PlugInLocate(PUVM pUVM, const char *pszName, PDBGFPLUGIN *ppPrev)
+{
+    PDBGFPLUGIN pPrev = NULL;
+    PDBGFPLUGIN pCur  = pUVM->dbgf.s.pPlugInHead;
+    while (pCur)
+    {
+        if (!RTStrICmp(pCur->szName, pszName))
+        {
+            if (ppPrev)
+                *ppPrev = pPrev;
+            return pCur;
+        }
+
+        /* advance */
+        pPrev = pCur;
+        pCur  = pCur->pNext;
+    }
+    return NULL;
+}
+
+
+/**
+ * Try load the specified plug-in module.
+ *
+ * @returns VINF_SUCCESS on success, path error or loader error on failure.
+ *
+ * @param   pPlugIn     The plug-in tracing record.
+ * @param   pszModule   Module name.
+ * @param   pErrInfo    Optional error information structure.
+ */
+static int dbgfR3PlugInTryLoad(PDBGFPLUGIN pPlugIn, const char *pszModule, PRTERRINFO pErrInfo)
+{
+    /*
+     * Load it and try resolve the entry point.
+     */
+    int rc = SUPR3HardenedVerifyPlugIn(pszModule, pErrInfo);
+    if (RT_SUCCESS(rc))
+        rc = RTLdrLoadEx(pszModule, &pPlugIn->hLdrMod, RTLDRLOAD_FLAGS_LOCAL, pErrInfo);
+    if (RT_SUCCESS(rc))
+    {
+        rc = RTLdrGetSymbol(pPlugIn->hLdrMod, DBGF_PLUG_IN_ENTRYPOINT, (void **)&pPlugIn->pfnEntry);
+        if (RT_SUCCESS(rc))
+        {
+            LogRel(("DBGF: Loaded Plug-In '%s' (%s).\n", pPlugIn->szName, pszModule));
+            return VINF_SUCCESS;
+        }
+
+        RTErrInfoSet(pErrInfo, rc, "Failed to locate plug-in entrypoint (" DBGF_PLUG_IN_ENTRYPOINT ")" );
+        LogRel(("DBGF: RTLdrGetSymbol('%s', '%s',) -> %Rrc\n", pszModule, DBGF_PLUG_IN_ENTRYPOINT, rc));
+
+        RTLdrClose(pPlugIn->hLdrMod);
+        pPlugIn->hLdrMod = NIL_RTLDRMOD;
+    }
+    return rc;
+}
+
+
+/**
+ * RTPathTraverseList callback.
+ *
+ * @returns See FNRTPATHTRAVERSER.
+ *
+ * @param   pchPath     See FNRTPATHTRAVERSER.
+ * @param   cchPath     See FNRTPATHTRAVERSER.
+ * @param   pvUser1     The plug-in specifier.
+ * @param   pvUser2     The plug-in tracking record.
+ */
+static DECLCALLBACK(int) dbgfR3PlugInLoadCallback(const char *pchPath, size_t cchPath, void *pvUser1, void *pvUser2)
+{
+    PDBGFPLUGIN pPlugIn   = (PDBGFPLUGIN)pvUser1;
+    PRTERRINFO  pErrInfo  = (PRTERRINFO)pvUser2;
+
+    /*
+     * Join the path and the specified plug-in name, adding prefix and suffix.
+     */
+    const char  *pszSuff   = RTLdrGetSuff();
+    size_t const cchSuff   = strlen(pszSuff);
+    size_t const cchModule = cchPath + sizeof(RTPATH_SLASH_STR) + sizeof(DBGF_PLUG_IN_PREFIX) + pPlugIn->cchName + cchSuff + 4;
+    char        *pszModule = (char *)alloca(cchModule);
+    AssertReturn(pszModule, VERR_TRY_AGAIN);
+    memcpy(pszModule, pchPath, cchPath);
+    pszModule[cchPath] = '\0';
+
+    int rc = RTPathAppend(pszModule, cchModule, DBGF_PLUG_IN_PREFIX);
+    AssertRCReturn(rc, VERR_TRY_AGAIN);
+    strcat(&pszModule[cchPath], pPlugIn->szName);
+    strcat(&pszModule[cchPath + sizeof(DBGF_PLUG_IN_PREFIX) - 1 + pPlugIn->cchName], pszSuff);
+    Assert(strlen(pszModule) < cchModule - 4);
+
+    if (RTPathExists(pszModule))
+    {
+        rc = dbgfR3PlugInTryLoad(pPlugIn, pszModule, pErrInfo);
+        if (RT_SUCCESS(rc))
+            return VINF_SUCCESS;
+    }
+
+    return VERR_TRY_AGAIN;
+}
+
+
+/**
+ * Loads a plug-in.
+ *
+ * @returns VBox status code.
+ * @param   pUVM                Pointer to the user-mode VM structure.
+ * @param   pszName             The plug-in name.
+ * @param   pszMaybeModule      Path to the plug-in, or just the
+ *                              plug-in name as specified by the user.  Ignored
+ *                              if no path.
+ * @param   pErrInfo            Optional error information structure.
+ */
+static DECLCALLBACK(int) dbgfR3PlugInLoad(PUVM pUVM, const char *pszName, const char *pszMaybeModule, PRTERRINFO pErrInfo)
+{
+    DBGF_PLUG_IN_WRITE_LOCK(pUVM);
+
+    /*
+     * Check if a plug-in by the given name already exists.
+     */
+    PDBGFPLUGIN pPlugIn = dbgfR3PlugInLocate(pUVM, pszName, NULL);
+    if (pPlugIn)
+    {
+        DBGF_PLUG_IN_WRITE_UNLOCK(pUVM);
+        return RTErrInfoSetF(pErrInfo, VERR_ALREADY_EXISTS, "A plug-in by the name '%s' already exists", pszName);
+    }
+
+    /*
+     * Create a module structure and we can pass around via RTPathTraverseList if needed.
+     */
+    size_t cbName = strlen(pszName) + 1;
+    pPlugIn = (PDBGFPLUGIN)MMR3HeapAllocZU(pUVM, MM_TAG_DBGF, RT_UOFFSETOF(DBGFPLUGIN, szName[cbName]));
+    if (RT_UNLIKELY(!pPlugIn))
+    {
+        DBGF_PLUG_IN_WRITE_UNLOCK(pUVM);
+        return VERR_NO_MEMORY;
+    }
+    memcpy(pPlugIn->szName, pszName, cbName);
+    pPlugIn->cchName = (uint8_t)cbName - 1;
+    Assert(pPlugIn->cchName == cbName - 1);
+
+    /*
+     * If the caller specified a path, try load exactly what was specified.
+     */
+    int rc;
+    if (RTPathHavePath(pszMaybeModule))
+        rc = dbgfR3PlugInTryLoad(pPlugIn, pszMaybeModule, pErrInfo);
+    else
+    {
+        /*
+         * No path specified, search for the plug-in using the canonical
+         * module name for it.
+         */
+        RTErrInfoClear(pErrInfo);
+
+        /* 1. The private architecture directory. */
+        char szPath[_4K];
+        rc = RTPathAppPrivateArch(szPath, sizeof(szPath));
+        if (RT_SUCCESS(rc))
+            rc = RTPathTraverseList(szPath, '\0', dbgfR3PlugInLoadCallback, pPlugIn, pErrInfo);
+        if (RT_FAILURE_NP(rc))
+        {
+            /* 2. The config value 'PlugInPath' */
+            int rc2 = CFGMR3QueryString(CFGMR3GetChild(CFGMR3GetRootU(pUVM), "/DBGF"), "PlugInPath", szPath, sizeof(szPath));
+            if (RT_SUCCESS(rc2))
+                rc = RTPathTraverseList(szPath, ';', dbgfR3PlugInLoadCallback, pPlugIn, pErrInfo);
+            if (RT_FAILURE_NP(rc))
+            {
+                /* 3. The VBOXDBG_PLUG_IN_PATH environment variable. */
+                rc2 = RTEnvGetEx(RTENV_DEFAULT, "VBOXDBG_PLUG_IN_PATH", szPath, sizeof(szPath), NULL);
+                if (RT_SUCCESS(rc2))
+                    rc = RTPathTraverseList(szPath, ';', dbgfR3PlugInLoadCallback, pPlugIn, pErrInfo);
+            }
+        }
+
+        if (rc == VERR_END_OF_STRING)
+            rc = VERR_FILE_NOT_FOUND;
+        if (pErrInfo && !RTErrInfoIsSet(pErrInfo))
+            RTErrInfoSetF(pErrInfo, rc, "Failed to locate '%s'", pPlugIn->szName);
+    }
+    if (RT_SUCCESS(rc))
+    {
+        /*
+         * Try initialize it.
+         */
+        rc = pPlugIn->pfnEntry(DBGFPLUGINOP_INIT, pUVM, VBOX_VERSION);
+        if (RT_SUCCESS(rc))
+        {
+            /*
+             * Link it and we're good.
+             */
+            pPlugIn->pNext = pUVM->dbgf.s.pPlugInHead;
+            pUVM->dbgf.s.pPlugInHead = pPlugIn;
+
+            DBGF_PLUG_IN_WRITE_UNLOCK(pUVM);
+            return VINF_SUCCESS;
+        }
+
+        RTErrInfoSet(pErrInfo, rc, "Plug-in init failed");
+        LogRel(("DBGF: Plug-in '%s' failed during init: %Rrc\n", pPlugIn->szName));
+        RTLdrClose(pPlugIn->hLdrMod);
+    }
+    MMR3HeapFree(pPlugIn);
+
+    DBGF_PLUG_IN_WRITE_UNLOCK(pUVM);
+    return rc;
+}
+
+
+/**
+ * Load a debugging plug-in.
+ *
+ * @returns VBox status code.
+ * @retval  VERR_ALREADY_EXISTS if the module was already loaded.
+ * @retval  VINF_BUFFER_OVERFLOW if the actual plug-in name buffer was too small
+ *          (the plug-in was still successfully loaded).
+ * @param   pUVM        Pointer to the user-mode VM structure.
+ * @param   pszPlugIn   The plug-in name.  This may specify the exact path to
+ *                      the plug-in module, or it may just specify the core name
+ *                      of the plug-in without prefix, suffix and path.
+ * @param   pszActual   Buffer to return the actual plug-in name in. Optional.
+ *                      This will be returned on VERR_ALREADY_EXSIST too.
+ * @param   cbActual    The size of @a pszActual.
+ * @param   pErrInfo    Optional error information structure.
+ */
+VMMR3DECL(int) DBGFR3PlugInLoad(PUVM pUVM, const char *pszPlugIn, char *pszActual, size_t cbActual, PRTERRINFO pErrInfo)
+{
+    UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
+    AssertPtrReturn(pszPlugIn, VERR_INVALID_PARAMETER);
+
+    /*
+     * Extract the plug-in name.  Copy it to the return buffer as we'll want to
+     * return it in the VERR_ALREADY_EXISTS case too.
+     */
+    char szName[DBGFPLUGIN_MAX_NAME];
+    int rc = dbgfPlugInExtractName(szName, pszPlugIn, pErrInfo);
+    if (RT_SUCCESS(rc))
+    {
+        int rc2 = VINF_SUCCESS;
+        if (pszActual)
+            rc2 = RTStrCopy(pszActual, cbActual, szName);
+
+        /*
+         * Write lock releated DBGF bits and try load it.
+         */
+        rc = VMR3ReqPriorityCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3PlugInLoad, 4, pUVM, szName, pszPlugIn, pErrInfo);
+        if (rc2 != VINF_SUCCESS && RT_SUCCESS(rc))
+            rc = VINF_BUFFER_OVERFLOW;
+    }
+
+    return rc;
+}
+
+
+/**
+ * Load all plug-ins from the architechture private directory of VBox.
+ *
+ * @param   pUVM    Pointer to the user-mode VM structure.
+ */
+VMMR3DECL(void) DBGFR3PlugInLoadAll(PUVM pUVM)
+{
+    UVM_ASSERT_VALID_EXT_RETURN_VOID(pUVM);
+
+    /*
+     * Pass it on to EMT(0) if necessary (thanks to DBGFR3Os*).
+     */
+    if (VMR3GetVMCPUId(pUVM->pVM) != 0)
+    {
+        VMR3ReqPriorityCallVoidWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)DBGFR3PlugInLoadAll, 1, pUVM);
+        return;
+    }
+
+
+    /*
+     * Open the architecture specific directory with a filter on our prefix
+     * and names including a dot.
+     */
+    const char *pszSuff = RTLdrGetSuff();
+    size_t      cchSuff = strlen(pszSuff);
+
+    char szPath[RTPATH_MAX];
+    int rc = RTPathAppPrivateArch(szPath, sizeof(szPath) - cchSuff);
+    AssertRCReturnVoid(rc);
+    size_t offDir = strlen(szPath);
+
+    rc = RTPathAppend(szPath, sizeof(szPath) - cchSuff, DBGF_PLUG_IN_PREFIX "*");
+    AssertRCReturnVoid(rc);
+    strcat(szPath, pszSuff);
+
+    PRTDIR pDir;
+    rc = RTDirOpenFiltered(&pDir, szPath, RTDIRFILTER_WINNT, 0);
+    if (RT_SUCCESS(rc))
+    {
+        /*
+         * Now read it and try load each of the plug-in modules.
+         */
+        RTDIRENTRY DirEntry;
+        while (RT_SUCCESS(RTDirRead(pDir, &DirEntry, NULL)))
+        {
+            szPath[offDir] = '\0';
+            rc = RTPathAppend(szPath, sizeof(szPath), DirEntry.szName);
+            if (RT_SUCCESS(rc))
+            {
+                char szName[DBGFPLUGIN_MAX_NAME];
+                rc = dbgfPlugInExtractName(szName, DirEntry.szName, NULL);
+                if (RT_SUCCESS(rc))
+                {
+                    DBGF_PLUG_IN_WRITE_LOCK(pUVM);
+                    dbgfR3PlugInLoad(pUVM, szName, szPath, NULL);
+                    DBGF_PLUG_IN_WRITE_UNLOCK(pUVM);
+                }
+            }
+        }
+
+        RTDirClose(pDir);
+    }
+}
+
+
+/**
+ * Unloads a plug-in by name (no path, prefix or suffix).
+ *
+ * @returns VBox status code.
+ * @retval  VERR_NOT_FOUND if the specified plug-in wasn't found.
+ * @param   pUVM        Pointer to the user-mode VM structure.
+ * @param   pszName     The name of the plug-in to unload.
+ */
+VMMR3DECL(int) DBGFR3PlugInUnload(PUVM pUVM, const char *pszName)
+{
+    UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
+
+    /*
+     * Pass it on to EMT(0) if necessary (thanks to DBGFR3Os*).
+     */
+    if (VMR3GetVMCPUId(pUVM->pVM) != 0)
+        return VMR3ReqPriorityCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)DBGFR3PlugInUnload, 2, pUVM, pszName);
+
+
+    /*
+     * Find the plug-in.
+     */
+    DBGF_PLUG_IN_WRITE_LOCK(pUVM);
+
+    int rc;
+    PDBGFPLUGIN pPrevPlugIn;
+    PDBGFPLUGIN pPlugIn = dbgfR3PlugInLocate(pUVM, pszName, &pPrevPlugIn);
+    if (pPlugIn)
+    {
+        /*
+         * Unlink, terminate, unload and free the plug-in.
+         */
+        if (pPrevPlugIn)
+            pPrevPlugIn->pNext = pPlugIn->pNext;
+        else
+            pUVM->dbgf.s.pPlugInHead = pPlugIn->pNext;
+
+        pPlugIn->pfnEntry(DBGFPLUGINOP_TERM, pUVM, 0);
+        RTLdrClose(pPlugIn->hLdrMod);
+
+        pPlugIn->pfnEntry = NULL;
+        pPlugIn->hLdrMod  = NIL_RTLDRMOD;
+        MMR3HeapFree(pPlugIn->pNext);
+    }
+    else
+        rc = VERR_NOT_FOUND;
+
+    DBGF_PLUG_IN_WRITE_UNLOCK(pUVM);
+    return rc;
+}
+
+
+/**
+ * Unload all plug-ins.
+ *
+ * @param   pUVM    Pointer to the user-mode VM structure.
+ */
+static DECLCALLBACK(void) dbgfPlugInUnloadAll(PUVM pUVM)
+{
+    DBGF_PLUG_IN_WRITE_LOCK(pUVM);
+
+    while (pUVM->dbgf.s.pPlugInHead)
+    {
+        PDBGFPLUGIN pPlugin = pUVM->dbgf.s.pPlugInHead;
+        pUVM->dbgf.s.pPlugInHead = pPlugin->pNext;
+
+        pPlugin->pfnEntry(DBGFPLUGINOP_TERM, pUVM, 0);
+
+        int rc2 = RTLdrClose(pPlugin->hLdrMod);
+        AssertRC(rc2);
+
+        pPlugin->pfnEntry = NULL;
+        pPlugin->hLdrMod  = NIL_RTLDRMOD;
+        MMR3HeapFree(pPlugin);
+    }
+
+    DBGF_PLUG_IN_WRITE_UNLOCK(pUVM);
+}
+
+
+/**
+ * Unloads all plug-ins.
+ *
+ * @param   pUVM    Pointer to the user-mode VM structure.
+ */
+VMMR3DECL(void) DBGFR3PlugInUnloadAll(PUVM pUVM)
+{
+    UVM_ASSERT_VALID_EXT_RETURN_VOID(pUVM);
+    /* Thanks to DBGFR3Os, this must be done on EMT(0). */
+    VMR3ReqPriorityCallVoidWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfPlugInUnloadAll, 1, pUVM);
+}
+
+
+
+/**
+ * @interface_method_impl{FNDBGFHANDLERINT, The 'plugins' info item.}
+ */
+static DECLCALLBACK(void) dbgfR3PlugInInfoList(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
+{
+    PDBGFPLUGIN pPlugIn = pVM->pUVM->dbgf.s.pPlugInHead;
+    if (pPlugIn)
+    {
+        pHlp->pfnPrintf(pHlp, "Debugging plug-in%s: %s", pPlugIn->pNext ? "s" : "", pPlugIn->szName);
+        while ((pPlugIn = pPlugIn->pNext) != NULL)
+            pHlp->pfnPrintf(pHlp, ", %s", pPlugIn->szName);
+        pHlp->pfnPrintf(pHlp, "\n");
+
+    }
+    else
+        pHlp->pfnPrintf(pHlp, "No plug-ins loaded\n");
+}
+
Index: /trunk/src/VBox/VMM/VMMR3/VM.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/VM.cpp	(revision 55880)
+++ /trunk/src/VBox/VMM/VMMR3/VM.cpp	(revision 55881)
@@ -2490,11 +2490,11 @@
         RTLogFlags(NULL, "nodisabled nobuffered");
 #endif
-#ifdef VBOX_WITH_STATISTICS
-        STAMR3Dump(pUVM, "*");
-#else
+//#ifdef VBOX_WITH_STATISTICS
+//        STAMR3Dump(pUVM, "*");
+//#else
         LogRel(("************************* Statistics *************************\n"));
         STAMR3DumpToReleaseLog(pUVM, "*");
         LogRel(("********************* End of statistics **********************\n"));
-#endif
+//#endif
 
         /*
Index: /trunk/src/VBox/VMM/include/DBGFInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/DBGFInternal.h	(revision 55880)
+++ /trunk/src/VBox/VMM/include/DBGFInternal.h	(revision 55881)
@@ -185,4 +185,5 @@
 
 
+
 /**
  * Converts a DBGF pointer into a VM pointer.
@@ -317,17 +318,20 @@
     bool                        afAlignment2[3];
 
+    /** Critical section protecting the Guest OS Digger data, the info handlers
+     * and the plugins.  These share to give the best possible plugin unload
+     * race protection. */
+    RTCRITSECTRW                CritSect;
+    /** Head of the LIFO of loaded DBGF plugins. */
+    R3PTRTYPE(struct DBGFPLUGIN *) pPlugInHead;
     /** The current Guest OS digger. */
     R3PTRTYPE(PDBGFOS)          pCurOS;
     /** The head of the Guest OS digger instances. */
     R3PTRTYPE(PDBGFOS)          pOSHead;
-    /** Critical section protecting the Guest OS Digger data. */
-    RTCRITSECTRW                OSCritSect;
-
     /** List of registered info handlers. */
     R3PTRTYPE(PDBGFINFO)        pInfoFirst;
-    /** Critical section protecting the above list. */
-    RTCRITSECT                  InfoCritSect;
 
 } DBGFUSERPERVM;
+typedef DBGFUSERPERVM *PDBGFUSERPERVM;
+typedef DBGFUSERPERVM const *PCDBGFUSERPERVM;
 
 /**
@@ -356,4 +360,6 @@
 void dbgfR3TraceRelocate(PVM pVM);
 void dbgfR3TraceTerm(PVM pVM);
+int  dbgfR3PlugInInit(PUVM pUVM);
+void dbgfR3PlugInTerm(PUVM pUVM);
 
 
