Index: /trunk/src/VBox/Debugger/DBGCDumpImage.cpp
===================================================================
--- /trunk/src/VBox/Debugger/DBGCDumpImage.cpp	(revision 73147)
+++ /trunk/src/VBox/Debugger/DBGCDumpImage.cpp	(revision 73148)
@@ -39,6 +39,42 @@
 #include <iprt/formats/elf32.h>
 #include <iprt/formats/elf64.h>
+#include <iprt/formats/codeview.h>
 
 #include "DBGCInternal.h"
+
+
+/*********************************************************************************************************************************
+*   Structures and Typedefs                                                                                                      *
+*********************************************************************************************************************************/
+/**
+ * PE dumper instance.
+ */
+typedef struct DUMPIMAGEPE
+{
+    /** Pointer to the image base address variable. */
+    PCDBGCVAR                   pImageBase;
+    /** Pointer to the file header. */
+    PCIMAGE_FILE_HEADER         pFileHdr;
+    /** Pointer to the NT headers. */
+    union
+    {
+        PCIMAGE_NT_HEADERS32    pNt32;
+        PCIMAGE_NT_HEADERS64    pNt64;
+        void                   *pv;
+    } u;
+    /** Pointer to the section headers. */
+    PCIMAGE_SECTION_HEADER      paShdrs;
+    /** Number of section headers. */
+    unsigned                    cShdrs;
+    /** Number of RVA and sizes (data directory entries). */
+    unsigned                    cDataDir;
+    /** Pointer to the data directory. */
+    PCIMAGE_DATA_DIRECTORY      paDataDir;
+
+    /** The command descriptor (for failing the command). */
+    PCDBGCCMD                   pCmd;
+} DUMPIMAGEPE;
+/** Pointer to a PE dumper instance. */
+typedef DUMPIMAGEPE *PDUMPIMAGEPE;
 
 
@@ -96,38 +132,199 @@
         case IMAGE_FILE_MACHINE_ARM64        : return "ARM64";
     }
-    return "";
-}
-
-static int dbgcDumpImagePeSectionHdrs(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pImageBase,
-                                      unsigned cShdrs, IMAGE_SECTION_HEADER const *paShdrs)
+    return "??";
+}
+
+
+static const char *dbgcPeDataDirName(unsigned iDir)
+{
+    switch (iDir)
+    {
+        case IMAGE_DIRECTORY_ENTRY_EXPORT:          return "EXPORT";
+        case IMAGE_DIRECTORY_ENTRY_IMPORT:          return "IMPORT";
+        case IMAGE_DIRECTORY_ENTRY_RESOURCE:        return "RESOURCE";
+        case IMAGE_DIRECTORY_ENTRY_EXCEPTION:       return "EXCEPTION";
+        case IMAGE_DIRECTORY_ENTRY_SECURITY:        return "SECURITY";
+        case IMAGE_DIRECTORY_ENTRY_BASERELOC:       return "BASERELOC";
+        case IMAGE_DIRECTORY_ENTRY_DEBUG:           return "DEBUG";
+        case IMAGE_DIRECTORY_ENTRY_ARCHITECTURE:    return "ARCHITECTURE";
+        case IMAGE_DIRECTORY_ENTRY_GLOBALPTR:       return "GLOBALPTR";
+        case IMAGE_DIRECTORY_ENTRY_TLS:             return "TLS";
+        case IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG:     return "LOAD_CONFIG";
+        case IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT:    return "BOUND_IMPORT";
+        case IMAGE_DIRECTORY_ENTRY_IAT:             return "IAT";
+        case IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT:    return "DELAY_IMPORT";
+        case IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR:  return "COM_DESCRIPTOR";
+    }
+    return "??";
+}
+
+
+static const char *dbgPeDebugTypeName(uint32_t uType)
+{
+    switch (uType)
+    {
+        case IMAGE_DEBUG_TYPE_UNKNOWN:       return "UNKNOWN";
+        case IMAGE_DEBUG_TYPE_COFF:          return "COFF";
+        case IMAGE_DEBUG_TYPE_CODEVIEW:      return "CODEVIEW";
+        case IMAGE_DEBUG_TYPE_FPO:           return "FPO";
+        case IMAGE_DEBUG_TYPE_MISC:          return "MISC";
+        case IMAGE_DEBUG_TYPE_EXCEPTION:     return "EXCEPTION";
+        case IMAGE_DEBUG_TYPE_FIXUP:         return "FIXUP";
+        case IMAGE_DEBUG_TYPE_OMAP_TO_SRC:   return "OMAP_TO_SRC";
+        case IMAGE_DEBUG_TYPE_OMAP_FROM_SRC: return "OMAP_FROM_SRC";
+        case IMAGE_DEBUG_TYPE_BORLAND:       return "BORLAND";
+        case IMAGE_DEBUG_TYPE_RESERVED10:    return "RESERVED10";
+        case IMAGE_DEBUG_TYPE_CLSID:         return "CLSID";
+        case IMAGE_DEBUG_TYPE_VC_FEATURE:    return "VC_FEATURE";
+        case IMAGE_DEBUG_TYPE_POGO:          return "POGO";
+        case IMAGE_DEBUG_TYPE_ILTCG:         return "ILTCG";
+        case IMAGE_DEBUG_TYPE_MPX:           return "MPX";
+        case IMAGE_DEBUG_TYPE_REPRO:         return "REPRO";
+    }
+    return "??";
+}
+
+
+static int dbgcDumpImagePeDebugDir(PDUMPIMAGEPE pThis, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pDataAddr, uint32_t cbData)
+{
+    uint32_t cEntries = cbData / sizeof(IMAGE_DEBUG_DIRECTORY);
+    for (uint32_t i = 0; i < cEntries; i++)
+    {
+        /*
+         * Read the entry into memory.
+         */
+        DBGCVAR DbgDirAddr;
+        int rc = DBGCCmdHlpEval(pCmdHlp, &DbgDirAddr, "%DV + %#RX32", pDataAddr, i * sizeof(IMAGE_DEBUG_DIRECTORY));
+        if (RT_FAILURE(rc))
+            return DBGCCmdHlpFailRc(pCmdHlp, pThis->pCmd, rc, "DBGCCmdHlpEval failed on debug entry %u", i);
+
+        IMAGE_DEBUG_DIRECTORY DbgDir;
+        rc = DBGCCmdHlpMemRead(pCmdHlp, &DbgDir, sizeof(DbgDir), &DbgDirAddr, NULL);
+        if (RT_FAILURE(rc))
+            return DBGCCmdHlpFailRc(pCmdHlp, pThis->pCmd, rc, "Failed to read %zu at %Dv", sizeof(DbgDir), &DbgDirAddr);
+
+        /*
+         * Dump it.
+         */
+        DBGCVAR DebugDataAddr = *pThis->pImageBase;
+        rc = DBGCCmdHlpEval(pCmdHlp, &DebugDataAddr, "%DV + %#RX32", pThis->pImageBase, DbgDir.AddressOfRawData);
+        DBGCCmdHlpPrintf(pCmdHlp, "  Debug[%u]: %Dv/%08RX32 LB %06RX32 %u (%s) v%u.%u file=%RX32 ts=%08RX32 fl=%RX32\n",
+                         i, &DebugDataAddr, DbgDir.AddressOfRawData, DbgDir.SizeOfData, DbgDir.Type,
+                         dbgPeDebugTypeName(DbgDir.Type), DbgDir.MajorVersion, DbgDir.MinorVersion, DbgDir.PointerToRawData,
+                         DbgDir.TimeDateStamp, DbgDir.Characteristics);
+        union
+        {
+            uint8_t             abPage[0x1000];
+            CVPDB20INFO         Pdb20;
+            CVPDB70INFO         Pdb70;
+            IMAGE_DEBUG_MISC    Misc;
+        } uBuf;
+        RT_ZERO(uBuf);
+
+        if (DbgDir.Type == IMAGE_DEBUG_TYPE_CODEVIEW)
+        {
+            if (   DbgDir.SizeOfData < sizeof(uBuf)
+                && DbgDir.SizeOfData > 16
+                && DbgDir.AddressOfRawData > 0
+                && RT_SUCCESS(rc))
+            {
+                rc = DBGCCmdHlpMemRead(pCmdHlp, &uBuf, DbgDir.SizeOfData, &DebugDataAddr, NULL);
+                if (RT_FAILURE(rc))
+                    return DBGCCmdHlpFailRc(pCmdHlp, pThis->pCmd, rc, "Failed to read %zu at %Dv",
+                                            DbgDir.SizeOfData, &DebugDataAddr);
+
+                if (   uBuf.Pdb20.u32Magic   == CVPDB20INFO_MAGIC
+                    && uBuf.Pdb20.offDbgInfo == 0
+                    && DbgDir.SizeOfData > RT_UOFFSETOF(CVPDB20INFO, szPdbFilename) )
+                    DBGCCmdHlpPrintf(pCmdHlp, "    PDB2.0: ts=%08RX32 age=%RX32 %s\n",
+                                     uBuf.Pdb20.uTimestamp, uBuf.Pdb20.uAge, uBuf.Pdb20.szPdbFilename);
+                else if (   uBuf.Pdb20.u32Magic == CVPDB70INFO_MAGIC
+                         && DbgDir.SizeOfData > RT_UOFFSETOF(CVPDB70INFO, szPdbFilename) )
+                    DBGCCmdHlpPrintf(pCmdHlp, "    PDB7.0: %RTuuid age=%u %s\n",
+                                     &uBuf.Pdb70.PdbUuid, uBuf.Pdb70.uAge, uBuf.Pdb70.szPdbFilename);
+                else
+                    DBGCCmdHlpPrintf(pCmdHlp, "    Unknown PDB/codeview magic: %.8Rhxs\n", uBuf.abPage);
+            }
+        }
+        else if (DbgDir.Type == IMAGE_DEBUG_TYPE_MISC)
+        {
+            if (   DbgDir.SizeOfData < sizeof(uBuf)
+                && DbgDir.SizeOfData > RT_UOFFSETOF(IMAGE_DEBUG_MISC, Data)
+                && DbgDir.AddressOfRawData > 0
+                && RT_SUCCESS(rc) )
+            {
+                rc = DBGCCmdHlpMemRead(pCmdHlp, &uBuf, DbgDir.SizeOfData, &DebugDataAddr, NULL);
+                if (RT_FAILURE(rc))
+                    return DBGCCmdHlpFailRc(pCmdHlp, pThis->pCmd, rc, "Failed to read %zu at %Dv",
+                                            DbgDir.SizeOfData, &DebugDataAddr);
+
+                if (   uBuf.Misc.DataType == IMAGE_DEBUG_MISC_EXENAME
+                    && uBuf.Misc.Length   == DbgDir.SizeOfData)
+                {
+                    if (!uBuf.Misc.Unicode)
+                        DBGCCmdHlpPrintf(pCmdHlp, "    Misc DBG: ts=%RX32 %s\n",
+                                         DbgDir.TimeDateStamp, (const char *)&uBuf.Misc.Data[0]);
+                    else
+                        DBGCCmdHlpPrintf(pCmdHlp, "    Misc DBG: ts=%RX32 %ls\n",
+                                         DbgDir.TimeDateStamp, (PCRTUTF16)&uBuf.Misc.Data[0]);
+                }
+            }
+        }
+    }
+    return VINF_SUCCESS;
+}
+
+
+static int dbgcDumpImagePeDataDirs(PDUMPIMAGEPE pThis, PDBGCCMDHLP pCmdHlp, unsigned cDataDirs, PCIMAGE_DATA_DIRECTORY paDataDirs)
+{
+    int rcRet = VINF_SUCCESS;
+    for (unsigned i = 0; i < cDataDirs; i++)
+    {
+        if (paDataDirs[i].Size || paDataDirs[i].VirtualAddress)
+        {
+            DBGCVAR DataAddr = *pThis->pImageBase;
+            DBGCCmdHlpEval(pCmdHlp, &DataAddr, "%DV + %#RX32", pThis->pImageBase, paDataDirs[i].VirtualAddress);
+            DBGCCmdHlpPrintf(pCmdHlp, "DataDir[%02u]: %Dv/%08RX32 LB %08RX32 %s\n",
+                             i, &DataAddr, paDataDirs[i].VirtualAddress, paDataDirs[i].Size, dbgcPeDataDirName(i));
+            int rc = VINF_SUCCESS;
+            if (   i == IMAGE_DIRECTORY_ENTRY_DEBUG
+                && paDataDirs[i].Size >= sizeof(IMAGE_DEBUG_DIRECTORY))
+                rc = dbgcDumpImagePeDebugDir(pThis, pCmdHlp, &DataAddr, paDataDirs[i].Size);
+            if (RT_FAILURE(rc) && RT_SUCCESS(rcRet))
+                rcRet = rc;
+        }
+    }
+    return rcRet;
+}
+
+
+static int dbgcDumpImagePeSectionHdrs(PDUMPIMAGEPE pThis, PDBGCCMDHLP pCmdHlp, unsigned cShdrs, PCIMAGE_SECTION_HEADER paShdrs)
 {
     for (unsigned i = 0; i < cShdrs; i++)
     {
-        DBGCVAR SectAddr = *pImageBase;
-        DBGCCmdHlpEval(pCmdHlp, &SectAddr, "%DV + %#RX32", pImageBase, paShdrs[i].VirtualAddress);
-        DBGCCmdHlpPrintf(pCmdHlp, "Section #%u: %Dv/%08RX32 LB %08RX32 %.8s\n",
+        DBGCVAR SectAddr = *pThis->pImageBase;
+        DBGCCmdHlpEval(pCmdHlp, &SectAddr, "%DV + %#RX32", pThis->pImageBase, paShdrs[i].VirtualAddress);
+        DBGCCmdHlpPrintf(pCmdHlp, "Section[%02u]: %Dv/%08RX32 LB %08RX32 %.8s\n",
                          i, &SectAddr, paShdrs[i].VirtualAddress, paShdrs[i].Misc.VirtualSize,  paShdrs[i].Name);
     }
-
-    RT_NOREF(pCmd);
     return VINF_SUCCESS;
 }
 
 
-static int dbgcDumpImagePeOptHdr32(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, IMAGE_NT_HEADERS32 const *pNtHdrs)
-{
-    RT_NOREF(pCmd, pCmdHlp, pNtHdrs);
+static int dbgcDumpImagePeOptHdr32(PDUMPIMAGEPE pThis, PDBGCCMDHLP pCmdHlp, PCIMAGE_NT_HEADERS32 pNtHdrs)
+{
+    RT_NOREF(pThis, pCmdHlp, pNtHdrs);
     return VINF_SUCCESS;
 }
 
-static int dbgcDumpImagePeOptHdr64(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, IMAGE_NT_HEADERS64 const *pNtHdrs)
-{
-    RT_NOREF(pCmd, pCmdHlp, pNtHdrs);
+static int dbgcDumpImagePeOptHdr64(PDUMPIMAGEPE pThis, PDBGCCMDHLP pCmdHlp, PCIMAGE_NT_HEADERS64 pNtHdrs)
+{
+    RT_NOREF(pThis, pCmdHlp, pNtHdrs);
     return VINF_SUCCESS;
 }
 
 
-static int dbgcDumpImagePe(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pImageBase, PCDBGCVAR pPeHdrAddr,
-                           IMAGE_FILE_HEADER const *pFileHdr)
+static int dbgcDumpImagePe(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pImageBase,
+                           PCDBGCVAR pPeHdrAddr, PCIMAGE_FILE_HEADER pFileHdr)
 {
     /*
@@ -169,13 +366,34 @@
     if (RT_SUCCESS(rc))
     {
+        DUMPIMAGEPE This;
+        RT_ZERO(This);
+        This.pImageBase = pImageBase;
+        This.pFileHdr   = pFileHdr;
+        This.u.pv       = pvBuf;
+        This.cShdrs     = pFileHdr->NumberOfSections;
+        This.paShdrs    = (PCIMAGE_SECTION_HEADER)((uintptr_t)pvBuf + offSHdrs);
+        This.pCmd       = pCmd;
+
         if (pFileHdr->SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32))
-            rc = dbgcDumpImagePeOptHdr32(pCmd, pCmdHlp, (IMAGE_NT_HEADERS32 const *)pvBuf);
+        {
+            This.paDataDir = This.u.pNt32->OptionalHeader.DataDirectory;
+            This.cDataDir  = This.u.pNt32->OptionalHeader.NumberOfRvaAndSizes;
+            rc = dbgcDumpImagePeOptHdr32(&This, pCmdHlp, This.u.pNt32);
+        }
         else if (pFileHdr->SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER64))
-            rc = dbgcDumpImagePeOptHdr64(pCmd, pCmdHlp, (IMAGE_NT_HEADERS64 const *)pvBuf);
+        {
+            This.paDataDir = This.u.pNt64->OptionalHeader.DataDirectory;
+            This.cDataDir  = This.u.pNt64->OptionalHeader.NumberOfRvaAndSizes;
+            rc = dbgcDumpImagePeOptHdr64(&This, pCmdHlp, This.u.pNt64);
+        }
         else
             rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "%Dv: Unsupported optional header size: %#x\n",
                                 pImageBase, pFileHdr->SizeOfOptionalHeader);
-        int rc2 = dbgcDumpImagePeSectionHdrs(pCmd, pCmdHlp, pImageBase, pFileHdr->NumberOfSections,
-                                             (IMAGE_SECTION_HEADER const *)((uintptr_t)pvBuf + offSHdrs));
+
+        int rc2 = dbgcDumpImagePeSectionHdrs(&This, pCmdHlp, This.cShdrs, This.paShdrs);
+        if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
+            rc = rc2;
+
+        rc2 = dbgcDumpImagePeDataDirs(&This, pCmdHlp, This.cDataDir, This.paDataDir);
         if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
             rc = rc2;
