VirtualBox

Changeset 73150 in vbox for trunk/src/VBox/VMM


Ignore:
Timestamp:
Jul 16, 2018 10:03:41 AM (6 years ago)
Author:
vboxsync
Message:

VMM,DBGC,IPRT: In memory

  • VMM: Morphed part of the NT kernel digger into DBGFR3ModInMem.
  • DBGC: Added 'loadinmem' command for accessing the DBGFR3ModInMem functionality.
  • IPRT: Modified RTDbgModCreateFromPeImage to clearly indicate to caller whether the loader module was consumed or not (missing direct ref counting).
  • IPRT: Added RTLdrGetHostArch for resolving RTLDRARCH_HOST.
  • IPRT: Added RTLdrArchName for naming a RTLDRARCH value.
Location:
trunk/src/VBox/VMM
Files:
1 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/Makefile.kmk

    r73088 r73150  
    9999        VMMR3/DBGFLog.cpp \
    100100        VMMR3/DBGFMem.cpp \
     101        VMMR3/DBGFR3ModInMem.cpp \
    101102        VMMR3/DBGFOS.cpp \
    102103        VMMR3/DBGFR3PlugIn.cpp \
  • trunk/src/VBox/VMM/VMMR3/DBGFR3ModInMem.cpp

    r73119 r73150  
    11/* $Id$ */
    22/** @file
    3  * DBGPlugInWindows - Debugger and Guest OS Digger Plugin For Windows NT.
     3 * DBGFR3ModInMemPe - In memory PE module 'loader'.
    44 */
    55
    66/*
    7  * Copyright (C) 2009-2017 Oracle Corporation
     7 * Copyright (C) 2009-2018 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2020*   Header Files                                                                                                                 *
    2121*********************************************************************************************************************************/
    22 #define LOG_GROUP LOG_GROUP_DBGF /// @todo add new log group.
    23 #include "DBGPlugIns.h"
     22#define LOG_GROUP LOG_GROUP_DBGF
    2423#include <VBox/vmm/dbgf.h>
     24
    2525#include <VBox/err.h>
    26 #include <VBox/param.h>
    2726#include <iprt/ldr.h>
    2827#include <iprt/mem.h>
    29 #include <iprt/stream.h>
    3028#include <iprt/string.h>
    3129#include <iprt/formats/pecoff.h>
    3230#include <iprt/formats/mz.h>
     31#include <iprt/formats/elf.h>
    3332
    3433
     
    3635*   Structures and Typedefs                                                                                                      *
    3736*********************************************************************************************************************************/
    38 
    39 /** @name Internal WinNT structures
    40  * @{ */
    41 /**
    42  * PsLoadedModuleList entry for 32-bit NT aka LDR_DATA_TABLE_ENTRY.
    43  * Tested with XP.
    44  */
    45 typedef struct NTMTE32
    46 {
    47     struct
    48     {
    49         uint32_t    Flink;
    50         uint32_t    Blink;
    51     }               InLoadOrderLinks,
    52                     InMemoryOrderModuleList,
    53                     InInitializationOrderModuleList;
    54     uint32_t        DllBase;
    55     uint32_t        EntryPoint;
    56     /** @note This field is not a size in NT 3.1. It's NULL for images loaded by the
    57      *        boot loader, for other images it looks like some kind of pointer.  */
    58     uint32_t        SizeOfImage;
    59     struct
    60     {
    61         uint16_t    Length;
    62         uint16_t    MaximumLength;
    63         uint32_t    Buffer;
    64     }               FullDllName,
    65                     BaseDllName;
    66     uint32_t        Flags;
    67     uint16_t        LoadCount;
    68     uint16_t        TlsIndex;
    69     /* ... there is more ... */
    70 } NTMTE32;
    71 typedef NTMTE32 *PNTMTE32;
    72 
    73 /**
    74  * PsLoadedModuleList entry for 64-bit NT aka LDR_DATA_TABLE_ENTRY.
    75  */
    76 typedef struct NTMTE64
    77 {
    78     struct
    79     {
    80         uint64_t    Flink;
    81         uint64_t    Blink;
    82     }               InLoadOrderLinks,                  /**< 0x00 */
    83                     InMemoryOrderModuleList,           /**< 0x10 */
    84                     InInitializationOrderModuleList;   /**< 0x20 */
    85     uint64_t        DllBase;                           /**< 0x30 */
    86     uint64_t        EntryPoint;                        /**< 0x38 */
    87     uint32_t        SizeOfImage;                       /**< 0x40 */
    88     uint32_t        Alignment;                         /**< 0x44 */
    89     struct
    90     {
    91         uint16_t    Length;                            /**< 0x48,0x58 */
    92         uint16_t    MaximumLength;                     /**< 0x4a,0x5a */
    93         uint32_t    Alignment;                         /**< 0x4c,0x5c */
    94         uint64_t    Buffer;                            /**< 0x50,0x60 */
    95     }               FullDllName,                       /**< 0x48 */
    96                     BaseDllName;                       /**< 0x58 */
    97     uint32_t        Flags;                             /**< 0x68 */
    98     uint16_t        LoadCount;                         /**< 0x6c */
    99     uint16_t        TlsIndex;                          /**< 0x6e */
    100     /* ... there is more ... */
    101 } NTMTE64;
    102 typedef NTMTE64 *PNTMTE64;
    103 
    104 /** MTE union. */
    105 typedef union NTMTE
    106 {
    107     NTMTE32         vX_32;
    108     NTMTE64         vX_64;
    109 } NTMTE;
    110 typedef NTMTE *PNTMTE;
    111 
    112 
    113 /**
    114  * The essential bits of the KUSER_SHARED_DATA structure.
    115  */
    116 typedef struct NTKUSERSHAREDDATA
    117 {
    118     uint32_t        TickCountLowDeprecated;
    119     uint32_t        TickCountMultiplier;
    120     struct
    121     {
    122         uint32_t    LowPart;
    123         int32_t     High1Time;
    124         int32_t     High2Time;
    125 
    126     }               InterruptTime,
    127                     SystemTime,
    128                     TimeZoneBias;
    129     uint16_t        ImageNumberLow;
    130     uint16_t        ImageNumberHigh;
    131     RTUTF16         NtSystemRoot[260];
    132     uint32_t        MaxStackTraceDepth;
    133     uint32_t        CryptoExponent;
    134     uint32_t        TimeZoneId;
    135     uint32_t        LargePageMinimum;
    136     uint32_t        Reserved2[7];
    137     uint32_t        NtProductType;
    138     uint8_t         ProductTypeIsValid;
    139     uint8_t         abPadding[3];
    140     uint32_t        NtMajorVersion;
    141     uint32_t        NtMinorVersion;
    142     /* uint8_t         ProcessorFeatures[64];
    143     ...
    144     */
    145 } NTKUSERSHAREDDATA;
    146 typedef NTKUSERSHAREDDATA *PNTKUSERSHAREDDATA;
    147 
    148 /** KI_USER_SHARED_DATA for i386 */
    149 #define NTKUSERSHAREDDATA_WINNT32   UINT32_C(0xffdf0000)
    150 /** KI_USER_SHARED_DATA for AMD64 */
    151 #define NTKUSERSHAREDDATA_WINNT64   UINT64_C(0xfffff78000000000)
    152 
    153 /** NTKUSERSHAREDDATA::NtProductType */
    154 typedef enum NTPRODUCTTYPE
    155 {
    156     kNtProductType_Invalid = 0,
    157     kNtProductType_WinNt = 1,
    158     kNtProductType_LanManNt,
    159     kNtProductType_Server
    160 } NTPRODUCTTYPE;
    161 
    162 
    163 /** NT image header union. */
    164 typedef union NTHDRSU
    165 {
    166     IMAGE_NT_HEADERS32  vX_32;
    167     IMAGE_NT_HEADERS64  vX_64;
    168 } NTHDRS;
    169 /** Pointer to NT image header union. */
    170 typedef NTHDRS *PNTHDRS;
    171 /** Pointer to const NT image header union. */
    172 typedef NTHDRS const *PCNTHDRS;
    173 
    174 /** @} */
    175 
    176 
    177 
    178 typedef enum DBGDIGGERWINNTVER
    179 {
    180     DBGDIGGERWINNTVER_UNKNOWN,
    181     DBGDIGGERWINNTVER_3_1,
    182     DBGDIGGERWINNTVER_3_5,
    183     DBGDIGGERWINNTVER_4_0,
    184     DBGDIGGERWINNTVER_5_0,
    185     DBGDIGGERWINNTVER_5_1,
    186     DBGDIGGERWINNTVER_6_0
    187 } DBGDIGGERWINNTVER;
    188 
    189 /**
    190  * WinNT guest OS digger instance data.
    191  */
    192 typedef struct DBGDIGGERWINNT
    193 {
    194     /** Whether the information is valid or not.
    195      * (For fending off illegal interface method calls.) */
    196     bool                fValid;
    197     /** 32-bit (true) or 64-bit (false) */
    198     bool                f32Bit;
    199     /** Set if NT 3.1 was detected.
    200      * This implies both Misc.VirtualSize and NTMTE32::SizeOfImage are zero. */
    201     bool                fNt31;
    202 
    203     /** The NT version. */
    204     DBGDIGGERWINNTVER   enmVer;
    205     /** NTKUSERSHAREDDATA::NtProductType */
    206     NTPRODUCTTYPE       NtProductType;
    207     /** NTKUSERSHAREDDATA::NtMajorVersion */
    208     uint32_t            NtMajorVersion;
    209     /** NTKUSERSHAREDDATA::NtMinorVersion */
    210     uint32_t            NtMinorVersion;
    211 
    212     /** The address of the ntoskrnl.exe image. */
    213     DBGFADDRESS         KernelAddr;
    214     /** The address of the ntoskrnl.exe module table entry. */
    215     DBGFADDRESS         KernelMteAddr;
    216     /** The address of PsLoadedModuleList. */
    217     DBGFADDRESS         PsLoadedModuleListAddr;
    218 } DBGDIGGERWINNT;
    219 /** Pointer to the linux guest OS digger instance data. */
    220 typedef DBGDIGGERWINNT *PDBGDIGGERWINNT;
    221 
    222 
    22337/**
    22438 * The WinNT digger's loader reader instance data.
    22539 */
    226 typedef struct DBGDIGGERWINNTRDR
     40typedef struct DBGFMODPERDR
    22741{
    22842    /** The VM handle (referenced). */
     
    25165        uint32_t        offMem;
    25266    } aMappings[1];
    253 } DBGDIGGERWINNTRDR;
     67} DBGFMODPERDR;
    25468/** Pointer a WinNT loader reader instance data. */
    255 typedef DBGDIGGERWINNTRDR *PDBGDIGGERWINNTRDR;
    256 
    257 
    258 /*********************************************************************************************************************************
    259 *   Defined Constants And Macros                                                                                                 *
    260 *********************************************************************************************************************************/
    261 /** Validates a 32-bit Windows NT kernel address */
    262 #define WINNT32_VALID_ADDRESS(Addr)         ((Addr) >         UINT32_C(0x80000000) && (Addr) <         UINT32_C(0xfffff000))
    263 /** Validates a 64-bit Windows NT kernel address */
    264  #define WINNT64_VALID_ADDRESS(Addr)         ((Addr) > UINT64_C(0xffff800000000000) && (Addr) < UINT64_C(0xfffffffffffff000))
    265 /** Validates a kernel address. */
    266 #define WINNT_VALID_ADDRESS(pThis, Addr)    ((pThis)->f32Bit ? WINNT32_VALID_ADDRESS(Addr) : WINNT64_VALID_ADDRESS(Addr))
    267 /** Versioned and bitness wrapper. */
    268 #define WINNT_UNION(pThis, pUnion, Member)  ((pThis)->f32Bit ? (pUnion)->vX_32. Member : (pUnion)->vX_64. Member )
    269 
    270 /** The length (in chars) of the kernel file name (no path). */
    271 #define WINNT_KERNEL_BASE_NAME_LEN          12
    272 
    273 /** WindowsNT on little endian ASCII systems. */
    274 #define DIG_WINNT_MOD_TAG                   UINT64_C(0x54696e646f774e54)
    275 
    276 
    277 /*********************************************************************************************************************************
    278 *   Internal Functions                                                                                                           *
    279 *********************************************************************************************************************************/
    280 static DECLCALLBACK(int)  dbgDiggerWinNtInit(PUVM pUVM, void *pvData);
    281 
    282 
    283 /*********************************************************************************************************************************
    284 *   Global Variables                                                                                                             *
    285 *********************************************************************************************************************************/
    286 /** Kernel names. */
    287 static const RTUTF16 g_wszKernelNames[][WINNT_KERNEL_BASE_NAME_LEN + 1] =
    288 {
    289     { 'n', 't', 'o', 's', 'k', 'r', 'n', 'l', '.', 'e', 'x', 'e' }
    290 };
    291 
    292 
    293 
    294 /** @callback_method_impl{PFNRTLDRRDRMEMREAD} */
    295 static DECLCALLBACK(int) dbgDiggerWinNtRdr_Read(void *pvBuf, size_t cb, size_t off, void *pvUser)
    296 {
    297     PDBGDIGGERWINNTRDR pThis = (PDBGDIGGERWINNTRDR)pvUser;
    298     uint32_t           offFile = (uint32_t)off;
     69typedef DBGFMODPERDR *PDBGFMODPERDR;
     70
     71/**
     72 * Stack buffer.
     73 */
     74typedef union DBGFMODINMEMBUF
     75{
     76    uint8_t             ab[0x2000];
     77    IMAGE_DOS_HEADER    DosHdr;
     78    IMAGE_NT_HEADERS32  Nt32;
     79    IMAGE_NT_HEADERS64  Nt64;
     80} DBGFMODINMEMBUF;
     81/** Pointer to stack buffer. */
     82typedef DBGFMODINMEMBUF *PDBGFMODINMEMBUF;
     83
     84
     85
     86/**
     87 * Handles in-memory ELF images.
     88 *
     89 * @returns VBox status code.
     90 * @param   pUVM            The user mode VM handle.
     91 * @param   pImageAddr      The image address.
     92 * @param   fFlags          Flags, DBGFMODINMEM_F_XXX.
     93 * @param   pszName         The image name, optional.
     94 * @param   enmArch         The image arch if we force it, pass
     95 *                          RTLDRARCH_WHATEVER if you don't care.
     96 * @param   cbImage         Image size.  Pass 0 if not known.
     97 * @param   puBuf           The header buffer.
     98 * @param   phDbgMod        Where to return the resulting debug module on success.
     99 * @param   pErrInfo        Where to return extended error info on failure.
     100 */
     101static int dbgfR3ModInMemElf(PUVM pUVM, PCDBGFADDRESS pImageAddr, uint32_t fFlags, const char *pszName,
     102                             RTLDRARCH enmArch, uint32_t cbImage, PDBGFMODINMEMBUF puBuf,
     103                             PRTDBGMOD phDbgMod, PRTERRINFO pErrInfo)
     104{
     105    RT_NOREF(pUVM, fFlags, pszName, enmArch, cbImage, puBuf, phDbgMod);
     106    return RTERRINFO_LOG_SET_F(pErrInfo, VERR_INVALID_EXE_SIGNATURE, "Found ELF magic at %RGv", pImageAddr->FlatPtr);
     107}
     108
     109
     110/**
     111 * @callback_method_impl{PFNRTLDRRDRMEMREAD}
     112 */
     113static DECLCALLBACK(int) dbgfModInMemPeRdr_Read(void *pvBuf, size_t cb, size_t off, void *pvUser)
     114{
     115    PDBGFMODPERDR pThis   = (PDBGFMODPERDR)pvUser;
     116    uint32_t      offFile = (uint32_t)off;
    299117    AssertReturn(offFile == off, VERR_INVALID_PARAMETER);
    300118
     
    381199
    382200
    383 /** @callback_method_impl{PFNRTLDRRDRMEMDTOR} */
    384 static DECLCALLBACK(void) dbgDiggerWinNtRdr_Dtor(void *pvUser)
    385 {
    386     PDBGDIGGERWINNTRDR pThis = (PDBGDIGGERWINNTRDR)pvUser;
     201/**
     202 * @callback_method_impl{PFNRTLDRRDRMEMDTOR}
     203 */
     204static DECLCALLBACK(void) dbgfModInMemPeRdr_Dtor(void *pvUser)
     205{
     206    PDBGFMODPERDR pThis = (PDBGFMODPERDR)pvUser;
    387207
    388208    VMR3ReleaseUVM(pThis->pUVM);
     
    395215 * Checks if the section headers look okay.
    396216 *
    397  * @returns true / false.
    398  * @param   paSh             Pointer to the section headers.
    399  * @param   cSh              Number of headers.
     217 * @returns VBox status code.
     218 * @param   paShdrs             Pointer to the section headers.
     219 * @param   cShdrs              Number of headers.
    400220 * @param   cbImage             The image size reported by NT.
    401221 * @param   cbImageFromHdr      The image size by the linker in the header.
     
    411231 *                              the resource directory.  These images will have
    412232 *                              a page aligned cbImage.
    413  */
    414 static bool dbgDiggerWinNtCheckSectHdrsAndImgSize(PCIMAGE_SECTION_HEADER paShs, uint32_t cShs, uint32_t cbImage,
    415                                                   uint32_t cbImageFromHdr, uint32_t uRvaRsrc, uint32_t cbSectAlign,
    416                                                   bool fNt31, uint32_t *pcbImageCorrect)
     233 *
     234 * @param   pErrInfo            Where to return more error details.
     235 */
     236static int dbgfR3ModPeCheckSectHdrsAndImgSize(PCIMAGE_SECTION_HEADER paShdrs, uint32_t cShdrs, uint32_t cbImage,
     237                                              uint32_t cbImageFromHdr, uint32_t uRvaRsrc, uint32_t cbSectAlign,
     238                                              bool fNt31, uint32_t *pcbImageCorrect, PRTERRINFO pErrInfo)
    417239{
    418240    *pcbImageCorrect = cbImage;
    419241
    420     for (uint32_t i = 0; i < cShs; i++)
    421     {
    422         if (!paShs[i].Name[0])
    423         {
    424             Log(("DigWinNt: Section header #%u has no name\n", i));
    425             return false;
    426         }
    427 
    428         if (paShs[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD)
     242    for (uint32_t i = 0; i < cShdrs; i++)
     243    {
     244        if (!paShdrs[i].Name[0])
     245            return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "Section header #%u has no name", i);
     246
     247        if (paShdrs[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD)
    429248            continue;
    430249
    431250        /* Tweak to determine the virtual size if the linker didn't set it (NT 3.1). */
    432251        /** @todo this isn't really perfect. cbImage is kind of wrong...   */
    433         uint32_t cbVirtual = paShs[i].Misc.VirtualSize;
     252        uint32_t cbVirtual = paShdrs[i].Misc.VirtualSize;
    434253        if (cbVirtual == 0)
    435254        {
    436             for (uint32_t j = i + 1; j < cShs; j++)
    437                 if (!(paShs[j].Characteristics & IMAGE_SCN_TYPE_NOLOAD)
    438                     && paShs[j].VirtualAddress > paShs[i].VirtualAddress)
     255            for (uint32_t j = i + 1; j < cShdrs; j++)
     256                if (   !(paShdrs[j].Characteristics & IMAGE_SCN_TYPE_NOLOAD)
     257                    && paShdrs[j].VirtualAddress > paShdrs[i].VirtualAddress)
    439258                {
    440                     cbVirtual = paShs[j].VirtualAddress - paShs[i].VirtualAddress;
     259                    cbVirtual = paShdrs[j].VirtualAddress - paShdrs[i].VirtualAddress;
    441260                    break;
    442261                }
    443262            if (!cbVirtual)
    444263            {
    445                 if (paShs[i].VirtualAddress < cbImageFromHdr)
    446                     cbVirtual = cbImageFromHdr - paShs[i].VirtualAddress;
    447                 else if (paShs[i].SizeOfRawData > 0)
    448                     cbVirtual = RT_ALIGN(paShs[i].SizeOfRawData, _4K);
     264                if (paShdrs[i].VirtualAddress < cbImageFromHdr)
     265                    cbVirtual = cbImageFromHdr - paShdrs[i].VirtualAddress;
     266                else if (paShdrs[i].SizeOfRawData > 0)
     267                    cbVirtual = RT_ALIGN(paShdrs[i].SizeOfRawData, _4K);
    449268            }
    450269        }
     
    452271        /* Check that sizes are within the same range and that both sizes and
    453272           addresses are within reasonable limits. */
    454         if (   RT_ALIGN(cbVirtual, _64K) < RT_ALIGN(paShs[i].SizeOfRawData, _64K)
     273        if (   RT_ALIGN(cbVirtual, _64K) < RT_ALIGN(paShdrs[i].SizeOfRawData, _64K)
    455274            || cbVirtual                >= _1G
    456             || paShs[i].SizeOfRawData   >= _1G)
    457         {
    458             Log(("DigWinNt: Section header #%u (%.8s) has a VirtualSize=%#x (%#x) and SizeOfRawData=%#x, that's too much data!\n",
    459                  i, paShs[i].Name, cbVirtual, paShs[i].Misc.VirtualSize, paShs[i].SizeOfRawData));
    460             return false;
    461         }
    462         uint32_t uRvaEnd = paShs[i].VirtualAddress + cbVirtual;
    463         if (uRvaEnd >= _1G || uRvaEnd < paShs[i].VirtualAddress)
    464         {
    465             Log(("DigWinNt: Section header #%u (%.8s) has a VirtualSize=%#x (%#x) and VirtualAddr=%#x, %#x in total, that's too much!\n",
    466                  i, paShs[i].Name, cbVirtual, paShs[i].Misc.VirtualSize, paShs[i].VirtualAddress, uRvaEnd));
    467             return false;
    468         }
     275            || paShdrs[i].SizeOfRawData >= _1G)
     276            return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
     277                                       "Section header #%u (%.8s) has a VirtualSize=%#x (%#x) and SizeOfRawData=%#x, that's too much data!",
     278                                       i, paShdrs[i].Name, cbVirtual, paShdrs[i].Misc.VirtualSize, paShdrs[i].SizeOfRawData);
     279        uint32_t uRvaEnd = paShdrs[i].VirtualAddress + cbVirtual;
     280        if (uRvaEnd >= _1G || uRvaEnd < paShdrs[i].VirtualAddress)
     281            return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
     282                                       "Section header #%u (%.8s) has a VirtualSize=%#x (%#x) and VirtualAddr=%#x, %#x in total, that's too much!",
     283                                       i, paShdrs[i].Name, cbVirtual, paShdrs[i].Misc.VirtualSize, paShdrs[i].VirtualAddress, uRvaEnd);
    469284
    470285        /* Check for images chopped off around '.rsrc'. */
     
    475290        /* Check that the section is within the image. */
    476291        if (uRvaEnd > cbImage && fNt31)
    477         {
    478             Log(("DigWinNt: Section header #%u has a virtual address range beyond the image: %#x TO %#x cbImage=%#x\n",
    479                  i, paShs[i].VirtualAddress, uRvaEnd, cbImage));
    480             return false;
    481         }
     292            return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
     293                                       "Section header #%u has a virtual address range beyond the image: %#x TO %#x cbImage=%#x",
     294                                       i, paShdrs[i].VirtualAddress, uRvaEnd, cbImage);
    482295    }
    483296
    484297    Assert(*pcbImageCorrect == cbImage || !(*pcbImageCorrect & 0xfff));
    485298    *pcbImageCorrect = cbImage;
    486     return true;
     299    return VINF_SUCCESS;
    487300}
    488301
     
    491304 * Create a loader module for the in-guest-memory PE module.
    492305 */
    493 static int dbgDiggerWinNtCreateLdrMod(PDBGDIGGERWINNT pThis, PUVM pUVM, const char *pszName, PCDBGFADDRESS pImageAddr,
    494                                       uint32_t cbImage, uint8_t *pbBuf, size_t cbBuf,
    495                                       uint32_t offHdrs, PCNTHDRS pHdrs, PRTLDRMOD phLdrMod)
     306static int dbgfR3ModInMemPeCreateLdrMod(PUVM pUVM, uint32_t fFlags, const char *pszName, PCDBGFADDRESS pImageAddr,
     307                                        uint32_t cbImage, uint32_t cbImageFromHdr, bool f32Bit,
     308                                        uint32_t cShdrs, PCIMAGE_SECTION_HEADER paShdrs, uint32_t cbSectAlign,
     309                                        uint32_t cDataDir, PCIMAGE_DATA_DIRECTORY paDataDir, uint32_t offHdrs,
     310                                        PRTLDRMOD phLdrMod, PRTERRINFO pErrInfo)
    496311{
    497312    /*
    498313     * Allocate and create a reader instance.
    499314     */
    500     uint32_t const      cShs = WINNT_UNION(pThis, pHdrs, FileHeader.NumberOfSections);
    501     PDBGDIGGERWINNTRDR  pRdr = (PDBGDIGGERWINNTRDR)RTMemAlloc(RT_UOFFSETOF_DYN(DBGDIGGERWINNTRDR, aMappings[cShs + 2]));
     315    PDBGFMODPERDR pRdr = (PDBGFMODPERDR)RTMemAlloc(RT_UOFFSETOF_DYN(DBGFMODPERDR, aMappings[cShdrs + 2]));
    502316    if (!pRdr)
    503317        return VERR_NO_MEMORY;
     
    512326
    513327    /*
    514      * Use the section table to construct a more accurate view of the file/
    515      * image if it's in the buffer (it should be).
     328     * Use the section table to construct a more accurate view of the file/image.
    516329     */
    517330    uint32_t uRvaRsrc = UINT32_MAX;
    518     if (WINNT_UNION(pThis, pHdrs, OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE]).Size > 0)
    519         uRvaRsrc = WINNT_UNION(pThis, pHdrs, OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE]).VirtualAddress;
    520     uint32_t offShs = offHdrs
    521                     + (  pThis->f32Bit
    522                        ? pHdrs->vX_32.FileHeader.SizeOfOptionalHeader + RT_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader)
    523                        : pHdrs->vX_64.FileHeader.SizeOfOptionalHeader + RT_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader));
    524     uint32_t cbShs  = cShs * sizeof(IMAGE_SECTION_HEADER);
    525     PCIMAGE_SECTION_HEADER paShs = (PCIMAGE_SECTION_HEADER)(pbBuf + offShs);
    526     if (   offShs + cbShs <= RT_MIN(cbImage, cbBuf)
    527         && dbgDiggerWinNtCheckSectHdrsAndImgSize(paShs, cShs, cbImage, WINNT_UNION(pThis, pHdrs, OptionalHeader.SizeOfImage),
    528                                                  uRvaRsrc, WINNT_UNION(pThis, pHdrs, OptionalHeader.SectionAlignment),
    529                                                  pThis->fNt31, &pRdr->cbCorrectImageSize))
     331    if (   cDataDir > IMAGE_DIRECTORY_ENTRY_RESOURCE
     332        && paDataDir[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size > 0)
     333        uRvaRsrc = paDataDir[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
     334
     335    int rc = dbgfR3ModPeCheckSectHdrsAndImgSize(paShdrs, cShdrs, cbImage, cbImageFromHdr, uRvaRsrc, cbSectAlign,
     336                                                RT_BOOL(fFlags & DBGFMODINMEM_F_PE_NT31), &pRdr->cbCorrectImageSize, pErrInfo);
     337    if (RT_SUCCESS(rc))
    530338    {
    531339        pRdr->cMappings = 0;
    532340
    533         for (uint32_t i = 0; i < cShs; i++)
    534             if (   paShs[i].SizeOfRawData    > 0
    535                 && paShs[i].PointerToRawData > 0)
     341        for (uint32_t i = 0; i < cShdrs; i++)
     342            if (   paShdrs[i].SizeOfRawData    > 0
     343                && paShdrs[i].PointerToRawData > 0)
    536344            {
    537345                uint32_t j = 1;
     
    540348                else
    541349                {
    542                     while (j < pRdr->cMappings && pRdr->aMappings[j].offFile < paShs[i].PointerToRawData)
     350                    while (j < pRdr->cMappings && pRdr->aMappings[j].offFile < paShdrs[i].PointerToRawData)
    543351                        j++;
    544352                    if (j < pRdr->cMappings)
    545353                        memmove(&pRdr->aMappings[j + 1], &pRdr->aMappings[j], (pRdr->cMappings - j) * sizeof(pRdr->aMappings));
    546354                }
    547                 pRdr->aMappings[j].offFile = paShs[i].PointerToRawData;
    548                 pRdr->aMappings[j].offMem  = paShs[i].VirtualAddress;
    549                 pRdr->aMappings[j].cbMem   = i + 1 < cShs
    550                                            ? paShs[i + 1].VirtualAddress - paShs[i].VirtualAddress
    551                                            : paShs[i].Misc.VirtualSize;
     355                pRdr->aMappings[j].offFile = paShdrs[i].PointerToRawData;
     356                pRdr->aMappings[j].offMem  = paShdrs[i].VirtualAddress;
     357                pRdr->aMappings[j].cbMem   = i + 1 < cShdrs
     358                                           ? paShdrs[i + 1].VirtualAddress - paShdrs[i].VirtualAddress
     359                                           : paShdrs[i].Misc.VirtualSize;
    552360                if (j == pRdr->cMappings)
    553                     pRdr->cbImage = paShs[i].PointerToRawData + paShs[i].SizeOfRawData;
     361                    pRdr->cbImage = paShdrs[i].PointerToRawData + paShdrs[i].SizeOfRawData;
    554362                pRdr->cMappings++;
    555363            }
     
    568376        }
    569377    }
     378    else if (fFlags & DBGFMODINMEM_F_NO_READER_FALLBACK)
     379        return rc;
    570380    else
    571381    {
     
    582392    if (pRdr->cbCorrectImageSize != cbImage)
    583393    {
    584         Log(("DigWinNT: The image is really %#x bytes long, not %#x as mapped by NT!\n", pRdr->cbCorrectImageSize, cbImage));
    585         pRdr->offSizeOfImage = pThis->f32Bit
     394        Log(("dbgfR3ModInMemPeCreateLdrMod: The image is really %#x bytes long, not %#x as mapped by NT!\n",
     395             pRdr->cbCorrectImageSize, cbImage));
     396        pRdr->offSizeOfImage = f32Bit
    586397                             ? offHdrs + RT_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader.SizeOfImage)
    587398                             : offHdrs + RT_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader.SizeOfImage);
     
    593404     */
    594405    RTLDRMOD hLdrMod;
    595     int rc = RTLdrOpenInMemory(pszName, RTLDR_O_FOR_DEBUG, RTLDRARCH_WHATEVER, pRdr->cbImage,
    596                                dbgDiggerWinNtRdr_Read, dbgDiggerWinNtRdr_Dtor, pRdr,
    597                                &hLdrMod);
     406    rc = RTLdrOpenInMemory(pszName, RTLDR_O_FOR_DEBUG, RTLDRARCH_WHATEVER, pRdr->cbImage,
     407                           dbgfModInMemPeRdr_Read, dbgfModInMemPeRdr_Dtor, pRdr,
     408                           &hLdrMod, pErrInfo);
    598409    if (RT_SUCCESS(rc))
    599410        *phLdrMod = hLdrMod;
     
    605416
    606417/**
     418 * Handles in-memory PE images.
     419 *
     420 * @returns VBox status code.
     421 * @param   pUVM            The user mode VM handle.
     422 * @param   pImageAddr      The image address.
     423 * @param   fFlags          Flags, DBGFMODINMEM_F_XXX.
     424 * @param   pszName         The image name, optional.
     425 * @param   enmArch         The image arch if we force it, pass
     426 *                          RTLDRARCH_WHATEVER if you don't care.
     427 * @param   cbImage         Image size.  Pass 0 if not known.
     428 * @param   offPeHdrs       Offset of the PE header.
     429 * @param   cbPeHdrsPart1   How read into uBuf at @a offPeHdrs.
     430 * @param   puBuf           The header buffer.
     431 * @param   phDbgMod        Where to return the resulting debug module on success.
     432 * @param   pErrInfo        Where to return extended error info on failure.
     433 */
     434static int dbgfR3ModInMemPe(PUVM pUVM, PCDBGFADDRESS pImageAddr, uint32_t fFlags, const char *pszName, RTLDRARCH enmArch,
     435                            uint32_t cbImage, uint32_t offPeHdrs, uint32_t cbPeHdrsPart1, PDBGFMODINMEMBUF puBuf,
     436                            PRTDBGMOD phDbgMod, PRTERRINFO pErrInfo)
     437{
     438    /*
     439     * Read the optional header and the section table after validating the
     440     * info we need from the file header.
     441     */
     442    /* Check the opt hdr size and number of sections as these are used to determine how much to read next. */
     443    if (   puBuf->Nt32.FileHeader.SizeOfOptionalHeader < sizeof(IMAGE_OPTIONAL_HEADER32)
     444        || puBuf->Nt32.FileHeader.SizeOfOptionalHeader > sizeof(IMAGE_OPTIONAL_HEADER64) + 128)
     445        return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "Invalid SizeOfOptionalHeader value: %#RX32",
     446                                   puBuf->Nt32.FileHeader.SizeOfOptionalHeader);
     447
     448    if (   puBuf->Nt32.FileHeader.NumberOfSections < 1
     449        || puBuf->Nt32.FileHeader.NumberOfSections > 190 /* what fits in our 8K buffer */)
     450        return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "NumberOfSections is out of range: %#RX32 (1..190)",
     451                                   puBuf->Nt32.FileHeader.NumberOfSections);
     452
     453    /* Read the optional header and section table. */
     454    uint32_t const cbHdrs = RT_UOFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader)
     455                          + puBuf->Nt32.FileHeader.SizeOfOptionalHeader
     456                          + puBuf->Nt32.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
     457    AssertReturn(cbHdrs <= sizeof(*puBuf), RTERRINFO_LOG_SET_F(pErrInfo, VERR_INTERNAL_ERROR_2, "cbHdrs=%#x", cbHdrs));
     458
     459    DBGFADDRESS PeHdrPart2Addr = *pImageAddr;
     460    DBGFR3AddrAdd(&PeHdrPart2Addr, offPeHdrs + cbPeHdrsPart1);
     461    int rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &PeHdrPart2Addr, &puBuf->ab[cbPeHdrsPart1], cbHdrs - cbPeHdrsPart1);
     462    if (RT_FAILURE(rc))
     463        return RTERRINFO_LOG_SET_F(pErrInfo, rc,
     464                                   "Failed to read the second part of the PE headers at %RGv (off=%#RX32 + %#RX32): %Rrc",
     465                                   PeHdrPart2Addr.FlatPtr, offPeHdrs, cbPeHdrsPart1, rc);
     466
     467    /*
     468     * Check the image architecture and determine the bitness.
     469     */
     470    RTLDRARCH enmArchActual;
     471    bool f32Bit;
     472    switch (puBuf->Nt32.FileHeader.Machine)
     473    {
     474        case IMAGE_FILE_MACHINE_I386:
     475            enmArchActual = RTLDRARCH_X86_32;
     476            f32Bit = true;
     477            break;
     478        case IMAGE_FILE_MACHINE_AMD64:
     479            enmArchActual = RTLDRARCH_AMD64;
     480            f32Bit = false;
     481            break;
     482        case IMAGE_FILE_MACHINE_ARM:
     483        case IMAGE_FILE_MACHINE_THUMB:
     484        case IMAGE_FILE_MACHINE_ARMNT:
     485            enmArchActual = RTLDRARCH_ARM32;
     486            f32Bit = true;
     487            break;
     488        case IMAGE_FILE_MACHINE_ARM64:
     489            enmArchActual = RTLDRARCH_ARM64;
     490            f32Bit = false;
     491            break;
     492        default:
     493            return RTERRINFO_LOG_SET_F(pErrInfo, VERR_LDR_ARCH_MISMATCH, "Unknown machine: %#x", puBuf->Nt32.FileHeader.Machine);
     494    }
     495    if (   enmArch != RTLDRARCH_WHATEVER
     496        && enmArch != enmArchActual)
     497        return RTERRINFO_LOG_SET_F(pErrInfo, VERR_LDR_ARCH_MISMATCH, "Found %s expected %s",
     498                                   RTLdrArchName(enmArchActual), RTLdrArchName(enmArch));
     499
     500    /*
     501     * Check optional header magic and size.
     502     */
     503    uint16_t const uOptMagic = f32Bit ? IMAGE_NT_OPTIONAL_HDR32_MAGIC : IMAGE_NT_OPTIONAL_HDR64_MAGIC;
     504    if (puBuf->Nt32.OptionalHeader.Magic != uOptMagic)
     505        return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "Unexpected optional header magic: %#x (expected %#x)",
     506                                   puBuf->Nt32.OptionalHeader.Magic, uOptMagic);
     507
     508    uint32_t const cDataDir = f32Bit ? puBuf->Nt32.OptionalHeader.NumberOfRvaAndSizes : puBuf->Nt64.OptionalHeader.NumberOfRvaAndSizes;
     509    if (   cDataDir <= IMAGE_DIRECTORY_ENTRY_BASERELOC /* a bit random */
     510        || cDataDir > 32 /* also random */)
     511        return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "Unexpected data directory size: %#x", cDataDir);
     512
     513    uint32_t cbOptHdr = f32Bit ? sizeof(IMAGE_OPTIONAL_HEADER32) : sizeof(IMAGE_OPTIONAL_HEADER64);
     514    cbOptHdr -= sizeof(IMAGE_DATA_DIRECTORY) * IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
     515    cbOptHdr += sizeof(IMAGE_DATA_DIRECTORY) * cDataDir;
     516    if (puBuf->Nt32.FileHeader.SizeOfOptionalHeader != cbOptHdr)
     517        return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "Unexpected optional header size: %#x (expected %#x)",
     518                                   puBuf->Nt32.FileHeader.SizeOfOptionalHeader, cbOptHdr);
     519
     520    uint32_t const cbSectAlign = f32Bit ? puBuf->Nt32.OptionalHeader.SectionAlignment : puBuf->Nt64.OptionalHeader.SectionAlignment;
     521    PCIMAGE_SECTION_HEADER pSHdrs    = (PCIMAGE_SECTION_HEADER)((uintptr_t)&puBuf->Nt32.OptionalHeader + cbOptHdr);
     522    PCIMAGE_DATA_DIRECTORY paDataDir = (PCIMAGE_DATA_DIRECTORY)((uintptr_t)pSHdrs - cDataDir * sizeof(IMAGE_DATA_DIRECTORY));
     523
     524    /*
     525     * Establish the image size.
     526     */
     527    uint32_t cbImageFromHdr = f32Bit ? puBuf->Nt32.OptionalHeader.SizeOfImage : puBuf->Nt64.OptionalHeader.SizeOfImage;
     528    if (   !cbImage
     529        || (fFlags & DBGFMODINMEM_F_PE_NT31))
     530        cbImage = RT_ALIGN(cbImageFromHdr, _4K);
     531    else if (RT_ALIGN(cbImageFromHdr, _4K) != RT_ALIGN(cbImage, _4K))
     532        return RTERRINFO_LOG_SET_F(pErrInfo, VERR_MISMATCH, "Image size mismatch: input=%#x header=%#x", cbImage, cbImageFromHdr);
     533
     534    /*
     535     * Guess the image name if not specified.
     536     */
     537    //char szImageName[64];
     538    if (!pszName)
     539    {
     540        /** @todo */
     541    }
     542
     543    /*
     544     * Create the module using the in memory image first, falling back on cached image.
     545     */
     546    RTLDRMOD hLdrMod;
     547    rc = dbgfR3ModInMemPeCreateLdrMod(pUVM, fFlags, pszName, pImageAddr, cbImage, cbImageFromHdr, f32Bit,
     548                                      puBuf->Nt32.FileHeader.NumberOfSections, pSHdrs, cbSectAlign, cDataDir, paDataDir,
     549                                      offPeHdrs, &hLdrMod, pErrInfo);
     550    if (RT_FAILURE(rc))
     551        hLdrMod = NIL_RTLDRMOD;
     552
     553    RTDBGMOD hMod;
     554    rc = RTDbgModCreateFromPeImage(&hMod, pszName, NULL, &hLdrMod, cbImageFromHdr,
     555                                   puBuf->Nt32.FileHeader.TimeDateStamp, DBGFR3AsGetConfig(pUVM));
     556    if (RT_SUCCESS(rc))
     557        *phDbgMod = hMod;
     558    else if (!(fFlags & DBGFMODINMEM_F_NO_CONTAINER_FALLBACK))
     559    {
     560        /*
     561         * Fallback is a container module.
     562         */
     563        rc = RTDbgModCreate(&hMod, pszName, cbImage, 0);
     564        if (RT_SUCCESS(rc))
     565        {
     566            rc = RTDbgModSymbolAdd(hMod, "Headers", 0 /*iSeg*/, 0, cbImage, 0 /*fFlags*/, NULL);
     567            AssertRC(rc);
     568        }
     569    }
     570    return rc;
     571}
     572
     573
     574
     575/**
    607576 * Process a PE image found in guest memory.
    608577 *
    609  * @param   pThis           The instance data.
    610578 * @param   pUVM            The user mode VM handle.
    611  * @param   pszName         The image name.
    612579 * @param   pImageAddr      The image address.
    613  * @param   cbImage         The size of the image.
    614  * @param   pbBuf           Scratch buffer containing the first
    615  *                          RT_MIN(cbBuf, cbImage) bytes of the image.
    616  * @param   cbBuf           The scratch buffer size.
    617  */
    618 static void dbgDiggerWinNtProcessImage(PDBGDIGGERWINNT pThis, PUVM pUVM, const char *pszName,
    619                                        PCDBGFADDRESS pImageAddr, uint32_t cbImage,
    620                                        uint8_t *pbBuf, size_t cbBuf)
    621 {
    622     LogFlow(("DigWinNt: %RGp %#x %s\n", pImageAddr->FlatPtr, cbImage, pszName));
    623 
    624     /*
    625      * NT 3.1 doesn't set the image size in the MTEs, so a little
    626      * bit of tweaking is necessary here.
    627      */
    628     uint32_t const cbImageValidate = !pThis->fNt31 ? cbImage : _64M;
    629 
    630     /*
    631      * Do some basic validation first.
    632      * This is the usual exteremely verbose and messy code...
    633      */
    634     Assert(cbBuf >= sizeof(IMAGE_NT_HEADERS64));
    635     if (   (cbImage < sizeof(IMAGE_NT_HEADERS64) && !pThis->fNt31)
    636         || cbImage >= _1M * 256)
    637     {
    638         Log(("DigWinNt: %s: Bad image size: %#x\n", pszName, cbImage));
    639         return;
    640     }
    641 
    642     /* Dig out the NT/PE headers. */
    643     IMAGE_DOS_HEADER const *pMzHdr = (IMAGE_DOS_HEADER const *)pbBuf;
    644     PCNTHDRS        pHdrs;
    645     uint32_t        offHdrs;
    646     if (pMzHdr->e_magic != IMAGE_DOS_SIGNATURE)
    647     {
    648         offHdrs = 0;
    649         pHdrs   = (PCNTHDRS)pbBuf;
    650     }
    651     else if (   pMzHdr->e_lfanew >= cbImageValidate
    652              || pMzHdr->e_lfanew < sizeof(*pMzHdr)
    653              || pMzHdr->e_lfanew + sizeof(IMAGE_NT_HEADERS64) > cbImageValidate)
    654     {
    655         Log(("DigWinNt: %s: PE header to far into image: %#x  cbImage=%#x\n", pszName, pMzHdr->e_lfanew, cbImage));
    656         return;
    657     }
    658     else if (   pMzHdr->e_lfanew < cbBuf
    659              && pMzHdr->e_lfanew + sizeof(IMAGE_NT_HEADERS64) <= cbBuf)
    660     {
    661         offHdrs = pMzHdr->e_lfanew;
    662         pHdrs = (NTHDRS const *)(pbBuf + offHdrs);
    663     }
     580 * @param   fFlags          Flags, DBGFMODINMEM_F_XXX.
     581 * @param   pszName         The image name, optional.
     582 * @param   enmArch         The image arch if we force it, pass
     583 *                          RTLDRARCH_WHATEVER if you don't care.
     584 * @param   cbImage         Image size.  Pass 0 if not known.
     585 * @param   phDbgMod        Where to return the resulting debug module on success.
     586 * @param   pErrInfo        Where to return extended error info on failure.
     587 */
     588VMMR3DECL(int) DBGFR3ModInMem(PUVM pUVM, PCDBGFADDRESS pImageAddr, uint32_t fFlags, const char *pszName,
     589                              RTLDRARCH enmArch, uint32_t cbImage, PRTDBGMOD phDbgMod, PRTERRINFO pErrInfo)
     590{
     591    /*
     592     * Validate and adjust.
     593     */
     594    AssertPtrReturn(phDbgMod, VERR_INVALID_POINTER);
     595    *phDbgMod = NIL_RTDBGMOD;
     596    AssertPtrReturn(pImageAddr, VERR_INVALID_POINTER);
     597    AssertMsgReturn(cbImage == 0 || cbImage >= sizeof(IMAGE_NT_HEADERS32) + sizeof(IMAGE_DOS_HEADER),
     598                    ("cbImage=%#x\n", cbImage), VERR_INVALID_PARAMETER);
     599    AssertMsgReturn(!(fFlags & ~DBGFMODINMEM_F_VALID_MASK), ("%#x\n", fFlags), VERR_INVALID_FLAGS);
     600    if (enmArch == RTLDRARCH_HOST)
     601        enmArch = RTLdrGetHostArch();
     602
     603    /*
     604     * Look for an image header we can work with.
     605     */
     606    DBGFMODINMEMBUF uBuf;
     607    RT_ZERO(uBuf);
     608
     609    int rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, pImageAddr, &uBuf, sizeof(uBuf.DosHdr));
     610    if (RT_FAILURE(rc))
     611        return RTERRINFO_LOG_SET_F(pErrInfo, rc, "Failed to read DOS header at %RGv: %Rrc", pImageAddr->FlatPtr, rc);
     612
     613    if (uBuf.ab[0] == ELFMAG0 && uBuf.ab[1] == ELFMAG1 && uBuf.ab[2] == ELFMAG2 && uBuf.ab[3] == ELFMAG3)
     614        return dbgfR3ModInMemElf(pUVM, pImageAddr, fFlags, pszName, enmArch, cbImage, &uBuf, phDbgMod, pErrInfo);
     615
     616    uint32_t offNewHdrs;
     617    if (uBuf.DosHdr.e_magic == IMAGE_DOS_SIGNATURE)
     618    {
     619        offNewHdrs = uBuf.DosHdr.e_lfanew;
     620        if (   offNewHdrs < 16
     621            || offNewHdrs > (cbImage ? _2M : cbImage - sizeof(IMAGE_NT_HEADERS32)))
     622            return RTERRINFO_LOG_SET_F(pErrInfo, rc, "e_lfanew value is out of range: %RX32 (16..%u)",
     623                                       offNewHdrs, (cbImage ? _2M : cbImage - sizeof(IMAGE_NT_HEADERS32)));
     624    }
     625    else if (uBuf.Nt32.Signature == IMAGE_NT_SIGNATURE)
     626        offNewHdrs = 0;
    664627    else
    665     {
    666         Log(("DigWinNt: %s: PE header to far into image (lazy bird): %#x\n", pszName, pMzHdr->e_lfanew));
    667         return;
    668     }
    669     if (pHdrs->vX_32.Signature != IMAGE_NT_SIGNATURE)
    670     {
    671         Log(("DigWinNt: %s: Bad PE signature: %#x\n", pszName, pHdrs->vX_32.Signature));
    672         return;
    673     }
    674 
    675     /* The file header is the same on both archs */
    676     if (pHdrs->vX_32.FileHeader.Machine != (pThis->f32Bit ? IMAGE_FILE_MACHINE_I386 : IMAGE_FILE_MACHINE_AMD64))
    677     {
    678         Log(("DigWinNt: %s: Invalid FH.Machine: %#x\n", pszName, pHdrs->vX_32.FileHeader.Machine));
    679         return;
    680     }
    681     if (pHdrs->vX_32.FileHeader.SizeOfOptionalHeader != (pThis->f32Bit ? sizeof(IMAGE_OPTIONAL_HEADER32) : sizeof(IMAGE_OPTIONAL_HEADER64)))
    682     {
    683         Log(("DigWinNt: %s: Invalid FH.SizeOfOptionalHeader: %#x\n", pszName, pHdrs->vX_32.FileHeader.SizeOfOptionalHeader));
    684         return;
    685     }
    686     if (WINNT_UNION(pThis, pHdrs, FileHeader.NumberOfSections) > 64)
    687     {
    688         Log(("DigWinNt: %s: Too many sections: %#x\n", pszName, WINNT_UNION(pThis, pHdrs, FileHeader.NumberOfSections)));
    689         return;
    690     }
    691 
    692     const uint32_t TimeDateStamp = pHdrs->vX_32.FileHeader.TimeDateStamp;
    693 
    694     /* The optional header is not... */
    695     if (WINNT_UNION(pThis, pHdrs, OptionalHeader.Magic) != (pThis->f32Bit ? IMAGE_NT_OPTIONAL_HDR32_MAGIC : IMAGE_NT_OPTIONAL_HDR64_MAGIC))
    696     {
    697         Log(("DigWinNt: %s: Invalid OH.Magic: %#x\n", pszName, WINNT_UNION(pThis, pHdrs, OptionalHeader.Magic)));
    698         return;
    699     }
    700     uint32_t cbImageFromHdr = WINNT_UNION(pThis, pHdrs, OptionalHeader.SizeOfImage);
    701     if (pThis->fNt31)
    702         cbImage = RT_ALIGN(cbImageFromHdr, _4K);
    703     else if (RT_ALIGN(cbImageFromHdr, _4K) != RT_ALIGN(cbImage, _4K))
    704     {
    705         Log(("DigWinNt: %s: Invalid OH.SizeOfImage: %#x, expected %#x\n", pszName, cbImageFromHdr, cbImage));
    706         return;
    707     }
    708     if (WINNT_UNION(pThis, pHdrs, OptionalHeader.NumberOfRvaAndSizes) != IMAGE_NUMBEROF_DIRECTORY_ENTRIES)
    709     {
    710         Log(("DigWinNt: %s: Invalid OH.NumberOfRvaAndSizes: %#x\n", pszName, WINNT_UNION(pThis, pHdrs, OptionalHeader.NumberOfRvaAndSizes)));
    711         return;
    712     }
    713 
    714     /*
    715      * Create the module using the in memory image first, falling back
    716      * on cached image.
    717      */
    718     RTLDRMOD hLdrMod;
    719     int rc = dbgDiggerWinNtCreateLdrMod(pThis, pUVM, pszName, pImageAddr, cbImage, pbBuf, cbBuf, offHdrs, pHdrs,
    720                                         &hLdrMod);
     628        return RTERRINFO_LOG_SET_F(pErrInfo, VERR_INVALID_EXE_SIGNATURE, "Unknown image magic at %RGv: %.8Rhxs",
     629                                   pImageAddr->FlatPtr, uBuf.ab);
     630
     631    /*
     632     * Read the next bit of header, assuming PE so stop at the end of
     633     * the COFF file header.
     634     */
     635    DBGFADDRESS PeHdrAddr = *pImageAddr;
     636    DBGFR3AddrAdd(&PeHdrAddr, offNewHdrs);
     637    uint32_t const cbPeHdrsPart1 = RT_UOFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader);
     638    rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &PeHdrAddr, &uBuf, cbPeHdrsPart1);
    721639    if (RT_FAILURE(rc))
    722         hLdrMod = NIL_RTLDRMOD;
    723 
    724     RTDBGMOD hMod;
    725     rc = RTDbgModCreateFromPeImage(&hMod, pszName, NULL, hLdrMod,
    726                                    cbImageFromHdr, TimeDateStamp, DBGFR3AsGetConfig(pUVM));
    727     if (RT_FAILURE(rc))
    728     {
    729         /*
    730          * Final fallback is a container module.
    731          */
    732         rc = RTDbgModCreate(&hMod, pszName, cbImage, 0);
    733         if (RT_FAILURE(rc))
    734             return;
    735 
    736         rc = RTDbgModSymbolAdd(hMod, "Headers", 0 /*iSeg*/, 0, cbImage, 0 /*fFlags*/, NULL);
    737         AssertRC(rc);
    738     }
    739 
    740     /* Tag the module. */
    741     rc = RTDbgModSetTag(hMod, DIG_WINNT_MOD_TAG);
    742     AssertRC(rc);
    743 
    744     /*
    745      * Link the module.
    746      */
    747     RTDBGAS hAs = DBGFR3AsResolveAndRetain(pUVM, DBGF_AS_KERNEL);
    748     if (hAs != NIL_RTDBGAS)
    749         rc = RTDbgAsModuleLink(hAs, hMod, pImageAddr->FlatPtr, RTDBGASLINK_FLAGS_REPLACE /*fFlags*/);
    750     else
    751         rc = VERR_INTERNAL_ERROR;
    752     RTDbgModRelease(hMod);
    753     RTDbgAsRelease(hAs);
     640        return RTERRINFO_LOG_SET_F(pErrInfo, rc, "Failed to read PE/LX/NE headers at %RGv (off=%#RX32): %Rrc",
     641                                   PeHdrAddr.FlatPtr, offNewHdrs, rc);
     642
     643    if (uBuf.Nt32.Signature == IMAGE_NT_SIGNATURE)
     644        return dbgfR3ModInMemPe(pUVM, pImageAddr, fFlags, pszName, enmArch, cbImage, offNewHdrs, cbPeHdrsPart1, &uBuf,
     645                                phDbgMod, pErrInfo);
     646
     647    return RTERRINFO_LOG_SET_F(pErrInfo, VERR_INVALID_EXE_SIGNATURE, "No PE/LX/NE header at %RGv (off=%#RX32): %.8Rhxs",
     648                               PeHdrAddr.FlatPtr, offNewHdrs, uBuf.ab);
    754649}
    755650
    756 
    757 /**
    758  * @copydoc DBGFOSREG::pfnQueryInterface
    759  */
    760 static DECLCALLBACK(void *) dbgDiggerWinNtQueryInterface(PUVM pUVM, void *pvData, DBGFOSINTERFACE enmIf)
    761 {
    762     RT_NOREF3(pUVM, pvData, enmIf);
    763     return NULL;
    764 }
    765 
    766 
    767 /**
    768  * @copydoc DBGFOSREG::pfnQueryVersion
    769  */
    770 static DECLCALLBACK(int)  dbgDiggerWinNtQueryVersion(PUVM pUVM, void *pvData, char *pszVersion, size_t cchVersion)
    771 {
    772     RT_NOREF1(pUVM);
    773     PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
    774     Assert(pThis->fValid);
    775     const char *pszNtProductType;
    776     switch (pThis->NtProductType)
    777     {
    778         case kNtProductType_WinNt:      pszNtProductType = "-WinNT";        break;
    779         case kNtProductType_LanManNt:   pszNtProductType = "-LanManNT";     break;
    780         case kNtProductType_Server:     pszNtProductType = "-Server";       break;
    781         default:                        pszNtProductType = "";              break;
    782     }
    783     RTStrPrintf(pszVersion, cchVersion, "%u.%u-%s%s", pThis->NtMajorVersion, pThis->NtMinorVersion,
    784                 pThis->f32Bit ? "x86" : "AMD64", pszNtProductType);
    785     return VINF_SUCCESS;
    786 }
    787 
    788 
    789 /**
    790  * @copydoc DBGFOSREG::pfnTerm
    791  */
    792 static DECLCALLBACK(void)  dbgDiggerWinNtTerm(PUVM pUVM, void *pvData)
    793 {
    794     RT_NOREF1(pUVM);
    795     PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
    796     Assert(pThis->fValid);
    797 
    798     pThis->fValid = false;
    799 }
    800 
    801 
    802 /**
    803  * @copydoc DBGFOSREG::pfnRefresh
    804  */
    805 static DECLCALLBACK(int)  dbgDiggerWinNtRefresh(PUVM pUVM, void *pvData)
    806 {
    807     PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
    808     NOREF(pThis);
    809     Assert(pThis->fValid);
    810 
    811     /*
    812      * For now we'll flush and reload everything.
    813      */
    814     RTDBGAS hDbgAs = DBGFR3AsResolveAndRetain(pUVM, DBGF_AS_KERNEL);
    815     if (hDbgAs != NIL_RTDBGAS)
    816     {
    817         uint32_t iMod = RTDbgAsModuleCount(hDbgAs);
    818         while (iMod-- > 0)
    819         {
    820             RTDBGMOD hMod = RTDbgAsModuleByIndex(hDbgAs, iMod);
    821             if (hMod != NIL_RTDBGMOD)
    822             {
    823                 if (RTDbgModGetTag(hMod) == DIG_WINNT_MOD_TAG)
    824                 {
    825                     int rc = RTDbgAsModuleUnlink(hDbgAs, hMod);
    826                     AssertRC(rc);
    827                 }
    828                 RTDbgModRelease(hMod);
    829             }
    830         }
    831         RTDbgAsRelease(hDbgAs);
    832     }
    833 
    834     dbgDiggerWinNtTerm(pUVM, pvData);
    835     return dbgDiggerWinNtInit(pUVM, pvData);
    836 }
    837 
    838 
    839 /**
    840  * @copydoc DBGFOSREG::pfnInit
    841  */
    842 static DECLCALLBACK(int)  dbgDiggerWinNtInit(PUVM pUVM, void *pvData)
    843 {
    844     PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
    845     Assert(!pThis->fValid);
    846 
    847     union
    848     {
    849         uint8_t             au8[0x2000];
    850         RTUTF16             wsz[0x2000/2];
    851         NTKUSERSHAREDDATA   UserSharedData;
    852     }               u;
    853     DBGFADDRESS     Addr;
    854     int             rc;
    855 
    856     /*
    857      * Figure the NT version.
    858      */
    859     DBGFR3AddrFromFlat(pUVM, &Addr, pThis->f32Bit ? NTKUSERSHAREDDATA_WINNT32 : NTKUSERSHAREDDATA_WINNT64);
    860     rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &Addr, &u, PAGE_SIZE);
    861     if (RT_SUCCESS(rc))
    862     {
    863         pThis->NtProductType  = u.UserSharedData.ProductTypeIsValid && u.UserSharedData.NtProductType <= kNtProductType_Server
    864                               ? (NTPRODUCTTYPE)u.UserSharedData.NtProductType
    865                               : kNtProductType_Invalid;
    866         pThis->NtMajorVersion = u.UserSharedData.NtMajorVersion;
    867         pThis->NtMinorVersion = u.UserSharedData.NtMinorVersion;
    868     }
    869     else if (pThis->fNt31)
    870     {
    871         pThis->NtProductType  = kNtProductType_WinNt;
    872         pThis->NtMajorVersion = 3;
    873         pThis->NtMinorVersion = 1;
    874     }
    875     else
    876     {
    877         Log(("DigWinNt: Error reading KUSER_SHARED_DATA: %Rrc\n", rc));
    878         return rc;
    879     }
    880 
    881     /*
    882      * Dig out the module chain.
    883      */
    884     DBGFADDRESS AddrPrev = pThis->PsLoadedModuleListAddr;
    885     Addr                 = pThis->KernelMteAddr;
    886     do
    887     {
    888         /* Read the validate the MTE. */
    889         NTMTE Mte;
    890         rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &Addr, &Mte, pThis->f32Bit ? sizeof(Mte.vX_32) : sizeof(Mte.vX_64));
    891         if (RT_FAILURE(rc))
    892             break;
    893         if (WINNT_UNION(pThis, &Mte, InLoadOrderLinks.Blink) != AddrPrev.FlatPtr)
    894         {
    895             Log(("DigWinNt: Bad Mte At %RGv - backpointer\n", Addr.FlatPtr));
    896             break;
    897         }
    898         if (!WINNT_VALID_ADDRESS(pThis, WINNT_UNION(pThis, &Mte, InLoadOrderLinks.Flink)) )
    899         {
    900             Log(("DigWinNt: Bad Mte at %RGv - forward pointer\n", Addr.FlatPtr));
    901             break;
    902         }
    903         if (!WINNT_VALID_ADDRESS(pThis, WINNT_UNION(pThis, &Mte, BaseDllName.Buffer)))
    904         {
    905             Log(("DigWinNt: Bad Mte at %RGv - BaseDllName=%llx\n", Addr.FlatPtr, WINNT_UNION(pThis, &Mte, BaseDllName.Buffer)));
    906             break;
    907         }
    908         if (!WINNT_VALID_ADDRESS(pThis, WINNT_UNION(pThis, &Mte, FullDllName.Buffer)))
    909         {
    910             Log(("DigWinNt: Bad Mte at %RGv - FullDllName=%llx\n", Addr.FlatPtr, WINNT_UNION(pThis, &Mte, FullDllName.Buffer)));
    911             break;
    912         }
    913         if (!WINNT_VALID_ADDRESS(pThis, WINNT_UNION(pThis, &Mte, DllBase)))
    914         {
    915             Log(("DigWinNt: Bad Mte at %RGv - DllBase=%llx\n", Addr.FlatPtr, WINNT_UNION(pThis, &Mte, DllBase) ));
    916             break;
    917         }
    918 
    919         uint32_t const cbImageMte = !pThis->fNt31 ? WINNT_UNION(pThis, &Mte, SizeOfImage) : 0;
    920         if (   !pThis->fNt31
    921             && (   cbImageMte > _256M
    922                 || WINNT_UNION(pThis, &Mte, EntryPoint) - WINNT_UNION(pThis, &Mte, DllBase) > cbImageMte) )
    923         {
    924             Log(("DigWinNt: Bad Mte at %RGv - EntryPoint=%llx SizeOfImage=%x DllBase=%llx\n",
    925                  Addr.FlatPtr, WINNT_UNION(pThis, &Mte, EntryPoint), cbImageMte, WINNT_UNION(pThis, &Mte, DllBase)));
    926             break;
    927         }
    928 
    929         /* Read the full name. */
    930         DBGFADDRESS AddrName;
    931         DBGFR3AddrFromFlat(pUVM, &AddrName, WINNT_UNION(pThis, &Mte, FullDllName.Buffer));
    932         uint16_t    cbName = WINNT_UNION(pThis, &Mte, FullDllName.Length);
    933         if (cbName < sizeof(u))
    934             rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &AddrName, &u, cbName);
    935         else
    936             rc = VERR_OUT_OF_RANGE;
    937         if (RT_FAILURE(rc))
    938         {
    939             DBGFR3AddrFromFlat(pUVM, &AddrName, WINNT_UNION(pThis, &Mte, BaseDllName.Buffer));
    940             cbName = WINNT_UNION(pThis, &Mte, BaseDllName.Length);
    941             if (cbName < sizeof(u))
    942                 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &AddrName, &u, cbName);
    943             else
    944                 rc = VERR_OUT_OF_RANGE;
    945         }
    946         if (RT_SUCCESS(rc))
    947         {
    948             u.wsz[cbName/2] = '\0';
    949             char *pszName;
    950             rc = RTUtf16ToUtf8(u.wsz, &pszName);
    951             if (RT_SUCCESS(rc))
    952             {
    953                 /* Read the start of the PE image and pass it along to a worker. */
    954                 DBGFADDRESS ImageAddr;
    955                 DBGFR3AddrFromFlat(pUVM, &ImageAddr, WINNT_UNION(pThis, &Mte, DllBase));
    956                 uint32_t    cbImageBuf = RT_MIN(sizeof(u), RT_MAX(cbImageMte, _4K));
    957                 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &ImageAddr, &u, cbImageBuf);
    958                 if (RT_SUCCESS(rc))
    959                     dbgDiggerWinNtProcessImage(pThis,
    960                                                pUVM,
    961                                                pszName,
    962                                                &ImageAddr,
    963                                                cbImageMte,
    964                                                &u.au8[0],
    965                                                sizeof(u));
    966                 RTStrFree(pszName);
    967             }
    968         }
    969 
    970         /* next */
    971         AddrPrev = Addr;
    972         DBGFR3AddrFromFlat(pUVM, &Addr, WINNT_UNION(pThis, &Mte, InLoadOrderLinks.Flink));
    973     } while (   Addr.FlatPtr != pThis->KernelMteAddr.FlatPtr
    974              && Addr.FlatPtr != pThis->PsLoadedModuleListAddr.FlatPtr);
    975 
    976     pThis->fValid = true;
    977     return VINF_SUCCESS;
    978 }
    979 
    980 
    981 /**
    982  * @copydoc DBGFOSREG::pfnProbe
    983  */
    984 static DECLCALLBACK(bool)  dbgDiggerWinNtProbe(PUVM pUVM, void *pvData)
    985 {
    986     PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
    987     DBGFADDRESS     Addr;
    988     union
    989     {
    990         uint8_t             au8[8192];
    991         uint16_t            au16[8192/2];
    992         uint32_t            au32[8192/4];
    993         IMAGE_DOS_HEADER    MzHdr;
    994         RTUTF16             wsz[8192/2];
    995     } u;
    996 
    997     union
    998     {
    999         NTMTE32 v32;
    1000         NTMTE64 v64;
    1001     } uMte, uMte2, uMte3;
    1002 
    1003     /*
    1004      * Look for the PAGELK section name that seems to be a part of all kernels.
    1005      * Then try find the module table entry for it.  Since it's the first entry
    1006      * in the PsLoadedModuleList we can easily validate the list head and report
    1007      * success.
    1008      *
    1009      * Note! We ASSUME the section name is 8 byte aligned.
    1010      */
    1011     CPUMMODE        enmMode = DBGFR3CpuGetMode(pUVM, 0 /*idCpu*/);
    1012     uint64_t const  uStart  = enmMode == CPUMMODE_LONG ? UINT64_C(0xffff080000000000) : UINT32_C(0x80001000);
    1013     uint64_t const  uEnd    = enmMode == CPUMMODE_LONG ? UINT64_C(0xffffffffffff0000) : UINT32_C(0xffff0000);
    1014     DBGFADDRESS     KernelAddr;
    1015     for (DBGFR3AddrFromFlat(pUVM, &KernelAddr, uStart);
    1016          KernelAddr.FlatPtr < uEnd;
    1017          KernelAddr.FlatPtr += PAGE_SIZE)
    1018     {
    1019         bool fNt31 = false;
    1020         DBGFADDRESS const RetryAddress = KernelAddr;
    1021         int rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &KernelAddr, uEnd - KernelAddr.FlatPtr,
    1022                                8, "PAGELK\0", sizeof("PAGELK\0"), &KernelAddr);
    1023         if (   rc == VERR_DBGF_MEM_NOT_FOUND
    1024             && enmMode != CPUMMODE_LONG)
    1025         {
    1026             /* NT3.1 didn't have a PAGELK section, so look for _TEXT instead.  The
    1027                following VirtualSize is zero, so check for that too. */
    1028             rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &RetryAddress, uEnd - RetryAddress.FlatPtr,
    1029                                8, "_TEXT\0\0\0\0\0\0", sizeof("_TEXT\0\0\0\0\0\0"), &KernelAddr);
    1030             fNt31 = true;
    1031         }
    1032         if (RT_FAILURE(rc))
    1033             break;
    1034         DBGFR3AddrSub(&KernelAddr, KernelAddr.FlatPtr & PAGE_OFFSET_MASK);
    1035 
    1036         /* MZ + PE header. */
    1037         rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &KernelAddr, &u, sizeof(u));
    1038         if (    RT_SUCCESS(rc)
    1039             &&  u.MzHdr.e_magic == IMAGE_DOS_SIGNATURE
    1040             &&  !(u.MzHdr.e_lfanew & 0x7)
    1041             &&  u.MzHdr.e_lfanew >= 0x080
    1042             &&  u.MzHdr.e_lfanew <= 0x400) /* W8 is at 0x288*/
    1043         {
    1044             if (enmMode != CPUMMODE_LONG)
    1045             {
    1046                 IMAGE_NT_HEADERS32 const *pHdrs = (IMAGE_NT_HEADERS32 const *)&u.au8[u.MzHdr.e_lfanew];
    1047                 if (    pHdrs->Signature                            == IMAGE_NT_SIGNATURE
    1048                     &&  pHdrs->FileHeader.Machine                   == IMAGE_FILE_MACHINE_I386
    1049                     &&  pHdrs->FileHeader.SizeOfOptionalHeader      == sizeof(pHdrs->OptionalHeader)
    1050                     &&  pHdrs->FileHeader.NumberOfSections          >= 10 /* the kernel has lots */
    1051                     &&  (pHdrs->FileHeader.Characteristics & (IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL)) == IMAGE_FILE_EXECUTABLE_IMAGE
    1052                     &&  pHdrs->OptionalHeader.Magic                 == IMAGE_NT_OPTIONAL_HDR32_MAGIC
    1053                     &&  pHdrs->OptionalHeader.NumberOfRvaAndSizes   == IMAGE_NUMBEROF_DIRECTORY_ENTRIES
    1054                     )
    1055                 {
    1056                     /* Find the MTE. */
    1057                     RT_ZERO(uMte);
    1058                     uMte.v32.DllBase     = KernelAddr.FlatPtr;
    1059                     uMte.v32.EntryPoint  = KernelAddr.FlatPtr + pHdrs->OptionalHeader.AddressOfEntryPoint;
    1060                     uMte.v32.SizeOfImage = !fNt31 ? pHdrs->OptionalHeader.SizeOfImage : 0; /* NT 3.1 didn't set the size. */
    1061                     DBGFADDRESS HitAddr;
    1062                     rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &KernelAddr, uEnd - KernelAddr.FlatPtr,
    1063                                        4 /*align*/, &uMte.v32.DllBase, 3 * sizeof(uint32_t), &HitAddr);
    1064                     while (RT_SUCCESS(rc))
    1065                     {
    1066                         /* check the name. */
    1067                         DBGFADDRESS MteAddr = HitAddr;
    1068                         rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrSub(&MteAddr, RT_OFFSETOF(NTMTE32, DllBase)),
    1069                                            &uMte2.v32, sizeof(uMte2.v32));
    1070                         if (    RT_SUCCESS(rc)
    1071                             &&  uMte2.v32.DllBase     == uMte.v32.DllBase
    1072                             &&  uMte2.v32.EntryPoint  == uMte.v32.EntryPoint
    1073                             &&  uMte2.v32.SizeOfImage == uMte.v32.SizeOfImage
    1074                             &&  WINNT32_VALID_ADDRESS(uMte2.v32.InLoadOrderLinks.Flink)
    1075                             &&  WINNT32_VALID_ADDRESS(uMte2.v32.BaseDllName.Buffer)
    1076                             &&  WINNT32_VALID_ADDRESS(uMte2.v32.FullDllName.Buffer)
    1077                             &&  uMte2.v32.BaseDllName.Length <= 128
    1078                             &&  uMte2.v32.FullDllName.Length <= 260
    1079                            )
    1080                         {
    1081                             rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pUVM, &Addr, uMte2.v32.BaseDllName.Buffer),
    1082                                                u.wsz, uMte2.v32.BaseDllName.Length);
    1083                             u.wsz[uMte2.v32.BaseDllName.Length / 2] = '\0';
    1084                             if (    RT_SUCCESS(rc)
    1085                                 &&  (   !RTUtf16ICmp(u.wsz, g_wszKernelNames[0])
    1086                                   /* || !RTUtf16ICmp(u.wsz, g_wszKernelNames[1]) */
    1087                                     )
    1088                                )
    1089                             {
    1090                                 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/,
    1091                                                    DBGFR3AddrFromFlat(pUVM, &Addr, uMte2.v32.InLoadOrderLinks.Blink),
    1092                                                    &uMte3.v32, RT_SIZEOFMEMB(NTMTE32, InLoadOrderLinks));
    1093                                 if (   RT_SUCCESS(rc)
    1094                                     && uMte3.v32.InLoadOrderLinks.Flink == MteAddr.FlatPtr
    1095                                     && WINNT32_VALID_ADDRESS(uMte3.v32.InLoadOrderLinks.Blink) )
    1096                                 {
    1097                                     Log(("DigWinNt: MteAddr=%RGv KernelAddr=%RGv SizeOfImage=%x &PsLoadedModuleList=%RGv (32-bit)\n",
    1098                                          MteAddr.FlatPtr, KernelAddr.FlatPtr, uMte2.v32.SizeOfImage, Addr.FlatPtr));
    1099                                     pThis->KernelAddr               = KernelAddr;
    1100                                     pThis->KernelMteAddr            = MteAddr;
    1101                                     pThis->PsLoadedModuleListAddr   = Addr;
    1102                                     pThis->f32Bit                   = true;
    1103                                     pThis->fNt31                    = fNt31;
    1104                                     return true;
    1105                                 }
    1106                             }
    1107                             else if (RT_SUCCESS(rc))
    1108                             {
    1109                                 Log2(("DigWinNt: Wrong module: MteAddr=%RGv ImageAddr=%RGv SizeOfImage=%#x '%ls'\n",
    1110                                       MteAddr.FlatPtr, KernelAddr.FlatPtr, uMte2.v32.SizeOfImage, u.wsz));
    1111                                 break; /* Not NT kernel */
    1112                             }
    1113                         }
    1114 
    1115                         /* next */
    1116                         DBGFR3AddrAdd(&HitAddr, 4);
    1117                         if (HitAddr.FlatPtr < uEnd)
    1118                             rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &HitAddr, uEnd - HitAddr.FlatPtr,
    1119                                                4 /*align*/, &uMte.v32.DllBase, 3 * sizeof(uint32_t), &HitAddr);
    1120                         else
    1121                             rc = VERR_DBGF_MEM_NOT_FOUND;
    1122                     }
    1123                 }
    1124             }
    1125             else
    1126             {
    1127                 IMAGE_NT_HEADERS64 const *pHdrs = (IMAGE_NT_HEADERS64 const *)&u.au8[u.MzHdr.e_lfanew];
    1128                 if (    pHdrs->Signature                            == IMAGE_NT_SIGNATURE
    1129                     &&  pHdrs->FileHeader.Machine                   == IMAGE_FILE_MACHINE_AMD64
    1130                     &&  pHdrs->FileHeader.SizeOfOptionalHeader      == sizeof(pHdrs->OptionalHeader)
    1131                     &&  pHdrs->FileHeader.NumberOfSections          >= 10 /* the kernel has lots */
    1132                     &&      (pHdrs->FileHeader.Characteristics & (IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL))
    1133                          == IMAGE_FILE_EXECUTABLE_IMAGE
    1134                     &&  pHdrs->OptionalHeader.Magic                 == IMAGE_NT_OPTIONAL_HDR64_MAGIC
    1135                     &&  pHdrs->OptionalHeader.NumberOfRvaAndSizes   == IMAGE_NUMBEROF_DIRECTORY_ENTRIES
    1136                     )
    1137                 {
    1138                     /* Find the MTE. */
    1139                     RT_ZERO(uMte.v64);
    1140                     uMte.v64.DllBase     = KernelAddr.FlatPtr;
    1141                     uMte.v64.EntryPoint  = KernelAddr.FlatPtr + pHdrs->OptionalHeader.AddressOfEntryPoint;
    1142                     uMte.v64.SizeOfImage = pHdrs->OptionalHeader.SizeOfImage;
    1143                     DBGFADDRESS ScanAddr;
    1144                     DBGFADDRESS HitAddr;
    1145                     rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pUVM, &ScanAddr, uStart),
    1146                                        uEnd - uStart, 8 /*align*/, &uMte.v64.DllBase, 5 * sizeof(uint32_t), &HitAddr);
    1147                     while (RT_SUCCESS(rc))
    1148                     {
    1149                         /* Read the start of the MTE and check some basic members. */
    1150                         DBGFADDRESS MteAddr = HitAddr;
    1151                         rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrSub(&MteAddr, RT_OFFSETOF(NTMTE64, DllBase)),
    1152                                            &uMte2.v64, sizeof(uMte2.v64));
    1153                         if (    RT_SUCCESS(rc)
    1154                             &&  uMte2.v64.DllBase     == uMte.v64.DllBase
    1155                             &&  uMte2.v64.EntryPoint  == uMte.v64.EntryPoint
    1156                             &&  uMte2.v64.SizeOfImage == uMte.v64.SizeOfImage
    1157                             &&  WINNT64_VALID_ADDRESS(uMte2.v64.InLoadOrderLinks.Flink)
    1158                             &&  WINNT64_VALID_ADDRESS(uMte2.v64.BaseDllName.Buffer)
    1159                             &&  WINNT64_VALID_ADDRESS(uMte2.v64.FullDllName.Buffer)
    1160                             &&  uMte2.v64.BaseDllName.Length <= 128
    1161                             &&  uMte2.v64.FullDllName.Length <= 260
    1162                             )
    1163                         {
    1164                             /* Try read the base name and compare with known NT kernel names. */
    1165                             rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pUVM, &Addr, uMte2.v64.BaseDllName.Buffer),
    1166                                                u.wsz, uMte2.v64.BaseDllName.Length);
    1167                             u.wsz[uMte2.v64.BaseDllName.Length / 2] = '\0';
    1168                             if (    RT_SUCCESS(rc)
    1169                                 &&  (   !RTUtf16ICmp(u.wsz, g_wszKernelNames[0])
    1170                                   /* || !RTUtf16ICmp(u.wsz, g_wszKernelNames[1]) */
    1171                                     )
    1172                                )
    1173                             {
    1174                                 /* Read the link entry of the previous entry in the list and check that its
    1175                                    forward pointer points at the MTE we've found. */
    1176                                 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/,
    1177                                                    DBGFR3AddrFromFlat(pUVM, &Addr, uMte2.v64.InLoadOrderLinks.Blink),
    1178                                                    &uMte3.v64, RT_SIZEOFMEMB(NTMTE64, InLoadOrderLinks));
    1179                                 if (   RT_SUCCESS(rc)
    1180                                     && uMte3.v64.InLoadOrderLinks.Flink == MteAddr.FlatPtr
    1181                                     && WINNT64_VALID_ADDRESS(uMte3.v64.InLoadOrderLinks.Blink) )
    1182                                 {
    1183                                     Log(("DigWinNt: MteAddr=%RGv KernelAddr=%RGv SizeOfImage=%x &PsLoadedModuleList=%RGv (32-bit)\n",
    1184                                          MteAddr.FlatPtr, KernelAddr.FlatPtr, uMte2.v64.SizeOfImage, Addr.FlatPtr));
    1185                                     pThis->KernelAddr               = KernelAddr;
    1186                                     pThis->KernelMteAddr            = MteAddr;
    1187                                     pThis->PsLoadedModuleListAddr   = Addr;
    1188                                     pThis->f32Bit                   = false;
    1189                                     pThis->fNt31                    = false;
    1190                                     return true;
    1191                                 }
    1192                             }
    1193                             else if (RT_SUCCESS(rc))
    1194                             {
    1195                                 Log2(("DigWinNt: Wrong module: MteAddr=%RGv ImageAddr=%RGv SizeOfImage=%#x '%ls'\n",
    1196                                       MteAddr.FlatPtr, KernelAddr.FlatPtr, uMte2.v64.SizeOfImage, u.wsz));
    1197                                 break; /* Not NT kernel */
    1198                             }
    1199                         }
    1200 
    1201                         /* next */
    1202                         DBGFR3AddrAdd(&HitAddr, 8);
    1203                         if (HitAddr.FlatPtr < uEnd)
    1204                             rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &HitAddr, uEnd - HitAddr.FlatPtr,
    1205                                                8 /*align*/, &uMte.v64.DllBase, 3 * sizeof(uint32_t), &HitAddr);
    1206                         else
    1207                             rc = VERR_DBGF_MEM_NOT_FOUND;
    1208                     }
    1209                 }
    1210             }
    1211         }
    1212     }
    1213     return false;
    1214 }
    1215 
    1216 
    1217 /**
    1218  * @copydoc DBGFOSREG::pfnDestruct
    1219  */
    1220 static DECLCALLBACK(void)  dbgDiggerWinNtDestruct(PUVM pUVM, void *pvData)
    1221 {
    1222     RT_NOREF2(pUVM, pvData);
    1223 }
    1224 
    1225 
    1226 /**
    1227  * @copydoc DBGFOSREG::pfnConstruct
    1228  */
    1229 static DECLCALLBACK(int)  dbgDiggerWinNtConstruct(PUVM pUVM, void *pvData)
    1230 {
    1231     RT_NOREF1(pUVM);
    1232     PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
    1233     pThis->fValid = false;
    1234     pThis->f32Bit = false;
    1235     pThis->enmVer = DBGDIGGERWINNTVER_UNKNOWN;
    1236     return VINF_SUCCESS;
    1237 }
    1238 
    1239 
    1240 const DBGFOSREG g_DBGDiggerWinNt =
    1241 {
    1242     /* .u32Magic = */           DBGFOSREG_MAGIC,
    1243     /* .fFlags = */             0,
    1244     /* .cbData = */             sizeof(DBGDIGGERWINNT),
    1245     /* .szName = */             "WinNT",
    1246     /* .pfnConstruct = */       dbgDiggerWinNtConstruct,
    1247     /* .pfnDestruct = */        dbgDiggerWinNtDestruct,
    1248     /* .pfnProbe = */           dbgDiggerWinNtProbe,
    1249     /* .pfnInit = */            dbgDiggerWinNtInit,
    1250     /* .pfnRefresh = */         dbgDiggerWinNtRefresh,
    1251     /* .pfnTerm = */            dbgDiggerWinNtTerm,
    1252     /* .pfnQueryVersion = */    dbgDiggerWinNtQueryVersion,
    1253     /* .pfnQueryInterface = */  dbgDiggerWinNtQueryInterface,
    1254     /* .u32EndMagic = */        DBGFOSREG_MAGIC
    1255 };
    1256 
Note: See TracChangeset for help on using the changeset viewer.

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