VirtualBox

Changeset 105508 in vbox


Ignore:
Timestamp:
Jul 26, 2024 1:46:01 AM (8 months ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
164173
Message:

VBoxDbg: Extended the dumpimage command, creating standalone tool of it (VBoxDumpImage). bugref:10727

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Debugger/DBGCDumpImage.cpp

    r98103 r105508  
    4545#include <iprt/path.h>
    4646#include <iprt/string.h>
     47#include <iprt/time.h>
     48#ifdef DBGC_DUMP_IMAGE_TOOL
     49# include <iprt/buildconfig.h>
     50# include <iprt/message.h>
     51# include <iprt/file.h>
     52# include <iprt/getopt.h>
     53# include <iprt/initterm.h>
     54# include <iprt/process.h>
     55# include <iprt/stream.h>
     56# include <iprt/vfs.h>
     57#endif
    4758#include <iprt/formats/mz.h>
    4859#include <iprt/formats/pecoff.h>
     
    5869*   Structures and Typedefs                                                                                                      *
    5970*********************************************************************************************************************************/
    60 /**
    61  * PE dumper instance.
    62  */
    63 typedef struct DUMPIMAGEPE
    64 {
    65     /** Pointer to the image base address variable. */
    66     PCDBGCVAR                   pImageBase;
    67     /** Pointer to the file header. */
    68     PCIMAGE_FILE_HEADER         pFileHdr;
    69     /** Pointer to the NT headers. */
    70     union
    71     {
    72         PCIMAGE_NT_HEADERS32    pNt32;
    73         PCIMAGE_NT_HEADERS64    pNt64;
    74         void                   *pv;
    75     } u;
    76     /** Pointer to the section headers. */
    77     PCIMAGE_SECTION_HEADER      paShdrs;
    78     /** Number of section headers. */
    79     unsigned                    cShdrs;
    80     /** Number of RVA and sizes (data directory entries). */
    81     unsigned                    cDataDir;
    82     /** Pointer to the data directory. */
    83     PCIMAGE_DATA_DIRECTORY      paDataDir;
    84 
    85     /** The command descriptor (for failing the command). */
    86     PCDBGCCMD                   pCmd;
    87 } DUMPIMAGEPE;
    88 /** Pointer to a PE dumper instance. */
    89 typedef DUMPIMAGEPE *PDUMPIMAGEPE;
     71#ifdef DBGC_DUMP_IMAGE_TOOL
     72/** Command helper state for the image dumper tool. */
     73typedef struct CMDHLPSTATE
     74{
     75    DBGCCMDHLP  Core;
     76    /** The exit code for the tool. */
     77    RTEXITCODE  rcExit;
     78    /** The current input file. */
     79    RTVFSFILE   hVfsFile;
     80} CMDHLPSTATE;
     81typedef CMDHLPSTATE *PCMDHLPSTATE;
     82#endif
    9083
    9184
     
    10295*   Internal Functions                                                                                                           *
    10396*********************************************************************************************************************************/
     97#ifndef DBGC_DUMP_IMAGE_TOOL
    10498extern FNDBGCCMD dbgcCmdDumpImage; /* See DBGCCommands.cpp. */
     99#endif
    105100
    106101
     
    112107            DBGCCmdHlpPrintf(pCmdHlp, " %s", paEntries[i].pszNm);
    113108}
     109
     110
     111/**
     112 * Early read function.
     113 *
     114 * @todo refactor/abstract this somehow...
     115 */
     116static int dumpReadAt(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, PCDBGCVAR pImageBase, const char *pszName,
     117                      size_t off, void *pvDst, size_t cbToRead, size_t *pcbRead)
     118{
     119    RT_BZERO(pvDst, cbToRead);
     120    if (pcbRead)
     121        *pcbRead = 0;
     122
     123#ifndef DBGC_DUMP_IMAGE_TOOL
     124    DBGCVAR AddrToReadAt;
     125    int rc = DBGCCmdHlpEval(pCmdHlp, &AddrToReadAt, "%DV + %#zx", pImageBase, off);
     126    if (RT_SUCCESS(rc))
     127    {
     128        rc = DBGCCmdHlpMemRead(pCmdHlp, pvDst, cbToRead, &AddrToReadAt, pcbRead);
     129        if (RT_SUCCESS(rc))
     130            return VINF_SUCCESS;
     131        return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "%s: Failed to read %zu bytes at offset %Dv", pszName, cbToRead, &AddrToReadAt);
     132    }
     133    return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "%s: Failed to calculate address %Dv + #%zx for %#zx byte read",
     134                            pszName, pImageBase, off, cbToRead);
     135
     136#else  /* DBGC_DUMP_IMAGE_TOOL */
     137    CMDHLPSTATE * const pToolState = RT_FROM_MEMBER(pCmdHlp, CMDHLPSTATE, Core);
     138    int rc = RTVfsFileReadAt(pToolState->hVfsFile, off, pvDst, cbToRead, pcbRead);
     139    if (RT_SUCCESS(rc))
     140        return VINF_SUCCESS;
     141    RT_NOREF(pImageBase);
     142    return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "%s: Failed to read %zu bytes at offset %#zx", pszName, cbToRead, off);
     143#endif /* DBGC_DUMP_IMAGE_TOOL */
     144}
     145
     146
     147/*********************************************************************************************************************************
     148*   DumpImageBase                                                                                                                *
     149*********************************************************************************************************************************/
     150class DumpImageBase
     151{
     152public:
     153    /** The name of what's being dumped (for error messages). */
     154    const char * const  m_pszName;
     155    /** Pointer to the image base address variable. */
     156    PCDBGCVAR const     m_pImageBase;
     157    /** Pointer to the command helpers. */
     158    PDBGCCMDHLP const   m_pCmdHlp;
     159    /** The command descriptor (for failing the command). */
     160    PCDBGCCMD const     m_pCmd;
     161
     162private:
     163    /** The Image base address. */
     164    uint64_t            m_uImageBaseAddr;
     165protected:
     166    /** The full formatted address width. */
     167    uint8_t             m_cchAddr;
     168private:
     169    /** The formatted address value width. */
     170    uint8_t             m_cchAddrValue;
     171    /** The address prefix length.   */
     172    uint8_t             m_cchAddrPfx;
     173    /** The address prefix.   */
     174    char                m_szAddrPfx[16 - 3];
     175
     176private:
     177    DumpImageBase();
     178
     179    void setupAddrFormatting(const char *a_pszImageBaseAddr)
     180    {
     181        /*
     182         * Expected inputs: %%12345678, %123456789abcdef, 0x12345678, 0008:12345678
     183         *
     184         * So, work backwards till be find the start of the address/offset value
     185         * component, and treat what comes first as a prefix.
     186         */
     187        size_t const cch        = strlen(a_pszImageBaseAddr);
     188        size_t       cchAddrPfx = cch;
     189        while (cchAddrPfx > 0 && RT_C_IS_XDIGIT(a_pszImageBaseAddr[cchAddrPfx - 1]))
     190            cchAddrPfx--;
     191
     192        size_t cchLeadingZeros = 0;
     193        while (a_pszImageBaseAddr[cchAddrPfx + cchLeadingZeros] == '0')
     194            cchLeadingZeros++;
     195
     196        int rc = RTStrToUInt64Full(&a_pszImageBaseAddr[cchAddrPfx], 16, &m_uImageBaseAddr);
     197        AssertRCSuccess(rc);
     198        m_cchAddrValue = (uint8_t)(cch - cchAddrPfx);
     199        Assert(m_cchAddrValue == cch - cchAddrPfx);
     200        if (m_cchAddrValue > 8 && cchLeadingZeros > 1)
     201            m_cchAddrValue = RT_ALIGN_T(m_cchAddrValue - (uint8_t)(cchLeadingZeros - 1), 2, uint8_t);
     202
     203        AssertStmt(cchAddrPfx < sizeof(m_szAddrPfx), cchAddrPfx = sizeof(m_szAddrPfx) - 1);
     204        memcpy(m_szAddrPfx, a_pszImageBaseAddr, cchAddrPfx);
     205        m_szAddrPfx[cchAddrPfx] = '\0';
     206        m_cchAddrPfx = (uint8_t)cchAddrPfx;
     207
     208        m_cchAddr = m_cchAddrPfx + m_cchAddrValue;
     209    }
     210
     211public:
     212    DumpImageBase(PDBGCCMDHLP a_pCmdHlp, PCDBGCCMD a_pCmd, PCDBGCVAR a_pImageBase,
     213                  const char *a_pszImageBaseAddr, const char *a_pszName)
     214        : m_pszName(a_pszName)
     215        , m_pImageBase(a_pImageBase)
     216        , m_pCmdHlp(a_pCmdHlp)
     217        , m_pCmd(a_pCmd)
     218        , m_uImageBaseAddr(0)
     219        , m_cchAddr(0)
     220        , m_cchAddrValue(12)
     221        , m_cchAddrPfx(2)
     222        , m_szAddrPfx("0x")
     223    {
     224        setupAddrFormatting(a_pszImageBaseAddr);
     225    }
     226
     227    virtual ~DumpImageBase() { }
     228
     229    virtual size_t rvaToFileOffset(size_t uRva) const = 0;
     230    virtual size_t getEndRva(bool a_fAligned = true) const = 0;
     231
     232    char *rvaToStringWithAddr(size_t uRva, char *pszDst, size_t cbDst, bool fWide = false)
     233    {
     234        if (!fWide)
     235            RTStrPrintf(pszDst, cbDst, "%#09zx/%s%0*RX64", uRva, m_szAddrPfx, m_cchAddrValue, m_uImageBaseAddr + uRva);
     236        else
     237            RTStrPrintf(pszDst, cbDst, "%#09zx / %s%0*RX64", uRva, m_szAddrPfx, m_cchAddrValue, m_uImageBaseAddr + uRva);
     238        return pszDst;
     239    }
     240
     241    virtual void myPrintf(const char *pszFormat, ...)
     242    {
     243        va_list va;
     244        va_start(va, pszFormat);
     245        m_pCmdHlp->pfnPrintfV(m_pCmdHlp, NULL, pszFormat, va);
     246        va_end(va);
     247    }
     248
     249    void myPrintHeader(size_t uRva, const char *pszFormat, ...)
     250    {
     251        char    szTmp[64];
     252        char    szLine[128];
     253        va_list va;
     254        va_start(va, pszFormat);
     255        size_t const cchLine = RTStrPrintf(szLine, sizeof(szLine), "%s - %N",
     256                                           rvaToStringWithAddr(uRva, szTmp, sizeof(szTmp), true), pszFormat, &va);
     257        va_end(va);
     258        myPrintf("\n"
     259                 "%s\n"
     260                 "%.*s====\n",
     261                 szLine,
     262                 cchLine, "===============================================================================");
     263    }
     264
     265    virtual int myError(const char *pszFormat, ...)
     266    {
     267        va_list va;
     268        va_start(va, pszFormat);
     269        int rc = DBGCCmdHlpFail(m_pCmdHlp, m_pCmd, "%s: %N", m_pszName, pszFormat, &va);
     270        va_end(va);
     271        return rc;
     272    }
     273
     274    virtual int myError(int rc, const char *pszFormat, ...)
     275    {
     276        va_list va;
     277        va_start(va, pszFormat);
     278        rc = DBGCCmdHlpFailRc(m_pCmdHlp, m_pCmd, rc, "%s: %N", m_pszName, pszFormat, &va);
     279        va_end(va);
     280        return rc;
     281    }
     282
     283    int readBytesAtRva(size_t uRva, void *pvBuf, size_t cbToRead, size_t *pcbRead = NULL)
     284    {
     285        /* Ensure buffer and return size is zero before we do anything. */
     286        if (pcbRead)
     287            *pcbRead = 0;
     288        RT_BZERO(pvBuf, cbToRead);
     289
     290#ifndef DBGC_DUMP_IMAGE_TOOL
     291        /* Calc the read address. */
     292        DBGCVAR AddrToReadAt;
     293        int rc = DBGCCmdHlpEval(m_pCmdHlp, &AddrToReadAt, "%DV + %#zx", m_pImageBase, uRva);
     294        if (RT_SUCCESS(rc))
     295        {
     296            rc = DBGCCmdHlpMemRead(m_pCmdHlp, pvBuf, cbToRead, &AddrToReadAt, pcbRead);
     297            if (RT_FAILURE(rc))
     298                rc = myError(rc, "Failed to read %zu bytes at %Dv", cbToRead, &AddrToReadAt);
     299        }
     300#else  /* DBGC_DUMP_IMAGE_TOOL */
     301        int rc;
     302        size_t const offFile = rvaToFileOffset(uRva);
     303        if (offFile != ~(size_t)0)
     304        {
     305            CMDHLPSTATE * const pToolState = RT_FROM_MEMBER(m_pCmdHlp, CMDHLPSTATE, Core);
     306            rc = RTVfsFileReadAt(pToolState->hVfsFile, offFile, pvBuf, cbToRead, pcbRead);
     307            if (RT_FAILURE(rc))
     308                rc = myError(rc, "Failed to read %zu bytes at %#zx (RVA %#zx)", cbToRead, offFile, uRva);
     309        }
     310        else
     311            rc = myError(VERR_READ_ERROR, "Failed to convert RVA %#zx to file offset for %zu byte read!", uRva, cbToRead);
     312#endif /* DBGC_DUMP_IMAGE_TOOL */
     313        return rc;
     314    }
     315};
     316
     317
     318/**
     319 * Buffered reading by relative virtual address (RVA).
     320 */
     321class DumpImageBufferedReader
     322{
     323private:
     324    /** Static sized buffer. */
     325    uint8_t         m_abBufFixed[4096];
     326    /** Pointer to m_abBufFixed if that's sufficient, otherwise heap buffer. */
     327    uint8_t        *m_pbBuf;
     328    /** The size of the buffer m_pbBuf points at. */
     329    size_t          m_cbBufAlloc;
     330    /** Number of valid bytes in the buffer. */
     331    size_t          m_cbBuf;
     332    /** The RVA of the first buffer byte, maximum value if empty. */
     333    size_t          m_uRvaBuf;
     334    /** Pointer to the image dumper. */
     335    DumpImageBase  *m_pImage;
     336
     337    int loadBuffer(size_t uRva)
     338    {
     339        /* Check that the RVA is within the image. */
     340        size_t const cbMaxRva = m_pImage->getEndRva();
     341        if (uRva >= cbMaxRva)
     342            return VERR_EOF;
     343
     344        /* Adjust the RVA if we're reading beyond the end of the image. */
     345        if (uRva + m_cbBufAlloc > RT_ALIGN_Z(cbMaxRva, 8))
     346            uRva = m_cbBufAlloc > RT_ALIGN_Z(cbMaxRva, 8) ? RT_ALIGN_Z(cbMaxRva, 8) - m_cbBufAlloc : 0;
     347
     348        /* Do the read.  In case of failure readBytesAtRva will zero the buffer. */
     349        m_uRvaBuf = uRva;
     350        m_cbBuf   = 0;
     351        return m_pImage->readBytesAtRva(uRva, m_pbBuf, RT_MIN(cbMaxRva - uRva, m_cbBufAlloc), &m_cbBuf);
     352    }
     353
     354    /** Resizes the buffer if the current one can't hold @a cbNeeded bytes. */
     355    int ensureBufferSpace(size_t cbNeeded)
     356    {
     357        if (cbNeeded > m_cbBufAlloc)
     358        {
     359            cbNeeded = RT_ALIGN_Z(cbNeeded, 512);
     360            void *pvNew = RTMemTmpAllocZ(cbNeeded);
     361            if (!pvNew)
     362                return DBGCCmdHlpFailRc(m_pImage->m_pCmdHlp, m_pImage->m_pCmd, VERR_NO_TMP_MEMORY,
     363                                        "Failed to allocate %zu (%#zx) bytes", cbNeeded, cbNeeded);
     364            memcpy(pvNew, m_pbBuf, RT_MIN(m_cbBuf, m_cbBufAlloc));
     365
     366            if (m_pbBuf != &m_abBufFixed[0])
     367                RTMemTmpFree(m_pbBuf);
     368            m_pbBuf      = (uint8_t *)pvNew;
     369            m_cbBufAlloc = cbNeeded;
     370        }
     371        return VINF_SUCCESS;
     372    }
     373
     374    DumpImageBufferedReader();
     375
     376public:
     377    DumpImageBufferedReader(DumpImageBase *a_pImage)
     378        : m_pbBuf(&m_abBufFixed[0])
     379        , m_cbBufAlloc(sizeof(m_abBufFixed))
     380        , m_cbBuf(0)
     381        , m_uRvaBuf(~(size_t)0)
     382        , m_pImage(a_pImage)
     383    {
     384        RT_ZERO(m_abBufFixed);
     385    }
     386
     387    /** Copy constructor. */
     388    DumpImageBufferedReader(DumpImageBufferedReader const &a_rThat)
     389        : m_pbBuf(&m_abBufFixed[0])
     390        , m_cbBufAlloc(sizeof(m_abBufFixed))
     391        , m_cbBuf(RT_MIN(a_rThat.m_cbBuf, sizeof(m_abBufFixed)))
     392        , m_uRvaBuf(a_rThat.m_uRvaBuf)
     393        , m_pImage(a_rThat.m_pImage)
     394    {
     395        memcpy(m_abBufFixed, a_rThat.m_pbBuf, m_cbBuf);
     396        if (m_cbBuf < sizeof(m_abBufFixed))
     397            RT_BZERO(&m_abBufFixed[m_cbBuf], sizeof(m_abBufFixed) - m_cbBuf);
     398    }
     399
     400    ~DumpImageBufferedReader()
     401    {
     402        if (m_pbBuf != &m_abBufFixed[0])
     403            RTMemTmpFree(m_pbBuf);
     404        m_pbBuf = NULL;
     405    }
     406
     407    /**
     408     * Reads @a cbToRead bytes at @a uRva into @a pvDst.
     409     *
     410     * The buffer is entirely zeroed before reading anything, so it's okay to ignore
     411     * the status code.
     412     */
     413    int readBytes(size_t uRva, void *pvDst, size_t cbToRead)
     414    {
     415        RT_BZERO(pvDst, cbToRead);
     416
     417        while (cbToRead)
     418        {
     419            /*
     420             * Is the start of the request overlapping with the buffer?
     421             */
     422            if (uRva >= m_uRvaBuf)
     423            {
     424                size_t const offBuf = uRva - m_uRvaBuf;
     425                if (offBuf < m_cbBuf)
     426                {
     427                    size_t const cbThisRead = RT_MIN(m_cbBuf - offBuf, cbToRead);
     428                    memcpy(pvDst, &m_pbBuf[offBuf], cbThisRead);
     429                    if (cbToRead <= cbThisRead)
     430                        return VINF_SUCCESS;
     431                    uRva     += cbThisRead;
     432                    cbToRead -= cbThisRead;
     433                    pvDst     = (uint8_t *)pvDst + cbThisRead;
     434                }
     435            }
     436
     437            /*
     438             * Fill buffer.
     439             */
     440            int rc = loadBuffer(uRva);
     441            if (RT_FAILURE(rc))
     442                return rc;
     443        }
     444        return VINF_SUCCESS;
     445    }
     446
     447    /**
     448     * Ensures @a cbItem at @a uRva is in the buffer and returns a pointer to it.
     449     *
     450     * The returned pointer is only valid till the next call to the reader instance.
     451     *
     452     * @returns NULL if failed to load the range into the buffer.
     453     * @note    Extra buffer space will be allocated if @a cbItem is larger than the
     454     *          internal buffer.
     455     */
     456    uint8_t const *bufferedBytes(size_t uRva, size_t cbItem)
     457    {
     458        /* Do we need to load the item into the buffer? */
     459        if (   uRva < m_uRvaBuf
     460            || uRva + cbItem > m_uRvaBuf + m_cbBuf)
     461        {
     462            int rc = ensureBufferSpace(cbItem);
     463            if (RT_SUCCESS(rc))
     464                rc = loadBuffer(uRva);
     465            if (RT_FAILURE(rc))
     466                return NULL;
     467        }
     468
     469        Assert(uRva >= m_uRvaBuf && uRva + cbItem <= m_uRvaBuf + m_cbBuf);
     470        return &m_pbBuf[uRva - m_uRvaBuf];
     471    }
     472
     473    /**
     474     * Gets a buffered zero terminated string at @a uRva.
     475     *
     476     * @note The implied max length is the size of the internal buffer.  No extra
     477     *       space will be allocated if the string doesn't terminate within the
     478     *       buffer size.
     479     */
     480    const char *bufferedString(size_t uRva)
     481    {
     482        /* Do we need to reload the buffer? */
     483        if (   uRva < m_uRvaBuf
     484            || uRva >= m_uRvaBuf + m_cbBuf
     485            || (   uRva != m_uRvaBuf
     486                && !memchr(&m_pbBuf[uRva - m_uRvaBuf], '\0', m_cbBufAlloc - (uRva - m_uRvaBuf))))
     487        {
     488            int rc = loadBuffer(uRva);
     489            AssertRCReturn(rc, NULL);
     490        }
     491
     492        /* The RVA is within the buffer now, just check that the string ends
     493           before the end of the buffer. */
     494        Assert(uRva >= m_uRvaBuf && uRva < m_uRvaBuf + m_cbBuf);
     495        size_t const       offString = uRva - m_uRvaBuf;
     496        const char * const pszString = (const char *)&m_pbBuf[offString];
     497        AssertReturn(memchr(pszString, '\0', m_cbBufAlloc - offString), NULL);
     498        return pszString;
     499    }
     500
     501    /**
     502     * Gets a simple integer value, with default in case of failure.
     503     */
     504    template<typename IntType>
     505    IntType bufferedInt(size_t uRva, IntType Default = 0)
     506    {
     507        AssertCompile(sizeof(IntType) <= 8);
     508        AssertReturn(uRva < uRva + sizeof(IntType), Default);
     509
     510        /* Do we need to reload the buffer? */
     511        if (   uRva < m_uRvaBuf
     512            || uRva + sizeof(IntType) > m_uRvaBuf + m_cbBuf)
     513        {
     514            int rc = loadBuffer(uRva);
     515            AssertRCReturn(rc, Default);
     516        }
     517
     518        /* The RVA is within the buffer now. */
     519        Assert(uRva >= m_uRvaBuf && uRva + sizeof(IntType) <= m_uRvaBuf + m_cbBuf);
     520        return *(IntType *)&m_pbBuf[uRva - m_uRvaBuf];
     521    }
     522
     523};
    114524
    115525
     
    193603
    194604
    195 static const char *dbgPeDebugTypeName(uint32_t uType)
     605static const char *dbgPeDebugTypeName(uint32_t uType, char *pszTmp, size_t cchTmp)
    196606{
    197607    switch (uType)
     
    215625        case IMAGE_DEBUG_TYPE_REPRO:         return "REPRO";
    216626    }
    217     return "??";
     627    RTStrPrintf(pszTmp, cchTmp, "%#RX32", uType);
     628    return pszTmp;
    218629}
    219630
    220631
    221 static int dbgcDumpImagePeDebugDir(PDUMPIMAGEPE pThis, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pDataAddr, uint32_t cbData)
    222 {
    223     uint32_t cEntries = cbData / sizeof(IMAGE_DEBUG_DIRECTORY);
    224     for (uint32_t i = 0; i < cEntries; i++)
    225     {
     632/**
     633 * PE dumper class.
     634 */
     635class DumpImagePe : public DumpImageBase
     636{
     637public:
     638    /** Pointer to the file header. */
     639    PCIMAGE_FILE_HEADER         m_pFileHdr;
     640    /** Pointer to the NT headers. */
     641    union
     642    {
     643        PCIMAGE_NT_HEADERS32    pNt32;
     644        PCIMAGE_NT_HEADERS64    pNt64;
     645        void                   *pv;
     646    } u;
     647    /** The PE header RVA / file offset. */
     648    uint32_t                    m_offPeHdr;
     649    /** Section table RVA / file offset. */
     650    uint32_t                    m_offShdrs;
     651    /** Pointer to the section headers. */
     652    PCIMAGE_SECTION_HEADER      m_paShdrs;
     653    /** Number of section headers. */
     654    unsigned                    m_cShdrs;
     655    /** Number of RVA and sizes (data directory entries). */
     656    unsigned                    cDataDir;
     657    /** Pointer to the data directory. */
     658    PCIMAGE_DATA_DIRECTORY      paDataDir;
     659
     660public:
     661    DumpImagePe(PDBGCCMDHLP a_pCmdHlp, PCDBGCCMD a_pCmd, PCDBGCVAR a_pImageBase,
     662                const char *a_pszImageBaseAddr, const char *a_pszName,
     663                uint32_t a_offPeHdr, PCIMAGE_FILE_HEADER a_pFileHdr, void *a_pvNtHdrs,
     664                uint32_t a_offShdrs, unsigned a_cShdrs, PCIMAGE_SECTION_HEADER a_paShdrs)
     665        : DumpImageBase(a_pCmdHlp, a_pCmd, a_pImageBase, a_pszImageBaseAddr, a_pszName)
     666        , m_pFileHdr(a_pFileHdr)
     667        , m_offPeHdr(a_offPeHdr)
     668        , m_offShdrs(a_offShdrs)
     669        , m_paShdrs(a_paShdrs)
     670        , m_cShdrs(a_cShdrs)
     671        , cDataDir(0)
     672        , paDataDir(NULL)
     673    {
     674        u.pv = a_pvNtHdrs;
     675        if (a_pFileHdr->SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32))
     676        {
     677            paDataDir = u.pNt32->OptionalHeader.DataDirectory;
     678            cDataDir  = u.pNt32->OptionalHeader.NumberOfRvaAndSizes;
     679        }
     680        else
     681        {
     682            paDataDir = u.pNt64->OptionalHeader.DataDirectory;
     683            cDataDir  = u.pNt64->OptionalHeader.NumberOfRvaAndSizes;
     684        }
     685    }
     686
     687    virtual size_t rvaToFileOffset(size_t uRva) const RT_OVERRIDE
     688    {
     689        AssertReturn(m_paShdrs, uRva);
     690        AssertReturn(u.pv, uRva);
     691        if (uRva < m_paShdrs[0].VirtualAddress)
     692            return uRva;
     693        unsigned iSh = m_cShdrs;
     694        while (iSh-- > 0)
     695        {
     696            if (uRva >= m_paShdrs[iSh].VirtualAddress)
     697            {
     698                size_t offSection = uRva - m_paShdrs[iSh].VirtualAddress;
     699                if (offSection < m_paShdrs[iSh].SizeOfRawData)
     700                    return m_paShdrs[iSh].PointerToRawData + offSection;
     701                return ~(size_t)0;
     702            }
     703        }
     704        return ~(size_t)0;
     705    }
     706
     707    virtual size_t getEndRva(bool a_fAligned = true) const RT_OVERRIDE
     708    {
     709        AssertCompileMembersAtSameOffset(IMAGE_NT_HEADERS32, OptionalHeader.SizeOfImage,
     710                                         IMAGE_NT_HEADERS64, OptionalHeader.SizeOfImage);
     711        if (a_fAligned)
     712        {
     713            uint32_t const cbAlignment = u.pNt32->OptionalHeader.SectionAlignment;
     714            if (RT_IS_POWER_OF_TWO(cbAlignment))
     715                return RT_ALIGN_Z((size_t)u.pNt32->OptionalHeader.SizeOfImage, cbAlignment);
     716        }
     717        return u.pNt32->OptionalHeader.SizeOfImage;
     718    }
     719
     720
     721    /** @name Helpers
     722     * @{
     723     */
     724
     725    char *timestampToString(uint32_t uTimestamp, char *pszDst, size_t cbDst) RT_NOEXCEPT
     726    {
     727        /** @todo detect random numbers and skip formatting them.   */
     728        RTTIMESPEC TimeSpec;
     729        RTTIME     Time;
     730        RTTimeToStringEx(RTTimeExplode(&Time, RTTimeSpecSetDosSeconds(&TimeSpec, uTimestamp)),
     731                         pszDst, cbDst, 0 /*cFractionDigits*/);
     732        return pszDst;
     733    }
     734
     735    /** @} */
     736
     737    /** @name Dumpers
     738     * @{
     739     */
     740
     741    int dumpPeHdr(void)
     742    {
     743        char szTmp[64];
     744        myPrintHeader(m_offPeHdr, "PE & File Header - %s", m_pszName);
     745        myPrintf("Signature:                    %#010RX32\n", u.pNt32->Signature);
     746        PCIMAGE_FILE_HEADER const pFileHdr = &u.pNt32->FileHeader;
     747        myPrintf("Machine:                      %s (%#06RX16)\n", dbgcPeMachineName(pFileHdr->Machine), pFileHdr->Machine);
     748        myPrintf("Number of sections:           %#06RX16\n", pFileHdr->NumberOfSections);
     749        myPrintf("Timestamp:                    %#010RX32\n",
     750                 pFileHdr->TimeDateStamp, timestampToString(pFileHdr->TimeDateStamp, szTmp, sizeof(szTmp)));
     751        if (pFileHdr->PointerToSymbolTable || pFileHdr->NumberOfSymbols)
     752            myPrintf("Symbol table:                 %#010RX32 L %#06RX16\n",
     753                     pFileHdr->PointerToSymbolTable, pFileHdr->NumberOfSymbols);
     754        myPrintf("Size of optional header:      %#06RX16\n", pFileHdr->SizeOfOptionalHeader);
     755
     756        myPrintf("Characteristics:              %#06RX16", pFileHdr->Characteristics);
     757        if (pFileHdr->Characteristics & IMAGE_FILE_RELOCS_STRIPPED)         myPrintf(" RELOCS_STRIPPED");
     758        if (pFileHdr->Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE)        myPrintf(" EXECUTABLE_IMAGE");
     759        if (pFileHdr->Characteristics & IMAGE_FILE_LINE_NUMS_STRIPPED)      myPrintf(" LINE_NUMS_STRIPPED");
     760        if (pFileHdr->Characteristics & IMAGE_FILE_LOCAL_SYMS_STRIPPED)     myPrintf(" LOCAL_SYMS_STRIPPED");
     761        if (pFileHdr->Characteristics & IMAGE_FILE_AGGRESIVE_WS_TRIM)       myPrintf(" AGGRESIVE_WS_TRIM");
     762        if (pFileHdr->Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE)     myPrintf(" LARGE_ADDRESS_AWARE");
     763        if (pFileHdr->Characteristics & IMAGE_FILE_16BIT_MACHINE)           myPrintf(" 16BIT_MACHINE");
     764        if (pFileHdr->Characteristics & IMAGE_FILE_BYTES_REVERSED_LO)       myPrintf(" BYTES_REVERSED_LO");
     765        if (pFileHdr->Characteristics & IMAGE_FILE_32BIT_MACHINE)           myPrintf(" 32BIT_MACHINE");
     766        if (pFileHdr->Characteristics & IMAGE_FILE_DEBUG_STRIPPED)          myPrintf(" DEBUG_STRIPPED");
     767        if (pFileHdr->Characteristics & IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP) myPrintf(" REMOVABLE_RUN_FROM_SWAP");
     768        if (pFileHdr->Characteristics & IMAGE_FILE_NET_RUN_FROM_SWAP)       myPrintf(" NET_RUN_FROM_SWAP");
     769        if (pFileHdr->Characteristics & IMAGE_FILE_SYSTEM)                  myPrintf(" SYSTEM");
     770        if (pFileHdr->Characteristics & IMAGE_FILE_DLL)                     myPrintf(" DLL");
     771        if (pFileHdr->Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY)          myPrintf(" UP_SYSTEM_ONLY");
     772        if (pFileHdr->Characteristics & IMAGE_FILE_BYTES_REVERSED_HI)       myPrintf(" BYTES_REVERSED_HI");
     773        myPrintf("\n");
     774        return VINF_SUCCESS;
     775    }
     776
     777    template<typename OptHdrType, bool const a_f32Bit>
     778    int dumpOptHdr(OptHdrType const *pOptHdr, uint32_t uBaseOfData = 0)
     779    {
     780        myPrintHeader(m_offPeHdr + RT_UOFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader), "Optional Header");
     781        char szTmp[64];
     782        myPrintf("Optional header magic:        %#06RX16\n", pOptHdr->Magic);
     783        myPrintf("Linker version:               %u.%02u\n", pOptHdr->MajorLinkerVersion, pOptHdr->MinorLinkerVersion);
     784        if (a_f32Bit)
     785            myPrintf("Image base:                   %#010RX32\n", pOptHdr->ImageBase);
     786        else
     787            myPrintf("Image base:                   %#018RX64\n", pOptHdr->ImageBase);
     788        myPrintf("Entrypoint:                   %s\n", rvaToStringWithAddr(pOptHdr->AddressOfEntryPoint, szTmp, sizeof(szTmp)));
     789        myPrintf("Base of code:                 %s\n", rvaToStringWithAddr(pOptHdr->BaseOfCode, szTmp, sizeof(szTmp)));
     790        if (a_f32Bit)
     791            myPrintf("Base of data:                 %s\n", rvaToStringWithAddr(uBaseOfData, szTmp, sizeof(szTmp)));
     792        myPrintf("Size of image:                %#010RX32\n", pOptHdr->SizeOfImage);
     793        myPrintf("Size of headers:              %#010RX32\n", pOptHdr->SizeOfHeaders);
     794        myPrintf("Size of code:                 %#010RX32\n", pOptHdr->SizeOfCode);
     795        myPrintf("Size of initialized data:     %#010RX32\n", pOptHdr->SizeOfInitializedData);
     796        myPrintf("Size of uninitialized data:   %#010RX32\n", pOptHdr->SizeOfUninitializedData);
     797        myPrintf("Section alignment:            %#010RX32\n", pOptHdr->SectionAlignment);
     798        myPrintf("File alignment:               %#010RX32\n", pOptHdr->FileAlignment);
     799        myPrintf("Image version:                %u.%02u\n", pOptHdr->MajorImageVersion, pOptHdr->MinorImageVersion);
     800        myPrintf("Operating system version:     %u.%02u\n", pOptHdr->MajorOperatingSystemVersion, pOptHdr->MinorOperatingSystemVersion);
     801        myPrintf("Windows version value:        %#010RX32\n", pOptHdr->Win32VersionValue);
     802        const char *pszSubSys;
     803        switch (pOptHdr->Subsystem)
     804        {
     805            case IMAGE_SUBSYSTEM_UNKNOWN:                   pszSubSys = "Unknown"; break;
     806            case IMAGE_SUBSYSTEM_NATIVE:                    pszSubSys = "Native"; break;
     807            case IMAGE_SUBSYSTEM_WINDOWS_GUI:               pszSubSys = "Windows GUI"; break;
     808            case IMAGE_SUBSYSTEM_WINDOWS_CUI:               pszSubSys = "Windows char"; break;
     809            case IMAGE_SUBSYSTEM_OS2_GUI:                   pszSubSys = "OS/2 GUI"; break;
     810            case IMAGE_SUBSYSTEM_OS2_CUI:                   pszSubSys = "OS/2 char"; break;
     811            case IMAGE_SUBSYSTEM_POSIX_CUI:                 pszSubSys = "POSIX"; break;
     812            case IMAGE_SUBSYSTEM_NATIVE_WINDOWS:            pszSubSys = "Native Windows 9x"; break;
     813            case IMAGE_SUBSYSTEM_WINDOWS_CE_GUI:            pszSubSys = "Windows CE GUI"; break;
     814            case IMAGE_SUBSYSTEM_EFI_APPLICATION:           pszSubSys = "EFI Application"; break;
     815            case IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:   pszSubSys = "EFI Boot Service Driver"; break;
     816            case IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:        pszSubSys = "EFI Runtime Driver"; break;
     817            case IMAGE_SUBSYSTEM_EFI_ROM:                   pszSubSys = "EFI ROM"; break;
     818            case IMAGE_SUBSYSTEM_XBOX:                      pszSubSys = "XBox"; break;
     819            case IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION:  pszSubSys = "Windows Boot Application"; break;
     820            default:                                        pszSubSys = "dunno"; break;
     821        }
     822        myPrintf("Subsystem:                    %s (%#x)\n", pszSubSys, pOptHdr->Subsystem);
     823        myPrintf("Subsystem version:            %u.%02u\n", pOptHdr->MajorSubsystemVersion, pOptHdr->MinorSubsystemVersion);
     824        myPrintf("DLL characteristics:          %#06RX16\n", pOptHdr->DllCharacteristics);
     825        myPrintf("Loader flags:                 %#010RX32\n", pOptHdr->LoaderFlags);
     826
     827        myPrintf("File checksum:                %#010RX32\n", pOptHdr->CheckSum);
     828        myPrintf("Size of stack reserve:        %#010RX64\n", (uint64_t)pOptHdr->SizeOfStackReserve);
     829        myPrintf("Size of stack commit:         %#010RX64\n", (uint64_t)pOptHdr->SizeOfStackReserve);
     830        myPrintf("Size of heap reserve:         %#010RX64\n", (uint64_t)pOptHdr->SizeOfHeapReserve);
     831        myPrintf("Size of heap commit:          %#010RX64\n", (uint64_t)pOptHdr->SizeOfHeapReserve);
     832
     833        myPrintf("Number of data directories:   %#010RX32%s\n", pOptHdr->NumberOfRvaAndSizes,
     834                 pOptHdr->NumberOfRvaAndSizes <= RT_ELEMENTS(pOptHdr->DataDirectory) ? "" : " - bogus!");
     835
     836        for (uint32_t i = 0; i < RT_ELEMENTS(pOptHdr->DataDirectory); i++)
     837            if (pOptHdr->DataDirectory[i].Size || pOptHdr->DataDirectory[i].VirtualAddress)
     838            {
     839                const char * const pszName = dbgcPeDataDirName(i);
     840                rvaToStringWithAddr(pOptHdr->DataDirectory[i].VirtualAddress, szTmp, sizeof(szTmp));
     841                if (i == IMAGE_DIRECTORY_ENTRY_SECURITY)
     842                {
     843                    size_t const cchWidth = strlen(szTmp);
     844                    size_t        cch     = RTStrPrintf(szTmp, sizeof(szTmp), "%#09RX32 (file off)",
     845                                                        pOptHdr->DataDirectory[i].VirtualAddress);
     846                    while (cch < cchWidth)
     847                        szTmp[cch++] = ' ';
     848                    szTmp[cch] = '\0';
     849                }
     850                myPrintf("DataDirectory[%#x]:           %s LB %#07RX32 %s\n", i, szTmp, pOptHdr->DataDirectory[i].Size, pszName);
     851            }
     852        return VINF_SUCCESS;
     853    }
     854
     855    int dumpSectionHdrs(void) RT_NOEXCEPT
     856    {
     857        myPrintHeader(m_offShdrs, "Section Table");
     858        for (unsigned i = 0; i < m_cShdrs; i++)
     859        {
     860            char szTmp[64];
     861            myPrintf("Section[%02u]: %s LB %08RX32 %.8s\n",
     862                     i, rvaToStringWithAddr(m_paShdrs[i].VirtualAddress, szTmp, sizeof(szTmp)),
     863                     m_paShdrs[i].Misc.VirtualSize, m_paShdrs[i].Name);
     864        }
     865        return VINF_SUCCESS;
     866    }
     867
     868    int dumpExportDir(DumpImageBufferedReader *pBufRdr, uint32_t uRvaData, uint32_t cbData)
     869    {
     870        myPrintHeader(uRvaData, "Export Table");
     871        RT_NOREF(cbData);
     872        char szTmp[64];
     873
     874        /* Use dedicated readers for each array, but saving one by using pBufRdr
     875           for function addresses. */
     876        DumpImageBufferedReader NmAddrRdr(*pBufRdr), OrdRdr(*pBufRdr), NameRdr(*pBufRdr);
     877
    226878        /*
    227879         * Read the entry into memory.
    228880         */
    229         DBGCVAR DbgDirAddr;
    230         int rc = DBGCCmdHlpEval(pCmdHlp, &DbgDirAddr, "%DV + %#RX32", pDataAddr, i * sizeof(IMAGE_DEBUG_DIRECTORY));
     881        IMAGE_EXPORT_DIRECTORY ExpDir;
     882        int rc = pBufRdr->readBytes(uRvaData, &ExpDir, sizeof(ExpDir));
    231883        if (RT_FAILURE(rc))
    232             return DBGCCmdHlpFailRc(pCmdHlp, pThis->pCmd, rc, "DBGCCmdHlpEval failed on debug entry %u", i);
    233 
    234         IMAGE_DEBUG_DIRECTORY DbgDir;
    235         rc = DBGCCmdHlpMemRead(pCmdHlp, &DbgDir, sizeof(DbgDir), &DbgDirAddr, NULL);
    236         if (RT_FAILURE(rc))
    237             return DBGCCmdHlpFailRc(pCmdHlp, pThis->pCmd, rc, "Failed to read %zu at %Dv", sizeof(DbgDir), &DbgDirAddr);
     884            return rc;
    238885
    239886        /*
    240          * Dump it.
     887         * Dump the directory.
    241888         */
    242         DBGCVAR DebugDataAddr = *pThis->pImageBase;
    243         rc = DBGCCmdHlpEval(pCmdHlp, &DebugDataAddr, "%DV + %#RX32", pThis->pImageBase, DbgDir.AddressOfRawData);
    244         DBGCCmdHlpPrintf(pCmdHlp, "  Debug[%u]: %Dv/%08RX32 LB %06RX32 %u (%s) v%u.%u file=%RX32 ts=%08RX32 fl=%RX32\n",
    245                          i, &DebugDataAddr, DbgDir.AddressOfRawData, DbgDir.SizeOfData, DbgDir.Type,
    246                          dbgPeDebugTypeName(DbgDir.Type), DbgDir.MajorVersion, DbgDir.MinorVersion, DbgDir.PointerToRawData,
    247                          DbgDir.TimeDateStamp, DbgDir.Characteristics);
    248         union
    249         {
    250             uint8_t             abPage[0x1000];
    251             CVPDB20INFO         Pdb20;
    252             CVPDB70INFO         Pdb70;
    253             IMAGE_DEBUG_MISC    Misc;
    254         } uBuf;
    255         RT_ZERO(uBuf);
    256 
    257         if (DbgDir.Type == IMAGE_DEBUG_TYPE_CODEVIEW)
    258         {
    259             if (   DbgDir.SizeOfData < sizeof(uBuf)
    260                 && DbgDir.SizeOfData > 16
    261                 && DbgDir.AddressOfRawData > 0
    262                 && RT_SUCCESS(rc))
     889        myPrintf("             Name: %s %s\n",
     890                 rvaToStringWithAddr(ExpDir.Name, szTmp, sizeof(szTmp)), NmAddrRdr.bufferedString(ExpDir.Name));
     891        myPrintf("    Address table: %s L %u\n",
     892                 rvaToStringWithAddr(ExpDir.AddressOfFunctions, szTmp, sizeof(szTmp)), ExpDir.NumberOfFunctions);
     893        myPrintf("       Name table: %s L %u\n",
     894                 rvaToStringWithAddr(ExpDir.AddressOfNames, szTmp, sizeof(szTmp)), ExpDir.NumberOfNames);
     895        myPrintf(" Name index table: %s L ditto\n",
     896                 rvaToStringWithAddr(ExpDir.AddressOfNameOrdinals, szTmp, sizeof(szTmp)), ExpDir.NumberOfNames);
     897        myPrintf("     Ordinal base: %u\n", ExpDir.Base);
     898        if (ExpDir.Characteristics)
     899            myPrintf("  Characteristics: %#RX32\n", ExpDir.Characteristics);
     900        if (ExpDir.TimeDateStamp && ExpDir.TimeDateStamp != UINT32_MAX)
     901            myPrintf("    TimeDateStamp: %#RX32 %s\n",
     902                     ExpDir.TimeDateStamp, timestampToString(ExpDir.TimeDateStamp, szTmp, sizeof(szTmp)));
     903        if (ExpDir.MajorVersion || ExpDir.MinorVersion)
     904            myPrintf("          Version: %u.%u\n", ExpDir.MajorVersion, ExpDir.MinorVersion);
     905
     906        uint32_t const cExports = ExpDir.NumberOfNames;
     907        if (cExports > _16K)
     908        {
     909            myPrintf("  Exports: Too many addresses! (%#x)\n", cExports);
     910            return VINF_SUCCESS;
     911        }
     912        uint32_t const cNames = ExpDir.NumberOfNames;
     913        if (cNames > _32K)
     914        {
     915            myPrintf("  Exports: Too many names! (%#x)\n", cNames);
     916            return VINF_SUCCESS;
     917        }
     918        if (cExports == 0)
     919        {
     920            myPrintf("  Exports: No exports!\n");
     921            return VINF_SUCCESS;
     922        }
     923
     924        /*
     925         * Read the export addresses and  name tables into memory.
     926         */
     927        uint32_t const *pauExportRvas = (uint32_t const *)pBufRdr->bufferedBytes(ExpDir.AddressOfFunctions,
     928                                                                                 sizeof(pauExportRvas[0])* cExports);
     929        uint16_t const *pau16Ordinals = NULL;
     930        uint32_t const *pauNameRvas   = NULL;
     931        bool            fOrderedOrdinals = true;
     932        if (cNames)
     933        {
     934            pauNameRvas   = (uint32_t const *)NmAddrRdr.bufferedBytes(ExpDir.AddressOfNames, sizeof(pauNameRvas[0]) * cNames);
     935            if (!pauNameRvas)
     936                return VINF_SUCCESS;
     937            pau16Ordinals = (uint16_t const *)OrdRdr.bufferedBytes(ExpDir.AddressOfNameOrdinals,
     938                                                                   sizeof(pau16Ordinals[0]) * cNames);
     939            if (!pau16Ordinals)
     940                return VINF_SUCCESS;
     941
     942            /* Check if the name ordinals are ordered. */
     943            uint16_t iPrev = pau16Ordinals[0];
     944            for (uint32_t iOrd = 1; iOrd < cNames; iOrd++)
    263945            {
    264                 rc = DBGCCmdHlpMemRead(pCmdHlp, &uBuf, DbgDir.SizeOfData, &DebugDataAddr, NULL);
    265                 if (RT_FAILURE(rc))
    266                     return DBGCCmdHlpFailRc(pCmdHlp, pThis->pCmd, rc, "Failed to read %zu at %Dv",
    267                                             DbgDir.SizeOfData, &DebugDataAddr);
    268 
    269                 if (   uBuf.Pdb20.u32Magic   == CVPDB20INFO_MAGIC
    270                     && uBuf.Pdb20.offDbgInfo == 0
    271                     && DbgDir.SizeOfData > RT_UOFFSETOF(CVPDB20INFO, szPdbFilename) )
    272                     DBGCCmdHlpPrintf(pCmdHlp, "    PDB2.0: ts=%08RX32 age=%RX32 %s\n",
    273                                      uBuf.Pdb20.uTimestamp, uBuf.Pdb20.uAge, uBuf.Pdb20.szPdbFilename);
    274                 else if (   uBuf.Pdb20.u32Magic == CVPDB70INFO_MAGIC
    275                          && DbgDir.SizeOfData > RT_UOFFSETOF(CVPDB70INFO, szPdbFilename) )
    276                     DBGCCmdHlpPrintf(pCmdHlp, "    PDB7.0: %RTuuid age=%u %s\n",
    277                                      &uBuf.Pdb70.PdbUuid, uBuf.Pdb70.uAge, uBuf.Pdb70.szPdbFilename);
     946                uint16_t const iCur = pau16Ordinals[iOrd];
     947                if (iCur > iPrev)
     948                    iPrev = iCur;
    278949                else
    279                     DBGCCmdHlpPrintf(pCmdHlp, "    Unknown PDB/codeview magic: %.8Rhxs\n", uBuf.abPage);
    280             }
    281         }
    282         else if (DbgDir.Type == IMAGE_DEBUG_TYPE_MISC)
    283         {
    284             if (   DbgDir.SizeOfData < sizeof(uBuf)
    285                 && DbgDir.SizeOfData > RT_UOFFSETOF(IMAGE_DEBUG_MISC, Data)
    286                 && DbgDir.AddressOfRawData > 0
    287                 && RT_SUCCESS(rc) )
    288             {
    289                 rc = DBGCCmdHlpMemRead(pCmdHlp, &uBuf, DbgDir.SizeOfData, &DebugDataAddr, NULL);
    290                 if (RT_FAILURE(rc))
    291                     return DBGCCmdHlpFailRc(pCmdHlp, pThis->pCmd, rc, "Failed to read %zu at %Dv",
    292                                             DbgDir.SizeOfData, &DebugDataAddr);
    293 
    294                 if (   uBuf.Misc.DataType == IMAGE_DEBUG_MISC_EXENAME
    295                     && uBuf.Misc.Length   == DbgDir.SizeOfData)
    296950                {
    297                     if (!uBuf.Misc.Unicode)
    298                         DBGCCmdHlpPrintf(pCmdHlp, "    Misc DBG: ts=%RX32 %s\n",
    299                                          DbgDir.TimeDateStamp, (const char *)&uBuf.Misc.Data[0]);
    300                     else
    301                         DBGCCmdHlpPrintf(pCmdHlp, "    Misc DBG: ts=%RX32 %ls\n",
    302                                          DbgDir.TimeDateStamp, (PCRTUTF16)&uBuf.Misc.Data[0]);
     951                    fOrderedOrdinals = false;
     952                    break;
    303953                }
    304954            }
    305         }
    306     }
    307     return VINF_SUCCESS;
    308 }
    309 
    310 
    311 static int dbgcDumpImagePeDataDirs(PDUMPIMAGEPE pThis, PDBGCCMDHLP pCmdHlp, unsigned cDataDirs, PCIMAGE_DATA_DIRECTORY paDataDirs)
    312 {
    313     int rcRet = VINF_SUCCESS;
    314     for (unsigned i = 0; i < cDataDirs; i++)
    315     {
    316         if (paDataDirs[i].Size || paDataDirs[i].VirtualAddress)
    317         {
    318             DBGCVAR DataAddr = *pThis->pImageBase;
    319             DBGCCmdHlpEval(pCmdHlp, &DataAddr, "%DV + %#RX32", pThis->pImageBase, paDataDirs[i].VirtualAddress);
    320             DBGCCmdHlpPrintf(pCmdHlp, "DataDir[%02u]: %Dv/%08RX32 LB %08RX32 %s\n",
    321                              i, &DataAddr, paDataDirs[i].VirtualAddress, paDataDirs[i].Size, dbgcPeDataDirName(i));
    322             int rc = VINF_SUCCESS;
    323             if (   i == IMAGE_DIRECTORY_ENTRY_DEBUG
    324                 && paDataDirs[i].Size >= sizeof(IMAGE_DEBUG_DIRECTORY))
    325                 rc = dbgcDumpImagePeDebugDir(pThis, pCmdHlp, &DataAddr, paDataDirs[i].Size);
    326             if (RT_FAILURE(rc) && RT_SUCCESS(rcRet))
    327                 rcRet = rc;
    328         }
    329     }
    330     return rcRet;
    331 }
    332 
    333 
    334 static int dbgcDumpImagePeSectionHdrs(PDUMPIMAGEPE pThis, PDBGCCMDHLP pCmdHlp, unsigned cShdrs, PCIMAGE_SECTION_HEADER paShdrs)
    335 {
    336     for (unsigned i = 0; i < cShdrs; i++)
    337     {
    338         DBGCVAR SectAddr = *pThis->pImageBase;
    339         DBGCCmdHlpEval(pCmdHlp, &SectAddr, "%DV + %#RX32", pThis->pImageBase, paShdrs[i].VirtualAddress);
    340         DBGCCmdHlpPrintf(pCmdHlp, "Section[%02u]: %Dv/%08RX32 LB %08RX32 %.8s\n",
    341                          i, &SectAddr, paShdrs[i].VirtualAddress, paShdrs[i].Misc.VirtualSize,  paShdrs[i].Name);
    342     }
    343     return VINF_SUCCESS;
    344 }
    345 
    346 
    347 static int dbgcDumpImagePeOptHdr32(PDUMPIMAGEPE pThis, PDBGCCMDHLP pCmdHlp, PCIMAGE_NT_HEADERS32 pNtHdrs)
    348 {
    349     RT_NOREF(pThis, pCmdHlp, pNtHdrs);
    350     return VINF_SUCCESS;
    351 }
    352 
    353 static int dbgcDumpImagePeOptHdr64(PDUMPIMAGEPE pThis, PDBGCCMDHLP pCmdHlp, PCIMAGE_NT_HEADERS64 pNtHdrs)
    354 {
    355     RT_NOREF(pThis, pCmdHlp, pNtHdrs);
    356     return VINF_SUCCESS;
    357 }
    358 
    359 
    360 static int dbgcDumpImagePe(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pImageBase,
    361                            PCDBGCVAR pPeHdrAddr, PCIMAGE_FILE_HEADER pFileHdr)
    362 {
    363     /*
    364      * Dump file header fields.
    365      */
    366     DBGCCmdHlpPrintf(pCmdHlp, "%Dv: PE image - %#x (%s), %u sections\n", pImageBase, pFileHdr->Machine,
     955
     956        }
     957
     958        /*
     959         * Dump the exports by named exports.
     960         */
     961        static const char s_szAddr[] = "Export RVA/Address";
     962        unsigned          cchAddr    = (unsigned)strlen(rvaToStringWithAddr(uRvaData, szTmp, sizeof(szTmp)));
     963        cchAddr = RT_MAX(cchAddr, sizeof(s_szAddr) - 1);
     964        myPrintf("\n"
     965                 "Ordinal %*s%s%*s Name RVA  Name\n"
     966                 "------- %*.*s --------- --------------------------------\n",
     967                 (cchAddr - sizeof(s_szAddr) + 1) / 2, "", s_szAddr, (cchAddr - sizeof(s_szAddr) + 1 + 1) / 2, "",
     968                 cchAddr, cchAddr, "--------------------------------------");
     969
     970        for (uint32_t iExp = 0, iName = 0; iExp < cExports; iExp++)
     971        {
     972            if (cNames > 0)
     973            {
     974                if (fOrderedOrdinals)
     975                {
     976                    if (iName < cNames && pau16Ordinals[iName] == iExp)
     977                    {
     978                        uint32_t     const uRvaName = pauNameRvas[iExp];
     979                        const char * const pszName = NameRdr.bufferedString(uRvaName);
     980                        myPrintf("%7u %s %#09RX32 %s\n", iExp + ExpDir.Base,
     981                                 rvaToStringWithAddr(pauExportRvas[iExp], szTmp, sizeof(szTmp)),
     982                                 uRvaName, pszName ? pszName : "");
     983                        iName++;
     984                        continue;
     985                    }
     986                }
     987                else
     988                {
     989                    /* Search the entire name ordinal table, not stopping on a hit
     990                       as there could in theory be different names for the same entry. */
     991                    uint32_t cPrinted = 0;
     992                    for (iName = 0; iName < cNames; iName++)
     993                        if (pau16Ordinals[iName] == iExp)
     994                        {
     995                            uint32_t     const uRvaName = pauNameRvas[iExp];
     996                            const char * const pszName = NameRdr.bufferedString(uRvaName);
     997                            myPrintf("%7u %s %#09RX32 %s\n", iExp + ExpDir.Base,
     998                                     rvaToStringWithAddr(pauExportRvas[iExp], szTmp, sizeof(szTmp)),
     999                                     uRvaName, pszName ? pszName : "");
     1000                            cPrinted++;
     1001                        }
     1002                    if (cPrinted)
     1003                        continue;
     1004                }
     1005            }
     1006            /* Ordinal only. */
     1007            myPrintf("%7u %s %#09RX32\n", iExp + ExpDir.Base,
     1008                     rvaToStringWithAddr(pauExportRvas[iExp], szTmp, sizeof(szTmp)), UINT32_MAX);
     1009        }
     1010        return VINF_SUCCESS;
     1011    }
     1012
     1013    template<typename ThunkType, bool const a_f32Bit, ThunkType const a_fOrdinalConst>
     1014    int dumpImportDir(DumpImageBufferedReader *pBufRdr, uint32_t uRvaData, uint32_t cbData)
     1015    {
     1016        char         szTmp[64];
     1017        char         szTmp2[64];
     1018        size_t const cchRvaWithAddr = strlen(rvaToStringWithAddr(uRvaData, szTmp, sizeof(szTmp)));
     1019
     1020        /* Use dedicated readers for each array and names */
     1021        DumpImageBufferedReader NameRdr(*pBufRdr), Thunk1stRdr(*pBufRdr), ThunkOrgRdr(*pBufRdr);
     1022
     1023        myPrintHeader(uRvaData, "Import table");
     1024        int            rcRet    = VINF_SUCCESS;
     1025        uint32_t const cEntries = cbData / sizeof(IMAGE_IMPORT_DESCRIPTOR);
     1026        for (uint32_t i = 0; i < cEntries; i += 1, uRvaData += sizeof(IMAGE_IMPORT_DESCRIPTOR))
     1027        {
     1028            /*
     1029             * Read the entry into memory.
     1030             */
     1031            IMAGE_IMPORT_DESCRIPTOR ImpDir;
     1032            int rc = pBufRdr->readBytes(uRvaData, &ImpDir, sizeof(ImpDir));
     1033            if (RT_FAILURE(rc))
     1034                return rc;
     1035
     1036            if (ImpDir.Name == 0)
     1037                continue;
     1038
     1039            /*
     1040             * Dump it.
     1041             */
     1042            if (i > 0)
     1043                myPrintf("\n");
     1044            myPrintf("         Entry #: %u\n",  i);
     1045            myPrintf("            Name: %s - %s\n", rvaToStringWithAddr(ImpDir.Name, szTmp, sizeof(szTmp)),
     1046                     ImpDir.Name ? NameRdr.bufferedString(ImpDir.Name) : "");
     1047            if (ImpDir.TimeDateStamp && ImpDir.TimeDateStamp != UINT32_MAX)
     1048                myPrintf("       Timestamp: %#010RX32 %s\n",
     1049                         ImpDir.TimeDateStamp, timestampToString(ImpDir.TimeDateStamp, szTmp, sizeof(szTmp)));
     1050            myPrintf("     First thunk: %s\n", rvaToStringWithAddr(ImpDir.FirstThunk, szTmp, sizeof(szTmp)));
     1051            myPrintf("  Original thunk: %s\n", rvaToStringWithAddr(ImpDir.u.OriginalFirstThunk, szTmp, sizeof(szTmp)));
     1052            if (ImpDir.ForwarderChain)
     1053                myPrintf(" Forwarder chain: %s\n", rvaToStringWithAddr(ImpDir.ForwarderChain, szTmp, sizeof(szTmp)));
     1054
     1055            /*
     1056             * Try process the arrays.
     1057             */
     1058            static char const s_szDashes[] = "-----------------------------------------------";
     1059            static char const s_szHdr1[]   = "Thunk RVA/Addr";
     1060            uint32_t uRvaNames = ImpDir.u.OriginalFirstThunk;
     1061            uint32_t uRvaThunk = ImpDir.FirstThunk;
     1062            if (uRvaThunk == 0)
     1063                uRvaThunk = uRvaNames;
     1064            if (uRvaNames != 0 && uRvaNames != uRvaThunk)
     1065            {
     1066                static char const s_szHdr2[] = "Thunk";
     1067                static char const s_szHdr4[] = "Hint+Name RVA/Addr";
     1068                size_t const      cchCol1    = RT_MAX(sizeof(s_szHdr1) - 1, cchRvaWithAddr);
     1069                size_t const      cchCol2    = RT_MAX(sizeof(s_szHdr2) - 1, 2 + sizeof(ThunkType) * 2);
     1070                size_t const      cchCol4    = RT_MAX(sizeof(s_szHdr4) - 1, cchRvaWithAddr);
     1071
     1072                myPrintf(" No.  %-*s %-*s Ord/Hint %-*s Name\n"
     1073                         "----  %.*s %.*s -------- %.*s ----------------\n",
     1074                         cchCol1, s_szHdr1,   cchCol2, s_szHdr2,   cchCol4, s_szHdr4,
     1075                         cchCol1, s_szDashes, cchCol2, s_szDashes, cchCol4, s_szDashes);
     1076                for (uint32_t iEntry = 0;; iEntry += 1, uRvaThunk += sizeof(ThunkType), uRvaNames += sizeof(ThunkType))
     1077                {
     1078                    ThunkType const uName  = ThunkOrgRdr.bufferedInt<ThunkType>(uRvaNames, 0);
     1079                    ThunkType const uThunk = Thunk1stRdr.bufferedInt<ThunkType>(uRvaThunk, 0);
     1080                    if (!uName || !uThunk)
     1081                        break;
     1082
     1083                    if (!(uName & a_fOrdinalConst))
     1084                    {
     1085                        uint16_t const     uHint   = NameRdr.bufferedInt<uint16_t>(uName);
     1086                        const char * const pszName = NameRdr.bufferedString(uName + 2);
     1087                        if (a_f32Bit)
     1088                            myPrintf("%4u: %s %#010RX32 %8RU16 %s %s\n",
     1089                                     iEntry, rvaToStringWithAddr(uRvaThunk, szTmp, sizeof(szTmp)), uThunk, uHint,
     1090                                     rvaToStringWithAddr(uName, szTmp2, sizeof(szTmp2)), pszName);
     1091                        else
     1092                            myPrintf("%4u: %s %#018RX64 %8RU16 %s %s\n",
     1093                                     iEntry, rvaToStringWithAddr(uRvaThunk, szTmp, sizeof(szTmp)), uThunk, uHint,
     1094                                     rvaToStringWithAddr(uName, szTmp2, sizeof(szTmp2)), pszName);
     1095                    }
     1096                    else
     1097                    {
     1098                        if (a_f32Bit)
     1099                            myPrintf("%4u: %s %#010RX32 %8RU32\n", iEntry,
     1100                                     rvaToStringWithAddr(uRvaThunk, szTmp, sizeof(szTmp)), uThunk, uName & ~a_fOrdinalConst);
     1101                        else
     1102                            myPrintf("%4u: %s %#018RX64 %8RU64\n", iEntry,
     1103                                     rvaToStringWithAddr(uRvaThunk, szTmp, sizeof(szTmp)), uThunk, uName & ~a_fOrdinalConst);
     1104                    }
     1105                }
     1106            }
     1107            /** @todo */
     1108            //else if (uRvaThunk)
     1109            //    for (;;)
     1110            //    {
     1111            //        ThunkType const *pThunk = (ThunkType const *)Thunk1stRdr.bufferedBytes(uRvaThunk, sizeof(*pThunk));
     1112            //        if (!pThunk->u1.AddressOfData == 0)
     1113            //            break;
     1114            //    }
     1115        }
     1116        return rcRet;
     1117    }
     1118
     1119    int dumpDebugDir(DumpImageBufferedReader *pBufRdr, uint32_t uRvaData, uint32_t cbData)
     1120    {
     1121        myPrintHeader(uRvaData, "Debug Directory");
     1122        int            rcRet    = VINF_SUCCESS;
     1123        uint32_t const cEntries = cbData / sizeof(IMAGE_DEBUG_DIRECTORY);
     1124        for (uint32_t i = 0; i < cEntries; i += 1, uRvaData += sizeof(IMAGE_DEBUG_DIRECTORY))
     1125        {
     1126            /*
     1127             * Read the entry into memory.
     1128             */
     1129            IMAGE_DEBUG_DIRECTORY DbgDir;
     1130            int rc = pBufRdr->readBytes(uRvaData, &DbgDir, sizeof(DbgDir));
     1131            if (RT_FAILURE(rc))
     1132                return rc;
     1133
     1134            /*
     1135             * Dump it.
     1136             * (longest type is 13 chars:'OMAP_FROM_SRC')
     1137             */
     1138            char szTmp[64];
     1139            char szTmp2[64];
     1140            myPrintf("%u: %s LB %06RX32  %#09RX32  %13s",
     1141                     i, rvaToStringWithAddr(DbgDir.AddressOfRawData, szTmp, sizeof(szTmp)), DbgDir.SizeOfData,
     1142                     DbgDir.PointerToRawData,
     1143                     dbgPeDebugTypeName(DbgDir.Type, szTmp2, sizeof(szTmp2)));
     1144            if (DbgDir.MajorVersion || DbgDir.MinorVersion)
     1145                myPrintf("  v%u.%u", DbgDir.MajorVersion, DbgDir.MinorVersion);
     1146            if (DbgDir.Characteristics)
     1147                myPrintf("  flags=%#RX32", DbgDir.Characteristics);
     1148            myPrintf("  %s (%#010RX32)\n", timestampToString(DbgDir.TimeDateStamp, szTmp, sizeof(szTmp)), DbgDir.TimeDateStamp);
     1149
     1150            union
     1151            {
     1152                uint8_t             abPage[0x1000];
     1153                CVPDB20INFO         Pdb20;
     1154                CVPDB70INFO         Pdb70;
     1155                IMAGE_DEBUG_MISC    Misc;
     1156            } uBuf;
     1157            RT_ZERO(uBuf);
     1158
     1159            if (DbgDir.Type == IMAGE_DEBUG_TYPE_CODEVIEW)
     1160            {
     1161                if (   DbgDir.SizeOfData < sizeof(uBuf)
     1162                    && DbgDir.SizeOfData > 16
     1163                    && DbgDir.AddressOfRawData > 0
     1164                    && RT_SUCCESS(rc))
     1165                {
     1166                    rc = pBufRdr->readBytes(DbgDir.AddressOfRawData, &uBuf, DbgDir.SizeOfData);
     1167                    if (RT_SUCCESS(rc))
     1168                    {
     1169                        if (   uBuf.Pdb20.u32Magic   == CVPDB20INFO_MAGIC
     1170                            && uBuf.Pdb20.offDbgInfo == 0
     1171                            && DbgDir.SizeOfData > RT_UOFFSETOF(CVPDB20INFO, szPdbFilename) )
     1172                            myPrintf("    PDB2.0: ts=%08RX32 age=%RX32 %s\n",
     1173                                     uBuf.Pdb20.uTimestamp, uBuf.Pdb20.uAge, uBuf.Pdb20.szPdbFilename);
     1174                        else if (   uBuf.Pdb20.u32Magic == CVPDB70INFO_MAGIC
     1175                                 && DbgDir.SizeOfData > RT_UOFFSETOF(CVPDB70INFO, szPdbFilename) )
     1176                            myPrintf("    PDB7.0: %RTuuid age=%u %s\n",
     1177                                     &uBuf.Pdb70.PdbUuid, uBuf.Pdb70.uAge, uBuf.Pdb70.szPdbFilename);
     1178                        else
     1179                            myPrintf("    Unknown PDB/codeview magic: %.8Rhxs\n", uBuf.abPage);
     1180                    }
     1181                    else
     1182                        rcRet = rc;
     1183                }
     1184            }
     1185            else if (DbgDir.Type == IMAGE_DEBUG_TYPE_MISC)
     1186            {
     1187                if (   DbgDir.SizeOfData < sizeof(uBuf)
     1188                    && DbgDir.SizeOfData > RT_UOFFSETOF(IMAGE_DEBUG_MISC, Data)
     1189                    && DbgDir.AddressOfRawData > 0)
     1190                {
     1191                    rc = pBufRdr->readBytes(DbgDir.AddressOfRawData, &uBuf, DbgDir.SizeOfData);
     1192                    if (RT_SUCCESS(rc))
     1193                    {
     1194                        if (   uBuf.Misc.DataType == IMAGE_DEBUG_MISC_EXENAME
     1195                            && uBuf.Misc.Length   == DbgDir.SizeOfData)
     1196                        {
     1197                            if (!uBuf.Misc.Unicode)
     1198                                myPrintf("    Misc DBG: ts=%RX32 %s\n", DbgDir.TimeDateStamp, (const char *)&uBuf.Misc.Data[0]);
     1199                            else
     1200                                myPrintf("    Misc DBG: ts=%RX32 %ls\n", DbgDir.TimeDateStamp, (PCRTUTF16)&uBuf.Misc.Data[0]);
     1201                        }
     1202                    }
     1203                    else
     1204                        rcRet = rc;
     1205                }
     1206            }
     1207        }
     1208        return rcRet;
     1209    }
     1210
     1211    int dumpDataDirs(DumpImageBufferedReader *pBufRdr, unsigned cDataDirs, PCIMAGE_DATA_DIRECTORY paDataDirs)
     1212    {
     1213        int rcRet = VINF_SUCCESS;
     1214        for (unsigned i = 0; i < cDataDirs; i++)
     1215            if (paDataDirs[i].Size > 0 && paDataDirs[i].VirtualAddress)
     1216            {
     1217                int rc;
     1218                if (   i == IMAGE_DIRECTORY_ENTRY_EXPORT
     1219                         && paDataDirs[i].Size >= sizeof(IMAGE_EXPORT_DIRECTORY))
     1220                    rc = dumpExportDir(pBufRdr, paDataDirs[i].VirtualAddress, paDataDirs[i].Size);
     1221                else if (   i == IMAGE_DIRECTORY_ENTRY_IMPORT
     1222                         && paDataDirs[i].Size >= sizeof(IMAGE_IMPORT_DESCRIPTOR))
     1223                {
     1224                    if (m_pFileHdr->SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32))
     1225                        rc = dumpImportDir<uint32_t,  true, IMAGE_ORDINAL_FLAG32>(pBufRdr, paDataDirs[i].VirtualAddress,
     1226                                                                                  paDataDirs[i].Size);
     1227                    else
     1228                        rc = dumpImportDir<uint64_t, false, IMAGE_ORDINAL_FLAG64>(pBufRdr, paDataDirs[i].VirtualAddress,
     1229                                                                                  paDataDirs[i].Size);
     1230                }
     1231                else if (   i == IMAGE_DIRECTORY_ENTRY_DEBUG
     1232                         && paDataDirs[i].Size >= sizeof(IMAGE_DEBUG_DIRECTORY))
     1233                    rc = dumpDebugDir(pBufRdr, paDataDirs[i].VirtualAddress, paDataDirs[i].Size);
     1234                else
     1235                    continue;
     1236                if (RT_FAILURE(rc))
     1237                    rcRet = rc;
     1238            }
     1239        return rcRet;
     1240    }
     1241
     1242    /** @} */
     1243};
     1244
     1245
     1246static int dbgcDumpImagePe(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pImageBase, const char *pszImageBaseAddr,
     1247                           const char *pszName, uint32_t offPeHdr, PCIMAGE_FILE_HEADER pFileHdr)
     1248{
     1249    DBGCCmdHlpPrintf(pCmdHlp, "%s: PE image - %#x (%s), %u sections\n", pszName, pFileHdr->Machine,
    3671250                     dbgcPeMachineName(pFileHdr->Machine), pFileHdr->NumberOfSections);
    368     DBGCCmdHlpPrintf(pCmdHlp, "Characteristics: %#06x", pFileHdr->Characteristics);
    369     if (pFileHdr->Characteristics & IMAGE_FILE_RELOCS_STRIPPED)         DBGCCmdHlpPrintf(pCmdHlp, " RELOCS_STRIPPED");
    370     if (pFileHdr->Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE)        DBGCCmdHlpPrintf(pCmdHlp, " EXECUTABLE_IMAGE");
    371     if (pFileHdr->Characteristics & IMAGE_FILE_LINE_NUMS_STRIPPED)      DBGCCmdHlpPrintf(pCmdHlp, " LINE_NUMS_STRIPPED");
    372     if (pFileHdr->Characteristics & IMAGE_FILE_LOCAL_SYMS_STRIPPED)     DBGCCmdHlpPrintf(pCmdHlp, " LOCAL_SYMS_STRIPPED");
    373     if (pFileHdr->Characteristics & IMAGE_FILE_AGGRESIVE_WS_TRIM)       DBGCCmdHlpPrintf(pCmdHlp, " AGGRESIVE_WS_TRIM");
    374     if (pFileHdr->Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE)     DBGCCmdHlpPrintf(pCmdHlp, " LARGE_ADDRESS_AWARE");
    375     if (pFileHdr->Characteristics & IMAGE_FILE_16BIT_MACHINE)           DBGCCmdHlpPrintf(pCmdHlp, " 16BIT_MACHINE");
    376     if (pFileHdr->Characteristics & IMAGE_FILE_BYTES_REVERSED_LO)       DBGCCmdHlpPrintf(pCmdHlp, " BYTES_REVERSED_LO");
    377     if (pFileHdr->Characteristics & IMAGE_FILE_32BIT_MACHINE)           DBGCCmdHlpPrintf(pCmdHlp, " 32BIT_MACHINE");
    378     if (pFileHdr->Characteristics & IMAGE_FILE_DEBUG_STRIPPED)          DBGCCmdHlpPrintf(pCmdHlp, " DEBUG_STRIPPED");
    379     if (pFileHdr->Characteristics & IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP) DBGCCmdHlpPrintf(pCmdHlp, " REMOVABLE_RUN_FROM_SWAP");
    380     if (pFileHdr->Characteristics & IMAGE_FILE_NET_RUN_FROM_SWAP)       DBGCCmdHlpPrintf(pCmdHlp, " NET_RUN_FROM_SWAP");
    381     if (pFileHdr->Characteristics & IMAGE_FILE_SYSTEM)                  DBGCCmdHlpPrintf(pCmdHlp, " SYSTEM");
    382     if (pFileHdr->Characteristics & IMAGE_FILE_DLL)                     DBGCCmdHlpPrintf(pCmdHlp, " DLL");
    383     if (pFileHdr->Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY)          DBGCCmdHlpPrintf(pCmdHlp, " UP_SYSTEM_ONLY");
    384     if (pFileHdr->Characteristics & IMAGE_FILE_BYTES_REVERSED_HI)       DBGCCmdHlpPrintf(pCmdHlp, " BYTES_REVERSED_HI");
    385     DBGCCmdHlpPrintf(pCmdHlp, "\n");
     1251
     1252    /* Is it a supported optional header size? */
     1253    uint8_t cBits;
     1254    if (pFileHdr->SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32))
     1255        cBits = 32;
     1256    else if (pFileHdr->SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER64))
     1257        cBits = 64;
     1258    else
     1259        return DBGCCmdHlpFail(pCmdHlp, pCmd, "%s: Unsupported optional header size: %#x\n",
     1260                              pszName, pFileHdr->SizeOfOptionalHeader);
    3861261
    3871262    /*
    3881263     * Allocate memory for all the headers, including section headers, and read them into memory.
    3891264     */
    390     size_t offSHdrs = pFileHdr->SizeOfOptionalHeader + sizeof(*pFileHdr) + sizeof(uint32_t);
    391     size_t cbHdrs = offSHdrs + pFileHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
     1265    size_t const offShdrs = pFileHdr->SizeOfOptionalHeader + sizeof(*pFileHdr) + sizeof(uint32_t);
     1266    size_t const cbHdrs   = offShdrs + pFileHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
    3921267    if (cbHdrs > _2M)
    393         return DBGCCmdHlpFail(pCmdHlp, pCmd, "%Dv: headers too big: %zu.\n", pImageBase, cbHdrs);
     1268        return DBGCCmdHlpFail(pCmdHlp, pCmd, "%s: headers too big: %zu.\n", pszName, cbHdrs);
    3941269
    3951270    void *pvBuf = RTMemTmpAllocZ(cbHdrs);
    3961271    if (!pvBuf)
    397         return DBGCCmdHlpFail(pCmdHlp, pCmd, "%Dv: failed to allocate %zu bytes.\n", pImageBase, cbHdrs);
    398     int rc = DBGCCmdHlpMemRead(pCmdHlp, pvBuf, cbHdrs, pPeHdrAddr, NULL);
     1272        return DBGCCmdHlpFail(pCmdHlp, pCmd, "%s: failed to allocate %zu bytes for headers.\n", pszName, cbHdrs);
     1273
     1274    int rc = dumpReadAt(pCmdHlp, pCmd, pImageBase, pszName, offPeHdr, pvBuf, cbHdrs, NULL);
    3991275    if (RT_SUCCESS(rc))
    4001276    {
    401         DUMPIMAGEPE This;
    402         RT_ZERO(This);
    403         This.pImageBase = pImageBase;
    404         This.pFileHdr   = pFileHdr;
    405         This.u.pv       = pvBuf;
    406         This.cShdrs     = pFileHdr->NumberOfSections;
    407         This.paShdrs    = (PCIMAGE_SECTION_HEADER)((uintptr_t)pvBuf + offSHdrs);
    408         This.pCmd       = pCmd;
    409 
    410         if (pFileHdr->SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32))
    411         {
    412             This.paDataDir = This.u.pNt32->OptionalHeader.DataDirectory;
    413             This.cDataDir  = This.u.pNt32->OptionalHeader.NumberOfRvaAndSizes;
    414             rc = dbgcDumpImagePeOptHdr32(&This, pCmdHlp, This.u.pNt32);
    415         }
    416         else if (pFileHdr->SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER64))
    417         {
    418             This.paDataDir = This.u.pNt64->OptionalHeader.DataDirectory;
    419             This.cDataDir  = This.u.pNt64->OptionalHeader.NumberOfRvaAndSizes;
    420             rc = dbgcDumpImagePeOptHdr64(&This, pCmdHlp, This.u.pNt64);
    421         }
     1277        /* Format the image base value from the header if one isn't specified. */
     1278        char szTmp[32];
     1279        if (!pszImageBaseAddr)
     1280        {
     1281            if (cBits == 32)
     1282                RTStrPrintf(szTmp, sizeof(szTmp), "%#010RX32", ((PIMAGE_NT_HEADERS32)pvBuf)->OptionalHeader.ImageBase);
     1283            else
     1284                RTStrPrintf(szTmp, sizeof(szTmp), "%#018RX64", ((PIMAGE_NT_HEADERS64)pvBuf)->OptionalHeader.ImageBase);
     1285            pszImageBaseAddr = szTmp;
     1286        }
     1287
     1288        /* Finally, instantiate dumper now that we've got the section table
     1289           loaded, and let it contiue. */
     1290        DumpImagePe This(pCmdHlp, pCmd, pImageBase, pszImageBaseAddr, pszName,
     1291                         offPeHdr, pFileHdr, pvBuf,
     1292                         (uint32_t)offShdrs, pFileHdr->NumberOfSections, (PCIMAGE_SECTION_HEADER)((uintptr_t)pvBuf + offShdrs));
     1293
     1294        This.dumpPeHdr();
     1295        if (cBits == 32)
     1296            rc = This.dumpOptHdr<IMAGE_OPTIONAL_HEADER32, true>(&This.u.pNt32->OptionalHeader,
     1297                                                                This.u.pNt32->OptionalHeader.BaseOfData);
    4221298        else
    423             rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "%Dv: Unsupported optional header size: %#x\n",
    424                                 pImageBase, pFileHdr->SizeOfOptionalHeader);
    425 
    426         int rc2 = dbgcDumpImagePeSectionHdrs(&This, pCmdHlp, This.cShdrs, This.paShdrs);
     1299            rc = This.dumpOptHdr<IMAGE_OPTIONAL_HEADER64, false>(&This.u.pNt64->OptionalHeader);
     1300
     1301        int rc2 = This.dumpSectionHdrs();
    4271302        if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
    4281303            rc = rc2;
    4291304
    430         rc2 = dbgcDumpImagePeDataDirs(&This, pCmdHlp, This.cDataDir, This.paDataDir);
     1305        DumpImageBufferedReader BufRdr(&This);
     1306        rc2 = This.dumpDataDirs(&BufRdr, This.cDataDir, This.paDataDir);
    4311307        if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
    4321308            rc = rc2;
    4331309    }
    434     else
    435         rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "%Dv: Failed to read %zu at %Dv", pImageBase, cbHdrs, pPeHdrAddr);
    4361310    RTMemTmpFree(pvBuf);
    4371311    return rc;
     
    4431317*********************************************************************************************************************************/
    4441318
    445 static int dbgcDumpImageElf(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pImageBase)
    446 {
    447     RT_NOREF_PV(pCmd);
    448     DBGCCmdHlpPrintf(pCmdHlp, "%Dv: ELF image dumping not implemented yet.\n", pImageBase);
     1319static int dbgcDumpImageElf(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pImageBase, const char *pszName)
     1320{
     1321    RT_NOREF(pCmd, pImageBase);
     1322    DBGCCmdHlpPrintf(pCmdHlp, "%s: ELF image dumping not implemented yet.\n", pszName);
    4491323    return VINF_SUCCESS;
    4501324}
     
    5791453
    5801454
    581 static int dbgcDumpImageMachO(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pImageBase, mach_header_64_t const *pHdr)
     1455static int dbgcDumpImageMachO(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pImageBase, const char *pszName,
     1456                              mach_header_64_t const *pHdr)
    5821457{
    5831458#define ENTRY(a_Define)  { a_Define, #a_Define }
     
    5871462     * Header:
    5881463     */
    589     DBGCCmdHlpPrintf(pCmdHlp, "%Dv: Mach-O image (%s bit) - %s (%u) - %s (%#x / %#x)\n",
    590                      pImageBase, pHdr->magic == IMAGE_MACHO64_SIGNATURE ? "64" : "32",
     1464    DBGCCmdHlpPrintf(pCmdHlp, "%s: Mach-O image (%s bit) - %s (%u) - %s (%#x / %#x)\n",
     1465                     pszName, pHdr->magic == IMAGE_MACHO64_SIGNATURE ? "64" : "32",
    5911466                     dbgcMachoFileType(pHdr->filetype), pHdr->filetype,
    5921467                     dbgcMachoCpuType(pHdr->cputype, pHdr->cpusubtype), pHdr->cputype, pHdr->cpusubtype);
    5931468
    594     DBGCCmdHlpPrintf(pCmdHlp, "%Dv: Flags: %#x", pImageBase, pHdr->flags);
     1469    DBGCCmdHlpPrintf(pCmdHlp, "%s: Flags: %#x", pszName, pHdr->flags);
    5951470    static DBGCDUMPFLAGENTRY const s_aHdrFlags[] =
    5961471    {
     
    6121487    DBGCCmdHlpPrintf(pCmdHlp, "\n");
    6131488    if (pHdr->reserved != 0 && pHdr->magic == IMAGE_MACHO64_SIGNATURE)
    614         DBGCCmdHlpPrintf(pCmdHlp, "%Dv: Reserved header field: %#x\n", pImageBase, pHdr->reserved);
     1489        DBGCCmdHlpPrintf(pCmdHlp, "%s: Reserved header field: %#x\n", pszName, pHdr->reserved);
    6151490
    6161491    /*
     
    6191494    const uint32_t cCmds  = pHdr->ncmds;
    6201495    const uint32_t cbCmds = pHdr->sizeofcmds;
    621     DBGCCmdHlpPrintf(pCmdHlp, "%Dv: %u load commands covering %#x bytes:\n", pImageBase, cCmds, cbCmds);
     1496    DBGCCmdHlpPrintf(pCmdHlp, "%s: %u load commands covering %#x bytes:\n", pszName, cCmds, cbCmds);
    6221497    if (cbCmds > _16M)
    6231498        return DBGCCmdHlpFailRc(pCmdHlp, pCmd, VERR_OUT_OF_RANGE,
    624                                 "%Dv: Commands too big: %#x bytes, max 16MiB\n", pImageBase, cbCmds);
    625 
    626     /* Calc address of the first command: */
     1499                                "%s: Commands too big: %#x bytes, max 16MiB\n", pszName, cbCmds);
     1500
     1501
     1502    /* Read the commands into a temp buffer: */
    6271503    const uint32_t cbHdr = pHdr->magic == IMAGE_MACHO64_SIGNATURE ? sizeof(mach_header_64_t) : sizeof(mach_header_32_t);
    628     DBGCVAR Addr;
    629     int rc = DBGCCmdHlpEval(pCmdHlp, &Addr, "%DV + %#RX32", pImageBase, cbHdr);
    630     AssertRCReturn(rc, rc);
    631 
    632     /* Read them into a temp buffer: */
    6331504    uint8_t *pbCmds = (uint8_t *)RTMemTmpAllocZ(cbCmds);
    6341505    if (!pbCmds)
    6351506        return VERR_NO_TMP_MEMORY;
    6361507
    637     rc = DBGCCmdHlpMemRead(pCmdHlp, pbCmds, cbCmds, &Addr, NULL);
     1508    int rc = dumpReadAt(pCmdHlp, pCmd, pImageBase, pszName, cbHdr, pbCmds, cbCmds, NULL);
    6381509    if (RT_SUCCESS(rc))
    6391510    {
     
    6521523            {
    6531524                rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, VERR_OUT_OF_RANGE,
    654                                       "%Dv: Load command #%u (offset %#x + %#x) is out of bounds! cmdsize=%u (%#x) cmd=%u\n",
    655                                       pImageBase, iCmd, offCmd, cbHdr, cbCurCmd, cbCurCmd,
     1525                                      "%s: Load command #%u (offset %#x + %#x) is out of bounds! cmdsize=%u (%#x) cmd=%u\n",
     1526                                      pszName, iCmd, offCmd, cbHdr, cbCurCmd, cbCurCmd,
    6561527                                      offCmd + RT_UOFFSET_AFTER(load_command_t, cmd) <= cbCmds ? pCurCmd->cmd : UINT32_MAX);
    6571528                break;
    6581529            }
    6591530
    660             DBGCCmdHlpPrintf(pCmdHlp, "%Dv: Load command #%u (offset %#x + %#x): %s (%u) LB %u\n",
    661                              pImageBase, iCmd, offCmd, cbHdr, dbgcMachoLoadCommand(pCurCmd->cmd), pCurCmd->cmd, cbCurCmd);
     1531            DBGCCmdHlpPrintf(pCmdHlp, "%s: Load command #%u (offset %#x + %#x): %s (%u) LB %u\n",
     1532                             pszName, iCmd, offCmd, cbHdr, dbgcMachoLoadCommand(pCurCmd->cmd), pCurCmd->cmd, cbCurCmd);
    6621533            switch (pCurCmd->cmd)
    6631534            {
     
    6651536                    if (cbCurCmd < sizeof(segment_command_64_t))
    6661537                        rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, VERR_LDRMACHO_BAD_LOAD_COMMAND,
    667                                               "%Dv: LC_SEGMENT64 is too short!\n", pImageBase);
     1538                                              "%s: LC_SEGMENT64 is too short!\n", pszName);
    6681539                    else
    6691540                    {
    6701541                        segment_command_64_t const *pSeg = (segment_command_64_t const *)pCurCmd;
    671                         DBGCCmdHlpPrintf(pCmdHlp, "%Dv:   vmaddr: %016RX64 LB %08RX64  prot: %s(%x)  maxprot: %s(%x)  name: %.16s\n",
    672                                          pImageBase, pSeg->vmaddr, pSeg->vmsize, dbgcMachoProt(pSeg->initprot), pSeg->initprot,
     1542                        DBGCCmdHlpPrintf(pCmdHlp, "%s:   vmaddr: %016RX64 LB %08RX64  prot: %s(%x)  maxprot: %s(%x)  name: %.16s\n",
     1543                                         pszName, pSeg->vmaddr, pSeg->vmsize, dbgcMachoProt(pSeg->initprot), pSeg->initprot,
    6731544                                         dbgcMachoProt(pSeg->maxprot), pSeg->maxprot, pSeg->segname);
    674                         DBGCCmdHlpPrintf(pCmdHlp, "%Dv:   file:   %016RX64 LB %08RX64  sections: %2u  flags: %#x",
    675                                          pImageBase, pSeg->fileoff, pSeg->filesize, pSeg->nsects, pSeg->flags);
     1545                        DBGCCmdHlpPrintf(pCmdHlp, "%s:   file:   %016RX64 LB %08RX64  sections: %2u  flags: %#x",
     1546                                         pszName, pSeg->fileoff, pSeg->filesize, pSeg->nsects, pSeg->flags);
    6761547                        dbgcDumpImageFlags32(pCmdHlp, pSeg->flags, s_aSegFlags, RT_ELEMENTS(s_aSegFlags));
    6771548                        DBGCCmdHlpPrintf(pCmdHlp, "\n");
     
    6791550                            || pSeg->nsects * sizeof(section_64_t) + sizeof(pSeg) > cbCurCmd)
    6801551                            rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, VERR_LDRMACHO_BAD_LOAD_COMMAND,
    681                                                   "%Dv: LC_SEGMENT64 is too short for all the sections!\n", pImageBase);
     1552                                                  "%s: LC_SEGMENT64 is too short for all the sections!\n", pszName);
    6821553                        else
    6831554                        {
     
    6861557                            {
    6871558                                DBGCCmdHlpPrintf(pCmdHlp,
    688                                                  "%Dv:   Section #%u: %016RX64 LB %08RX64  align: 2**%-2u  name: %.16s",
    689                                                  pImageBase, iSec, paSec[iSec].addr, paSec[iSec].size, paSec[iSec].align,
     1559                                                 "%s:   Section #%u: %016RX64 LB %08RX64  align: 2**%-2u  name: %.16s",
     1560                                                 pszName, iSec, paSec[iSec].addr, paSec[iSec].size, paSec[iSec].align,
    6901561                                                 paSec[iSec].sectname);
    6911562                                if (strncmp(pSeg->segname, paSec[iSec].segname, sizeof(pSeg->segname)))
     
    7141585        }
    7151586    }
    716     else
    717         rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "%Dv: Error reading load commands %Dv LB %#x\n",
    718                               pImageBase, &Addr, cbCmds);
    7191587    RTMemTmpFree(pbCmds);
    7201588    return rc;
     
    7241592
    7251593/**
     1594 * Common worker for the dumpimage command and the VBoxDumpImage tool.
     1595 */
     1596static int dumpImageCommon(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pImageBase, const char *pszImageBaseAddr,
     1597                           const char *pszName)
     1598{
     1599    union
     1600    {
     1601        uint8_t             ab[0x10];
     1602        IMAGE_DOS_HEADER    DosHdr;
     1603        struct
     1604        {
     1605            uint32_t            u32Magic;
     1606            IMAGE_FILE_HEADER   FileHdr;
     1607        } Nt;
     1608        mach_header_64_t    MachO64;
     1609    } uBuf;
     1610    int rc = dumpReadAt(pCmdHlp, pCmd, pImageBase, pszName, 0, &uBuf.DosHdr, sizeof(uBuf.DosHdr), NULL);
     1611    if (RT_SUCCESS(rc))
     1612    {
     1613        /*
     1614         * MZ.
     1615         */
     1616        if (uBuf.DosHdr.e_magic == IMAGE_DOS_SIGNATURE)
     1617        {
     1618            uint32_t offNewHdr = uBuf.DosHdr.e_lfanew;
     1619            if (offNewHdr < _256K && offNewHdr >= 16)
     1620            {
     1621                /* Look for new header. */
     1622                rc = dumpReadAt(pCmdHlp, pCmd, pImageBase, pszName, offNewHdr, &uBuf.Nt, sizeof(uBuf.Nt), NULL);
     1623                if (RT_SUCCESS(rc))
     1624                {
     1625                    /* PE: */
     1626                    if (uBuf.Nt.u32Magic == IMAGE_NT_SIGNATURE)
     1627                        rc = dbgcDumpImagePe(pCmd, pCmdHlp, pImageBase, pszImageBaseAddr, pszName, offNewHdr, &uBuf.Nt.FileHdr);
     1628                    else
     1629                        rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "%s: Unknown new header magic: %.8Rhxs\n", pszName, uBuf.ab);
     1630                }
     1631            }
     1632            else
     1633                rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "%s: MZ header but e_lfanew=%#RX32 is out of bounds (16..256K).\n",
     1634                                    pszName, offNewHdr);
     1635        }
     1636        /*
     1637         * ELF.
     1638         */
     1639        else if (uBuf.ab[0] == ELFMAG0 && uBuf.ab[1] == ELFMAG1 && uBuf.ab[2] == ELFMAG2 && uBuf.ab[3] == ELFMAG3)
     1640            rc = dbgcDumpImageElf(pCmd, pCmdHlp, pImageBase, pszImageBaseAddr);
     1641        /*
     1642         * Mach-O.
     1643         */
     1644        else if (   uBuf.MachO64.magic == IMAGE_MACHO64_SIGNATURE
     1645                 || uBuf.MachO64.magic == IMAGE_MACHO32_SIGNATURE )
     1646            rc = dbgcDumpImageMachO(pCmd, pCmdHlp, pImageBase, pszImageBaseAddr, &uBuf.MachO64);
     1647        /*
     1648         * Dunno.
     1649         */
     1650        else
     1651            rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "%s: Unknown magic: %.8Rhxs\n", pszName, uBuf.ab);
     1652    }
     1653    else
     1654        rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "%s: Failed to read %zu", pszName, sizeof(uBuf.DosHdr));
     1655    return rc;
     1656}
     1657
     1658
     1659#ifndef DBGC_DUMP_IMAGE_TOOL
     1660
     1661/**
    7261662 * @callback_method_impl{FNDBGCCMD, The 'dumpimage' command.}
    7271663 */
     
    7311667    for (unsigned iArg = 0; iArg < cArgs; iArg++)
    7321668    {
    733         union
    734         {
    735             uint8_t             ab[0x10];
    736             IMAGE_DOS_HEADER    DosHdr;
    737             struct
    738             {
    739                 uint32_t            u32Magic;
    740                 IMAGE_FILE_HEADER   FileHdr;
    741             } Nt;
    742             mach_header_64_t    MachO64;
    743         } uBuf;
    7441669        DBGCVAR const ImageBase = paArgs[iArg];
    745         int rc = DBGCCmdHlpMemRead(pCmdHlp, &uBuf.DosHdr, sizeof(uBuf.DosHdr), &ImageBase, NULL);
    746         if (RT_SUCCESS(rc))
    747         {
    748             /*
    749              * MZ.
    750              */
    751             if (uBuf.DosHdr.e_magic == IMAGE_DOS_SIGNATURE)
    752             {
    753                 uint32_t offNewHdr = uBuf.DosHdr.e_lfanew;
    754                 if (offNewHdr < _256K && offNewHdr >= 16)
    755                 {
    756                     /* Look for new header. */
    757                     DBGCVAR NewHdrAddr;
    758                     rc = DBGCCmdHlpEval(pCmdHlp, &NewHdrAddr, "%DV + %#RX32", &ImageBase, offNewHdr);
    759                     if (RT_SUCCESS(rc))
    760                     {
    761                         rc = DBGCCmdHlpMemRead(pCmdHlp, &uBuf.Nt, sizeof(uBuf.Nt), &NewHdrAddr, NULL);
    762                         if (RT_SUCCESS(rc))
    763                         {
    764                             /* PE: */
    765                             if (uBuf.Nt.u32Magic == IMAGE_NT_SIGNATURE)
    766                                 rc = dbgcDumpImagePe(pCmd, pCmdHlp, &ImageBase, &NewHdrAddr, &uBuf.Nt.FileHdr);
    767                             else
    768                                 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "%Dv: Unknown new header magic: %.8Rhxs\n",
    769                                                     &ImageBase, uBuf.ab);
    770                         }
    771                         else
    772                             rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "%Dv: Failed to read %zu at %Dv",
    773                                                   &ImageBase, sizeof(uBuf.Nt), &NewHdrAddr);
    774                     }
    775                     else
    776                         rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "%Dv: Failed to calc address of new header", &ImageBase);
    777                 }
    778                 else
    779                     rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "%Dv: MZ header but e_lfanew=%#RX32 is out of bounds (16..256K).\n",
    780                                         &ImageBase, offNewHdr);
    781             }
    782             /*
    783              * ELF.
    784              */
    785             else if (uBuf.ab[0] == ELFMAG0 && uBuf.ab[1] == ELFMAG1 && uBuf.ab[2] == ELFMAG2 && uBuf.ab[3] == ELFMAG3)
    786                 rc = dbgcDumpImageElf(pCmd, pCmdHlp, &ImageBase);
    787             /*
    788              * Mach-O.
    789              */
    790             else if (   uBuf.MachO64.magic == IMAGE_MACHO64_SIGNATURE
    791                      || uBuf.MachO64.magic == IMAGE_MACHO32_SIGNATURE )
    792                 rc = dbgcDumpImageMachO(pCmd, pCmdHlp, &ImageBase, &uBuf.MachO64);
    793             /*
    794              * Dunno.
    795              */
    796             else
    797                 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "%Dv: Unknown magic: %.8Rhxs\n", &ImageBase, uBuf.ab);
    798         }
    799         else
    800             rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "%Dv: Failed to read %zu", &ImageBase, sizeof(uBuf.DosHdr));
     1670        char          szImageBaseAddr[64];
     1671        DBGCCmdHlpStrPrintf(pCmdHlp, szImageBaseAddr, sizeof(szImageBaseAddr), "%Dv", &ImageBase);
     1672        int rc = dumpImageCommon(pCmd, pCmdHlp, &ImageBase, szImageBaseAddr, szImageBaseAddr);
    8011673        if (RT_FAILURE(rc) && RT_SUCCESS(rcRet))
    8021674            rcRet = rc;
     
    8061678}
    8071679
     1680#else /* DBGC_DUMP_IMAGE_TOOL */
     1681
     1682
     1683/**
     1684 * @interface_member_impl{DBGCCMDHLP,pfnPrintfV}
     1685 */
     1686static DECLCALLBACK(int) toolPrintfV(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, const char *pszFormat, va_list args)
     1687{
     1688    int rc = RTPrintfV(pszFormat, args);
     1689    if (rc >= 0)
     1690    {
     1691        if (pcbWritten)
     1692            *pcbWritten = (unsigned)rc;
     1693        return VINF_SUCCESS;
     1694    }
     1695    if (pcbWritten)
     1696        *pcbWritten = 0;
     1697    RT_NOREF(pCmdHlp);
     1698    return VERR_IO_GEN_FAILURE;
     1699}
     1700
     1701
     1702/**
     1703 * @interface_member_impl{DBGCCMDHLP,pfnFailV}
     1704 */
     1705static DECLCALLBACK(int) toolFailV(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, const char *pszFormat, va_list va)
     1706{
     1707    CMDHLPSTATE * const pCmdHlpState = RT_FROM_MEMBER(pCmdHlp, CMDHLPSTATE, Core);
     1708    pCmdHlpState->rcExit = RTEXITCODE_FAILURE;
     1709    RTMsgErrorV(pszFormat, va);
     1710    RT_NOREF(pCmd);
     1711    return VERR_GENERAL_FAILURE;
     1712}
     1713
     1714
     1715/**
     1716 * @interface_member_impl{DBGCCMDHLP,pfnFailRcV}
     1717 */
     1718static DECLCALLBACK(int) toolFailRcV(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, int rc, const char *pszFormat, va_list va)
     1719{
     1720    CMDHLPSTATE * const pCmdHlpState = RT_FROM_MEMBER(pCmdHlp, CMDHLPSTATE, Core);
     1721    pCmdHlpState->rcExit = RTEXITCODE_FAILURE;
     1722
     1723    va_list vaCopy;
     1724    va_copy(vaCopy, va);
     1725    RTMsgError("%N: %Rrc", pszFormat, &vaCopy, rc);
     1726    va_end(vaCopy);
     1727
     1728    RT_NOREF(pCmd);
     1729    return rc;
     1730}
     1731
     1732
     1733int main(int argc, char **argv)
     1734{
     1735    int rc = RTR3InitExe(argc, &argv, 0);
     1736    if (RT_FAILURE(rc))
     1737        return RTMsgInitFailure(rc);
     1738
     1739    /*
     1740     * Setup image helper code.
     1741     */
     1742    CMDHLPSTATE ToolState;
     1743    RT_ZERO(ToolState);
     1744    ToolState.Core.pfnPrintfV = toolPrintfV;
     1745    ToolState.Core.pfnFailV   = toolFailV;
     1746    ToolState.Core.pfnFailRcV = toolFailRcV;
     1747    ToolState.hVfsFile        = NIL_RTVFSFILE;
     1748    ToolState.rcExit          = RTEXITCODE_SUCCESS;
     1749
     1750    char szImageBaseAddr[32] = {0};
     1751
     1752    static const RTGETOPTDEF s_aOptions[] =
     1753    {
     1754        { "--image-base", 'b', RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_HEX },
     1755    };
     1756
     1757    RTGETOPTSTATE GetState;
     1758    rc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
     1759    AssertRCReturn(rc, RTEXITCODE_FAILURE);
     1760
     1761    RTGETOPTUNION ValueUnion;
     1762    int           chOpt;
     1763    while ((chOpt = RTGetOpt(&GetState, &ValueUnion)) != 0)
     1764    {
     1765        switch (chOpt)
     1766        {
     1767            case 'b':
     1768                if (ValueUnion.u64 >= UINT32_MAX - _16M)
     1769                    RTStrPrintf(szImageBaseAddr, sizeof(szImageBaseAddr), "%#018RX64", ValueUnion.u64);
     1770                else
     1771                    RTStrPrintf(szImageBaseAddr, sizeof(szImageBaseAddr), "%#010RX64", ValueUnion.u64);
     1772                break;
     1773
     1774            case 'V':
     1775                RTPrintf("%s\n", RTBldCfgRevision());
     1776                return RTEXITCODE_SUCCESS;
     1777
     1778            case 'h':
     1779                RTPrintf("usage: %s [options] <file> [file2..]\n", RTProcShortName());
     1780                return RTEXITCODE_SUCCESS;
     1781
     1782            case VINF_GETOPT_NOT_OPTION:
     1783            {
     1784                RTERRINFOSTATIC ErrInfo;
     1785                uint32_t        offError = 0;
     1786                rc = RTVfsChainOpenFile(ValueUnion.psz, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE,
     1787                                        &ToolState.hVfsFile, &offError, RTErrInfoInitStatic(&ErrInfo));
     1788                if (RT_SUCCESS(rc))
     1789                {
     1790                    rc = dumpImageCommon(NULL, &ToolState.Core, NULL, szImageBaseAddr[0] ? szImageBaseAddr : NULL, ValueUnion.psz);
     1791                    if (RT_FAILURE(rc) && ToolState.rcExit == RTEXITCODE_SUCCESS)
     1792                        ToolState.rcExit = RTEXITCODE_FAILURE;
     1793                    RTVfsFileRelease(ToolState.hVfsFile);
     1794                }
     1795                else
     1796                    ToolState.rcExit = RTVfsChainMsgErrorExitFailure("RTVfsChainOpenFile", ValueUnion.psz,
     1797                                                                     rc, offError, &ErrInfo.Core);
     1798                ToolState.hVfsFile = NIL_RTVFSFILE;
     1799                break;
     1800            }
     1801
     1802            default:
     1803                return RTGetOptPrintError(chOpt, &ValueUnion);
     1804        }
     1805    }
     1806
     1807    return ToolState.rcExit;
     1808
     1809}
     1810#endif /* !DBGC_DUMP_IMAGE_TOOL */
     1811
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette