Index: trunk/src/VBox/Runtime/common/dbg/dbgcfg.cpp
===================================================================
--- trunk/src/VBox/Runtime/common/dbg/dbgcfg.cpp	(revision 46149)
+++ trunk/src/VBox/Runtime/common/dbg/dbgcfg.cpp	(revision 46161)
@@ -33,4 +33,5 @@
 #include "internal/iprt.h"
 
+#include <iprt/alloca.h>
 #include <iprt/asm.h>
 #include <iprt/assert.h>
@@ -626,4 +627,6 @@
     if (pThis->fFlags & RTDBGCFG_FLAGS_NO_SYM_SRV)
         return VWRN_NOT_FOUND;
+    if (!pszCacheSubDir || !*pszCacheSubDir)
+        return VWRN_NOT_FOUND;
 
     /*
@@ -749,4 +752,7 @@
                                    const char *pszCacheSubDir, PRTPATHSPLIT pSplitFn)
 {
+    if (!pszCacheSubDir || !*pszCacheSubDir)
+        return VINF_SUCCESS;
+
     /** @todo copy to cache */
     return VINF_SUCCESS;
@@ -1002,4 +1008,5 @@
     if (RT_FAILURE(rc2))
         return rc2;
+    AssertReturnStmt(pSplitFn->fProps & RTPATH_PROP_FILENAME, RTPathSplitFree(pSplitFn), VERR_IS_A_DIRECTORY);
 
     /*
@@ -1014,5 +1021,5 @@
             RTPathChangeToUnixSlashes(szPath, false);
             rtDbgCfgLog1(pThis, "Trying '%s'...\n", szPath);
-            rc2 = pfnCallback(pThis, pszFilename, pvUser1, pvUser2);
+            rc2 = pfnCallback(pThis, szPath, pvUser1, pvUser2);
             if (rc2 == VINF_CALLBACK_RETURN)
                 rtDbgCfgLog1(pThis, "Found '%s'.\n", szPath);
@@ -1168,4 +1175,376 @@
                                   pfnCallback, pvUser1, pvUser2);
 }
+
+
+
+/*
+ *
+ *  D a r w i n   . d S Y M   b u n d l e s
+ *  D a r w i n   . d S Y M   b u n d l e s
+ *  D a r w i n   . d S Y M   b u n d l e s
+ *
+ */
+
+/**
+ * Very similar to rtDbgCfgTryOpenDir.
+ */
+static int rtDbgCfgTryOpenDsymBundleInDir(PRTDBGCFGINT pThis, char *pszPath, PRTPATHSPLIT pSplitFn, const char *pszDsymName,
+                                          uint32_t fFlags, PFNDBGCFGOPEN pfnCallback, void *pvUser1, void *pvUser2)
+{
+    int rcRet = VWRN_NOT_FOUND;
+    int rc2;
+
+    /* If the directory doesn't exist, just quit immediately.
+       Note! Our case insensitivity doesn't extend to the search dirs themselfs,
+             only to the bits under neath them. */
+    if (!RTDirExists(pszPath))
+    {
+        rtDbgCfgLog2(pThis, "Dir does not exist: '%s'\n", pszPath);
+        return rcRet;
+    }
+
+    /* Figure out whether we have to do a case sensitive search or not.
+       Note! As a simplification, we don't ask for case settings in each
+             directory under the user specified path, we assume the file
+             systems that mounted there have compatible settings. Faster
+             that way. */
+    bool const fCaseInsensitive = (fFlags & RTDBGCFG_O_CASE_INSENSITIVE)
+                               && !rtDbgCfgIsFsCaseInsensitive(pszPath);
+
+    size_t const cchPath = strlen(pszPath);
+
+    /*
+     * Look for the file with less and less of the original path given.
+     */
+    for (unsigned i = RTPATH_PROP_HAS_ROOT_SPEC(pSplitFn->fProps); i < pSplitFn->cComps; i++)
+    {
+        pszPath[cchPath] = '\0';
+
+        rc2 = VINF_SUCCESS;
+        for (unsigned j = i; j < pSplitFn->cComps - 1U && RT_SUCCESS(rc2); j++)
+            if (!rtDbgCfgIsDirAndFixCase(pszPath, pSplitFn->apszComps[i], fCaseInsensitive))
+                rc2 = VERR_FILE_NOT_FOUND;
+        if (    RT_SUCCESS(rc2)
+            && !rtDbgCfgIsDirAndFixCase(pszPath, pszDsymName, fCaseInsensitive)
+            && !rtDbgCfgIsDirAndFixCase(pszPath, "Contents", fCaseInsensitive)
+            && !rtDbgCfgIsDirAndFixCase(pszPath, "Resources", fCaseInsensitive)
+            && !rtDbgCfgIsDirAndFixCase(pszPath, "DWARF", fCaseInsensitive))
+        {
+            if (rtDbgCfgIsFileAndFixCase(pszPath, pSplitFn->apszComps[pSplitFn->cComps - 1], fCaseInsensitive, false, NULL))
+            {
+                rtDbgCfgLog1(pThis, "Trying '%s'...\n", pszPath);
+                rc2 = pfnCallback(pThis, pszPath, pvUser1, pvUser2);
+                if (rc2 == VINF_CALLBACK_RETURN || rc2 == VERR_CALLBACK_RETURN)
+                {
+                    if (rc2 == VINF_CALLBACK_RETURN)
+                        rtDbgCfgLog1(pThis, "Found '%s'.\n", pszPath);
+                    else
+                        rtDbgCfgLog1(pThis, "Error opening '%s'.\n", pszPath);
+                    return rc2;
+                }
+                rtDbgCfgLog1(pThis, "Error %Rrc opening '%s'.\n", rc2, pszPath);
+                if (RT_FAILURE(rc2) && RT_SUCCESS_NP(rcRet))
+                    rcRet = rc2;
+            }
+        }
+        rc2 = VERR_FILE_NOT_FOUND;
+    }
+
+    /*
+     * Do a recursive search if requested.
+     */
+    if (   (fFlags & RTDBGCFG_O_RECURSIVE)
+        && !(pThis->fFlags & RTDBGCFG_FLAGS_NO_RECURSIV_SEARCH) )
+    {
+        /** @todo Recursive searching will be done later. */
+    }
+
+    return rcRet;
+}
+
+
+/**
+ * Very similar to rtDbgCfgTryOpenList.
+ */
+static int rtDbgCfgTryOpenDsumBundleInList(PRTDBGCFGINT pThis, PRTLISTANCHOR pList, PRTPATHSPLIT pSplitFn,
+                                           const char *pszDsymName, const char *pszCacheSubDir, uint32_t fFlags, char *pszPath,
+                                           PFNDBGCFGOPEN pfnCallback, void *pvUser1, void *pvUser2)
+{
+    int rcRet = VWRN_NOT_FOUND;
+    int rc2;
+
+    const char *pchCache = NULL;
+    size_t      cchCache = 0;
+    int         rcCache  = VWRN_NOT_FOUND;
+
+    PRTDBGCFGSTR pCur;
+    RTListForEach(pList, pCur, RTDBGCFGSTR, ListEntry)
+    {
+        size_t      cchDir = pCur->cch;
+        const char *pszDir = pCur->sz;
+        rtDbgCfgLog2(pThis, "Path list entry: '%s'\n", pszDir);
+
+        /* This is very simplistic, but we have a unreasonably large path
+           buffer, so it'll work just fine and simplify things greatly below. */
+        if (cchDir >= RTPATH_MAX - 8U)
+        {
+            if (RT_SUCCESS_NP(rcRet))
+                rcRet = VERR_FILENAME_TOO_LONG;
+            continue;
+        }
+
+        /*
+         * Process the path according to it's type.
+         */
+        if (!strncmp(pszDir, RT_STR_TUPLE("srv*")))
+        {
+            /*
+             * Symbol server.
+             */
+            pszDir += sizeof("srv*") - 1;
+            cchDir -= sizeof("srv*") - 1;
+            bool        fSearchCache = false;
+            const char *pszServer = (const char *)memchr(pszDir, '*', cchDir);
+            if (!pszServer)
+                pszServer = pszDir;
+            else if (pszServer == pszDir)
+                continue;
+            {
+                fSearchCache = true;
+                pchCache = pszDir;
+                cchCache = pszServer - pszDir;
+                pszServer++;
+            }
+
+            /* We don't have any default cache directory, so skip if the cache is missing. */
+            if (cchCache == 0)
+                continue;
+
+            /* Search the cache first (if we haven't already done so). */
+            if (fSearchCache)
+            {
+                memcpy(pszPath, pchCache, cchCache);
+                pszPath[cchCache] = '\0';
+                RTPathChangeToUnixSlashes(pszPath, false);
+
+                rcCache = rc2 = rtDbgCfgTryOpenCache(pThis, pszPath, pszCacheSubDir, pSplitFn, fFlags,
+                                                     pfnCallback, pvUser1, pvUser2);
+                if (rc2 == VINF_CALLBACK_RETURN || rc2 == VERR_CALLBACK_RETURN)
+                    return rc2;
+            }
+
+            /* Try downloading the file. */
+            if (rcCache == VWRN_NOT_FOUND)
+            {
+                memcpy(pszPath, pchCache, cchCache);
+                pszPath[cchCache] = '\0';
+                RTPathChangeToUnixSlashes(pszPath, false);
+
+                rc2 = rtDbgCfgTryDownloadAndOpen(pThis, pszServer, pszPath, pszCacheSubDir, pSplitFn, fFlags,
+                                                 pfnCallback, pvUser1, pvUser2);
+                if (rc2 == VINF_CALLBACK_RETURN || rc2 == VERR_CALLBACK_RETURN)
+                    return rc2;
+            }
+        }
+        else if (!strncmp(pszDir, RT_STR_TUPLE("cache*")))
+        {
+            /*
+             * Cache directory.
+             */
+            pszDir += sizeof("cache*") - 1;
+            cchDir -= sizeof("cache*") - 1;
+            if (!cchDir)
+                continue;
+            pchCache = pszDir;
+            cchCache = cchDir;
+
+            memcpy(pszPath, pchCache, cchCache);
+            pszPath[cchCache] = '\0';
+            RTPathChangeToUnixSlashes(pszPath, false);
+
+            rcCache = rc2 = rtDbgCfgTryOpenCache(pThis, pszPath, pszCacheSubDir, pSplitFn, fFlags,
+                                                 pfnCallback, pvUser1, pvUser2);
+            if (rc2 == VINF_CALLBACK_RETURN || rc2 == VERR_CALLBACK_RETURN)
+                return rc2;
+        }
+        else
+        {
+            /*
+             * Normal directory. Check for our own 'rec*' and 'norec*' prefix
+             * flags governing recursive searching.
+             */
+            uint32_t fFlagsDir = fFlags;
+            if (!strncmp(pszDir, RT_STR_TUPLE("rec*")))
+            {
+                pszDir += sizeof("rec*") - 1;
+                cchDir -= sizeof("rec*") - 1;
+                fFlagsDir |= RTDBGCFG_O_RECURSIVE;
+            }
+            else if (!strncmp(pszDir, RT_STR_TUPLE("norec*")))
+            {
+                pszDir += sizeof("norec*") - 1;
+                cchDir -= sizeof("norec*") - 1;
+                fFlagsDir &= ~RTDBGCFG_O_RECURSIVE;
+            }
+
+            /* Copy the path into the buffer and do the searching. */
+            memcpy(pszPath, pszDir, cchDir);
+            pszPath[cchDir] = '\0';
+            RTPathChangeToUnixSlashes(pszPath, false);
+
+            rc2 = rtDbgCfgTryOpenDsymBundleInDir(pThis, pszPath, pSplitFn, pszDsymName, fFlagsDir,
+                                                 pfnCallback, pvUser1, pvUser2);
+            if (rc2 == VINF_CALLBACK_RETURN || rc2 == VERR_CALLBACK_RETURN)
+            {
+                if (   rc2 == VINF_CALLBACK_RETURN
+                    && cchCache > 0)
+                    rtDbgCfgCopyFileToCache(pThis, pszPath, pchCache, cchCache, pszCacheSubDir, pSplitFn);
+                return rc2;
+            }
+        }
+
+        /* Propagate errors. */
+        if (RT_FAILURE(rc2) && RT_SUCCESS_NP(rcRet))
+            rcRet = rc2;
+    }
+
+    return rcRet;
+}
+
+
+RTDECL(int) RTDbgCfgOpenDsymBundle(RTDBGCFG hDbgCfg, const char *pszImage, PCRTUUID pUuid,
+                                   PFNDBGCFGOPEN pfnCallback, void *pvUser1, void *pvUser2)
+{
+    /*
+     * Bundles are directories, means we can forget about sharing code much
+     * with the other RTDbgCfgOpenXXX methods.  Thus we're duplicating a lot of
+     * code from rtDbgCfgOpenWithSubDir with .dSYM related adjustments, so, a bug
+     * found here or there probably means the other version needs updating.
+     */
+    int rcRet = VINF_SUCCESS;
+    int rc2;
+
+    //RTStrPrintf(szFile, sizeof(szFile), "%s.dSYM/Contents/Resources/DWARF/%s", pszFilename, pszFilename);
+
+    /*
+     * Do a little validating first.
+     */
+    PRTDBGCFGINT pThis = hDbgCfg;
+    if (pThis != NIL_RTDBGCFG)
+        RTDBGCFG_VALID_RETURN_RC(pThis, VERR_INVALID_HANDLE);
+    else
+        pThis = NULL;
+    AssertPtrReturn(pszImage, VERR_INVALID_POINTER);
+    AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER);
+
+    /*
+     * Set up rtDbgCfgOpenWithSubDir parameters.
+     */
+    uint32_t fFlags = RTDBGCFG_O_EXT_DEBUG_FILE | RT_OPSYS_DARWIN;
+    const char *pszCacheSubDir = NULL;
+    char szCacheSubDir[RTUUID_STR_LENGTH];
+    if (pUuid)
+    {
+        RTUuidToStr(pUuid, szCacheSubDir, sizeof(szCacheSubDir));
+        pszCacheSubDir = szCacheSubDir;
+    }
+
+    /*
+     * Do some guessing as to the way we should parse the filename and whether
+     * it's case exact or not.
+     */
+    bool fDosPath = strchr(pszImage, ':')  != NULL
+                 || strchr(pszImage, '\\') != NULL
+                 || RT_OPSYS_USES_DOS_PATHS(fFlags & RTDBGCFG_O_OPSYS_MASK)
+                 || (fFlags & RTDBGCFG_O_CASE_INSENSITIVE);
+    if (fDosPath)
+        fFlags |= RTDBGCFG_O_CASE_INSENSITIVE;
+
+    rtDbgCfgLog2(pThis, "Looking for '%s' with %#x flags...\n", pszImage, fFlags);
+
+    PRTPATHSPLIT pSplitFn;
+    rc2 = RTPathSplitA(pszImage, &pSplitFn, fDosPath ? RTPATH_STR_F_STYLE_DOS : RTPATH_STR_F_STYLE_UNIX);
+    if (RT_FAILURE(rc2))
+        return rc2;
+    AssertReturnStmt(pSplitFn->fProps & RTPATH_PROP_FILENAME, RTPathSplitFree(pSplitFn), VERR_IS_A_DIRECTORY);
+
+    /*
+     * Try the image directory first.
+     */
+    char szPath[RTPATH_MAX];
+    if (pSplitFn->cComps > 0)
+    {
+        rc2 = RTPathSplitReassemble(pSplitFn, RTPATH_STR_F_STYLE_HOST, szPath, sizeof(szPath));
+        if (RT_SUCCESS(rc2))
+            rc2 = RTStrCat(szPath, sizeof(szPath),
+                           ".dSYM" RTPATH_SLASH_STR "Contents" RTPATH_SLASH_STR "Resources" RTPATH_SLASH_STR "DWARF");
+        if (RT_SUCCESS(rc2))
+            rc2 = RTPathAppend(szPath, sizeof(szPath), pSplitFn->apszComps[pSplitFn->cComps - 1]);
+        if (RT_SUCCESS(rc2))
+        {
+            RTPathChangeToUnixSlashes(szPath, false);
+            rtDbgCfgLog1(pThis, "Trying '%s'...\n", szPath);
+            rc2 = pfnCallback(pThis, szPath, pvUser1, pvUser2);
+            if (rc2 == VINF_CALLBACK_RETURN)
+                rtDbgCfgLog1(pThis, "Found '%s'.\n", szPath);
+            else if (rc2 == VERR_CALLBACK_RETURN)
+                rtDbgCfgLog1(pThis, "Error opening '%s'.\n", szPath);
+            else
+                rtDbgCfgLog1(pThis, "Error %Rrc opening '%s'.\n", rc2, szPath);
+        }
+    }
+    if (   rc2 != VINF_CALLBACK_RETURN
+        && rc2 != VERR_CALLBACK_RETURN)
+    {
+        char *pszDsymName = (char *)alloca(strlen(pSplitFn->apszComps[pSplitFn->cComps - 1]) + sizeof(".dSYM"));
+        strcat(strcpy(pszDsymName, pSplitFn->apszComps[pSplitFn->cComps - 1]), ".dSYM");
+
+        /*
+         * Try the current directory (will take cover relative paths
+         * skipped above).
+         */
+        rc2 = RTPathGetCurrent(szPath, sizeof(szPath));
+        if (RT_FAILURE(rc2))
+            strcpy(szPath, ".");
+        RTPathChangeToUnixSlashes(szPath, false);
+
+        rc2 = rtDbgCfgTryOpenDsymBundleInDir(pThis, szPath, pSplitFn, pszDsymName, fFlags, pfnCallback, pvUser1, pvUser2);
+        if (RT_FAILURE(rc2) && RT_SUCCESS_NP(rcRet))
+            rcRet = rc2;
+
+        if (   rc2 != VINF_CALLBACK_RETURN
+            && rc2 != VERR_CALLBACK_RETURN
+            && pThis)
+        {
+            rc2 = RTCritSectRwEnterShared(&pThis->CritSect);
+            if (RT_SUCCESS(rc2))
+            {
+                /*
+                 * Run the applicable lists.
+                 */
+                rc2 = rtDbgCfgTryOpenDsumBundleInList(pThis, &pThis->PathList, pSplitFn, pszDsymName,
+                                                      pszCacheSubDir, fFlags, szPath,
+                                                      pfnCallback, pvUser1, pvUser2);
+                if (RT_FAILURE(rc2) && RT_SUCCESS_NP(rcRet))
+                    rcRet = rc2;
+
+                RTCritSectRwLeaveShared(&pThis->CritSect);
+            }
+            else if (RT_SUCCESS(rcRet))
+                rcRet = rc2;
+        }
+    }
+
+    RTPathSplitFree(pSplitFn);
+    if (   rc2 == VINF_CALLBACK_RETURN
+        || rc2 == VERR_CALLBACK_RETURN)
+        rcRet = rc2;
+    else if (RT_SUCCESS(rcRet))
+        rcRet = VERR_NOT_FOUND;
+    return rcRet;
+
+
+}
+
 
 
Index: trunk/src/VBox/Runtime/common/dbg/dbgmod.cpp
===================================================================
--- trunk/src/VBox/Runtime/common/dbg/dbgmod.cpp	(revision 46149)
+++ trunk/src/VBox/Runtime/common/dbg/dbgmod.cpp	(revision 46161)
@@ -123,4 +123,6 @@
 
 
+
+
 /**
  * Cleanup debug info interpreter globals.
@@ -359,144 +361,4 @@
 }
 RT_EXPORT_SYMBOL(RTDbgModCreate);
-
-
-RTDECL(int) RTDbgModCreateFromImage(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName, RTDBGCFG hDbgCfg)
-{
-    /*
-     * Input validation and lazy initialization.
-     */
-    AssertPtrReturn(phDbgMod, VERR_INVALID_POINTER);
-    *phDbgMod = NIL_RTDBGMOD;
-    AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
-    AssertReturn(*pszFilename, VERR_INVALID_PARAMETER);
-    AssertPtrNullReturn(pszName, VERR_INVALID_POINTER);
-
-    int rc = rtDbgModLazyInit();
-    if (RT_FAILURE(rc))
-        return rc;
-
-    if (!pszName)
-        pszName = RTPathFilenameEx(pszFilename, RTPATH_STR_F_STYLE_DOS);
-
-    /*
-     * Allocate a new module instance.
-     */
-    PRTDBGMODINT pDbgMod = (PRTDBGMODINT)RTMemAllocZ(sizeof(*pDbgMod));
-    if (!pDbgMod)
-        return VERR_NO_MEMORY;
-    pDbgMod->u32Magic = RTDBGMOD_MAGIC;
-    pDbgMod->cRefs = 1;
-    rc = RTCritSectInit(&pDbgMod->CritSect);
-    if (RT_SUCCESS(rc))
-    {
-        pDbgMod->pszName = RTStrCacheEnterLower(g_hDbgModStrCache, pszName);
-        if (pDbgMod->pszName)
-        {
-            pDbgMod->pszImgFile = RTStrCacheEnter(g_hDbgModStrCache, pszFilename);
-            if (pDbgMod->pszImgFile)
-            {
-                RTStrCacheRetain(pDbgMod->pszImgFile);
-                pDbgMod->pszImgFileSpecified = pDbgMod->pszImgFile;
-
-                /*
-                 * Find an image reader which groks the file.
-                 */
-                rc = RTSemRWRequestRead(g_hDbgModRWSem, RT_INDEFINITE_WAIT);
-                if (RT_SUCCESS(rc))
-                {
-                    rc = VERR_DBG_NO_MATCHING_INTERPRETER;
-                    PRTDBGMODREGIMG pImg;
-                    for (pImg = g_pImgHead; pImg; pImg = pImg->pNext)
-                    {
-                        pDbgMod->pImgVt    = pImg->pVt;
-                        pDbgMod->pvImgPriv = NULL;
-                        rc = pImg->pVt->pfnTryOpen(pDbgMod);
-                        if (RT_SUCCESS(rc))
-                        {
-                            /*
-                             * Find a debug info interpreter.
-                             */
-                            rc = VERR_DBG_NO_MATCHING_INTERPRETER;
-                            for (PRTDBGMODREGDBG pDbg = g_pDbgHead; pDbg; pDbg = pDbg->pNext)
-                            {
-                                pDbgMod->pDbgVt = pDbg->pVt;
-                                pDbgMod->pvDbgPriv = NULL;
-                                rc = pDbg->pVt->pfnTryOpen(pDbgMod);
-                                if (RT_SUCCESS(rc))
-                                {
-                                    /*
-                                     * That's it!
-                                     */
-                                    ASMAtomicIncU32(&pDbg->cUsers);
-                                    ASMAtomicIncU32(&pImg->cUsers);
-                                    RTSemRWReleaseRead(g_hDbgModRWSem);
-
-                                    *phDbgMod = pDbgMod;
-                                    return rc;
-                                }
-                            }
-
-                            /*
-                             * Image detected, but found no debug info we were
-                             * able to understand.
-                             */
-                            /** @todo Fall back on exported symbols! */
-                            pDbgMod->pImgVt->pfnClose(pDbgMod);
-                            break;
-                        }
-                    }
-
-                    /*
-                     * Could it be a file containing raw debug info?
-                     */
-                    if (!pImg)
-                    {
-                        pDbgMod->pImgVt     = NULL;
-                        pDbgMod->pvImgPriv  = NULL;
-                        pDbgMod->pszDbgFile = pDbgMod->pszImgFile;
-                        pDbgMod->pszImgFile = NULL;
-
-                        for (PRTDBGMODREGDBG pDbg = g_pDbgHead; pDbg; pDbg = pDbg->pNext)
-                        {
-                            pDbgMod->pDbgVt = pDbg->pVt;
-                            pDbgMod->pvDbgPriv = NULL;
-                            rc = pDbg->pVt->pfnTryOpen(pDbgMod);
-                            if (RT_SUCCESS(rc))
-                            {
-                                /*
-                                 * That's it!
-                                 */
-                                ASMAtomicIncU32(&pDbg->cUsers);
-                                RTSemRWReleaseRead(g_hDbgModRWSem);
-
-                                *phDbgMod = pDbgMod;
-                                return rc;
-                            }
-                        }
-
-                        pDbgMod->pszImgFile = pDbgMod->pszDbgFile;
-                        pDbgMod->pszDbgFile = NULL;
-                    }
-
-                    /* bail out */
-                    RTSemRWReleaseRead(g_hDbgModRWSem);
-                }
-                RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszImgFileSpecified);
-                RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszImgFile);
-            }
-            else
-                rc = VERR_NO_STR_MEMORY;
-            RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszName);
-        }
-        else
-            rc = VERR_NO_STR_MEMORY;
-        RTCritSectDelete(&pDbgMod->CritSect);
-    }
-
-    RTMemFree(pDbgMod);
-    return rc;
-}
-RT_EXPORT_SYMBOL(RTDbgModCreateFromImage);
-
 
 
@@ -584,10 +446,9 @@
 
 
-
 /*
  *
- *  P E   I M A G E
- *  P E   I M A G E
- *  P E   I M A G E
+ *  E x e c u t a b l e   I m a g e   F i l e s
+ *  E x e c u t a b l e   I m a g e   F i l e s
+ *  E x e c u t a b l e   I m a g e   F i l e s
  *
  */
@@ -804,4 +665,257 @@
 
 
+/** @callback_method_impl{FNRTDBGCFGOPEN} */
+static DECLCALLBACK(int) rtDbgModExtDbgInfoOpenCallback2(RTDBGCFG hDbgCfg, const char *pszFilename, void *pvUser1, void *pvUser2)
+{
+    PRTDBGMODINT        pDbgMod   = (PRTDBGMODINT)pvUser1;
+    NOREF(pvUser2); /** @todo image matching string or smth. */
+
+    Assert(!pDbgMod->pDbgVt);
+    Assert(!pDbgMod->pvDbgPriv);
+    Assert(!pDbgMod->pszDbgFile);
+
+    /*
+     * Set the debug file name and try possible interpreters.
+     */
+    pDbgMod->pszDbgFile = RTStrCacheEnter(g_hDbgModStrCache, pszFilename);
+
+    int rc = RTSemRWRequestRead(g_hDbgModRWSem, RT_INDEFINITE_WAIT);
+    if (RT_SUCCESS(rc))
+    {
+        for (PRTDBGMODREGDBG pDbg = g_pDbgHead; pDbg; pDbg = pDbg->pNext)
+        {
+            pDbgMod->pDbgVt    = pDbg->pVt;
+            pDbgMod->pvDbgPriv = NULL;
+            rc = pDbg->pVt->pfnTryOpen(pDbgMod);
+            if (RT_SUCCESS(rc))
+            {
+                /*
+                 * Got it!
+                 */
+                ASMAtomicIncU32(&pDbg->cUsers);
+                RTSemRWReleaseRead(g_hDbgModRWSem);
+                return VINF_CALLBACK_RETURN;
+            }
+            pDbgMod->pDbgVt    = NULL;
+            Assert(pDbgMod->pvDbgPriv == NULL);
+        }
+    }
+
+    /* No joy. */
+    RTSemRWReleaseRead(g_hDbgModRWSem);
+    RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszDbgFile);
+    pDbgMod->pszDbgFile = NULL;
+    return rc;
+}
+
+
+/**
+ * Opens external debug info that is not listed in the image.
+ *
+ * @returns IPRT status code
+ * @param   pDbgMod             The debug module.
+ * @param   hDbgCfg             The debug config.  Can be NIL.
+ */
+static int rtDbgModOpenDebugInfoExternalToImage2(PRTDBGMODINT pDbgMod, RTDBGCFG hDbgCfg)
+{
+    int rc;
+    Assert(!pDbgMod->pDbgVt);
+    Assert(pDbgMod->pImgVt);
+
+    /*
+     * Figure out what to search for based on the image format.
+     */
+    const char *pszzExts = NULL;
+    RTLDRFMT    enmFmt = pDbgMod->pImgVt->pfnGetFormat(pDbgMod);
+    switch (enmFmt)
+    {
+        case RTLDRFMT_MACHO:
+        {
+            rc = RTDbgCfgOpenDsymBundle(hDbgCfg, pDbgMod->pszImgFile, NULL /**@todo pUuid*/,
+                                        rtDbgModExtDbgInfoOpenCallback2, pDbgMod, NULL /*pvUser2*/);
+            if (RT_SUCCESS(rc))
+                return VINF_SUCCESS;
+            break;
+        }
+
+#if 0 /* Will be links in the image if these apply. .map readers for PE or ELF we don't have. */
+        case RTLDRFMT_ELF:
+            pszzExts = ".debug\0.dwo\0";
+            break;
+        case RTLDRFMT_PE:
+            pszzExts = ".map\0";
+            break;
+#endif
+#if 0 /* Haven't implemented .sym or .map file readers for OS/2 yet. */
+        case RTLDRFMT_LX:
+            pszzExts = ".sym\0.map\0";
+            break;
+#endif
+        default:
+            break;
+    }
+
+    NOREF(pszzExts);
+#if 0 /* Later */
+    if (pszzExts)
+    {
+
+    }
+#endif
+
+    LogFlow(("rtDbgModOpenDebugInfoExternalToImage2: rc=%Rrc\n", rc));
+    return VERR_NOT_FOUND;
+}
+
+
+RTDECL(int) RTDbgModCreateFromImage(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName,
+                                    RTLDRARCH enmArch, RTDBGCFG hDbgCfg)
+{
+    /*
+     * Input validation and lazy initialization.
+     */
+    AssertPtrReturn(phDbgMod, VERR_INVALID_POINTER);
+    *phDbgMod = NIL_RTDBGMOD;
+    AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
+    AssertReturn(*pszFilename, VERR_INVALID_PARAMETER);
+    AssertPtrNullReturn(pszName, VERR_INVALID_POINTER);
+    AssertReturn(enmArch > RTLDRARCH_INVALID && enmArch < RTLDRARCH_END, VERR_INVALID_PARAMETER);
+
+    int rc = rtDbgModLazyInit();
+    if (RT_FAILURE(rc))
+        return rc;
+
+    if (!pszName)
+        pszName = RTPathFilenameEx(pszFilename, RTPATH_STR_F_STYLE_DOS);
+
+    /*
+     * Allocate a new module instance.
+     */
+    PRTDBGMODINT pDbgMod = (PRTDBGMODINT)RTMemAllocZ(sizeof(*pDbgMod));
+    if (!pDbgMod)
+        return VERR_NO_MEMORY;
+    pDbgMod->u32Magic = RTDBGMOD_MAGIC;
+    pDbgMod->cRefs = 1;
+    rc = RTCritSectInit(&pDbgMod->CritSect);
+    if (RT_SUCCESS(rc))
+    {
+        pDbgMod->pszName = RTStrCacheEnterLower(g_hDbgModStrCache, pszName);
+        if (pDbgMod->pszName)
+        {
+            pDbgMod->pszImgFile = RTStrCacheEnter(g_hDbgModStrCache, pszFilename);
+            if (pDbgMod->pszImgFile)
+            {
+                RTStrCacheRetain(pDbgMod->pszImgFile);
+                pDbgMod->pszImgFileSpecified = pDbgMod->pszImgFile;
+
+                /*
+                 * Find an image reader which groks the file.
+                 */
+                rc = RTSemRWRequestRead(g_hDbgModRWSem, RT_INDEFINITE_WAIT);
+                if (RT_SUCCESS(rc))
+                {
+                    rc = VERR_DBG_NO_MATCHING_INTERPRETER;
+                    PRTDBGMODREGIMG pImg;
+                    for (pImg = g_pImgHead; pImg; pImg = pImg->pNext)
+                    {
+                        pDbgMod->pImgVt    = pImg->pVt;
+                        pDbgMod->pvImgPriv = NULL;
+                        /** @todo need to specify some arch stuff here. */
+                        rc = pImg->pVt->pfnTryOpen(pDbgMod, enmArch);
+                        if (RT_SUCCESS(rc))
+                        {
+                            /*
+                             * Image detected, but found no debug info we were
+                             * able to understand.
+                             */
+                            /** @todo some generic way of matching image and debug info, flexible signature
+                             *        of some kind. Apple uses UUIDs, microsoft uses a UUID+age or a
+                             *        size+timestamp, and GNU a CRC32 (last time I checked). */
+                            rc = rtDbgModOpenDebugInfoExternalToImage(pDbgMod, hDbgCfg);
+                            if (RT_FAILURE(rc))
+                                rc = rtDbgModOpenDebugInfoInsideImage(pDbgMod);
+                            if (RT_FAILURE(rc))
+                                rc = rtDbgModOpenDebugInfoExternalToImage2(pDbgMod, hDbgCfg);
+                            if (RT_FAILURE(rc))
+                                rc = rtDbgModCreateForExports(pDbgMod);
+                            if (RT_SUCCESS(rc))
+                            {
+                                *phDbgMod = pDbgMod;
+                                return VINF_SUCCESS;
+                            }
+
+                            /* Failed, close up the shop. */
+                            pDbgMod->pImgVt->pfnClose(pDbgMod);
+                            pDbgMod->pImgVt = NULL;
+                            pDbgMod->pvImgPriv = NULL;
+                            break;
+                        }
+                    }
+
+                    /*
+                     * Could it be a file containing raw debug info?
+                     */
+                    if (!pImg)
+                    {
+                        pDbgMod->pImgVt     = NULL;
+                        pDbgMod->pvImgPriv  = NULL;
+                        pDbgMod->pszDbgFile = pDbgMod->pszImgFile;
+                        pDbgMod->pszImgFile = NULL;
+
+                        for (PRTDBGMODREGDBG pDbg = g_pDbgHead; pDbg; pDbg = pDbg->pNext)
+                        {
+                            pDbgMod->pDbgVt = pDbg->pVt;
+                            pDbgMod->pvDbgPriv = NULL;
+                            rc = pDbg->pVt->pfnTryOpen(pDbgMod);
+                            if (RT_SUCCESS(rc))
+                            {
+                                /*
+                                 * That's it!
+                                 */
+                                ASMAtomicIncU32(&pDbg->cUsers);
+                                RTSemRWReleaseRead(g_hDbgModRWSem);
+
+                                *phDbgMod = pDbgMod;
+                                return rc;
+                            }
+                        }
+
+                        pDbgMod->pszImgFile = pDbgMod->pszDbgFile;
+                        pDbgMod->pszDbgFile = NULL;
+                    }
+
+                    /* bail out */
+                    RTSemRWReleaseRead(g_hDbgModRWSem);
+                }
+                RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszImgFileSpecified);
+                RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszImgFile);
+            }
+            else
+                rc = VERR_NO_STR_MEMORY;
+            RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszName);
+        }
+        else
+            rc = VERR_NO_STR_MEMORY;
+        RTCritSectDelete(&pDbgMod->CritSect);
+    }
+
+    RTMemFree(pDbgMod);
+    return rc;
+}
+RT_EXPORT_SYMBOL(RTDbgModCreateFromImage);
+
+
+
+
+
+/*
+ *
+ *  P E   I M A G E
+ *  P E   I M A G E
+ *  P E   I M A G E
+ *
+ */
+
+
 
 /** @callback_method_impl{FNRTDBGCFGOPEN} */
@@ -838,5 +952,5 @@
             pDbgMod->pImgVt    = pImg->pVt;
             pDbgMod->pvImgPriv = NULL;
-            rc = pImg->pVt->pfnTryOpen(pDbgMod);
+            rc = pImg->pVt->pfnTryOpen(pDbgMod, RTLDRARCH_WHATEVER);
             if (RT_SUCCESS(rc))
                 break;
@@ -1040,5 +1154,5 @@
     return rc;
 }
-RT_EXPORT_SYMBOL(RTDbgModCreateFromImage);
+RT_EXPORT_SYMBOL(RTDbgModCreateFromPeImage);
 
 
Index: trunk/src/VBox/Runtime/common/dbg/dbgmoddeferred.cpp
===================================================================
--- trunk/src/VBox/Runtime/common/dbg/dbgmoddeferred.cpp	(revision 46149)
+++ trunk/src/VBox/Runtime/common/dbg/dbgmoddeferred.cpp	(revision 46161)
@@ -440,4 +440,17 @@
 
 
+/** @interface_method_impl{RTDBGMODVTIMG,pfnGetFormat} */
+static DECLCALLBACK(RTLDRFMT) rtDbgModDeferredImg_GetFormat(PRTDBGMODINT pMod)
+{
+    RTLDRFMT enmFmt;
+    int rc = rtDbgModDeferredDoIt(pMod, false /*fForceRetry*/);
+    if (RT_SUCCESS(rc))
+        enmFmt = pMod->pImgVt->pfnGetFormat(pMod);
+    else
+        enmFmt = RTLDRFMT_INVALID;
+    return enmFmt;
+}
+
+
 /** @interface_method_impl{RTDBGMODVTIMG,pfnUnmapPart} */
 static DECLCALLBACK(int) rtDbgModDeferredImg_UnmapPart(PRTDBGMODINT pMod, size_t cb, void const **ppvMap)
@@ -530,6 +543,7 @@
 
 /** @interface_method_impl{RTDBGMODVTIMG,pfnTryOpen} */
-static DECLCALLBACK(int) rtDbgModDeferredImg_TryOpen(PRTDBGMODINT pMod)
-{
+static DECLCALLBACK(int) rtDbgModDeferredImg_TryOpen(PRTDBGMODINT pMod, RTLDRARCH enmArch)
+{
+    NOREF(enmArch);
     return rtDbgModDeferredDoIt(pMod, true /*fForceRetry*/);
 }
@@ -552,4 +566,5 @@
     /*.pfnMapPart = */                  rtDbgModDeferredImg_MapPart,
     /*.pfnUnmapPart = */                rtDbgModDeferredImg_UnmapPart,
+    /*.pfnGetFormat = */                rtDbgModDeferredImg_GetFormat,
 
     /*.u32EndMagic = */                 RTDBGMODVTIMG_MAGIC
Index: trunk/src/VBox/Runtime/common/dbg/dbgmodldr.cpp
===================================================================
--- trunk/src/VBox/Runtime/common/dbg/dbgmodldr.cpp	(revision 46149)
+++ trunk/src/VBox/Runtime/common/dbg/dbgmodldr.cpp	(revision 46161)
@@ -60,4 +60,13 @@
 
 
+
+/** @interface_method_impl{RTDBGMODVTIMG,pfnGetFormat} */
+static DECLCALLBACK(RTLDRFMT) rtDbgModLdr_GetFormat(PRTDBGMODINT pMod)
+{
+    PRTDBGMODLDR pThis = (PRTDBGMODLDR)pMod->pvImgPriv;
+    return RTLdrGetFormat(pThis->hLdrMod);
+}
+
+
 /** @interface_method_impl{RTDBGMODVTIMG,pfnUnmapPart} */
 static DECLCALLBACK(int) rtDbgModLdr_UnmapPart(PRTDBGMODINT pMod, size_t cb, void const **ppvMap)
@@ -158,8 +167,8 @@
 
 /** @interface_method_impl{RTDBGMODVTIMG,pfnTryOpen} */
-static DECLCALLBACK(int) rtDbgModLdr_TryOpen(PRTDBGMODINT pMod)
+static DECLCALLBACK(int) rtDbgModLdr_TryOpen(PRTDBGMODINT pMod, RTLDRARCH enmArch)
 {
     RTLDRMOD hLdrMod;
-    int rc = RTLdrOpen(pMod->pszImgFile, RTLDR_O_FOR_DEBUG, RTLDRARCH_WHATEVER, &hLdrMod);
+    int rc = RTLdrOpen(pMod->pszImgFile, RTLDR_O_FOR_DEBUG, enmArch, &hLdrMod);
     if (RT_SUCCESS(rc))
     {
@@ -188,4 +197,5 @@
     /*.pfnMapPart = */                  rtDbgModLdr_MapPart,
     /*.pfnUnmapPart = */                rtDbgModLdr_UnmapPart,
+    /*.pfnGetFormat = */                rtDbgModLdr_GetFormat,
 
     /*.u32EndMagic = */                 RTDBGMODVTIMG_MAGIC
