VirtualBox

source: vbox/trunk/src/VBox/Debugger/DBGPlugInWinNt.cpp@ 46108

Last change on this file since 46108 was 46108, checked in by vboxsync, 12 years ago

Got the NT4 ntfs.sys case working. Turned out to be some memory saving strategy applied to some images during early (?) loading.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 40.6 KB
Line 
1/* $Id: DBGPlugInWinNt.cpp 46108 2013-05-15 19:22:38Z vboxsync $ */
2/** @file
3 * DBGPlugInWindows - Debugger and Guest OS Digger Plugin For Windows NT.
4 */
5
6/*
7 * Copyright (C) 2009-2013 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/ldr.h>
28#include <iprt/mem.h>
29#include <iprt/stream.h>
30#include <iprt/string.h>
31
32#include "../Runtime/include/internal/ldrMZ.h" /* ugly */
33#include "../Runtime/include/internal/ldrPE.h" /* ugly */
34
35
36/*******************************************************************************
37* Structures and Typedefs *
38*******************************************************************************/
39
40/** @name Internal WinNT structures
41 * @{ */
42/**
43 * PsLoadedModuleList entry for 32-bit NT aka LDR_DATA_TABLE_ENTRY.
44 * Tested with XP.
45 */
46typedef struct NTMTE32
47{
48 struct
49 {
50 uint32_t Flink;
51 uint32_t Blink;
52 } InLoadOrderLinks,
53 InMemoryOrderModuleList,
54 InInitializationOrderModuleList;
55 uint32_t DllBase;
56 uint32_t EntryPoint;
57 uint32_t SizeOfImage;
58 struct
59 {
60 uint16_t Length;
61 uint16_t MaximumLength;
62 uint32_t Buffer;
63 } FullDllName,
64 BaseDllName;
65 uint32_t Flags;
66 uint16_t LoadCount;
67 uint16_t TlsIndex;
68 /* ... there is more ... */
69} NTMTE32;
70typedef NTMTE32 *PNTMTE32;
71
72/**
73 * PsLoadedModuleList entry for 32-bit NT aka LDR_DATA_TABLE_ENTRY.
74 * Tested with XP.
75 *
76 * @todo This is incomplete and just to get rid of warnings.
77 */
78typedef struct NTMTE64
79{
80 struct
81 {
82 uint64_t Flink;
83 uint64_t Blink;
84 } InLoadOrderLinks,
85 InMemoryOrderModuleList,
86 InInitializationOrderModuleList;
87 uint64_t DllBase;
88 uint64_t EntryPoint;
89 uint32_t SizeOfImage;
90 uint32_t Alignment;
91 struct
92 {
93 uint16_t Length;
94 uint16_t MaximumLength;
95 uint32_t Alignment;
96 uint64_t Buffer;
97 } FullDllName,
98 BaseDllName;
99 uint32_t Flags;
100 uint16_t LoadCount;
101 uint16_t TlsIndex;
102 /* ... there is more ... */
103} NTMTE64;
104typedef NTMTE64 *PNTMTE64;
105
106/** MTE union. */
107typedef union NTMTE
108{
109 NTMTE32 vX_32;
110 NTMTE64 vX_64;
111} NTMTE;
112typedef NTMTE *PNTMTE;
113
114
115/**
116 * The essential bits of the KUSER_SHARED_DATA structure.
117 */
118typedef struct NTKUSERSHAREDDATA
119{
120 uint32_t TickCountLowDeprecated;
121 uint32_t TickCountMultiplier;
122 struct
123 {
124 uint32_t LowPart;
125 int32_t High1Time;
126 int32_t High2Time;
127
128 } InterruptTime,
129 SystemTime,
130 TimeZoneBias;
131 uint16_t ImageNumberLow;
132 uint16_t ImageNumberHigh;
133 RTUTF16 NtSystemRoot[260];
134 uint32_t MaxStackTraceDepth;
135 uint32_t CryptoExponent;
136 uint32_t TimeZoneId;
137 uint32_t LargePageMinimum;
138 uint32_t Reserved2[7];
139 uint32_t NtProductType;
140 uint8_t ProductTypeIsValid;
141 uint8_t abPadding[3];
142 uint32_t NtMajorVersion;
143 uint32_t NtMinorVersion;
144 /* uint8_t ProcessorFeatures[64];
145 ...
146 */
147} NTKUSERSHAREDDATA;
148typedef NTKUSERSHAREDDATA *PNTKUSERSHAREDDATA;
149
150/** KI_USER_SHARED_DATA for i386 */
151#define NTKUSERSHAREDDATA_WINNT32 UINT32_C(0xffdf0000)
152/** KI_USER_SHARED_DATA for AMD64 */
153#define NTKUSERSHAREDDATA_WINNT64 UINT64_C(0xfffff78000000000)
154
155/** NTKUSERSHAREDDATA::NtProductType */
156typedef enum NTPRODUCTTYPE
157{
158 kNtProductType_Invalid = 0,
159 kNtProductType_WinNt = 1,
160 kNtProductType_LanManNt,
161 kNtProductType_Server
162} NTPRODUCTTYPE;
163
164
165/** NT image header union. */
166typedef union NTHDRSU
167{
168 IMAGE_NT_HEADERS32 vX_32;
169 IMAGE_NT_HEADERS64 vX_64;
170} NTHDRS;
171/** Pointer to NT image header union. */
172typedef NTHDRS *PNTHDRS;
173/** Pointer to const NT image header union. */
174typedef NTHDRS const *PCNTHDRS;
175
176/** @} */
177
178
179
180typedef enum DBGDIGGERWINNTVER
181{
182 DBGDIGGERWINNTVER_UNKNOWN,
183 DBGDIGGERWINNTVER_3_1,
184 DBGDIGGERWINNTVER_3_5,
185 DBGDIGGERWINNTVER_4_0,
186 DBGDIGGERWINNTVER_5_0,
187 DBGDIGGERWINNTVER_5_1,
188 DBGDIGGERWINNTVER_6_0
189} DBGDIGGERWINNTVER;
190
191/**
192 * WinNT guest OS digger instance data.
193 */
194typedef struct DBGDIGGERWINNT
195{
196 /** Whether the information is valid or not.
197 * (For fending off illegal interface method calls.) */
198 bool fValid;
199 /** 32-bit (true) or 64-bit (false) */
200 bool f32Bit;
201
202 /** The NT version. */
203 DBGDIGGERWINNTVER enmVer;
204 /** NTKUSERSHAREDDATA::NtProductType */
205 NTPRODUCTTYPE NtProductType;
206 /** NTKUSERSHAREDDATA::NtMajorVersion */
207 uint32_t NtMajorVersion;
208 /** NTKUSERSHAREDDATA::NtMinorVersion */
209 uint32_t NtMinorVersion;
210
211 /** The address of the ntoskrnl.exe image. */
212 DBGFADDRESS KernelAddr;
213 /** The address of the ntoskrnl.exe module table entry. */
214 DBGFADDRESS KernelMteAddr;
215 /** The address of PsLoadedModuleList. */
216 DBGFADDRESS PsLoadedModuleListAddr;
217} DBGDIGGERWINNT;
218/** Pointer to the linux guest OS digger instance data. */
219typedef DBGDIGGERWINNT *PDBGDIGGERWINNT;
220
221
222/**
223 * The WinNT digger's loader reader instance data.
224 */
225typedef struct DBGDIGGERWINNTRDR
226{
227 /** The VM handle (referenced). */
228 PUVM pUVM;
229 /** The image base. */
230 DBGFADDRESS ImageAddr;
231 /** The image size. */
232 uint32_t cbImage;
233 /** The file offset of the SizeOfImage field in the optional header if it
234 * needs patching, otherwise set to UINT32_MAX. */
235 uint32_t offSizeOfImage;
236 /** The correct image size. */
237 uint32_t cbCorrectImageSize;
238 /** Number of entries in the aMappings table. */
239 uint32_t cMappings;
240 /** Mapping hint. */
241 uint32_t iHint;
242 /** Mapping file offset to memory offsets, ordered by file offset. */
243 struct
244 {
245 /** The file offset. */
246 uint32_t offFile;
247 /** The size of this mapping. */
248 uint32_t cbMem;
249 /** The offset to the memory from the start of the image. */
250 uint32_t offMem;
251 } aMappings[1];
252} DBGDIGGERWINNTRDR;
253/** Pointer a WinNT loader reader instance data. */
254typedef DBGDIGGERWINNTRDR *PDBGDIGGERWINNTRDR;
255
256
257/*******************************************************************************
258* Defined Constants And Macros *
259*******************************************************************************/
260/** Validates a 32-bit Windows NT kernel address */
261#define WINNT32_VALID_ADDRESS(Addr) ((Addr) > UINT32_C(0x80000000) && (Addr) < UINT32_C(0xfffff000))
262/** Validates a 64-bit Windows NT kernel address */
263#define WINNT64_VALID_ADDRESS(Addr) ((Addr) > UINT64_C(0xffffffff80000000) && (Addr) < UINT64_C(0xfffffffffffff000))
264/** Validates a kernel address. */
265#define WINNT_VALID_ADDRESS(pThis, Addr) ((pThis)->f32Bit ? WINNT32_VALID_ADDRESS(Addr) : WINNT64_VALID_ADDRESS(Addr))
266/** Versioned and bitness wrapper. */
267#define WINNT_UNION(pThis, pUnion, Member) ((pThis)->f32Bit ? (pUnion)->vX_32. Member : (pUnion)->vX_64. Member )
268
269/** The length (in chars) of the kernel file name (no path). */
270#define WINNT_KERNEL_BASE_NAME_LEN 12
271
272/** WindowsNT on little endian ASCII systems. */
273#define DIG_WINNT_MOD_TAG UINT64_C(0x54696e646f774e54)
274
275
276/*******************************************************************************
277* Internal Functions *
278*******************************************************************************/
279static DECLCALLBACK(int) dbgDiggerWinNtInit(PUVM pUVM, void *pvData);
280
281
282/*******************************************************************************
283* Global Variables *
284*******************************************************************************/
285/** Kernel names. */
286static const RTUTF16 g_wszKernelNames[][WINNT_KERNEL_BASE_NAME_LEN + 1] =
287{
288 { 'n', 't', 'o', 's', 'k', 'r', 'n', 'l', '.', 'e', 'x', 'e' }
289};
290
291
292
293/** @callback_method_impl{PFNRTLDRRDRMEMREAD} */
294static DECLCALLBACK(int) dbgDiggerWinNtRdr_Read(void *pvBuf, size_t cb, size_t off, void *pvUser)
295{
296 PDBGDIGGERWINNTRDR pThis = (PDBGDIGGERWINNTRDR)pvUser;
297 uint32_t offFile = (uint32_t)off;
298 AssertReturn(offFile == off, VERR_INVALID_PARAMETER);
299
300 uint32_t i = pThis->iHint;
301 if (pThis->aMappings[i].offFile > offFile)
302 {
303 i = pThis->cMappings;
304 while (i-- > 0)
305 if (offFile >= pThis->aMappings[i].offFile)
306 break;
307 pThis->iHint = i;
308 }
309
310 while (cb > 0)
311 {
312 uint32_t offNextMap = i + 1 < pThis->cMappings ? pThis->aMappings[i + 1].offFile : pThis->cbImage;
313 uint32_t offMap = offFile - pThis->aMappings[i].offFile;
314
315 /* Read file bits backed by memory. */
316 if (offMap < pThis->aMappings[i].cbMem)
317 {
318 uint32_t cbToRead = pThis->aMappings[i].cbMem - offMap;
319 if (cbToRead > cb)
320 cbToRead = (uint32_t)cb;
321
322 DBGFADDRESS Addr = pThis->ImageAddr;
323 DBGFR3AddrAdd(&Addr, pThis->aMappings[i].offMem + offMap);
324
325 int rc = DBGFR3MemRead(pThis->pUVM, 0 /*idCpu*/, &Addr, pvBuf, cbToRead);
326 if (RT_FAILURE(rc))
327 return rc;
328
329 /* Apply SizeOfImage patch? */
330 if ( pThis->offSizeOfImage != UINT32_MAX
331 && offFile < pThis->offSizeOfImage + 4
332 && offFile + cbToRead > pThis->offSizeOfImage)
333 {
334 uint32_t SizeOfImage = pThis->cbCorrectImageSize;
335 uint32_t cbPatch = sizeof(SizeOfImage);
336 int32_t offPatch = pThis->offSizeOfImage - offFile;
337 uint8_t *pbPatch = (uint8_t *)pvBuf + offPatch;
338 if (offFile + cbToRead < pThis->offSizeOfImage + cbPatch)
339 cbPatch = offFile + cbToRead - pThis->offSizeOfImage;
340 while (cbPatch-- > 0)
341 {
342 if (offPatch >= 0)
343 *pbPatch = (uint8_t)SizeOfImage;
344 offPatch++;
345 pbPatch++;
346 SizeOfImage >>= 8;
347 }
348 }
349
350 /* Done? */
351 if (cbToRead == cb)
352 break;
353
354 offFile += cbToRead;
355 cb -= cbToRead;
356 pvBuf = (char *)pvBuf + cbToRead;
357 }
358
359 /* Mind the gap. */
360 if (offNextMap > offFile)
361 {
362 uint32_t cbZero = offNextMap - offFile;
363 if (cbZero > cb)
364 {
365 RT_BZERO(pvBuf, cb);
366 break;
367 }
368
369 RT_BZERO(pvBuf, cbZero);
370 offFile += cbZero;
371 cb -= cbZero;
372 pvBuf = (char *)pvBuf + cbZero;
373 }
374
375 pThis->iHint = ++i;
376 }
377
378 return VINF_SUCCESS;
379}
380
381
382/** @callback_method_impl{PFNRTLDRRDRMEMDTOR} */
383static DECLCALLBACK(void) dbgDiggerWinNtRdr_Dtor(void *pvUser)
384{
385 PDBGDIGGERWINNTRDR pThis = (PDBGDIGGERWINNTRDR)pvUser;
386
387 VMR3ReleaseUVM(pThis->pUVM);
388 pThis->pUVM = NULL;
389 RTMemFree(pvUser);
390}
391
392
393/**
394 * Checks if the section headers look okay.
395 *
396 * @returns true / false.
397 * @param paShs Pointer to the section headers.
398 * @param cShs Number of headers.
399 * @param cbImage The image size reported by NT.
400 * @param uRvaRsrc The RVA of the resource directory. UINT32_MAX if
401 * no resource directory.
402 * @param cbSectAlign The section alignment specified in the header.
403 * @param pcbImageCorrect The corrected image size. This is derived from
404 * cbImage and virtual range of the section tables.
405 *
406 * The problem is that NT may choose to drop the
407 * last pages in images it loads early, starting at
408 * the resource directory. These images will have
409 * a page aligned cbImage.
410 */
411static bool dbgDiggerWinNtCheckSectHdrsAndImgSize(PCIMAGE_SECTION_HEADER paShs, uint32_t cShs, uint32_t cbImage,
412 uint32_t uRvaRsrc, uint32_t cbSectAlign, uint32_t *pcbImageCorrect)
413{
414 *pcbImageCorrect = cbImage;
415
416 for (uint32_t i = 0; i < cShs; i++)
417 {
418 if (!paShs[i].Name[0])
419 {
420 Log(("DigWinNt: Section header #%u has no name\n", i));
421 return false;
422 }
423
424 if (paShs[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD)
425 continue;
426
427 /* Check that sizes are within the same range and that both sizes and
428 addresses are within reasonable limits. */
429 if ( RT_ALIGN(paShs[i].Misc.VirtualSize, _64K) > RT_ALIGN(paShs[i].SizeOfRawData, _64K)
430 || paShs[i].Misc.VirtualSize >= _1G
431 || paShs[i].SizeOfRawData >= _1G)
432 {
433 Log(("DigWinNt: Section header #%u has a VirtualSize=%#x and SizeOfRawData=%#x, that's too much data!\n",
434 i, paShs[i].Misc.VirtualSize, paShs[i].SizeOfRawData));
435 return false;
436 }
437 uint32_t uRvaEnd = paShs[i].VirtualAddress + paShs[i].Misc.VirtualSize;
438 if (uRvaEnd >= _1G || uRvaEnd < paShs[i].VirtualAddress)
439 {
440 Log(("DigWinNt: Section header #%u has a VirtualSize=%#x and VirtualAddr=%#x, %#x in total, that's too much!\n",
441 i, paShs[i].Misc.VirtualSize, paShs[i].VirtualAddress, uRvaEnd));
442 return false;
443 }
444
445 /* Check for images chopped off around '.rsrc'. */
446 if ( cbImage < uRvaEnd
447 && uRvaEnd >= uRvaRsrc)
448 cbImage = RT_ALIGN(uRvaEnd, cbSectAlign);
449
450 /* Check that the section is within the image. */
451 if (uRvaEnd > cbImage)
452 {
453 Log(("DigWinNt: Section header #%u has a virtual address range beyond the image: %#x TO %#x cbImage=%#x\n",
454 i, paShs[i].VirtualAddress, uRvaEnd, cbImage));
455 return false;
456 }
457 }
458
459 Assert(*pcbImageCorrect == cbImage || !(*pcbImageCorrect & 0xfff));
460 *pcbImageCorrect = cbImage;
461 return true;
462}
463
464
465/**
466 * Create a loader module for the in-guest-memory PE module.
467 */
468static int dbgDiggerWinNtCreateLdrMod(PDBGDIGGERWINNT pThis, PUVM pUVM, const char *pszName, PCDBGFADDRESS pImageAddr,
469 uint32_t cbImage, uint8_t *pbBuf, size_t cbBuf,
470 uint32_t offHdrs, PCNTHDRS pHdrs, PRTLDRMOD phLdrMod)
471{
472 /*
473 * Allocate and create a reader instance.
474 */
475 uint32_t const cShs = WINNT_UNION(pThis, pHdrs, FileHeader.NumberOfSections);
476 PDBGDIGGERWINNTRDR pRdr = (PDBGDIGGERWINNTRDR)RTMemAlloc(RT_OFFSETOF(DBGDIGGERWINNTRDR, aMappings[cShs + 2]));
477 if (!pRdr)
478 return VERR_NO_MEMORY;
479
480 VMR3RetainUVM(pUVM);
481 pRdr->pUVM = pUVM;
482 pRdr->ImageAddr = *pImageAddr;
483 pRdr->cbImage = cbImage;
484 pRdr->cbCorrectImageSize = cbImage;
485 pRdr->offSizeOfImage = UINT32_MAX;
486 pRdr->iHint = 0;
487
488 /*
489 * Use the section table to construct a more accurate view of the file/
490 * image if it's in the buffer (it should be).
491 */
492 uint32_t uRvaRsrc = UINT32_MAX;
493 if (WINNT_UNION(pThis, pHdrs, OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE]).Size > 0)
494 uRvaRsrc = WINNT_UNION(pThis, pHdrs, OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE]).VirtualAddress;
495 uint32_t offShs = offHdrs
496 + ( pThis->f32Bit
497 ? pHdrs->vX_32.FileHeader.SizeOfOptionalHeader + RT_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader)
498 : pHdrs->vX_64.FileHeader.SizeOfOptionalHeader + RT_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader));
499 uint32_t cbShs = cShs * sizeof(IMAGE_SECTION_HEADER);
500 PCIMAGE_SECTION_HEADER paShs = (PCIMAGE_SECTION_HEADER)(pbBuf + offShs);
501 if ( offShs + cbShs <= RT_MIN(cbImage, cbBuf)
502 && dbgDiggerWinNtCheckSectHdrsAndImgSize(paShs, cShs, cbImage, uRvaRsrc,
503 WINNT_UNION(pThis, pHdrs, OptionalHeader.SectionAlignment),
504 &pRdr->cbCorrectImageSize))
505 {
506 pRdr->cMappings = 0;
507
508 for (uint32_t i = 0; i < cShs; i++)
509 if ( paShs[i].SizeOfRawData > 0
510 && paShs[i].PointerToRawData > 0)
511 {
512 uint32_t j = 1;
513 if (!pRdr->cMappings)
514 pRdr->cMappings++;
515 else
516 {
517 while (j < pRdr->cMappings && pRdr->aMappings[j].offFile < paShs[i].PointerToRawData)
518 j++;
519 if (j < pRdr->cMappings)
520 memmove(&pRdr->aMappings[j + 1], &pRdr->aMappings[j], (pRdr->cMappings - j) * sizeof(pRdr->aMappings));
521 }
522 pRdr->aMappings[j].offFile = paShs[i].PointerToRawData;
523 pRdr->aMappings[j].offMem = paShs[i].VirtualAddress;
524 pRdr->aMappings[j].cbMem = i + 1 < cShs
525 ? paShs[i + 1].VirtualAddress - paShs[i].VirtualAddress
526 : paShs[i].Misc.VirtualSize;
527 if (j == pRdr->cMappings)
528 pRdr->cbImage = paShs[i].PointerToRawData + paShs[i].SizeOfRawData;
529 pRdr->cMappings++;
530 }
531
532 /* Insert the mapping of the headers that isn't covered by the section table. */
533 pRdr->aMappings[0].offFile = 0;
534 pRdr->aMappings[0].offMem = 0;
535 pRdr->aMappings[0].cbMem = pRdr->cMappings ? pRdr->aMappings[1].offFile : pRdr->cbImage;
536
537 int j = pRdr->cMappings - 1;
538 while (j-- > 0)
539 {
540 uint32_t cbFile = pRdr->aMappings[j + 1].offFile - pRdr->aMappings[j].offFile;
541 if (pRdr->aMappings[j].cbMem > cbFile)
542 pRdr->aMappings[j].cbMem = cbFile;
543 }
544 }
545 else
546 {
547 /*
548 * Fallback, fake identity mapped file data.
549 */
550 pRdr->cMappings = 1;
551 pRdr->aMappings[0].offFile = 0;
552 pRdr->aMappings[0].offMem = 0;
553 pRdr->aMappings[0].cbMem = pRdr->cbImage;
554 }
555
556 /* Enable the SizeOfImage patching if necessary. */
557 if (pRdr->cbCorrectImageSize != cbImage)
558 {
559 Log(("DigWinNT: The image is really %#x bytes long, not %#x as mapped by NT!\n", pRdr->cbCorrectImageSize, cbImage));
560 pRdr->offSizeOfImage = pThis->f32Bit
561 ? offHdrs + RT_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader.SizeOfImage)
562 : offHdrs + RT_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader.SizeOfImage);
563 }
564
565 /*
566 * Call the loader to open the PE image for debugging.
567 * Note! It always calls pfnDtor.
568 */
569 RTLDRMOD hLdrMod;
570 int rc = RTLdrOpenInMemory(pszName, RTLDR_O_FOR_DEBUG, RTLDRARCH_WHATEVER, pRdr->cbImage,
571 dbgDiggerWinNtRdr_Read, dbgDiggerWinNtRdr_Dtor, pRdr,
572 &hLdrMod);
573 if (RT_SUCCESS(rc))
574 *phLdrMod = hLdrMod;
575 else
576 *phLdrMod = NIL_RTLDRMOD;
577 return rc;
578}
579
580
581/**
582 * Process a PE image found in guest memory.
583 *
584 * @param pThis The instance data.
585 * @param pUVM The user mode VM handle.
586 * @param pszName The image name.
587 * @param pImageAddr The image address.
588 * @param cbImage The size of the image.
589 * @param pbBuf Scratch buffer containing the first
590 * RT_MIN(cbBuf, cbImage) bytes of the image.
591 * @param cbBuf The scratch buffer size.
592 */
593static void dbgDiggerWinNtProcessImage(PDBGDIGGERWINNT pThis, PUVM pUVM, const char *pszName,
594 PCDBGFADDRESS pImageAddr, uint32_t cbImage,
595 uint8_t *pbBuf, size_t cbBuf)
596{
597 LogFlow(("DigWinNt: %RGp %#x %s\n", pImageAddr->FlatPtr, cbImage, pszName));
598
599 /*
600 * Do some basic validation first.
601 * This is the usual exteremely verbose and messy code...
602 */
603 Assert(cbBuf >= sizeof(IMAGE_NT_HEADERS64));
604 if ( cbImage < sizeof(IMAGE_NT_HEADERS64)
605 || cbImage >= _1M * 256)
606 {
607 Log(("DigWinNt: %s: Bad image size: %#x\n", pszName, cbImage));
608 return;
609 }
610
611 /* Dig out the NT/PE headers. */
612 IMAGE_DOS_HEADER const *pMzHdr = (IMAGE_DOS_HEADER const *)pbBuf;
613 PCNTHDRS pHdrs;
614 uint32_t offHdrs;
615 if (pMzHdr->e_magic != IMAGE_DOS_SIGNATURE)
616 {
617 offHdrs = 0;
618 pHdrs = (PCNTHDRS)pbBuf;
619 }
620 else if ( pMzHdr->e_lfanew >= cbImage
621 || pMzHdr->e_lfanew < sizeof(*pMzHdr)
622 || pMzHdr->e_lfanew + sizeof(IMAGE_NT_HEADERS64) > cbImage)
623 {
624 Log(("DigWinNt: %s: PE header to far into image: %#x cbImage=%#x\n", pMzHdr->e_lfanew, cbImage));
625 return;
626 }
627 else if ( pMzHdr->e_lfanew < cbBuf
628 && pMzHdr->e_lfanew + sizeof(IMAGE_NT_HEADERS64) <= cbBuf)
629 {
630 offHdrs = pMzHdr->e_lfanew;
631 pHdrs = (NTHDRS const *)(pbBuf + offHdrs);
632 }
633 else
634 {
635 Log(("DigWinNt: %s: PE header to far into image (lazy bird): %#x\n", pMzHdr->e_lfanew));
636 return;
637 }
638 if (pHdrs->vX_32.Signature != IMAGE_NT_SIGNATURE)
639 {
640 Log(("DigWinNt: %s: Bad PE signature: %#x\n", pszName, pHdrs->vX_32.Signature));
641 return;
642 }
643
644 /* The file header is the same on both archs */
645 if (pHdrs->vX_32.FileHeader.Machine != (pThis->f32Bit ? IMAGE_FILE_MACHINE_I386 : IMAGE_FILE_MACHINE_AMD64))
646 {
647 Log(("DigWinNt: %s: Invalid FH.Machine: %#x\n", pszName, pHdrs->vX_32.FileHeader.Machine));
648 return;
649 }
650 if (pHdrs->vX_32.FileHeader.SizeOfOptionalHeader != (pThis->f32Bit ? sizeof(IMAGE_OPTIONAL_HEADER32) : sizeof(IMAGE_OPTIONAL_HEADER64)))
651 {
652 Log(("DigWinNt: %s: Invalid FH.SizeOfOptionalHeader: %#x\n", pszName, pHdrs->vX_32.FileHeader.SizeOfOptionalHeader));
653 return;
654 }
655 if (WINNT_UNION(pThis, pHdrs, FileHeader.NumberOfSections) > 64)
656 {
657 Log(("DigWinNt: %s: Too many sections: %#x\n", pszName, WINNT_UNION(pThis, pHdrs, FileHeader.NumberOfSections)));
658 return;
659 }
660
661 const uint32_t TimeDateStamp = pHdrs->vX_32.FileHeader.TimeDateStamp;
662
663 /* The optional header is not... */
664 if (WINNT_UNION(pThis, pHdrs, OptionalHeader.Magic) != (pThis->f32Bit ? IMAGE_NT_OPTIONAL_HDR32_MAGIC : IMAGE_NT_OPTIONAL_HDR64_MAGIC))
665 {
666 Log(("DigWinNt: %s: Invalid OH.Magic: %#x\n", pszName, WINNT_UNION(pThis, pHdrs, OptionalHeader.Magic)));
667 return;
668 }
669 uint32_t cbImageFromHdr = WINNT_UNION(pThis, pHdrs, OptionalHeader.SizeOfImage);
670 if (RT_ALIGN(cbImageFromHdr, _4K) != RT_ALIGN(cbImage, _4K))
671 {
672 Log(("DigWinNt: %s: Invalid OH.SizeOfImage: %#x, expected %#x\n", pszName, cbImageFromHdr, cbImage));
673 return;
674 }
675 if (WINNT_UNION(pThis, pHdrs, OptionalHeader.NumberOfRvaAndSizes) != IMAGE_NUMBEROF_DIRECTORY_ENTRIES)
676 {
677 Log(("DigWinNt: %s: Invalid OH.NumberOfRvaAndSizes: %#x\n", pszName, WINNT_UNION(pThis, pHdrs, OptionalHeader.NumberOfRvaAndSizes)));
678 return;
679 }
680
681 /*
682 * Create the module using the in memory image first, falling back
683 * on cached image.
684 */
685 RTLDRMOD hLdrMod;
686 int rc = dbgDiggerWinNtCreateLdrMod(pThis, pUVM, pszName, pImageAddr, cbImage, pbBuf, cbBuf, offHdrs, pHdrs,
687 &hLdrMod);
688 if (RT_FAILURE(rc))
689 hLdrMod = NIL_RTLDRMOD;
690
691 RTDBGMOD hMod;
692 rc = RTDbgModCreateFromPeImage(&hMod, pszName, NULL, hLdrMod,
693 cbImageFromHdr, TimeDateStamp, DBGFR3AsGetConfig(pUVM));
694 if (RT_FAILURE(rc))
695 {
696 /*
697 * Final fallback is a container module.
698 */
699 rc = RTDbgModCreate(&hMod, pszName, cbImage, 0);
700 if (RT_FAILURE(rc))
701 return;
702
703 rc = RTDbgModSymbolAdd(hMod, "Headers", 0 /*iSeg*/, 0, cbImage, 0 /*fFlags*/, NULL);
704 AssertRC(rc);
705 }
706
707 /* Tag the module. */
708 rc = RTDbgModSetTag(hMod, DIG_WINNT_MOD_TAG);
709 AssertRC(rc);
710
711 /*
712 * Link the module.
713 */
714 RTDBGAS hAs = DBGFR3AsResolveAndRetain(pUVM, DBGF_AS_KERNEL);
715 if (hAs != NIL_RTDBGAS)
716 rc = RTDbgAsModuleLink(hAs, hMod, pImageAddr->FlatPtr, RTDBGASLINK_FLAGS_REPLACE /*fFlags*/);
717 else
718 rc = VERR_INTERNAL_ERROR;
719 RTDbgModRelease(hMod);
720 RTDbgAsRelease(hAs);
721}
722
723
724/**
725 * @copydoc DBGFOSREG::pfnQueryInterface
726 */
727static DECLCALLBACK(void *) dbgDiggerWinNtQueryInterface(PUVM pUVM, void *pvData, DBGFOSINTERFACE enmIf)
728{
729 return NULL;
730}
731
732
733/**
734 * @copydoc DBGFOSREG::pfnQueryVersion
735 */
736static DECLCALLBACK(int) dbgDiggerWinNtQueryVersion(PUVM pUVM, void *pvData, char *pszVersion, size_t cchVersion)
737{
738 PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
739 Assert(pThis->fValid);
740 const char *pszNtProductType;
741 switch (pThis->NtProductType)
742 {
743 case kNtProductType_WinNt: pszNtProductType = "-WinNT"; break;
744 case kNtProductType_LanManNt: pszNtProductType = "-LanManNT"; break;
745 case kNtProductType_Server: pszNtProductType = "-Server"; break;
746 default: pszNtProductType = ""; break;
747 }
748 RTStrPrintf(pszVersion, cchVersion, "%u.%u%s", pThis->NtMajorVersion, pThis->NtMinorVersion, pszNtProductType);
749 return VINF_SUCCESS;
750}
751
752
753/**
754 * @copydoc DBGFOSREG::pfnTerm
755 */
756static DECLCALLBACK(void) dbgDiggerWinNtTerm(PUVM pUVM, void *pvData)
757{
758 PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
759 Assert(pThis->fValid);
760
761 pThis->fValid = false;
762}
763
764
765/**
766 * @copydoc DBGFOSREG::pfnRefresh
767 */
768static DECLCALLBACK(int) dbgDiggerWinNtRefresh(PUVM pUVM, void *pvData)
769{
770 PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
771 NOREF(pThis);
772 Assert(pThis->fValid);
773
774 /*
775 * For now we'll flush and reload everything.
776 */
777 RTDBGAS hDbgAs = DBGFR3AsResolveAndRetain(pUVM, DBGF_AS_KERNEL);
778 if (hDbgAs != NIL_RTDBGAS)
779 {
780 uint32_t iMod = RTDbgAsModuleCount(hDbgAs);
781 while (iMod-- > 0)
782 {
783 RTDBGMOD hMod = RTDbgAsModuleByIndex(hDbgAs, iMod);
784 if (hMod != NIL_RTDBGMOD)
785 {
786 if (RTDbgModGetTag(hMod) == DIG_WINNT_MOD_TAG)
787 {
788 int rc = RTDbgAsModuleUnlink(hDbgAs, hMod);
789 AssertRC(rc);
790 }
791 RTDbgModRelease(hMod);
792 }
793 }
794 RTDbgAsRelease(hDbgAs);
795 }
796
797 dbgDiggerWinNtTerm(pUVM, pvData);
798 return dbgDiggerWinNtInit(pUVM, pvData);
799}
800
801
802/**
803 * @copydoc DBGFOSREG::pfnInit
804 */
805static DECLCALLBACK(int) dbgDiggerWinNtInit(PUVM pUVM, void *pvData)
806{
807 PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
808 Assert(!pThis->fValid);
809
810 union
811 {
812 uint8_t au8[0x2000];
813 RTUTF16 wsz[0x2000/2];
814 NTKUSERSHAREDDATA UserSharedData;
815 } u;
816 DBGFADDRESS Addr;
817 int rc;
818
819 /*
820 * Figure the NT version.
821 */
822 DBGFR3AddrFromFlat(pUVM, &Addr, pThis->f32Bit ? NTKUSERSHAREDDATA_WINNT32 : NTKUSERSHAREDDATA_WINNT64);
823 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &Addr, &u, PAGE_SIZE);
824 if (RT_FAILURE(rc))
825 return rc;
826 pThis->NtProductType = u.UserSharedData.ProductTypeIsValid && u.UserSharedData.NtProductType <= kNtProductType_Server
827 ? (NTPRODUCTTYPE)u.UserSharedData.NtProductType
828 : kNtProductType_Invalid;
829 pThis->NtMajorVersion = u.UserSharedData.NtMajorVersion;
830 pThis->NtMinorVersion = u.UserSharedData.NtMinorVersion;
831
832 /*
833 * Dig out the module chain.
834 */
835 DBGFADDRESS AddrPrev = pThis->PsLoadedModuleListAddr;
836 Addr = pThis->KernelMteAddr;
837 do
838 {
839 /* Read the validate the MTE. */
840 NTMTE Mte;
841 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &Addr, &Mte, pThis->f32Bit ? sizeof(Mte.vX_32) : sizeof(Mte.vX_64));
842 if (RT_FAILURE(rc))
843 break;
844 if (WINNT_UNION(pThis, &Mte, InLoadOrderLinks.Blink) != AddrPrev.FlatPtr)
845 {
846 Log(("DigWinNt: Bad Mte At %RGv - backpointer\n", Addr.FlatPtr));
847 break;
848 }
849 if (!WINNT_VALID_ADDRESS(pThis, WINNT_UNION(pThis, &Mte, InLoadOrderLinks.Flink)) )
850 {
851 Log(("DigWinNt: Bad Mte at %RGv - forward pointer\n", Addr.FlatPtr));
852 break;
853 }
854 if (!WINNT_VALID_ADDRESS(pThis, WINNT_UNION(pThis, &Mte, BaseDllName.Buffer)))
855 {
856 Log(("DigWinNt: Bad Mte at %RGv - BaseDllName=%llx\n", Addr.FlatPtr, WINNT_UNION(pThis, &Mte, BaseDllName.Buffer)));
857 break;
858 }
859 if (!WINNT_VALID_ADDRESS(pThis, WINNT_UNION(pThis, &Mte, FullDllName.Buffer)))
860 {
861 Log(("DigWinNt: Bad Mte at %RGv - FullDllName=%llx\n", Addr.FlatPtr, WINNT_UNION(pThis, &Mte, FullDllName.Buffer)));
862 break;
863 }
864 if ( !WINNT_VALID_ADDRESS(pThis, WINNT_UNION(pThis, &Mte, DllBase))
865 || WINNT_UNION(pThis, &Mte, SizeOfImage) > _1M*256
866 || WINNT_UNION(pThis, &Mte, EntryPoint) - WINNT_UNION(pThis, &Mte, DllBase) > WINNT_UNION(pThis, &Mte, SizeOfImage) )
867 {
868 Log(("DigWinNt: Bad Mte at %RGv - EntryPoint=%llx SizeOfImage=%x DllBase=%llx\n",
869 Addr.FlatPtr, WINNT_UNION(pThis, &Mte, EntryPoint), WINNT_UNION(pThis, &Mte, SizeOfImage), WINNT_UNION(pThis, &Mte, DllBase)));
870 break;
871 }
872
873 /* Read the full name. */
874 DBGFADDRESS AddrName;
875 DBGFR3AddrFromFlat(pUVM, &AddrName, WINNT_UNION(pThis, &Mte, FullDllName.Buffer));
876 uint16_t cbName = WINNT_UNION(pThis, &Mte, FullDllName.Length);
877 if (cbName < sizeof(u))
878 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &AddrName, &u, cbName);
879 else
880 rc = VERR_OUT_OF_RANGE;
881 if (RT_FAILURE(rc))
882 {
883 DBGFR3AddrFromFlat(pUVM, &AddrName, WINNT_UNION(pThis, &Mte, BaseDllName.Buffer));
884 cbName = WINNT_UNION(pThis, &Mte, BaseDllName.Length);
885 if (cbName < sizeof(u))
886 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &AddrName, &u, cbName);
887 else
888 rc = VERR_OUT_OF_RANGE;
889 }
890 if (RT_SUCCESS(rc))
891 {
892 u.wsz[cbName/2] = '\0';
893 char *pszName;
894 rc = RTUtf16ToUtf8(u.wsz, &pszName);
895 if (RT_SUCCESS(rc))
896 {
897 /* Read the start of the PE image and pass it along to a worker. */
898 DBGFADDRESS ImageAddr;
899 DBGFR3AddrFromFlat(pUVM, &ImageAddr, WINNT_UNION(pThis, &Mte, DllBase));
900 uint32_t cbImageBuf = RT_MIN(sizeof(u), WINNT_UNION(pThis, &Mte, SizeOfImage));
901 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &ImageAddr, &u, cbImageBuf);
902 if (RT_SUCCESS(rc))
903 dbgDiggerWinNtProcessImage(pThis,
904 pUVM,
905 pszName,
906 &ImageAddr,
907 WINNT_UNION(pThis, &Mte, SizeOfImage),
908 &u.au8[0],
909 sizeof(u));
910 RTStrFree(pszName);
911 }
912 }
913
914 /* next */
915 AddrPrev = Addr;
916 DBGFR3AddrFromFlat(pUVM, &Addr, WINNT_UNION(pThis, &Mte, InLoadOrderLinks.Flink));
917 } while ( Addr.FlatPtr != pThis->KernelMteAddr.FlatPtr
918 && Addr.FlatPtr != pThis->PsLoadedModuleListAddr.FlatPtr);
919
920 pThis->fValid = true;
921 return VINF_SUCCESS;
922}
923
924
925/**
926 * @copydoc DBGFOSREG::pfnProbe
927 */
928static DECLCALLBACK(bool) dbgDiggerWinNtProbe(PUVM pUVM, void *pvData)
929{
930 PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
931 DBGFADDRESS Addr;
932 union
933 {
934 uint8_t au8[8192];
935 uint16_t au16[8192/2];
936 uint32_t au32[8192/4];
937 IMAGE_DOS_HEADER MzHdr;
938 RTUTF16 wsz[8192/2];
939 } u;
940
941 /*
942 * Look for the PAGELK section name that seems to be a part of all kernels.
943 * Then try find the module table entry for it. Since it's the first entry
944 * in the PsLoadedModuleList we can easily validate the list head and report
945 * success.
946 */
947 CPUMMODE enmMode = DBGFR3CpuGetMode(pUVM, 0 /*idCpu*/);
948 if (enmMode == CPUMMODE_LONG)
949 {
950 /** @todo when 32-bit is working, add support for 64-bit windows nt. */
951 }
952 else
953 {
954 DBGFADDRESS KernelAddr;
955 for (DBGFR3AddrFromFlat(pUVM, &KernelAddr, UINT32_C(0x80001000));
956 KernelAddr.FlatPtr < UINT32_C(0xffff0000);
957 KernelAddr.FlatPtr += PAGE_SIZE)
958 {
959 int rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &KernelAddr, UINT32_C(0xffff0000) - KernelAddr.FlatPtr,
960 1, "PAGELK\0", sizeof("PAGELK\0"), &KernelAddr);
961 if (RT_FAILURE(rc))
962 break;
963 DBGFR3AddrSub(&KernelAddr, KernelAddr.FlatPtr & PAGE_OFFSET_MASK);
964
965 /* MZ + PE header. */
966 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &KernelAddr, &u, sizeof(u));
967 if ( RT_SUCCESS(rc)
968 && u.MzHdr.e_magic == IMAGE_DOS_SIGNATURE
969 && !(u.MzHdr.e_lfanew & 0x7)
970 && u.MzHdr.e_lfanew >= 0x080
971 && u.MzHdr.e_lfanew <= 0x200)
972 {
973 IMAGE_NT_HEADERS32 const *pHdrs = (IMAGE_NT_HEADERS32 const *)&u.au8[u.MzHdr.e_lfanew];
974 if ( pHdrs->Signature == IMAGE_NT_SIGNATURE
975 && pHdrs->FileHeader.Machine == IMAGE_FILE_MACHINE_I386
976 && pHdrs->FileHeader.SizeOfOptionalHeader == sizeof(pHdrs->OptionalHeader)
977 && pHdrs->FileHeader.NumberOfSections >= 10 /* the kernel has lots */
978 && (pHdrs->FileHeader.Characteristics & (IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL)) == IMAGE_FILE_EXECUTABLE_IMAGE
979 && pHdrs->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC
980 && pHdrs->OptionalHeader.NumberOfRvaAndSizes == IMAGE_NUMBEROF_DIRECTORY_ENTRIES
981 /** @todo need more ntoskrnl signs? */
982 )
983 {
984 /* Find the MTE. */
985 NTMTE32 Mte;
986 RT_ZERO(Mte);
987 Mte.DllBase = KernelAddr.FlatPtr;
988 Mte.EntryPoint = KernelAddr.FlatPtr + pHdrs->OptionalHeader.AddressOfEntryPoint;
989 Mte.SizeOfImage = pHdrs->OptionalHeader.SizeOfImage;
990 DBGFADDRESS HitAddr;
991 rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &KernelAddr, UINT32_MAX - KernelAddr.FlatPtr,
992 4 /*align*/, &Mte.DllBase, 3 * sizeof(uint32_t), &HitAddr);
993 while (RT_SUCCESS(rc))
994 {
995 /* check the name. */
996 NTMTE32 Mte2;
997 DBGFADDRESS MteAddr = HitAddr;
998 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrSub(&MteAddr, RT_OFFSETOF(NTMTE32, DllBase)),
999 &Mte2, sizeof(Mte2));
1000 if ( RT_SUCCESS(rc)
1001 && Mte2.DllBase == Mte.DllBase
1002 && Mte2.EntryPoint == Mte.EntryPoint
1003 && Mte2.SizeOfImage == Mte.SizeOfImage
1004 && WINNT32_VALID_ADDRESS(Mte2.InLoadOrderLinks.Flink)
1005 && Mte2.InLoadOrderLinks.Blink > KernelAddr.FlatPtr /* list head inside ntoskrnl */
1006 && Mte2.InLoadOrderLinks.Blink < KernelAddr.FlatPtr + Mte.SizeOfImage
1007 && WINNT32_VALID_ADDRESS(Mte2.BaseDllName.Buffer)
1008 && WINNT32_VALID_ADDRESS(Mte2.FullDllName.Buffer)
1009 && Mte2.BaseDllName.Length <= Mte2.BaseDllName.MaximumLength
1010 && Mte2.BaseDllName.Length == WINNT_KERNEL_BASE_NAME_LEN * 2
1011 && Mte2.FullDllName.Length <= Mte2.FullDllName.MaximumLength
1012 && Mte2.FullDllName.Length <= 256
1013 )
1014 {
1015 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pUVM, &Addr, Mte2.BaseDllName.Buffer),
1016 u.wsz, Mte2.BaseDllName.Length);
1017 u.wsz[Mte2.BaseDllName.Length / 2] = '\0';
1018 if ( RT_SUCCESS(rc)
1019 && ( !RTUtf16ICmp(u.wsz, g_wszKernelNames[0])
1020 /* || !RTUtf16ICmp(u.wsz, g_wszKernelNames[1]) */
1021 )
1022 )
1023 {
1024 NTMTE32 Mte3;
1025 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pUVM, &Addr, Mte2.InLoadOrderLinks.Blink),
1026 &Mte3, RT_SIZEOFMEMB(NTMTE32, InLoadOrderLinks));
1027 if ( RT_SUCCESS(rc)
1028 && Mte3.InLoadOrderLinks.Flink == MteAddr.FlatPtr
1029 && WINNT32_VALID_ADDRESS(Mte3.InLoadOrderLinks.Blink) )
1030 {
1031 Log(("DigWinNt: MteAddr=%RGv KernelAddr=%RGv SizeOfImage=%x &PsLoadedModuleList=%RGv (32-bit)\n",
1032 MteAddr.FlatPtr, KernelAddr.FlatPtr, Mte2.SizeOfImage, Addr.FlatPtr));
1033 pThis->KernelAddr = KernelAddr;
1034 pThis->KernelMteAddr = MteAddr;
1035 pThis->PsLoadedModuleListAddr = Addr;
1036 pThis->f32Bit = true;
1037 return true;
1038 }
1039 }
1040 }
1041
1042 /* next */
1043 DBGFR3AddrAdd(&HitAddr, 4);
1044 if (HitAddr.FlatPtr <= UINT32_C(0xfffff000))
1045 rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &HitAddr, UINT32_MAX - HitAddr.FlatPtr,
1046 4 /*align*/, &Mte.DllBase, 3 * sizeof(uint32_t), &HitAddr);
1047 else
1048 rc = VERR_DBGF_MEM_NOT_FOUND;
1049 }
1050 }
1051 }
1052 }
1053 }
1054 return false;
1055}
1056
1057
1058/**
1059 * @copydoc DBGFOSREG::pfnDestruct
1060 */
1061static DECLCALLBACK(void) dbgDiggerWinNtDestruct(PUVM pUVM, void *pvData)
1062{
1063
1064}
1065
1066
1067/**
1068 * @copydoc DBGFOSREG::pfnConstruct
1069 */
1070static DECLCALLBACK(int) dbgDiggerWinNtConstruct(PUVM pUVM, void *pvData)
1071{
1072 PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
1073 pThis->fValid = false;
1074 pThis->f32Bit = false;
1075 pThis->enmVer = DBGDIGGERWINNTVER_UNKNOWN;
1076 return VINF_SUCCESS;
1077}
1078
1079
1080const DBGFOSREG g_DBGDiggerWinNt =
1081{
1082 /* .u32Magic = */ DBGFOSREG_MAGIC,
1083 /* .fFlags = */ 0,
1084 /* .cbData = */ sizeof(DBGDIGGERWINNT),
1085 /* .szName = */ "WinNT",
1086 /* .pfnConstruct = */ dbgDiggerWinNtConstruct,
1087 /* .pfnDestruct = */ dbgDiggerWinNtDestruct,
1088 /* .pfnProbe = */ dbgDiggerWinNtProbe,
1089 /* .pfnInit = */ dbgDiggerWinNtInit,
1090 /* .pfnRefresh = */ dbgDiggerWinNtRefresh,
1091 /* .pfnTerm = */ dbgDiggerWinNtTerm,
1092 /* .pfnQueryVersion = */ dbgDiggerWinNtQueryVersion,
1093 /* .pfnQueryInterface = */ dbgDiggerWinNtQueryInterface,
1094 /* .u32EndMagic = */ DBGFOSREG_MAGIC
1095};
1096
Note: See TracBrowser for help on using the repository browser.

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