~ubuntu-branches/ubuntu/raring/virtualbox-ose/raring

« back to all changes in this revision

Viewing changes to src/VBox/Debugger/DBGPlugInWinNt.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2011-01-30 23:27:25 UTC
  • mfrom: (0.3.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20110130232725-2ouajjd2ggdet0zd
Tags: 4.0.2-dfsg-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Add Apport hook.
    - debian/virtualbox-ose.files/source_virtualbox-ose.py
    - debian/virtualbox-ose.install
  - Drop *-source packages.
* Drop ubuntu-01-fix-build-gcc45.patch, fixed upstream.
* Drop ubuntu-02-as-needed.patch, added to the Debian package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: DBGPlugInWinNt.cpp 35346 2010-12-27 16:13:13Z vboxsync $ */
 
2
/** @file
 
3
 * DBGPlugInWindows - Debugger and Guest OS Digger Plugin For Windows NT.
 
4
 */
 
5
 
 
6
/*
 
7
 * Copyright (C) 2009-2010 Oracle Corporation
 
8
 *
 
9
 * This file is part of VirtualBox Open Source Edition (OSE), as
 
10
 * available from http://www.virtualbox.org. This file is free software;
 
11
 * you can redistribute it and/or modify it under the terms of the GNU
 
12
 * General Public License (GPL) as published by the Free Software
 
13
 * Foundation, in version 2 as it comes in the "COPYING" file of the
 
14
 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
 
15
 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
 
16
 */
 
17
 
 
18
 
 
19
/*******************************************************************************
 
20
*   Header Files                                                               *
 
21
*******************************************************************************/
 
22
#define LOG_GROUP LOG_GROUP_DBGF ///@todo add new log group.
 
23
#include "DBGPlugIns.h"
 
24
#include <VBox/vmm/dbgf.h>
 
25
#include <VBox/err.h>
 
26
#include <VBox/param.h>
 
27
#include <iprt/string.h>
 
28
#include <iprt/mem.h>
 
29
#include <iprt/stream.h>
 
30
 
 
31
#include "../Runtime/include/internal/ldrMZ.h"  /* ugly */
 
32
#include "../Runtime/include/internal/ldrPE.h"  /* ugly */
 
33
 
 
34
 
 
35
/*******************************************************************************
 
36
*   Structures and Typedefs                                                    *
 
37
*******************************************************************************/
 
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
    uint32_t        SizeOfImage;
 
57
    struct
 
58
    {
 
59
        uint16_t    Length;
 
60
        uint16_t    MaximumLength;
 
61
        uint32_t    Buffer;
 
62
    }               FullDllName,
 
63
                    BaseDllName;
 
64
    uint32_t        Flags;
 
65
    uint16_t        LoadCount;
 
66
    uint16_t        TlsIndex;
 
67
    /* ... there is more ... */
 
68
} NTMTE32;
 
69
typedef NTMTE32 *PNTMTE32;
 
70
 
 
71
/**
 
72
 * PsLoadedModuleList entry for 32-bit NT aka LDR_DATA_TABLE_ENTRY.
 
73
 * Tested with XP.
 
74
 *
 
75
 * @todo This is incomplete and just to get rid of warnings.
 
76
 */
 
77
typedef struct NTMTE64
 
78
{
 
79
    struct
 
80
    {
 
81
        uint64_t    Flink;
 
82
        uint64_t    Blink;
 
83
    }               InLoadOrderLinks,
 
84
                    InMemoryOrderModuleList,
 
85
                    InInitializationOrderModuleList;
 
86
    uint64_t        DllBase;
 
87
    uint64_t        EntryPoint;
 
88
    uint32_t        SizeOfImage;
 
89
    uint32_t        Alignment;
 
90
    struct
 
91
    {
 
92
        uint16_t    Length;
 
93
        uint16_t    MaximumLength;
 
94
        uint32_t    Alignment;
 
95
        uint64_t    Buffer;
 
96
    }               FullDllName,
 
97
                    BaseDllName;
 
98
    uint32_t        Flags;
 
99
    uint16_t        LoadCount;
 
100
    uint16_t        TlsIndex;
 
101
    /* ... there is more ... */
 
102
} NTMTE64;
 
103
typedef NTMTE64 *PNTMTE64;
 
104
 
 
105
/** MTE union. */
 
106
typedef union NTMTE
 
107
{
 
108
    NTMTE32         vX_32;
 
109
    NTMTE64         vX_64;
 
110
} NTMTE;
 
111
typedef NTMTE *PNTMTE;
 
112
 
 
113
 
 
114
/**
 
115
 * The essential bits of the KUSER_SHARED_DATA structure.
 
116
 */
 
117
typedef struct NTKUSERSHAREDDATA
 
118
{
 
119
    uint32_t        TickCountLowDeprecated;
 
120
    uint32_t        TickCountMultiplier;
 
121
    struct
 
122
    {
 
123
        uint32_t    LowPart;
 
124
        int32_t     High1Time;
 
125
        int32_t     High2Time;
 
126
 
 
127
    }               InterruptTime,
 
128
                    SystemTime,
 
129
                    TimeZoneBias;
 
130
    uint16_t        ImageNumberLow;
 
131
    uint16_t        ImageNumberHigh;
 
132
    RTUTF16         NtSystemRoot[260];
 
133
    uint32_t        MaxStackTraceDepth;
 
134
    uint32_t        CryptoExponent;
 
135
    uint32_t        TimeZoneId;
 
136
    uint32_t        LargePageMinimum;
 
137
    uint32_t        Reserved2[7];
 
138
    uint32_t        NtProductType;
 
139
    uint8_t         ProductTypeIsValid;
 
140
    uint8_t         abPadding[3];
 
141
    uint32_t        NtMajorVersion;
 
142
    uint32_t        NtMinorVersion;
 
143
    /* uint8_t         ProcessorFeatures[64];
 
144
    ...
 
145
    */
 
146
} NTKUSERSHAREDDATA;
 
147
typedef NTKUSERSHAREDDATA *PNTKUSERSHAREDDATA;
 
148
 
 
149
/** KI_USER_SHARED_DATA for i386 */
 
150
#define NTKUSERSHAREDDATA_WINNT32   UINT32_C(0xffdf0000)
 
151
/** KI_USER_SHARED_DATA for AMD64 */
 
152
#define NTKUSERSHAREDDATA_WINNT64   UINT64_C(0xfffff78000000000)
 
153
 
 
154
/** NTKUSERSHAREDDATA::NtProductType */
 
155
typedef enum NTPRODUCTTYPE
 
156
{
 
157
    kNtProductType_Invalid = 0,
 
158
    kNtProductType_WinNt = 1,
 
159
    kNtProductType_LanManNt,
 
160
    kNtProductType_Server
 
161
} NTPRODUCTTYPE;
 
162
 
 
163
/**
 
164
 * PDB v2.0 in image debug info.
 
165
 * The URL is constructed from the timestamp and the %02x age?
 
166
 */
 
167
typedef struct CV_INFO_PDB20
 
168
{
 
169
    uint32_t    Signature;              /**< CV_SIGNATURE_PDB70. */
 
170
    int32_t     Offset;                 /**< Always 0. Used to be the offset to the real debug info. */
 
171
    uint32_t    TimeDateStamp;
 
172
    uint32_t    Age;
 
173
    uint8_t     PdbFilename[4];
 
174
} CV_INFO_PDB20;
 
175
/** The CV_INFO_PDB20 signature. */
 
176
#define CV_SIGNATURE_PDB20  RT_MAKE_U32_FROM_U8('N','B','1','0')
 
177
 
 
178
/**
 
179
 * PDB v7.0 in image debug info.
 
180
 * The URL is constructed from the signature and the %02x age.
 
181
 */
 
182
#pragma pack(4)
 
183
typedef struct CV_INFO_PDB70
 
184
{
 
185
    uint32_t    CvSignature;            /**< CV_SIGNATURE_PDB70. */
 
186
    RTUUID      Signature;
 
187
    uint32_t    Age;
 
188
    uint8_t     PdbFilename[4];
 
189
} CV_INFO_PDB70;
 
190
#pragma pack()
 
191
AssertCompileMemberOffset(CV_INFO_PDB70, Signature, 4);
 
192
AssertCompileMemberOffset(CV_INFO_PDB70, Age, 4 + 16);
 
193
/** The CV_INFO_PDB70 signature. */
 
194
#define CV_SIGNATURE_PDB70  RT_MAKE_U32_FROM_U8('R','S','D','S')
 
195
 
 
196
/** @} */
 
197
 
 
198
 
 
199
typedef enum DBGDIGGERWINNTVER
 
200
{
 
201
    DBGDIGGERWINNTVER_UNKNOWN,
 
202
    DBGDIGGERWINNTVER_3_1,
 
203
    DBGDIGGERWINNTVER_3_5,
 
204
    DBGDIGGERWINNTVER_4_0,
 
205
    DBGDIGGERWINNTVER_5_0,
 
206
    DBGDIGGERWINNTVER_5_1,
 
207
    DBGDIGGERWINNTVER_6_0
 
208
} DBGDIGGERWINNTVER;
 
209
 
 
210
/**
 
211
 * WinNT guest OS digger instance data.
 
212
 */
 
213
typedef struct DBGDIGGERWINNT
 
214
{
 
215
    /** Whether the information is valid or not.
 
216
     * (For fending off illegal interface method calls.) */
 
217
    bool                fValid;
 
218
    /** 32-bit (true) or 64-bit (false) */
 
219
    bool                f32Bit;
 
220
 
 
221
    /** The NT version. */
 
222
    DBGDIGGERWINNTVER   enmVer;
 
223
    /** NTKUSERSHAREDDATA::NtProductType */
 
224
    NTPRODUCTTYPE       NtProductType;
 
225
    /** NTKUSERSHAREDDATA::NtMajorVersion */
 
226
    uint32_t            NtMajorVersion;
 
227
    /** NTKUSERSHAREDDATA::NtMinorVersion */
 
228
    uint32_t            NtMinorVersion;
 
229
 
 
230
    /** The address of the ntoskrnl.exe image. */
 
231
    DBGFADDRESS         KernelAddr;
 
232
    /** The address of the ntoskrnl.exe module table entry. */
 
233
    DBGFADDRESS         KernelMteAddr;
 
234
    /** The address of PsLoadedModuleList. */
 
235
    DBGFADDRESS         PsLoadedModuleListAddr;
 
236
} DBGDIGGERWINNT;
 
237
/** Pointer to the linux guest OS digger instance data. */
 
238
typedef DBGDIGGERWINNT *PDBGDIGGERWINNT;
 
239
 
 
240
 
 
241
/*******************************************************************************
 
242
*   Defined Constants And Macros                                               *
 
243
*******************************************************************************/
 
244
/** Validates a 32-bit Windows NT kernel address */
 
245
#define WINNT32_VALID_ADDRESS(Addr)         ((Addr) >         UINT32_C(0x80000000) && (Addr) <         UINT32_C(0xfffff000))
 
246
/** Validates a 64-bit Windows NT kernel address */
 
247
#define WINNT64_VALID_ADDRESS(Addr)         ((Addr) > UINT64_C(0xffffffff80000000) && (Addr) < UINT64_C(0xfffffffffffff000))
 
248
/** Validates a kernel address. */
 
249
#define WINNT_VALID_ADDRESS(pThis, Addr)    ((pThis)->f32Bit ? WINNT32_VALID_ADDRESS(Addr) : WINNT64_VALID_ADDRESS(Addr))
 
250
/** Versioned and bitness wrapper. */
 
251
#define WINNT_UNION(pThis, pUnion, Member)  ((pThis)->f32Bit ? (pUnion)->vX_32. Member : (pUnion)->vX_64. Member )
 
252
 
 
253
/** The length (in chars) of the kernel file name (no path). */
 
254
#define WINNT_KERNEL_BASE_NAME_LEN          12
 
255
 
 
256
/** WindowsNT on little endian ASCII systems. */
 
257
#define DIG_WINNT_MOD_TAG                   UINT64_C(0x54696e646f774e54)
 
258
 
 
259
 
 
260
/*******************************************************************************
 
261
*   Internal Functions                                                         *
 
262
*******************************************************************************/
 
263
static DECLCALLBACK(int)  dbgDiggerWinNtInit(PVM pVM, void *pvData);
 
264
 
 
265
 
 
266
/*******************************************************************************
 
267
*   Global Variables                                                           *
 
268
*******************************************************************************/
 
269
/** Kernel names. */
 
270
static const RTUTF16 g_wszKernelNames[][WINNT_KERNEL_BASE_NAME_LEN + 1] =
 
271
{
 
272
    { 'n', 't', 'o', 's', 'k', 'r', 'n', 'l', '.', 'e', 'x', 'e' }
 
273
};
 
274
 
 
275
 
 
276
/**
 
277
 * Process a PE image found in guest memory.
 
278
 *
 
279
 * @param   pThis               The instance data.
 
280
 * @param   pVM                 The VM handle.
 
281
 * @param   pszName             The image name.
 
282
 * @param   pImageAddr          The image address.
 
283
 * @param   cbImage             The size of the image.
 
284
 * @param   pbBuf               Scratch buffer containing the first
 
285
 *                              RT_MIN(cbBuf, cbImage) bytes of the image.
 
286
 * @param   cbBuf               The scratch buffer size.
 
287
 */
 
288
static void dbgDiggerWinNtProcessImage(PDBGDIGGERWINNT pThis, PVM pVM, const char *pszName,
 
289
                                       PCDBGFADDRESS pImageAddr, uint32_t cbImage,
 
290
                                       uint8_t *pbBuf, size_t cbBuf)
 
291
{
 
292
    LogFlow(("DigWinNt: %RGp %#x %s\n", pImageAddr->FlatPtr, cbImage, pszName));
 
293
 
 
294
    /*
 
295
     * Do some basic validation first.
 
296
     * This is the usual exteremely verbose and messy code...
 
297
     */
 
298
    Assert(cbBuf >= sizeof(IMAGE_NT_HEADERS64));
 
299
    if (   cbImage < sizeof(IMAGE_NT_HEADERS64)
 
300
        || cbImage >= _1M * 256)
 
301
    {
 
302
        Log(("DigWinNt: %s: Bad image size: %#x\n", pszName, cbImage));
 
303
        return;
 
304
    }
 
305
 
 
306
    /* Dig out the NT/PE headers. */
 
307
    IMAGE_DOS_HEADER const *pMzHdr = (IMAGE_DOS_HEADER const *)pbBuf;
 
308
    typedef union NTHDRS
 
309
    {
 
310
        IMAGE_NT_HEADERS64  vX_32;
 
311
        IMAGE_NT_HEADERS64  vX_64;
 
312
    } NTHDRS;
 
313
    NTHDRS const   *pHdrs;
 
314
    uint32_t        offHdrs;
 
315
    if (pMzHdr->e_magic != IMAGE_DOS_SIGNATURE)
 
316
    {
 
317
        offHdrs = 0;
 
318
        pHdrs   = (NTHDRS const *)pbBuf;
 
319
    }
 
320
    else if (   pMzHdr->e_lfanew >= cbImage
 
321
             || pMzHdr->e_lfanew < sizeof(*pMzHdr)
 
322
             || pMzHdr->e_lfanew + sizeof(IMAGE_NT_HEADERS64) > cbImage)
 
323
    {
 
324
        Log(("DigWinNt: %s: PE header to far into image: %#x  cbImage=%#x\n", pMzHdr->e_lfanew, cbImage));
 
325
        return;
 
326
    }
 
327
    else if (   pMzHdr->e_lfanew < cbBuf
 
328
             && pMzHdr->e_lfanew + sizeof(IMAGE_NT_HEADERS64) <= cbBuf)
 
329
    {
 
330
        offHdrs = pMzHdr->e_lfanew;
 
331
        pHdrs = (NTHDRS const *)(pbBuf + offHdrs);
 
332
    }
 
333
    else
 
334
    {
 
335
        Log(("DigWinNt: %s: PE header to far into image (lazy bird): %#x\n",  pMzHdr->e_lfanew));
 
336
        return;
 
337
    }
 
338
    if (pHdrs->vX_32.Signature != IMAGE_NT_SIGNATURE)
 
339
    {
 
340
        Log(("DigWinNt: %s: Bad PE signature: %#x\n", pszName, pHdrs->vX_32.Signature));
 
341
        return;
 
342
    }
 
343
 
 
344
    /* The file header is the same on both archs */
 
345
    if (pHdrs->vX_32.FileHeader.Machine != (pThis->f32Bit ? IMAGE_FILE_MACHINE_I386 : IMAGE_FILE_MACHINE_AMD64))
 
346
    {
 
347
        Log(("DigWinNt: %s: Invalid FH.Machine: %#x\n", pszName, pHdrs->vX_32.FileHeader.Machine));
 
348
        return;
 
349
    }
 
350
    if (pHdrs->vX_32.FileHeader.SizeOfOptionalHeader != (pThis->f32Bit ? sizeof(IMAGE_OPTIONAL_HEADER32) : sizeof(IMAGE_OPTIONAL_HEADER64)))
 
351
    {
 
352
        Log(("DigWinNt: %s: Invalid FH.SizeOfOptionalHeader: %#x\n", pszName, pHdrs->vX_32.FileHeader.SizeOfOptionalHeader));
 
353
        return;
 
354
    }
 
355
    const uint32_t TimeDateStamp = pHdrs->vX_32.FileHeader.TimeDateStamp;
 
356
 
 
357
    /* The optional header is not... */
 
358
    if (WINNT_UNION(pThis, pHdrs, OptionalHeader.Magic) != (pThis->f32Bit ? IMAGE_NT_OPTIONAL_HDR32_MAGIC : IMAGE_NT_OPTIONAL_HDR64_MAGIC))
 
359
    {
 
360
        Log(("DigWinNt: %s: Invalid OH.Magic: %#x\n", pszName, WINNT_UNION(pThis, pHdrs, OptionalHeader.Magic)));
 
361
        return;
 
362
    }
 
363
    if (WINNT_UNION(pThis, pHdrs, OptionalHeader.SizeOfImage) != cbImage)
 
364
    {
 
365
        Log(("DigWinNt: %s: Invalid OH.SizeOfImage: %#x, expected %#x\n", pszName, WINNT_UNION(pThis, pHdrs, OptionalHeader.SizeOfImage), cbImage));
 
366
        return;
 
367
    }
 
368
    if (WINNT_UNION(pThis, pHdrs, OptionalHeader.NumberOfRvaAndSizes) != IMAGE_NUMBEROF_DIRECTORY_ENTRIES)
 
369
    {
 
370
        Log(("DigWinNt: %s: Invalid OH.SizeOfImage: %#x\n", pszName, WINNT_UNION(pThis, pHdrs, OptionalHeader.NumberOfRvaAndSizes)));
 
371
        return;
 
372
    }
 
373
 
 
374
    uint32_t uRvaDebugDir = 0;
 
375
    uint32_t cbDebugDir   = 0;
 
376
    IMAGE_DATA_DIRECTORY const *pDir = &WINNT_UNION(pThis, pHdrs, OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG]);
 
377
    if (    pDir->VirtualAddress > offHdrs
 
378
        &&  pDir->VirtualAddress < cbImage
 
379
        &&  pDir->Size           >= sizeof(IMAGE_DEBUG_DIRECTORY)
 
380
        &&  pDir->Size           < cbImage
 
381
        &&  pDir->VirtualAddress + pDir->Size <= cbImage
 
382
       )
 
383
    {
 
384
        uRvaDebugDir = pDir->VirtualAddress;
 
385
        cbDebugDir   = pDir->Size;
 
386
    }
 
387
 
 
388
    /* dig into the section table... */
 
389
 
 
390
    /*
 
391
     * Create the module.
 
392
     */
 
393
    RTDBGMOD hMod;
 
394
    int rc = RTDbgModCreate(&hMod, pszName, cbImage, 0 /*fFlags*/);
 
395
    if (RT_FAILURE(rc))
 
396
        return;
 
397
    rc = RTDbgModSetTag(hMod, DIG_WINNT_MOD_TAG); AssertRC(rc);
 
398
 
 
399
    /* temp hack: */
 
400
    rc = RTDbgModSymbolAdd(hMod, "start", 0 /*iSeg*/, 0, cbImage, 0 /*fFlags*/, NULL); AssertRC(rc);
 
401
 
 
402
    /* add sections? */
 
403
 
 
404
    /*
 
405
     * Dig out debug info if possible.  What we're after is the CODEVIEW part.
 
406
     */
 
407
    if (uRvaDebugDir != 0)
 
408
    {
 
409
        DBGFADDRESS Addr = *pImageAddr;
 
410
        DBGFR3AddrAdd(&Addr, uRvaDebugDir);
 
411
        rc = DBGFR3MemRead(pVM, 0 /*idCpu*/, &Addr, pbBuf, RT_MIN(cbDebugDir, cbBuf));
 
412
        if (RT_SUCCESS(rc))
 
413
        {
 
414
            IMAGE_DEBUG_DIRECTORY const    *pa = (IMAGE_DEBUG_DIRECTORY const *)pbBuf;
 
415
            size_t                          c  = RT_MIN(RT_MIN(cbDebugDir, cbBuf) / sizeof(*pa), 10);
 
416
            for (uint32_t i = 0; i < c; i++)
 
417
                if (    pa[i].AddressOfRawData > offHdrs
 
418
                    &&  pa[i].AddressOfRawData < cbImage
 
419
                    &&  pa[i].SizeOfData       < cbImage
 
420
                    &&  pa[i].AddressOfRawData + pa[i].SizeOfData <= cbImage
 
421
                    &&  pa[i].TimeDateStamp   == TimeDateStamp /* too paranoid? */
 
422
                    &&  pa[i].Type == IMAGE_DEBUG_TYPE_CODEVIEW
 
423
                    )
 
424
                {
 
425
                }
 
426
        }
 
427
    }
 
428
 
 
429
    /*
 
430
     * Link the module.
 
431
     */
 
432
    RTDBGAS hAs = DBGFR3AsResolveAndRetain(pVM, DBGF_AS_KERNEL);
 
433
    if (hAs != NIL_RTDBGAS)
 
434
        rc = RTDbgAsModuleLink(hAs, hMod, pImageAddr->FlatPtr, RTDBGASLINK_FLAGS_REPLACE /*fFlags*/);
 
