Index: trunk/src/VBox/Runtime/common/dbg/dbgmod.cpp
===================================================================
--- trunk/src/VBox/Runtime/common/dbg/dbgmod.cpp	(revision 46266)
+++ trunk/src/VBox/Runtime/common/dbg/dbgmod.cpp	(revision 46269)
@@ -280,12 +280,10 @@
         if (RT_SUCCESS(rc))
             rc = rtDbgModDebugInterpreterRegister(&g_rtDbgModVtDbgDwarf);
-#if 0 /* NOTE!! EXPERIMENTAL, SHOULDN'T BE ENABLED IN SVN YET!! */
-        if (RT_SUCCESS(rc))
-            rc = rtDbgModDebugInterpreterRegister(&g_rtDbgModVtDbgCodeView);
-#endif
 #ifdef RT_OS_WINDOWS
         if (RT_SUCCESS(rc))
             rc = rtDbgModDebugInterpreterRegister(&g_rtDbgModVtDbgDbgHelp);
 #endif
+        if (RT_SUCCESS(rc))
+            rc = rtDbgModDebugInterpreterRegister(&g_rtDbgModVtDbgCodeView);
         if (RT_SUCCESS(rc))
             rc = rtDbgModImageInterpreterRegister(&g_rtDbgModVtImgLdr);
Index: trunk/src/VBox/Runtime/common/dbg/dbgmodcodeview.cpp
===================================================================
--- trunk/src/VBox/Runtime/common/dbg/dbgmodcodeview.cpp	(revision 46266)
+++ trunk/src/VBox/Runtime/common/dbg/dbgmodcodeview.cpp	(revision 46269)
@@ -2,4 +2,15 @@
 /** @file
  * IPRT - Debug Module Reader For Microsoft CodeView.
+ *
+ * Based on the following documentation (plus guess work and googling):
+ *
+ *  - "Tools Interface Standard (TIS) Formats Specification for Windows",
+ *    dated February 1993, version 1.0.
+ *
+ *  - "Visual C++ 5.0 Symbolic Debug Information Specification" chapter of
+ *     SPECS.CHM from MSDN Library October 2001.
+ *
+ *  - "High Level Languages Debug Table Documentation", aka HLLDBG.HTML, aka
+ *     IBMHLL.HTML, last changed 1996-07-08.
  */
 
@@ -43,4 +54,5 @@
 #include <iprt/path.h>
 #include <iprt/string.h>
+#include <iprt/strcache.h>
 #include "internal/dbgmod.h"
 #include "internal/ldrPE.h"