435
    else
 
436
        rc = VERR_INTERNAL_ERROR;
 
437
    RTDbgModRelease(hMod);
 
438
    RTDbgAsRelease(hAs);
 
439
}
 
440
 
 
441
 
 
442
/**
 
443
 * @copydoc DBGFOSREG::pfnQueryInterface
 
444
 */
 
445
static DECLCALLBACK(void *) dbgDiggerWinNtQueryInterface(PVM pVM, void *pvData, DBGFOSINTERFACE enmIf)
 
446
{
 
447
    return NULL;
 
448
}
 
449
 
 
450
 
 
451
/**
 
452
 * @copydoc DBGFOSREG::pfnQueryVersion
 
453
 */
 
454
static DECLCALLBACK(int)  dbgDiggerWinNtQueryVersion(PVM pVM, void *pvData, char *pszVersion, size_t cchVersion)
 
455
{
 
456
    PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
 
457
    Assert(pThis->fValid);
 
458
    const char *pszNtProductType;
 
459
    switch (pThis->NtProductType)
 
460
    {
 
461
        case kNtProductType_WinNt:      pszNtProductType = "-WinNT";        break;
 
462
        case kNtProductType_LanManNt:   pszNtProductType = "-LanManNT";     break;
 
463
        case kNtProductType_Server:     pszNtProductType = "-Server";       break;
 
464
        default:                        pszNtProductType = "";              break;
 
465
    }
 
466
    RTStrPrintf(pszVersion, cchVersion, "%u.%u%s", pThis->NtMajorVersion, pThis->NtMinorVersion, pszNtProductType);
 
467
    return VINF_SUCCESS;
 
468
}
 
469
 
 
470
 
 
471
/**
 
472
 * @copydoc DBGFOSREG::pfnTerm
 
473
 */
 
474
static DECLCALLBACK(void)  dbgDiggerWinNtTerm(PVM pVM, void *pvData)
 
475
{
 
476
    PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
 
477
    Assert(pThis->fValid);
 
478
 
 
479
    pThis->fValid = false;
 
480
}
 
481
 
 
482
 
 
483
/**
 
484
 * @copydoc DBGFOSREG::pfnRefresh
 
485
 */
 
486
static DECLCALLBACK(int)  dbgDiggerWinNtRefresh(PVM pVM, void *pvData)
 
487
{
 
488
    PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
 
489
    NOREF(pThis);
 
490
    Assert(pThis->fValid);
 
491
 
 
492
    /*
 
493
     * For now we'll flush and reload everything.
 
494
     */
 
495
    RTDBGAS hDbgAs = DBGFR3AsResolveAndRetain(pVM, DBGF_AS_KERNEL);
 
496
    if (hDbgAs != NIL_RTDBGAS)
 
497
    {
 
498
        uint32_t iMod = RTDbgAsModuleCount(hDbgAs);
 
499
        while (iMod-- > 0)
 
500
        {
 
501
            RTDBGMOD hMod = RTDbgAsModuleByIndex(hDbgAs, iMod);
 
502
            if (hMod != NIL_RTDBGMOD)
 
503
            {
 
504
                if (RTDbgModGetTag(hMod) == DIG_WINNT_MOD_TAG)
 
505
                {
 
506
                    int rc = RTDbgAsModuleUnlink(hDbgAs, hMod);
 
507
                    AssertRC(rc);
 
508
                }
 
509
                RTDbgModRelease(hMod);
 
510
            }
 
511
        }
 
512
        RTDbgAsRelease(hDbgAs);
 
513
    }
 
514
 
 
515
    dbgDiggerWinNtTerm(pVM, pvData);
 
516
    return dbgDiggerWinNtInit(pVM, pvData);
 
517
}
 
518
 
 
519
 
 
520
/**
 
521
 * @copydoc DBGFOSREG::pfnInit
 
522
 */
 
523
static DECLCALLBACK(int)  dbgDiggerWinNtInit(PVM pVM, void *pvData)
 
524
{
 
525
    PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
 
526
    Assert(!pThis->fValid);
 
527
 
 
528
    union
 
529
    {
 
530
        uint8_t             au8[0x2000];
 
531
        RTUTF16             wsz[0x2000/2];
 
532
        NTKUSERSHAREDDATA   UserSharedData;
 
533
    }               u;
 
534
    DBGFADDRESS     Addr;
 
535
    int             rc;
 
536
 
 
537
    /*
 
538
     * Figure the NT version.
 
539
     */
 
540
    DBGFR3AddrFromFlat(pVM, &Addr, pThis->f32Bit ? NTKUSERSHAREDDATA_WINNT32 : NTKUSERSHAREDDATA_WINNT64);
 
541
    rc = DBGFR3MemRead(pVM, 0 /*idCpu*/, &Addr, &u, PAGE_SIZE);
 
542
    if (RT_FAILURE(rc))
 
543
        return rc;
 
544
    pThis->NtProductType  = u.UserSharedData.ProductTypeIsValid && u.UserSharedData.NtProductType <= kNtProductType_Server
 
545
                          ? (NTPRODUCTTYPE)u.UserSharedData.NtProductType
 
546
                          : kNtProductType_Invalid;
 
547
    pThis->NtMajorVersion = u.UserSharedData.NtMajorVersion;
 
548
    pThis->NtMinorVersion = u.UserSharedData.NtMinorVersion;
 
549
 
 
550
    /*
 
551
     * Dig out the module chain.
 
552
     */
 
553
    DBGFADDRESS AddrPrev = pThis->PsLoadedModuleListAddr;
 
554
    Addr                 = pThis->KernelMteAddr;
 
555
    do
 
556
    {
 
557
        /* Read the validate the MTE. */
 
558
        NTMTE Mte;
 
559
        rc = DBGFR3MemRead(pVM, 0 /*idCpu*/, &Addr, &Mte, pThis->f32Bit ? sizeof(Mte.vX_32) : sizeof(Mte.vX_64));
 
560
        if (RT_FAILURE(rc))
 
561
            break;
 
562
        if (WINNT_UNION(pThis, &Mte, InLoadOrderLinks.Blink) != AddrPrev.FlatPtr)
 
563
        {
 
564
            Log(("DigWinNt: Bad Mte At %RGv - backpointer\n", Addr.FlatPtr));
 
565
            break;
 
566
        }
 
567
        if (!WINNT_VALID_ADDRESS(pThis, WINNT_UNION(pThis, &Mte, InLoadOrderLinks.Flink)) )
 
568
        {
 
569
            Log(("DigWinNt: Bad Mte at %RGv - forward pointer\n", Addr.FlatPtr));
 
570
            break;
 
571
        }
 
572
        if (!WINNT_VALID_ADDRESS(pThis, WINNT_UNION(pThis, &Mte, BaseDllName.Buffer)))
 
573
        {
 
574
            Log(("DigWinNt: Bad Mte at %RGv - BaseDllName=%llx\n", Addr.FlatPtr, WINNT_UNION(pThis, &Mte, BaseDllName.Buffer)));
 
575
            break;
 
576
        }
 
577
        if (!WINNT_VALID_ADDRESS(pThis, WINNT_UNION(pThis, &Mte, FullDllName.Buffer)))
 
578
        {
 
579
            Log(("DigWinNt: Bad Mte at %RGv - FullDllName=%llx\n", Addr.FlatPtr, WINNT_UNION(pThis, &Mte, FullDllName.Buffer)));
 
580
            break;
 
581
        }
 
582
        if (    !WINNT_VALID_ADDRESS(pThis, WINNT_UNION(pThis, &Mte, DllBase))
 
583
            ||  WINNT_UNION(pThis, &Mte, SizeOfImage) > _1M*256
 
584
            ||  WINNT_UNION(pThis, &Mte, EntryPoint) - WINNT_UNION(pThis, &Mte, DllBase) > WINNT_UNION(pThis, &Mte, SizeOfImage) )
 
585
        {
 
586
            Log(("DigWinNt: Bad Mte at %RGv - EntryPoint=%llx SizeOfImage=%x DllBase=%llx\n",
 
587
                 Addr.FlatPtr, WINNT_UNION(pThis, &Mte, EntryPoint), WINNT_UNION(pThis, &Mte, SizeOfImage), WINNT_UNION(pThis, &Mte, DllBase)));
 
588
            break;
 
589
        }
 
590
 
 
591
        /* Read the full name. */
 
592
        DBGFADDRESS AddrName;
 
593
        DBGFR3AddrFromFlat(pVM, &AddrName, WINNT_UNION(pThis, &Mte, FullDllName.Buffer));
 
594
        uint16_t    cbName = WINNT_UNION(pThis, &Mte, FullDllName.Length);
 
595
        if (cbName < sizeof(u))
 
596
            rc = DBGFR3MemRead(pVM, 0 /*idCpu*/, &AddrName, &u, cbName);
 
597
        else
 
598
            rc = VERR_OUT_OF_RANGE;
 
599
        if (RT_FAILURE(rc))
 
600
        {
 
601
            DBGFR3AddrFromFlat(pVM, &AddrName, WINNT_UNION(pThis, &Mte, BaseDllName.Buffer));
 
602
            cbName = WINNT_UNION(pThis, &Mte, BaseDllName.Length);
 
603
            if (cbName < sizeof(u))
 
604
                rc = DBGFR3MemRead(pVM, 0 /*idCpu*/, &AddrName, &u, cbName);
 
605
            else
 
606
                rc = VERR_OUT_OF_RANGE;
 
607
        }
 
608
        if (RT_SUCCESS(rc))
 
609
        {
 
610
            u.wsz[cbName/2] = '\0';
 
611
            char *pszName;
 
612
            rc = RTUtf16ToUtf8(u.wsz, &pszName);
 
613
            if (RT_SUCCESS(rc))
 
614
            {
 
615
                /* Read the start of the PE image and pass it along to a worker. */
 
616
                DBGFADDRESS ImageAddr;
 
617
                DBGFR3AddrFromFlat(pVM, &ImageAddr, WINNT_UNION(pThis, &Mte, DllBase));
 
618
                uint32_t    cbImageBuf = RT_MIN(sizeof(u), WINNT_UNION(pThis, &Mte, SizeOfImage));
 
619
                rc = DBGFR3MemRead(pVM, 0 /*idCpu*/, &ImageAddr, &u, cbImageBuf);
 
620
                if (RT_SUCCESS(rc))
 
621
                    dbgDiggerWinNtProcessImage(pThis,
 
622
                                               pVM,
 
623
                                               pszName,
 
624
                                               &ImageAddr,
 
625
                                               WINNT_UNION(pThis, &Mte, SizeOfImage),
 
626
                                               &u.au8[0],
 
627
                                               sizeof(u));
 
628
                RTStrFree(pszName);
 
629
            }
 
630
        }
 
631
 
 
632
        /* next */
 
633
        AddrPrev = Addr;
 
634
        DBGFR3AddrFromFlat(pVM, &Addr, WINNT_UNION(pThis, &Mte, InLoadOrderLinks.Flink));
 
635
    } while (   Addr.FlatPtr != pThis->KernelMteAddr.FlatPtr
 
636
             && Addr.FlatPtr != pThis->PsLoadedModuleListAddr.FlatPtr);
 
637
 
 
638
    pThis->fValid = true;
 
639
    return VINF_SUCCESS;
 
640
}
 
641
 
 
642
 
 
643
/**
 
644
 * @copydoc DBGFOSREG::pfnProbe
 
645
 */
 
646
static DECLCALLBACK(bool)  dbgDiggerWinNtProbe(PVM pVM, void *pvData)
 
647
{
 
648
    PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
 
649
    DBGFADDRESS     Addr;
 
650
    union
 
651
    {
 
652
        uint8_t             au8[8192];
 
653
        uint16_t            au16[8192/2];
 
654
        uint32_t            au32[8192/4];
 
655
        IMAGE_DOS_HEADER    MzHdr;
 
656
        RTUTF16             wsz[8192/2];
 
657
    } u;
 
658
 
 
659
    /*
 
660
     * Look for the MISYSPTE section name that seems to be a part of all kernels.
 
661
     * Then try find the module table entry for it.  Since it's the first entry
 
662
     * in the PsLoadedModuleList we can easily validate the list head and report
 
663
     * success.
 
664
     */
 
665
    CPUMMODE enmMode = DBGFR3CpuGetMode(pVM, 0 /*idCpu*/);
 
666
    if (enmMode == CPUMMODE_LONG)
 
667
    {
 
668
        /** @todo when 32-bit is working, add support for 64-bit windows nt. */
 
669
    }
 
670
    else
 
671
    {
 
672
        DBGFADDRESS KernelAddr;
 
673
        for (DBGFR3AddrFromFlat(pVM, &KernelAddr, UINT32_C(0x80001000));
 
674
             KernelAddr.FlatPtr < UINT32_C(0xffff0000);
 
675
             KernelAddr.FlatPtr += PAGE_SIZE)
 
676
        {
 
677
            int rc = DBGFR3MemScan(pVM, 0 /*idCpu*/, &KernelAddr, UINT32_C(0xffff0000) - KernelAddr.FlatPtr,
 
678
                                   1, "MISYSPTE", sizeof("MISYSPTE") - 1, &KernelAddr);
 
679
            if (RT_FAILURE(rc))
 
680
                break;
 
681
            DBGFR3AddrSub(&KernelAddr, KernelAddr.FlatPtr & PAGE_OFFSET_MASK);
 
682
 
 
683
            /* MZ + PE header. */
 
684
            rc = DBGFR3MemRead(pVM, 0 /*idCpu*/, &KernelAddr, &u, sizeof(u));
 
685
            if (    RT_SUCCESS(rc)
 
686
                &&  u.MzHdr.e_magic == IMAGE_DOS_SIGNATURE
 
687
                &&  !(u.MzHdr.e_lfanew & 0x7)
 
688
                &&  u.MzHdr.e_lfanew >= 0x080
 
689
                &&  u.MzHdr.e_lfanew <= 0x200)
 
690
            {
 
691
                IMAGE_NT_HEADERS32 const *pHdrs = (IMAGE_NT_HEADERS32 const *)&u.au8[u.MzHdr.e_lfanew];
 
692
                if (    pHdrs->Signature                            == IMAGE_NT_SIGNATURE
 
693
                    &&  pHdrs->FileHeader.Machine                   == IMAGE_FILE_MACHINE_I386
 
694
                    &&  pHdrs->FileHeader.SizeOfOptionalHeader      == sizeof(pHdrs->OptionalHeader)
 
695
                    &&  pHdrs->FileHeader.NumberOfSections          >= 10 /* the kernel has lots */
 
696
                    &&  (pHdrs->FileHeader.Characteristics & (IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL)) == IMAGE_FILE_EXECUTABLE_IMAGE
 
697
                    &&  pHdrs->OptionalHeader.Magic                 == IMAGE_NT_OPTIONAL_HDR32_MAGIC
 
698
                    &&  pHdrs->OptionalHeader.NumberOfRvaAndSizes   == IMAGE_NUMBEROF_DIRECTORY_ENTRIES
 
699
                    /** @todo need more ntoskrnl signs? */
 
700
                    )
 
701
                {
 
702
                    /* Find the MTE. */
 
703
                    NTMTE32 Mte;
 
704
                    RT_ZERO(Mte);
 
705
                    Mte.DllBase     = KernelAddr.FlatPtr;
 
706
                    Mte.EntryPoint  = KernelAddr.FlatPtr + pHdrs->OptionalHeader.AddressOfEntryPoint;
 
707
                    Mte.SizeOfImage = pHdrs->OptionalHeader.SizeOfImage;
 
708
                    DBGFADDRESS HitAddr;
 
709
                    rc = DBGFR3MemScan(pVM, 0 /*idCpu*/, &KernelAddr, UINT32_MAX - KernelAddr.FlatPtr,
 
710
                                       4 /*align*/, &Mte.DllBase, 3 * sizeof(uint32_t), &HitAddr);
 
711
                    while (RT_SUCCESS(rc))
 
712
                    {
 
713
                        /* check the name. */
 
714
                        NTMTE32 Mte2;
 
715
                        DBGFADDRESS MteAddr = HitAddr;
 
716
                        rc = DBGFR3MemRead(pVM, 0 /*idCpu*/, DBGFR3AddrSub(&MteAddr, RT_OFFSETOF(NTMTE32, DllBase)),
 
717
                                           &Mte2, sizeof(Mte2));
 
718
                        if (    RT_SUCCESS(rc)
 
719
                            &&  Mte2.DllBase     == Mte.DllBase
 
720
                            &&  Mte2.EntryPoint  == Mte.EntryPoint
 
721
                            &&  Mte2.SizeOfImage == Mte.SizeOfImage
 
722
                            &&  WINNT32_VALID_ADDRESS(Mte2.InLoadOrderLinks.Flink)
 
723
                            &&  Mte2.InLoadOrderLinks.Blink > KernelAddr.FlatPtr    /* list head inside ntoskrnl */
 
724
                            &&  Mte2.InLoadOrderLinks.Blink < KernelAddr.FlatPtr + Mte.SizeOfImage
 
725
                            &&  WINNT32_VALID_ADDRESS(Mte2.BaseDllName.Buffer)
 
726
                            &&  WINNT32_VALID_ADDRESS(Mte2.FullDllName.Buffer)
 
727
                            &&  Mte2.BaseDllName.Length <= Mte2.BaseDllName.MaximumLength
 
728
                            &&  Mte2.BaseDllName.Length == WINNT_KERNEL_BASE_NAME_LEN * 2
 
729
                            &&  Mte2.FullDllName.Length <= Mte2.FullDllName.MaximumLength
 
730
                            &&  Mte2.FullDllName.Length <= 256
 
731
                           )
 
732
                        {
 
733
                            rc = DBGFR3MemRead(pVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pVM, &Addr, Mte2.BaseDllName.Buffer),
 
734
                                               u.wsz, Mte2.BaseDllName.Length);
 
735
                            u.wsz[Mte2.BaseDllName.Length / 2] = '\0';
 
736
                            if (    RT_SUCCESS(rc)
 
737
                                &&  (   !RTUtf16ICmp(u.wsz, g_wszKernelNames[0])
 
738
                                  /* || !RTUtf16ICmp(u.wsz, g_wszKernelNames[1]) */
 
739
                                    )
 
740
                               )
 
741
                            {
 
742
                                NTMTE32 Mte3;
 
743
                                rc = DBGFR3MemRead(pVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pVM, &Addr, Mte2.InLoadOrderLinks.Blink),
 
744
                                                   &Mte3, RT_SIZEOFMEMB(NTMTE32, InLoadOrderLinks));
 
745
                                if (   RT_SUCCESS(rc)
 
746
                                    && Mte3.InLoadOrderLinks.Flink == MteAddr.FlatPtr
 
747
                                    && WINNT32_VALID_ADDRESS(Mte3.InLoadOrderLinks.Blink) )
 
748
                                {
 
749
                                    Log(("DigWinNt: MteAddr=%RGv KernelAddr=%RGv SizeOfImage=%x &PsLoadedModuleList=%RGv (32-bit)\n",
 
750
                                         MteAddr.FlatPtr, KernelAddr.FlatPtr, Mte2.SizeOfImage, Addr.FlatPtr));
 
751
                                    pThis->KernelAddr               = KernelAddr;
 
752
                                    pThis->KernelMteAddr            = MteAddr;
 
753
                                    pThis->PsLoadedModuleListAddr   = Addr;
 
754
                                    pThis->f32Bit                   = true;
 
755
                                    return true;
 
756
                                }
 
757
                            }
 
758
                        }
 
759
 
 
760
                        /* next */
 
761
                        DBGFR3AddrAdd(&HitAddr, 4);
 
762
                        if (HitAddr.FlatPtr <= UINT32_C(0xfffff000))
 
763
                            rc = DBGFR3MemScan(pVM, 0 /*idCpu*/, &HitAddr, UINT32_MAX - HitAddr.FlatPtr,
 
764
                                               4 /*align*/, &Mte.DllBase, 3 * sizeof(uint32_t), &HitAddr);
 
765
                        else
 
766
                            rc = VERR_DBGF_MEM_NOT_FOUND;
 
767
                    }
 
768
                }
 
769
            }
 
770
        }
 
771
    }
 
772
    return false;
 
773
}
 
774
 
 
775
 
 
776
/**
 
777
 * @copydoc DBGFOSREG::pfnDestruct
 
778
 */
 
779
static DECLCALLBACK(void)  dbgDiggerWinNtDestruct(PVM pVM, void *pvData)
 
780
{
 
781
 
 
782
}
 
783
 
 
784
 
 
785
/**
 
786
 * @copydoc DBGFOSREG::pfnConstruct
 
787
 */
 
788
static DECLCALLBACK(int)  dbgDiggerWinNtConstruct(PVM pVM, void *pvData)
 
789
{
 
790
    PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
 
791
    pThis->fValid = false;
 
792
    pThis->f32Bit = false;
 
793
    pThis->enmVer = DBGDIGGERWINNTVER_UNKNOWN;
 
794
    return VINF_SUCCESS;
 
795
}
 
796
 
 
797
 
 
798
const DBGFOSREG g_DBGDiggerWinNt =
 
799
{
 
800
    /* .u32Magic = */           DBGFOSREG_MAGIC,
 
801
    /* .fFlags = */             0,
 
802
    /* .cbData = */             sizeof(DBGDIGGERWINNT),
 
803
    /* .szName = */             "WinNT",
 
804
    /* .pfnConstruct = */       dbgDiggerWinNtConstruct,
 
805
    /* .pfnDestruct = */        dbgDiggerWinNtDestruct,
 
806
    /* .pfnProbe = */           dbgDiggerWinNtProbe,
 
807
    /* .pfnInit = */            dbgDiggerWinNtInit,
 
808
    /* .pfnRefresh = */         dbgDiggerWinNtRefresh,
 
809
    /* .pfnTerm = */            dbgDiggerWinNtTerm,
 
810
    /* .pfnQueryVersion = */    dbgDiggerWinNtQueryVersion,
 
811
    /* .pfnQueryInterface = */  dbgDiggerWinNtQueryInterface,
 
812
    /* .u32EndMagic = */        DBGFOSREG_MAGIC
 
813
};
 
814