@@ -57,5 +69,5 @@
 typedef struct RTCVHDR
 {
-    /** The magic ('NBxx'). */
+    /** The magic ('NBxx'), see RTCVHDR_MAGIC_XXX. */
     uint32_t    u32Magic;
     /**
@@ -69,4 +81,33 @@
 /** Pointer to a CodeView header. */
 typedef RTCVHDR *PRTCVHDR;
+
+/** @name CodeView magic values (RTCVHDR::u32Magic).
+ * @{  */
+/** CodeView from Visual C++ 5.0.  Specified in the 2001 MSDN specs.chm file. */
+#define RTCVHDR_MAGIC_NB11  RT_MAKE_U32_FROM_U8('N', 'B', '1', '1')
+/** External PDB reference (often referred to as PDB 2.0). */
+#define RTCVHDR_MAGIC_NB10  RT_MAKE_U32_FROM_U8('N', 'B', '1', '0')
+/** CodeView v4.10, packed. Specified in the TIS document. */
+#define RTCVHDR_MAGIC_NB09  RT_MAKE_U32_FROM_U8('N', 'B', '0', '9')
+/** CodeView v4.00 thru v4.05.  Specified in the TIS document?  */
+#define RTCVHDR_MAGIC_NB08  RT_MAKE_U32_FROM_U8('N', 'B', '0', '8')
+/** Quick C for Windows 1.0 debug info. */
+#define RTCVHDR_MAGIC_NB07  RT_MAKE_U32_FROM_U8('N', 'B', '0', '7')
+/** Emitted by ILINK indicating incremental link. Comparable to NB05?  */
+#define RTCVHDR_MAGIC_NB06  RT_MAKE_U32_FROM_U8('N', 'B', '0', '6')
+/** Emitted by LINK version 5.20 and later before packing. */
+#define RTCVHDR_MAGIC_NB05  RT_MAKE_U32_FROM_U8('N', 'B', '0', '5')
+/** Emitted by IBM ILINK for HLL (similar to NB02 in many ways). */
+#define RTCVHDR_MAGIC_NB04  RT_MAKE_U32_FROM_U8('N', 'B', '0', '4')
+/** Emitted by LINK version 5.10 (or similar OMF linkers), as shipped with
+ * Microsoft C v6.0 for example.  More or less entirely 16-bit. */
+#define RTCVHDR_MAGIC_NB02  RT_MAKE_U32_FROM_U8('N', 'B', '0', '2')
+/* No idea what NB03 might have been. */
+/** AIX debugger format according to "IBM OS/2 16/32-bit Object Module Format
+ *  (OMF) and Linear eXecutable Module Format (LX)" revision 10 (LXOMF.PDF). */
+#define RTCVHDR_MAGIC_NB01  RT_MAKE_U32_FROM_U8('N', 'B', '0', '1')
+/** Ancient CodeView format according to LXOMF.PDF. */
+#define RTCVHDR_MAGIC_NB00  RT_MAKE_U32_FROM_U8('N', 'B', '0', '0')
+/** @} */
 
 
@@ -216,32 +257,193 @@
 
 
-/** @name CodeView magic values.
- * @{  */
-/** CodeView from Visual C++ 5.0.  Specified in the 2001 MSDN specs.chm file. */
-#define RTCVHDR_MAGIC_NB11  RT_MAKE_U32_FROM_U8('N', 'B', '1', '1')
-/** External PDB reference (often referred to as PDB 2.0). */
-#define RTCVHDR_MAGIC_NB10  RT_MAKE_U32_FROM_U8('N', 'B', '1', '0')
-/** CodeView v4.10, packed. Specified in the TIS document. */
-#define RTCVHDR_MAGIC_NB09  RT_MAKE_U32_FROM_U8('N', 'B', '0', '9')
-/** CodeView v4.00 thru v4.05.  Specified in the TIS document?  */
-#define RTCVHDR_MAGIC_NB08  RT_MAKE_U32_FROM_U8('N', 'B', '0', '8')
-/** Quick C for Windows 1.0 debug info. */
-#define RTCVHDR_MAGIC_NB07  RT_MAKE_U32_FROM_U8('N', 'B', '0', '7')
-/** Emitted by ILINK indicating incremental link. Comparable to NB05?  */
-#define RTCVHDR_MAGIC_NB06  RT_MAKE_U32_FROM_U8('N', 'B', '0', '6')
-/** Emitted by LINK version 5.20 and later before packing. */
-#define RTCVHDR_MAGIC_NB05  RT_MAKE_U32_FROM_U8('N', 'B', '0', '5')
-/** Emitted by IBM ILINK for HLL (similar to NB02 in many ways). */
-#define RTCVHDR_MAGIC_NB04  RT_MAKE_U32_FROM_U8('N', 'B', '0', '4')
-/** Emitted by LINK version 5.10 (or similar OMF linkers), as shipped with
- * Microsoft C v6.0 for example.  More or less entirely 16-bit. */
-#define RTCVHDR_MAGIC_NB02  RT_MAKE_U32_FROM_U8('N', 'B', '0', '2')
-/* No idea what NB03 might have been. */
-/** AIX debugger format according to "IBM OS/2 16/32-bit Object Module Format
- *  (OMF) and Linear eXecutable Module Format (LX)" revision 10 (LXOMF.PDF). */
-#define RTCVHDR_MAGIC_NB01  RT_MAKE_U32_FROM_U8('N', 'B', '0', '1')
-/** Ancient CodeView format according to LXOMF.PDF. */
-#define RTCVHDR_MAGIC_NB00  RT_MAKE_U32_FROM_U8('N', 'B', '0', '0')
+/**
+ * CV4 module segment info.
+ */
+typedef struct RTCVMODSEGINFO32
+{
+    /** The segment number. */
+    uint16_t        iSeg;
+    /** Explicit padding. */
+    uint16_t        u16Padding;
+    /** Offset into the segment. */
+    uint32_t        off;
+    /** The size of the contribution. */
+    uint32_t        cb;
+} RTCVMODSEGINFO32;
+typedef RTCVMODSEGINFO32 *PRTCVMODSEGINFO32;
+typedef RTCVMODSEGINFO32 const *PCRTCVMODSEGINFO32;
+
+
+/**
+ * CV4 segment map header.
+ */
+typedef struct RTCVSEGMAPHDR
+{
+    /** Number of segments descriptors in the table. */
+    uint16_t        cSegs;
+    /** Number of logical segment descriptors. */
+    uint16_t        cLogSegs;
+} RTCVSEGMAPHDR;
+/** Pointer to a CV4 segment map header. */
+typedef RTCVSEGMAPHDR *PRTCVSEGMAPHDR;
+/** Pointer to a const CV4 segment map header. */
+typedef RTCVSEGMAPHDR const *PCRTCVSEGMAPHDR;
+
+/**
+ * CV4 Segment map descriptor entry.
+ */
+typedef struct RTCVSEGMAPDESC
+{
+    /** Segment flags. */
+    uint16_t        fFlags;
+    /** The overlay number. */
+    uint16_t        iOverlay;
+    /** Group index into this segment descriptor array. 0 if not relevant.
+     * The group descriptors are found in the second half of the table.  */
+    uint16_t        iGroup;
+    /** Complicated. */
+    uint16_t        iFrame;
+    /** Offset (byte) into the kCvSst_SegName table of the segment name, or
+     * 0xffff. */
+    uint16_t        offSegName;
+    /** Offset (byte) into the kCvSst_SegName table of the class name, or 0xffff. */
+    uint16_t        offClassName;
+    /** Offset into the physical segment. */
+    uint32_t        off;
+    /** Size of segment. */
+    uint32_t        cb;
+} RTCVSEGMAPDESC;
+/** Pointer to a segment map descriptor entry. */
+typedef RTCVSEGMAPDESC *PRTCVSEGMAPDESC;
+/** Pointer to a const segment map descriptor entry. */
+typedef RTCVSEGMAPDESC const *PCRTCVSEGMAPDESC;
+
+/** @name RTCVSEGMAPDESC_F_XXX - RTCVSEGMAPDESC::fFlags values.
+ * @{ */
+#define RTCVSEGMAPDESC_F_READ       UINT16_C(0x0001)
+#define RTCVSEGMAPDESC_F_WRITE      UINT16_C(0x0002)
+#define RTCVSEGMAPDESC_F_EXECUTE    UINT16_C(0x0004)
+#define RTCVSEGMAPDESC_F_32BIT      UINT16_C(0x0008)
+#define RTCVSEGMAPDESC_F_SEL        UINT16_C(0x0100)
+#define RTCVSEGMAPDESC_F_ABS        UINT16_C(0x0200)
+#define RTCVSEGMAPDESC_F_GROUP      UINT16_C(0x1000)
+#define RTCVSEGMAPDESC_F_RESERVED   UINT16_C(0xecf0)
 /** @} */
+
+/**
+ * CV4 segment map subsection.
+ */
+typedef struct RTCVSEGMAP
+{
+    /** The header. */
+    RTCVSEGMAPHDR   Hdr;
+    /** Descriptor array. */
+    RTCVSEGMAPDESC  aDescs[1];
+} RTCVSEGMAP;
+/** Pointer to a segment map subsection. */
+typedef RTCVSEGMAP *PRTCVSEGMAP;
+/** Pointer to a const segment map subsection. */
+typedef RTCVSEGMAP const *PCRTCVSEGMAP;
+
+
+/**
+ * Global symbol table header, used by kCvSst_GlobalSym and kCvSst_GlobalPub.
+ */
+typedef struct RTCVGLOBALSYMTABHDR
+{
+    /** The symbol hash function. */
+    uint16_t        uSymHash;
+    /** The address hash function. */
+    uint16_t        uAddrHash;
+    /** The amount of symbol information following immediately after the header. */
+    uint32_t        cbSymbols;
+    /** The amount of symbol hash tables following the symbols. */
+    uint32_t        cbSymHash;
+    /** The amount of address hash tables following the symbol hash tables. */
+    uint32_t        cbAddrHash;
+} RTCVGLOBALSYMTABHDR;
+/** Pointer to a global symbol table header. */
+typedef RTCVGLOBALSYMTABHDR *PRTCVGLOBALSYMTABHDR;
+/** Pointer to a const global symbol table header. */
+typedef RTCVGLOBALSYMTABHDR const *PCRTCVGLOBALSYMTABHDR;
+
+
+typedef enum RTCVSYMTYPE
+{
+    /** @name Symbols that doesn't change with compilation model or target machine.
+     * @{ */
+    kCvSymType_Compile = 0x0001,
+    kCvSymType_Register,
+    kCvSymType_Constant,
+    kCvSymType_UDT,
+    kCvSymType_SSearch,
+    kCvSymType_End,
+    kCvSymType_Skip,
+    kCvSymType_CVReserve,
+    kCvSymType_ObjName,
+    kCvSymType_EndArg,
+    kCvSymType_CobolUDT,
+    kCvSymType_ManyReg,
+    kCvSymType_Return,
+    kCvSymType_EntryThis,
+    /** @}  */
+
+    /** @name Symbols with 16:16 addresses.
+     * @{ */
+    kCvSymType_BpRel16 = 0x0100,
+    kCvSymType_LData16,
+    kCvSymType_GData16,
+    kCvSymType_Pub16,
+    kCvSymType_LProc16,
+    kCvSymType_GProc16,
+    kCvSymType_Thunk16,
+    kCvSymType_BLock16,
+    kCvSymType_With16,
+    kCvSymType_Label16,
+    kCvSymType_CExModel16,
+    kCvSymType_VftPath16,
+    kCvSymType_RegRel16,
+    /** @}  */
+
+    /** @name Symbols with 16:32 addresses.
+     * @{ */
+    kCvSymType_BpRel32 = 0x0200,
+    kCvSymType_LData32,
+    kCvSymType_GData32,
+    kCvSymType_Pub32,
+    kCvSymType_LProc32,
+    kCvSymType_GProc32,
+    kCvSymType_Thunk32,
+    kCvSymType_Block32,
+    kCvSymType_With32,
+    kCvSymType_Label32,
+    kCvSymType_CExModel32,
+    kCvSymType_VftPath32,
+    kCvSymType_RegRel32,
+    kCvSymType_LThread32,
+    kCvSymType_GThread32,
+    /** @}  */
+
+    /** @name Symbols for MIPS.
+     * @{ */
+    kCvSymType_LProcMips = 0x0300,
+    kCvSymType_GProcMips,
+    /** @} */
+
+    /** @name Symbols for Microsoft CodeView.
+     * @{ */
+    kCvSymType_ProcRef,
+    kCvSymType_DataRef,
+    kCvSymType_Align,
+    /** @} */
+} RTCVSYMTYPE;
+typedef RTCVSYMTYPE *PRTCVSYMTYPE;
+typedef RTCVSYMTYPE const *PCRTCVSYMTYPE;
+
+
+/** The $$SYMBOL table signature for CV4. */
+#define RTCVSYMBOLS_SIGNATURE_CV4   UINT32_C(0x00000001)
+
+
 
 
@@ -303,4 +505,15 @@
     /** The directory (converted to 32-bit). */
     PRTCVDIRENT32   paDirEnts;
+    /** Current debugging style when parsing modules. */
+    uint16_t        uCurStyle;
+    /** Current debugging style version (HLL only). */
+    uint16_t        uCurStyleVer;
+
+    /** The segment map (if present). */
+    PRTCVSEGMAP     pSegMap;
+    /** Segment names. */
+    char           *pszzSegNames;
+    /** The size of the segment names. */
+    uint32_t        cbSegNames;
 
     /** @}  */
@@ -313,14 +526,81 @@
 
 
+
+/**
+ * Subsection callback.
+ *
+ * @returns IPRT status code.
+ * @param   pThis           The CodeView debug info reader instance.
+ * @param   pvSubSect       Pointer to the subsection data.
+ * @param   cbSubSect       The size of the subsection data.
+ * @param   pDirEnt         The directory entry.
+ */
+typedef DECLCALLBACK(int) FNDBGMODCVSUBSECTCALLBACK(PRTDBGMODCV pThis, void const *pvSubSect, size_t cbSubSect,
+                                                    PCRTCVDIRENT32 pDirEnt);
+/** Pointer to a subsection callback. */
+typedef FNDBGMODCVSUBSECTCALLBACK *PFNDBGMODCVSUBSECTCALLBACK;
+
+
+
+/*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+/** Light weight assert + return w/ fixed status code. */
+#define RTDBGMODCV_CHECK_RET_BF(a_Expr, a_LogArgs) \
+    do { \
+        if (!(a_Expr)) \
+        { \
+            Log(("RTDbgCv: Check failed on line %d: " #a_Expr "\n", __LINE__)); \
+            Log(a_LogArgs); \
+            return VERR_CV_BAD_FORMAT; \
+        } \
+    } while (0)
+
+
+/** Light weight assert + return w/ fixed status code. */
+#define RTDBGMODCV_CHECK_NOMSG_RET_BF(a_Expr) \
+    do { \
+        if (!(a_Expr)) \
+        { \
+            Log(("RTDbgCv: Check failed on line %d: " #a_Expr "\n", __LINE__)); \
+            return VERR_CV_BAD_FORMAT; \
+        } \
+    } while (0)
+
+
+
+
+
 static int rtDbgModCvReadAt(PRTDBGMODCV pThis, uint32_t off, void *pvBuf, size_t cb)
 {
     int rc;
     if (pThis->hFile == NIL_RTFILE)
-        rc = pThis->pMod->pImgVt->pfnReadAt(pThis->pMod, UINT32_MAX, off, pvBuf, cb);
+        rc = pThis->pMod->pImgVt->pfnReadAt(pThis->pMod, UINT32_MAX, off + pThis->offBase, pvBuf, cb);
     else
-        rc = RTFileReadAt(pThis->hFile, off, pvBuf, cb, NULL);
+        rc = RTFileReadAt(pThis->hFile, off + pThis->offBase, pvBuf, cb, NULL);
     return rc;
 }
 
+
+static int rtDbgModCvReadAtAlloc(PRTDBGMODCV pThis, uint32_t off, void **ppvBuf, size_t cb)
+{
+    int   rc;
+    void *pvBuf = *ppvBuf = RTMemAlloc(cb);
+    if (pvBuf)
+    {
+        if (pThis->hFile == NIL_RTFILE)
+            rc = pThis->pMod->pImgVt->pfnReadAt(pThis->pMod, UINT32_MAX, off + pThis->offBase, pvBuf, cb);
+        else
+            rc = RTFileReadAt(pThis->hFile, off + pThis->offBase, pvBuf, cb, NULL);
+        if (RT_SUCCESS(rc))
+            return VINF_SUCCESS;
+
+        RTMemFree(pvBuf);
+        *ppvBuf = NULL;
+    }
+    else
+        rc = VERR_NO_MEMORY;
+    return rc;
+}
 
 
@@ -375,4 +655,410 @@
 
 /**
+ * Adds a symbol to the container.
+ *
+ * @returns IPRT status code
+ * @param   pThis               The CodeView debug info reader instance.
+ * @param   iSeg                Segment number.
+ * @param   off                 Offset into the segment
+ * @param   pchName             The symbol name (not necessarily terminated).
+ * @param   cchName             The symbol name length.
+ * @param   fFlags              Flags reserved for future exploits, MBZ.
+ */
+static int rtDbgModCvAddSymbol(PRTDBGMODCV pThis, uint32_t iSeg, uint64_t off, const char *pchName,
+                               uint8_t cchName, uint32_t fFlags)
+{
+    const char *pszName = RTStrCacheEnterN(g_hDbgModStrCache, pchName, cchName);
+    if (!pszName)
+        return VERR_NO_STR_MEMORY;
+#if 1
+    if (iSeg == 0)
+        iSeg = RTDBGSEGIDX_ABS;
+    else if (pThis->pSegMap)
+    {
+        if (   iSeg > pThis->pSegMap->Hdr.cSegs
+            || iSeg == 0
+            || off > pThis->pSegMap->aDescs[iSeg - 1].cb)
+        {
+            Log(("Invalid segment index/offset %#06x:%08x for symbol %.*s\n", iSeg, off, cchName, pchName));
+            return VERR_CV_BAD_FORMAT;
+        }
+        off += pThis->pSegMap->aDescs[iSeg - 1].off;
+        if (pThis->pSegMap->aDescs[iSeg - 1].fFlags & RTCVSEGMAPDESC_F_ABS)
+            iSeg = RTDBGSEGIDX_ABS;
+        else
+            iSeg = pThis->pSegMap->aDescs[iSeg - 1].iGroup;
+    }
+
+    int rc = RTDbgModSymbolAdd(pThis->hCnt, pszName, iSeg, off, 0, 0 /*fFlags*/, NULL);
+    Log(("Symbol: %04x:%08x %.*s [%Rrc]\n", iSeg, off, cchName, pchName, rc));
+    if (rc == VERR_DBG_ADDRESS_CONFLICT || rc == VERR_DBG_DUPLICATE_SYMBOL)
+        rc = VINF_SUCCESS;
+    RTStrCacheRelease(g_hDbgModStrCache, pszName);
+    return rc;
+#else
+    Log(("Symbol: %04x:%08x %.*s\n", iSeg, off, cchName, pchName));
+    return VINF_SUCCESS;
+#endif
+}
+
+
+/**
+ * Parses a CV4 symbol table, adding symbols to the container.
+ *
+ * @returns IPRT status code
+ * @param   pThis               The CodeView debug info reader instance.
+ * @param   pbSymTab            The symbol table.
+ * @param   cbSymTab            The size of the symbol table.
+ * @param   fFlags              Flags reserved for future exploits, MBZ.
+ */
+static int rtDbgModCvSsProcessV4SymTab(PRTDBGMODCV pThis, void const *pvSymTab, size_t cbSymTab, uint32_t fFlags)
+{
+    int         rc = VINF_SUCCESS;
+    RTCPTRUNION uCursor;
+    uCursor.pv = pvSymTab;
+
+    while (cbSymTab > 0 && RT_SUCCESS(rc))
+    {
+        uint8_t const * const pbRecStart = uCursor.pu8;
+        uint16_t cbRec = *uCursor.pu16++;
+        if (cbRec >= 2)
+        {
+            uint16_t uSymType = *uCursor.pu16++;
+
+            Log3(("    %p: uSymType=%#06x LB %#x\n", pbRecStart - (uint8_t *)pvSymTab, uSymType, cbRec));
+            RTDBGMODCV_CHECK_RET_BF(cbRec >= 2 && cbRec <= cbSymTab, ("cbRec=%#x cbSymTab=%#x\n", cbRec, cbSymTab));
+
+            switch (uSymType)
+            {
+                case kCvSymType_LData16:
+                case kCvSymType_GData16:
+                case kCvSymType_Pub16:
+                {
+                    RTDBGMODCV_CHECK_NOMSG_RET_BF(cbRec > 2 + 2+2+2+1);
+                    uint16_t off     = *uCursor.pu16++;
+                    uint16_t iSeg    = *uCursor.pu16++;
+                    /*uint16_t iType   =*/ *uCursor.pu16++;
+                    uint8_t  cchName = *uCursor.pu8++;
+                    RTDBGMODCV_CHECK_NOMSG_RET_BF(cchName > 0);
+                    RTDBGMODCV_CHECK_NOMSG_RET_BF(cbRec >= 2 + 2+2+2+1 + cchName);
+
+                    rc = rtDbgModCvAddSymbol(pThis, iSeg, off, uCursor.pch, cchName, 0);
+                    break;
+                }
+
+                case kCvSymType_LData32:
+                case kCvSymType_GData32:
+                case kCvSymType_Pub32:
+                {
+                    RTDBGMODCV_CHECK_NOMSG_RET_BF(cbRec > 2 + 4+2+2+1);
+                    uint32_t off     = *uCursor.pu32++;
+                    uint16_t iSeg    = *uCursor.pu16++;
+                    /*uint16_t iType   =*/ *uCursor.pu16++;
+                    uint8_t  cchName = *uCursor.pu8++;
+                    RTDBGMODCV_CHECK_NOMSG_RET_BF(cchName > 0);
+                    RTDBGMODCV_CHECK_NOMSG_RET_BF(cbRec >= 2 + 4+2+2+1 + cchName);
+
+                    rc = rtDbgModCvAddSymbol(pThis, iSeg, off, uCursor.pch, cchName, 0);
+                    break;
+                }
+
+                /** @todo add GProc and LProc so we can gather sizes as well as just symbols. */
+            }
+        }
+        /*else: shorter records can be used for alignment, I guess. */
+
+        /* next */
+        uCursor.pu8 = pbRecStart + cbRec + 2;
+        cbSymTab   -= cbRec + 2;
+    }
+    return rc;
+}
+
+
+/** @callback_method_impl{FNDBGMODCVSUBSECTCALLBACK,
+ * Parses kCvSst_GlobalPub, kCvSst_GlobalSym and kCvSst_StaticSym subsections,
+ * adding symbols it finds to the container.} */
+static DECLCALLBACK(int)
+rtDbgModCvSs_GlobalPub_GlobalSym_StaticSym(PRTDBGMODCV pThis, void const *pvSubSect, size_t cbSubSect, PCRTCVDIRENT32 pDirEnt)
+{
+    PCRTCVGLOBALSYMTABHDR pHdr = (PCRTCVGLOBALSYMTABHDR)pvSubSect;
+
+    /*
+     * Quick data validation.
+     */
+    Log2(("RTDbgModCv: %s: uSymHash=%#x uAddrHash=%#x cbSymbols=%#x cbSymHash=%#x cbAddrHash=%#x\n",
+          rtDbgModCvGetSubSectionName(pDirEnt->uSubSectType), pHdr->uSymHash,
+          pHdr->uAddrHash, pHdr->cbSymbols, pHdr->cbSymHash, pHdr->cbAddrHash));
+    RTDBGMODCV_CHECK_NOMSG_RET_BF(cbSubSect >= sizeof(RTCVGLOBALSYMTABHDR));
+    RTDBGMODCV_CHECK_NOMSG_RET_BF((uint64_t)pHdr->cbSymbols + pHdr->cbSymHash + pHdr->cbAddrHash <= cbSubSect - sizeof(*pHdr));
+    RTDBGMODCV_CHECK_NOMSG_RET_BF(pHdr->uSymHash  < 0x20);
+    RTDBGMODCV_CHECK_NOMSG_RET_BF(pHdr->uAddrHash < 0x20);
+    if (!pHdr->cbSymbols)
+        return VINF_SUCCESS;
+
+    /*
+     * Parse the symbols.
+     */
+    return rtDbgModCvSsProcessV4SymTab(pThis, pHdr + 1, pHdr->cbSymbols, 0);
+}
+
+
+/** @callback_method_impl{FNDBGMODCVSUBSECTCALLBACK,
+ * Parses kCvSst_Module subsection, storing the debugging style in pThis.} */
+static DECLCALLBACK(int)
+rtDbgModCvSs_Module(PRTDBGMODCV pThis, void const *pvSubSect, size_t cbSubSect, PCRTCVDIRENT32 pDirEnt)
+{
+    RTCPTRUNION uCursor;
+    uCursor.pv = pvSubSect;
+    RTDBGMODCV_CHECK_NOMSG_RET_BF(cbSubSect >= 2 + 2 + 2 + 2 + 0 + 1);
+    uint16_t iOverlay = *uCursor.pu16++;
+    uint16_t iLib     = *uCursor.pu16++;
+    uint16_t cSegs    = *uCursor.pu16++;
+    pThis->uCurStyle  = *uCursor.pu16++;
+    if (pThis->uCurStyle == 0)
+        pThis->uCurStyle = RT_MAKE_U16('C', 'V');
+    pThis->uCurStyleVer = 0;
+    uint8_t cchName   = uCursor.pu8[cSegs * 12];
+    RTDBGMODCV_CHECK_NOMSG_RET_BF(cbSubSect >= 2 + 2 + 2 + 2 + cSegs * 12U + 1 + cchName);
+
+    const char *pchName = (const char *)&uCursor.pu8[cSegs * 12 + 1];
+    Log2(("RTDbgModCv: Module: iOverlay=%#x iLib=%#x cSegs=%#x Style=%c%c (%#x) %.*s\n", iOverlay, iLib, cSegs,
+          RT_BYTE1(pThis->uCurStyle), RT_BYTE2(pThis->uCurStyle), pThis->uCurStyle, cchName, pchName));
+    RTDBGMODCV_CHECK_NOMSG_RET_BF(pThis->uCurStyle == RT_MAKE_U16('C', 'V'));
+
+    PCRTCVMODSEGINFO32 paSegs = (PCRTCVMODSEGINFO32)uCursor.pv;
+    for (uint16_t iSeg = 0; iSeg < cSegs; iSeg++)
+        Log2(("    #%02u: %04x:%08x LB %08x\n", iSeg, paSegs[iSeg].iSeg, paSegs[iSeg].off, paSegs[iSeg].cb));
+
+    return VINF_SUCCESS;
+}
+
+
+/** @callback_method_impl{FNDBGMODCVSUBSECTCALLBACK,
+ * Parses kCvSst_Symbols, kCvSst_PublicSym and kCvSst_AlignSym subsections,
+ * adding symbols it finds to the container.} */
+static DECLCALLBACK(int)
+rtDbgModCvSs_Symbols_PublicSym_AlignSym(PRTDBGMODCV pThis, void const *pvSubSect, size_t cbSubSect, PCRTCVDIRENT32 pDirEnt)
+{
+    RTDBGMODCV_CHECK_NOMSG_RET_BF(pThis->uCurStyle == RT_MAKE_U16('C', 'V'));
+    RTDBGMODCV_CHECK_NOMSG_RET_BF(cbSubSect >= 8);
+
+    uint32_t u32Signature = *(uint32_t const *)pvSubSect;
+    RTDBGMODCV_CHECK_RET_BF(u32Signature == RTCVSYMBOLS_SIGNATURE_CV4,
+                            ("%#x, expected %#x\n", u32Signature, RTCVSYMBOLS_SIGNATURE_CV4));
+
+    return rtDbgModCvSsProcessV4SymTab(pThis, (uint8_t const *)pvSubSect + 4, cbSubSect - 4, 0);
+}
+
+
+static int rtDbgModCvLoadSegmentMap(PRTDBGMODCV pThis)
+{
+    /*
+     * Search for the segment map and segment names. They will be at the end of the directory.
+     */
+    uint32_t iSegMap   = UINT32_MAX;
+    uint32_t iSegNames = UINT32_MAX;
+    uint32_t i = pThis->cDirEnts;
+    while (i-- > 0)
+    {
+        if (   pThis->paDirEnts[i].iMod != 0xffff
+            && pThis->paDirEnts[i].iMod != 0x0000)
+            break;
+        if (pThis->paDirEnts[i].uSubSectType == kCvSst_SegMap)
+            iSegMap = i;
+        else if (pThis->paDirEnts[i].uSubSectType == kCvSst_SegName)
+            iSegNames = i;
+    }
+    if (iSegMap == UINT32_MAX)
+    {
+        Log(("RTDbgModCv: No segment map present, using segment indexes as is then...\n"));
+        return VINF_SUCCESS;
+    }
+    RTDBGMODCV_CHECK_RET_BF(pThis->paDirEnts[iSegMap].cb >= sizeof(RTCVSEGMAPHDR),
+                            ("Bad sstSegMap entry: cb=%#x\n", pThis->paDirEnts[iSegMap].cb));
+    RTDBGMODCV_CHECK_NOMSG_RET_BF(iSegNames == UINT32_MAX || pThis->paDirEnts[iSegNames].cb > 0);
+
+    /*
+     * Read them into memory.
+     */
+    int rc = rtDbgModCvReadAtAlloc(pThis, pThis->paDirEnts[iSegMap].off, (void **)&pThis->pSegMap,
+                                   pThis->paDirEnts[iSegMap].cb);
+    if (iSegNames != UINT32_MAX && RT_SUCCESS(rc))
+    {
+        pThis->cbSegNames = pThis->paDirEnts[iSegNames].cb;
+        rc = rtDbgModCvReadAtAlloc(pThis, pThis->paDirEnts[iSegNames].off, (void **)&pThis->pszzSegNames,
+                                   pThis->paDirEnts[iSegNames].cb);
+    }
+    if (RT_FAILURE(rc))
+        return rc;
+    RTDBGMODCV_CHECK_NOMSG_RET_BF(!pThis->pszzSegNames || !pThis->pszzSegNames[pThis->cbSegNames - 1]); /* must be terminated */
+
+    /* Use local pointers to avoid lots of indirection and typing. */
+    PCRTCVSEGMAPHDR  pHdr    = &pThis->pSegMap->Hdr;
+    PRTCVSEGMAPDESC  paDescs = &pThis->pSegMap->aDescs[0];
+
+    /*
+     * If there are only logical segments, assume a direct mapping.
+     * PE images, like the NT4 kernel, does it like this.
+     */
+    bool const fNoGroups = pHdr->cSegs == pHdr->cLogSegs;
+
+    /*
+     * Validate and display it all.
+     */
+    Log2(("RTDbgModCv: SegMap: cSegs=%#x cLogSegs=%#x (cbSegNames=%#x)\n", pHdr->cSegs, pHdr->cLogSegs, pThis->cbSegNames));
+    RTDBGMODCV_CHECK_RET_BF(pThis->paDirEnts[iSegMap].cb >= sizeof(*pHdr) + pHdr->cSegs * sizeof(paDescs[0]),
+                            ("SegMap is out of bounds: cbSubSect=%#x cSegs=%#x\n", pThis->paDirEnts[iSegMap].cb, pHdr->cSegs));
+    RTDBGMODCV_CHECK_NOMSG_RET_BF(pHdr->cSegs >= pHdr->cLogSegs);
+
+    Log2(("Logical segment descriptors: %u\n", pHdr->cLogSegs));
+    for (uint16_t i = 0; i < pHdr->cSegs; i++)
+    {
+        if (i == pHdr->cLogSegs)
+            Log2(("Group/Physical descriptors: %u\n", pHdr->cSegs - pHdr->cLogSegs));
+        uint16_t idx = i < pHdr->cLogSegs ? i : i - pHdr->cLogSegs;
+        char szFlags[16];
+        memset(szFlags, '-', sizeof(szFlags));
+        if (paDescs[i].fFlags & RTCVSEGMAPDESC_F_READ)
+            szFlags[0] = 'R';
+        if (paDescs[i].fFlags & RTCVSEGMAPDESC_F_WRITE)
+            szFlags[1] = 'W';
+        if (paDescs[i].fFlags & RTCVSEGMAPDESC_F_EXECUTE)
+            szFlags[2] = 'X';
+        if (paDescs[i].fFlags & RTCVSEGMAPDESC_F_32BIT)
+            szFlags[3] = '3', szFlags[4]  = '2';
+        if (paDescs[i].fFlags & RTCVSEGMAPDESC_F_SEL)
+            szFlags[5] = 'S';
+        if (paDescs[i].fFlags & RTCVSEGMAPDESC_F_ABS)
+            szFlags[6] = 'A';
+        if (paDescs[i].fFlags & RTCVSEGMAPDESC_F_GROUP)
+            szFlags[7] = 'G';
+        szFlags[8] = '\0';
+        if (paDescs[i].fFlags & RTCVSEGMAPDESC_F_RESERVED)
+            szFlags[8]  = '!', szFlags[9] = '\0';
+        Log2(("    #%02u: %#010x LB %#010x flags=%#06x ovl=%#06x group=%#06x frame=%#06x iSegName=%#06x iClassName=%#06x %s\n",
+              idx, paDescs[i].off, paDescs[i].cb, paDescs[i].fFlags, paDescs[i].iOverlay, paDescs[i].iGroup,
+              paDescs[i].iFrame, paDescs[i].offSegName, paDescs[i].offClassName, szFlags));
+
+        RTDBGMODCV_CHECK_NOMSG_RET_BF(paDescs[i].offSegName == UINT16_MAX || paDescs[i].offSegName < pThis->cbSegNames);
+        RTDBGMODCV_CHECK_NOMSG_RET_BF(paDescs[i].offClassName == UINT16_MAX || paDescs[i].offClassName < pThis->cbSegNames);
+        const char *pszName  = paDescs[i].offSegName   != UINT16_MAX
+                             ? pThis->pszzSegNames + paDescs[i].offSegName
+                             : NULL;
+        const char *pszClass = paDescs[i].offClassName != UINT16_MAX
+                             ? pThis->pszzSegNames + paDescs[i].offClassName
+                             : NULL;
+        if (pszName || pszClass)
+            Log2(("              pszName=%s pszClass=%s\n", pszName, pszClass));
+
+        /* Validate the group link. */
+        RTDBGMODCV_CHECK_NOMSG_RET_BF(paDescs[i].iGroup == 0 || !(paDescs[i].fFlags & RTCVSEGMAPDESC_F_GROUP));
+        RTDBGMODCV_CHECK_NOMSG_RET_BF(   paDescs[i].iGroup == 0
+                                      || (   paDescs[i].iGroup >= pHdr->cLogSegs
+                                          && paDescs[i].iGroup <  pHdr->cSegs));
+        RTDBGMODCV_CHECK_NOMSG_RET_BF(   paDescs[i].iGroup == 0
+                                      || (paDescs[paDescs[i].iGroup].fFlags & RTCVSEGMAPDESC_F_GROUP));
+        RTDBGMODCV_CHECK_NOMSG_RET_BF(!(paDescs[i].fFlags & RTCVSEGMAPDESC_F_GROUP) || paDescs[i].off == 0); /* assumed below */
+
+        if (fNoGroups)
+        {
+            RTDBGMODCV_CHECK_NOMSG_RET_BF(paDescs[i].iGroup == 0);
+            RTDBGMODCV_CHECK_NOMSG_RET_BF(paDescs[i].off == 0);
+        }
+    }
+
+    /*
+     * Modify the groups index to be the loader segment index instead, also
+     * add the segments to the container if we haven't done that already.
+     */
+
+    /* Guess work: Group can be implicit if used.  Observed Visual C++ v1.5,
+       omitting the CODE group. */
+    const char *pszGroup0 = NULL;
+    uint64_t    cbGroup0  = 0;
+    if (!fNoGroups)
+    {
+        for (uint16_t i = 0; i < pHdr->cSegs; i++)
+            if (   !(paDescs[i].fFlags & (RTCVSEGMAPDESC_F_GROUP | RTCVSEGMAPDESC_F_ABS))
+                && paDescs[i].iGroup == 0)
+            {
+                if (pszGroup0 == NULL && paDescs[i].offClassName != UINT16_MAX)
+                    pszGroup0 = pThis->pszzSegNames + paDescs[i].offClassName;
+                uint64_t offEnd = (uint64_t)paDescs[i].off + paDescs[i].cb;
+                if (offEnd > cbGroup0)
+                    cbGroup0 = offEnd;
+            }
+    }
+
+    /* Add the segments.
+       Note! The RVAs derived from this exercise are all wrong. :-/
+       Note! We don't have an image loader, so we cannot add any fake sections. */
+    /** @todo Try see if we can figure something out from the frame value later. */
+    if (!pThis->fHaveLoadedSegments)
+    {
+        Assert(!pThis->pMod->pImgVt); Assert(pThis->enmType != RTCVFILETYPE_DBG);
+        uint16_t iSeg = 0;
+        uint64_t uRva = 0;
+        if (cbGroup0 && !fNoGroups)
+        {
+            rc = RTDbgModSegmentAdd(pThis->hCnt, 0, cbGroup0, pszGroup0 ? pszGroup0 : "Seg00", 0 /*fFlags*/, NULL);
+            uRva += cbGroup0;
+            iSeg++;
+        }
+
+        for (uint32_t i = 0; RT_SUCCESS(rc) && i < pHdr->cSegs; i++)
+            if ((paDescs[i].fFlags & RTCVSEGMAPDESC_F_GROUP) || fNoGroups)
+            {
+                char szName[16];
+                char *pszName = szName;
+                if (paDescs[i].offSegName != UINT16_MAX)
+                    pszName = pThis->pszzSegNames + paDescs[i].offSegName;
+                else
+                    RTStrPrintf(szName, sizeof(szName), "Seg%02u", iSeg);
+                rc = RTDbgModSegmentAdd(pThis->hCnt, uRva, paDescs[i].cb, pszName, 0 /*fFlags*/, NULL);
+                uRva += paDescs[i].cb;
+                iSeg++;
+            }
+
+        if (RT_FAILURE(rc))
+        {
+            Log(("RTDbgModCv: %Rrc while adding segments from SegMap\n", rc));
+            return rc;
+        }
+
+        pThis->fHaveLoadedSegments = true;
+    }
+
+    /* The PE image has an extra section/segment for the headers, the others doesn't. */
+    RTLDRFMT enmImgFmt = RTLDRFMT_INVALID;
+    if (pThis->pMod->pImgVt)
+        enmImgFmt = pThis->pMod->pImgVt->pfnGetFormat(pThis->pMod);
+
+    /* Pass one: Fixate the group segment indexes. */
+    uint16_t iSeg0 = enmImgFmt == RTLDRFMT_PE || pThis->enmType == RTCVFILETYPE_DBG ? 1 : 0;
+    uint16_t iSeg = iSeg0 + cbGroup0 > 0;
+    for (uint16_t i = 0; i < pHdr->cSegs; i++)
+        if (paDescs[i].fFlags & RTCVSEGMAPDESC_F_ABS)
+            paDescs[i].iGroup = (uint16_t)RTDBGSEGIDX_ABS;
+        else if ((paDescs[i].fFlags & RTCVSEGMAPDESC_F_GROUP) || fNoGroups)
+            paDescs[i].iGroup = iSeg++;
+
+    /* Pass two: Resolve group references in to segment indexes. */
+    Log2(("Mapped segments (both kinds):\n"));
+    for (uint16_t i = 0; i < pHdr->cSegs; i++)
+    {
+        if (!fNoGroups && !(paDescs[i].fFlags & (RTCVSEGMAPDESC_F_GROUP | RTCVSEGMAPDESC_F_ABS)))
+            paDescs[i].iGroup = paDescs[i].iGroup == 0 ? iSeg0 : paDescs[paDescs[i].iGroup].iGroup;
+
+        Log2(("    #%02u: %#010x LB %#010x -> %#06x (flags=%#06x ovl=%#06x frame=%#06x)\n",
+              i, paDescs[i].off, paDescs[i].cb, paDescs[i].iGroup,
+              paDescs[i].fFlags, paDescs[i].iOverlay, paDescs[i].iFrame));
+    }
+
+    return VINF_SUCCESS;
+}
+
+
+/**
  * Loads the directory into memory (RTDBGMODCV::paDirEnts and
  * RTDBGMODCV::cDirEnts).
@@ -398,5 +1084,5 @@
          */
         RTCVDIRHDR16 DirHdr;
-        rc = rtDbgModCvReadAt(pThis, pThis->offBase + pThis->offDir, &DirHdr, sizeof(DirHdr));
+        rc = rtDbgModCvReadAt(pThis, pThis->offDir, &DirHdr, sizeof(DirHdr));
         if (RT_SUCCESS(rc))
         {
@@ -407,5 +1093,5 @@
                 if (pThis->paDirEnts)
                 {
-                    rc = rtDbgModCvReadAt(pThis, pThis->offBase + pThis->offDir + sizeof(DirHdr),
+                    rc = rtDbgModCvReadAt(pThis, pThis->offDir + sizeof(DirHdr),
                                           pThis->paDirEnts, DirHdr.cEntries * sizeof(RTCVDIRENT16));
                     if (RT_SUCCESS(rc))
@@ -443,5 +1129,5 @@
          */
         RTCVDIRHDR32EX DirHdr;
-        rc = rtDbgModCvReadAt(pThis, pThis->offBase + pThis->offDir, &DirHdr, sizeof(DirHdr));
+        rc = rtDbgModCvReadAt(pThis, pThis->offDir, &DirHdr, sizeof(DirHdr));
         if (RT_SUCCESS(rc))
         {
@@ -475,5 +1161,5 @@
                 pThis->paDirEnts = (PRTCVDIRENT32)RTMemAlloc(DirHdr.Core.cEntries * sizeof(pThis->paDirEnts[0]));
                 if (pThis->paDirEnts)
-                    rc = rtDbgModCvReadAt(pThis, pThis->offBase + pThis->offDir + DirHdr.Core.cbHdr,
+                    rc = rtDbgModCvReadAt(pThis, pThis->offDir + DirHdr.Core.cbHdr,
                                           pThis->paDirEnts, DirHdr.Core.cEntries * sizeof(RTCVDIRENT32));
                 else
@@ -488,4 +1174,5 @@
     if (RT_SUCCESS(rc))
     {
+        uint16_t       iMod      = 0;
         uint32_t const cbDbgInfo = pThis->cbDbgInfo;
         uint32_t const cDirEnts  = pThis->cDirEnts;
@@ -513,4 +1200,26 @@
                 rc = VERR_CV_BAD_FORMAT;
             }
+            if (   pDirEnt->iMod < iMod
+                && (   pDirEnt->iMod != 0
+                    || (   pThis->u32CvMagic != RTCVHDR_MAGIC_NB00 /* May be first, maybe last. */
+                        && pThis->u32CvMagic != RTCVHDR_MAGIC_NB02
+                        && pThis->u32CvMagic != RTCVHDR_MAGIC_NB04) ) )
+            {
+                Log(("CV directory entry #%u is out of module order, this mod %u, prev mod %#u\n", i, pDirEnt->iMod, iMod));
+                rc = VERR_CV_BAD_FORMAT;
+            }
+            if (pDirEnt->iMod != iMod)
+            {
+                iMod = pDirEnt->iMod;
+                if (   iMod != 0
+                    && iMod != 0xffff
+                    && pDirEnt->uSubSectType != kCvSst_Module
+                    && pDirEnt->uSubSectType != kCvSst_OldModule)
+                {
+                    Log(("CV directory entry #%u: expected module subsection first, found %s (%#x)\n",
+                         i, rtDbgModCvGetSubSectionName(pDirEnt->uSubSectType), pDirEnt->uSubSectType));
+                    rc = VERR_CV_BAD_FORMAT;
+                }
+            }
         }
     }
@@ -520,34 +1229,90 @@
 
 
-
 static int rtDbgModCvLoadInfo(PRTDBGMODCV pThis)
 {
     /*
-     * Load the directory and segments.
+     * Load the directory, the segment map (if any) and then scan for segments
+     * if necessary.
      */
     int rc = rtDbgModCvLoadDirectory(pThis);
+    if (RT_SUCCESS(rc))
+        rc = rtDbgModCvLoadSegmentMap(pThis);
     if (RT_SUCCESS(rc) && !pThis->fHaveLoadedSegments)
+    {
         rc = VERR_CV_TODO; /** @todo Scan anything containing address, in particular sstSegMap and sstModule,
                             * and reconstruct the segments from that information. */
-
-    /*
-     * Load segment map, if present.
-     */
-    //if (RT_SUCCESS(rc))
-    //    rc = rtDbgModCvLoadGlobals(pThis);
+        pThis->cbImage = 0x1000;
+        rc = VINF_SUCCESS;
+    }
 
     /*
      * Process the directory.
      */
-    uint32_t i = pThis->cDirEnts;
-    while (i-- > 0)
-    {
-#if 0
-        if (   pThis->paDirEnts[i].uSubSectType == kCvSst_OldPublic
-            || pThis->paDirEnts[i].uSubSectType == kCvSst_Public
-            )
+    for (uint32_t i = 0; RT_SUCCESS(rc) && i < pThis->cDirEnts; i++)
+    {
+        PCRTCVDIRENT32              pDirEnt     = &pThis->paDirEnts[i];
+        Log3(("Processing subsection %#u %s\n", i, rtDbgModCvGetSubSectionName(pDirEnt->uSubSectType)));
+        PFNDBGMODCVSUBSECTCALLBACK  pfnCallback = NULL;
+        switch (pDirEnt->uSubSectType)
         {
+            case kCvSst_GlobalPub:
+            case kCvSst_GlobalSym:
+            case kCvSst_StaticSym:
+                pfnCallback = rtDbgModCvSs_GlobalPub_GlobalSym_StaticSym;
+                break;
+            case kCvSst_Module:
+                pfnCallback = rtDbgModCvSs_Module;
+                break;
+            case kCvSst_PublicSym:
+            case kCvSst_Symbols:
+            case kCvSst_AlignSym:
+                pfnCallback = rtDbgModCvSs_Symbols_PublicSym_AlignSym;
+                break;
+
+            case kCvSst_OldModule:
+            case kCvSst_OldPublic:
+            case kCvSst_OldTypes:
+            case kCvSst_OldSymbols:
+            case kCvSst_OldSrcLines:
+            case kCvSst_OldLibraries:
+            case kCvSst_OldImports:
+            case kCvSst_OldCompacted:
+            case kCvSst_OldSrcLnSeg:
+            case kCvSst_OldSrcLines3:
+
+            case kCvSst_Types:
+            case kCvSst_Public:
+            case kCvSst_SrcLnSeg:
+            case kCvSst_SrcModule:
+            case kCvSst_Libraries:
+            case kCvSst_GlobalTypes:
+            case kCvSst_MPC:
+            case kCvSst_PreComp:
+            case kCvSst_PreCompMap:
+            case kCvSst_OffsetMap16:
+            case kCvSst_OffsetMap32:
+            case kCvSst_FileIndex:
+
+            default:
+                /** @todo implement more. */
+                break;
+
+            /* Skip because we've already processed them: */
+            case kCvSst_SegMap:
+            case kCvSst_SegName:
+                pfnCallback = NULL;
+                break;
         }
-#endif
+
+        if (pfnCallback)
+        {
+            void *pvSubSect;
+            rc = rtDbgModCvReadAtAlloc(pThis, pDirEnt->off, &pvSubSect, pDirEnt->cb);
+            if (RT_SUCCESS(rc))
+            {
+                rc = pfnCallback(pThis, pvSubSect, pDirEnt->cb, pDirEnt);
+                RTMemFree(pvSubSect);
+            }
+        }
     }
 
@@ -905,4 +1670,5 @@
                     pThis->offDir     = pCvHdr->off;
                     pThis->hFile      = hFile;
+                    pThis->pMod       = pDbgMod;
                     return VINF_CALLBACK_RETURN;
                 }
