VirtualBox

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

Last change on this file since 73461 was 73461, checked in by vboxsync, 6 years ago

IPRT,DBGF,Diggers: Moved DBGFRETURNTYPE and the unwind state structure to IPRT (dbg.h) in prep for debug module interface and more. Added stack unwind assist callback for the OS diggers so they can identify special stack frames and supply more info via the sure-register-value array and frame flags. Identify and decode NT/AMD64 trap frames. [build fix]

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 43.6 KB
Line 
1/* $Id: DBGPlugInWinNt.cpp 73461 2018-08-02 21:15:29Z vboxsync $ */
2/** @file
3 * DBGPlugInWindows - Debugger and Guest OS Digger Plugin For Windows NT.
4 */
5
6/*
7 * Copyright (C) 2009-2017 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/vmm/cpumctx.h>
26#include <VBox/vmm/mm.h>
27#include <VBox/err.h>
28#include <VBox/param.h>
29#include <iprt/ldr.h>
30#include <iprt/mem.h>
31#include <iprt/stream.h>
32#include <iprt/string.h>
33#include <iprt/formats/pecoff.h>
34#include <iprt/formats/mz.h>
35#include <iprt/nt/nt-structures.h>
36
37
38/*********************************************************************************************************************************
39* Structures and Typedefs *
40*********************************************************************************************************************************/
41
42/** @name Internal WinNT structures
43 * @{ */
44/**
45 * PsLoadedModuleList entry for 32-bit NT aka LDR_DATA_TABLE_ENTRY.
46 * Tested with XP.
47 */
48typedef struct NTMTE32
49{
50 struct
51 {
52 uint32_t Flink;
53 uint32_t Blink;
54 } InLoadOrderLinks,
55 InMemoryOrderModuleList,
56 InInitializationOrderModuleList;
57 uint32_t DllBase;
58 uint32_t EntryPoint;
59 /** @note This field is not a size in NT 3.1. It's NULL for images loaded by the
60 * boot loader, for other images it looks like some kind of pointer. */
61 uint32_t SizeOfImage;
62 struct
63 {
64 uint16_t Length;
65 uint16_t MaximumLength;
66 uint32_t Buffer;
67 } FullDllName,
68 BaseDllName;
69 uint32_t Flags;
70 uint16_t LoadCount;
71 uint16_t TlsIndex;
72 /* ... there is more ... */
73} NTMTE32;
74typedef NTMTE32 *PNTMTE32;
75
76/**
77 * PsLoadedModuleList entry for 64-bit NT aka LDR_DATA_TABLE_ENTRY.
78 */
79typedef struct NTMTE64
80{
81 struct
82 {
83 uint64_t Flink;
84 uint64_t Blink;
85 } InLoadOrderLinks, /**< 0x00 */
86 InMemoryOrderModuleList, /**< 0x10 */
87 InInitializationOrderModuleList; /**< 0x20 */
88 uint64_t DllBase; /**< 0x30 */
89 uint64_t EntryPoint; /**< 0x38 */
90 uint32_t SizeOfImage; /**< 0x40 */
91 uint32_t Alignment; /**< 0x44 */
92 struct
93 {
94 uint16_t Length; /**< 0x48,0x58 */
95 uint16_t MaximumLength; /**< 0x4a,0x5a */
96 uint32_t Alignment; /**< 0x4c,0x5c */
97 uint64_t Buffer; /**< 0x50,0x60 */
98 } FullDllName, /**< 0x48 */
99 BaseDllName; /**< 0x58 */
100 uint32_t Flags; /**< 0x68 */
101 uint16_t LoadCount; /**< 0x6c */
102 uint16_t TlsIndex; /**< 0x6e */
103 /* ... there is more ... */
104} NTMTE64;
105typedef NTMTE64 *PNTMTE64;
106
107/** MTE union. */
108typedef union NTMTE
109{
110 NTMTE32 vX_32;
111 NTMTE64 vX_64;
112} NTMTE;
113typedef NTMTE *PNTMTE;
114
115
116/**
117 * The essential bits of the KUSER_SHARED_DATA structure.
118 */
119typedef struct NTKUSERSHAREDDATA
120{
121 uint32_t TickCountLowDeprecated;
122 uint32_t TickCountMultiplier;
123 struct
124 {
125 uint32_t LowPart;
126 int32_t High1Time;
127 int32_t High2Time;
128
129 } InterruptTime,
130 SystemTime,
131 TimeZoneBias;
132 uint16_t ImageNumberLow;
133 uint16_t ImageNumberHigh;
134 RTUTF16 NtSystemRoot[260];
135 uint32_t MaxStackTraceDepth;
136 uint32_t CryptoExponent;
137 uint32_t TimeZoneId;
138 uint32_t LargePageMinimum;
139 uint32_t Reserved2[7];
140 uint32_t NtProductType;
141 uint8_t ProductTypeIsValid;
142 uint8_t abPadding[3];
143 uint32_t NtMajorVersion;
144 uint32_t NtMinorVersion;
145 /* uint8_t ProcessorFeatures[64];
146 ...
147 */
148} NTKUSERSHAREDDATA;
149typedef NTKUSERSHAREDDATA *PNTKUSERSHAREDDATA;
150
151/** KI_USER_SHARED_DATA for i386 */
152#define NTKUSERSHAREDDATA_WINNT32 UINT32_C(0xffdf0000)
153/** KI_USER_SHARED_DATA for AMD64 */
154#define NTKUSERSHAREDDATA_WINNT64 UINT64_C(0xfffff78000000000)
155
156/** NTKUSERSHAREDDATA::NtProductType */
157typedef enum NTPRODUCTTYPE
158{
159 kNtProductType_Invalid = 0,
160 kNtProductType_WinNt = 1,
161 kNtProductType_LanManNt,
162 kNtProductType_Server
163} NTPRODUCTTYPE;
164
165
166/** NT image header union. */
167typedef union NTHDRSU
168{
169 IMAGE_NT_HEADERS32 vX_32;
170 IMAGE_NT_HEADERS64 vX_64;
171} NTHDRS;
172/** Pointer to NT image header union. */
173typedef NTHDRS *PNTHDRS;
174/** Pointer to const NT image header union. */
175typedef NTHDRS const *PCNTHDRS;
176
177/** @} */
178
179
180
181typedef enum DBGDIGGERWINNTVER
182{
183 DBGDIGGERWINNTVER_UNKNOWN,
184 DBGDIGGERWINNTVER_3_1,
185 DBGDIGGERWINNTVER_3_5,
186 DBGDIGGERWINNTVER_4_0,
187 DBGDIGGERWINNTVER_5_0,
188 DBGDIGGERWINNTVER_5_1,
189 DBGDIGGERWINNTVER_6_0
190} DBGDIGGERWINNTVER;
191
192/**
193 * WinNT guest OS digger instance data.
194 */
195typedef struct DBGDIGGERWINNT
196{
197 /** Whether the information is valid or not.
198 * (For fending off illegal interface method calls.) */
199 bool fValid;
200 /** 32-bit (true) or 64-bit (false) */
201 bool f32Bit;
202 /** Set if NT 3.1 was detected.
203 * This implies both Misc.VirtualSize and NTMTE32::SizeOfImage are zero. */
204 bool fNt31;
205
206 /** The NT version. */
207 DBGDIGGERWINNTVER enmVer;
208 /** NTKUSERSHAREDDATA::NtProductType */
209 NTPRODUCTTYPE NtProductType;
210 /** NTKUSERSHAREDDATA::NtMajorVersion */
211 uint32_t NtMajorVersion;
212 /** NTKUSERSHAREDDATA::NtMinorVersion */
213 uint32_t NtMinorVersion;
214
215 /** The address of the ntoskrnl.exe image. */
216 DBGFADDRESS KernelAddr;
217 /** The address of the ntoskrnl.exe module table entry. */
218 DBGFADDRESS KernelMteAddr;
219 /** The address of PsLoadedModuleList. */
220 DBGFADDRESS PsLoadedModuleListAddr;
221} DBGDIGGERWINNT;
222/** Pointer to the linux guest OS digger instance data. */
223typedef DBGDIGGERWINNT *PDBGDIGGERWINNT;
224
225
226/**
227 * The WinNT digger's loader reader instance data.
228 */
229typedef struct DBGDIGGERWINNTRDR
230{
231 /** The VM handle (referenced). */
232 PUVM pUVM;
233 /** The image base. */
234 DBGFADDRESS ImageAddr;
235 /** The image size. */
236 uint32_t cbImage;
237 /** The file offset of the SizeOfImage field in the optional header if it
238 * needs patching, otherwise set to UINT32_MAX. */
239 uint32_t offSizeOfImage;
240 /** The correct image size. */
241 uint32_t cbCorrectImageSize;
242 /** Number of entries in the aMappings table. */
243 uint32_t cMappings;
244 /** Mapping hint. */
245 uint32_t iHint;
246 /** Mapping file offset to memory offsets, ordered by file offset. */
247 struct
248 {
249 /** The file offset. */
250 uint32_t offFile;
251 /** The size of this mapping. */
252 uint32_t cbMem;
253 /** The offset to the memory from the start of the image. */
254 uint32_t offMem;
255 } aMappings[1];
256} DBGDIGGERWINNTRDR;
257/** Pointer a WinNT loader reader instance data. */
258typedef DBGDIGGERWINNTRDR *PDBGDIGGERWINNTRDR;
259
260
261/*********************************************************************************************************************************
262* Defined Constants And Macros *
263*********************************************************************************************************************************/
264/** Validates a 32-bit Windows NT kernel address */
265#define WINNT32_VALID_ADDRESS(Addr) ((Addr) > UINT32_C(0x80000000) && (Addr) < UINT32_C(0xfffff000))
266/** Validates a 64-bit Windows NT kernel address */
267#define WINNT64_VALID_ADDRESS(Addr) ((Addr) > UINT64_C(0xffff800000000000) && (Addr) < UINT64_C(0xfffffffffffff000))
268/** Validates a kernel address. */
269#define WINNT_VALID_ADDRESS(pThis, Addr) ((pThis)->f32Bit ? WINNT32_VALID_ADDRESS(Addr) : WINNT64_VALID_ADDRESS(Addr))
270/** Versioned and bitness wrapper. */
271#define WINNT_UNION(pThis, pUnion, Member) ((pThis)->f32Bit ? (pUnion)->vX_32. Member : (pUnion)->vX_64. Member )
272
273/** The length (in chars) of the kernel file name (no path). */
274#define WINNT_KERNEL_BASE_NAME_LEN 12
275
276/** WindowsNT on little endian ASCII systems. */
277#define DIG_WINNT_MOD_TAG UINT64_C(0x54696e646f774e54)
278
279
280/*********************************************************************************************************************************
281* Internal Functions *
282*********************************************************************************************************************************/
283static DECLCALLBACK(int) dbgDiggerWinNtInit(PUVM pUVM, void *pvData);
284
285
286/*********************************************************************************************************************************
287* Global Variables *
288*********************************************************************************************************************************/
289/** Kernel names. */
290static const RTUTF16 g_wszKernelNames[][WINNT_KERNEL_BASE_NAME_LEN + 1] =
291{
292 { 'n', 't', 'o', 's', 'k', 'r', 'n', 'l', '.', 'e', 'x', 'e' }
293};
294
295
296
297/**
298 * Process a PE image found in guest memory.
299 *
300 * @param pThis The instance data.
301 * @param pUVM The user mode VM handle.
302 * @param pszName The image name.
303 * @param pImageAddr The image address.
304 * @param cbImage The size of the image.
305 */
306static void dbgDiggerWinNtProcessImage(PDBGDIGGERWINNT pThis, PUVM pUVM, const char *pszName,
307 PCDBGFADDRESS pImageAddr, uint32_t cbImage)
308{
309 LogFlow(("DigWinNt: %RGp %#x %s\n", pImageAddr->FlatPtr, cbImage, pszName));
310
311 /*
312 * Do some basic validation first.
313 */
314 if ( (cbImage < sizeof(IMAGE_NT_HEADERS64) && !pThis->fNt31)
315 || cbImage >= _1M * 256)
316 {
317 Log(("DigWinNt: %s: Bad image size: %#x\n", pszName, cbImage));
318 return;
319 }
320
321 /*
322 * Use the common in-memory module reader to create a debug module.
323 */
324 RTERRINFOSTATIC ErrInfo;
325 RTDBGMOD hDbgMod = NIL_RTDBGMOD;
326 int rc = DBGFR3ModInMem(pUVM, pImageAddr, pThis->fNt31 ? DBGFMODINMEM_F_PE_NT31 : 0, pszName,
327 pThis->f32Bit ? RTLDRARCH_X86_32 : RTLDRARCH_AMD64, cbImage,
328 &hDbgMod, RTErrInfoInitStatic(&ErrInfo));
329 if (RT_SUCCESS(rc))
330 {
331 /*
332 * Tag the module.
333 */
334 rc = RTDbgModSetTag(hDbgMod, DIG_WINNT_MOD_TAG);
335 AssertRC(rc);
336
337 /*
338 * Link the module.
339 */
340 RTDBGAS hAs = DBGFR3AsResolveAndRetain(pUVM, DBGF_AS_KERNEL);
341 if (hAs != NIL_RTDBGAS)
342 rc = RTDbgAsModuleLink(hAs, hDbgMod, pImageAddr->FlatPtr, RTDBGASLINK_FLAGS_REPLACE /*fFlags*/);
343 else
344 rc = VERR_INTERNAL_ERROR;
345 RTDbgModRelease(hDbgMod);
346 RTDbgAsRelease(hAs);
347 }
348 else if (RTErrInfoIsSet(&ErrInfo.Core))
349 Log(("DigWinNt: %s: DBGFR3ModInMem failed: %Rrc - %s\n", pszName, rc, ErrInfo.Core.pszMsg));
350 else
351 Log(("DigWinNt: %s: DBGFR3ModInMem failed: %Rrc\n", pszName, rc));
352}
353
354
355/**
356 * @copydoc DBGFOSREG::pfnStackUnwindAssist
357 */
358static DECLCALLBACK(int) dbgDiggerWinNtStackUnwindAssist(PUVM pUVM, void *pvData, VMCPUID idCpu, PDBGFSTACKFRAME pFrame,
359 PRTDBGUNWINDSTATE pState, PCCPUMCTX pInitialCtx, RTDBGAS hAs,
360 uint64_t *puScratch)
361{
362 Assert(pInitialCtx);
363
364 /*
365 * We want to locate trap frames here. The trap frame structure contains
366 * the 64-bit IRET frame, so given unwind information it's easy to identify
367 * using the return type and frame address.
368 */
369 if (pFrame->fFlags & DBGFSTACKFRAME_FLAGS_64BIT)
370 {
371 /*
372 * Is this a trap frame? If so, try read the trap frame.
373 */
374 if ( pFrame->enmReturnType == RTDBGRETURNTYPE_IRET64
375 && !(pFrame->AddrFrame.FlatPtr & 0x7)
376 && WINNT64_VALID_ADDRESS(pFrame->AddrFrame.FlatPtr) )
377 {
378 KTRAP_FRAME_AMD64 TrapFrame;
379 RT_ZERO(TrapFrame);
380 uint64_t const uTrapFrameAddr = pFrame->AddrFrame.FlatPtr
381 - RT_UOFFSETOF(KTRAP_FRAME_AMD64, ErrCdOrXcptFrameOrS);
382 int rc = pState->pfnReadStack(pState, uTrapFrameAddr, sizeof(TrapFrame), &TrapFrame);
383 if (RT_SUCCESS(rc))
384 {
385 /* Valid? Not too much else we can check here (EFlags isn't
386 reliable in manually construct frames). */
387 if (TrapFrame.ExceptionActive <= 2)
388 {
389 pFrame->fFlags |= DBGFSTACKFRAME_FLAGS_TRAP_FRAME;
390
391 /*
392 * Add sure 'register' information from the frame to the frame.
393 *
394 * To avoid code duplication, we do this in two steps in a loop.
395 * The first iteration only figures out how many registers we're
396 * going to save and allocates room for them. The second iteration
397 * does the actual adding.
398 */
399 uint32_t cRegs = pFrame->cSureRegs;
400 PDBGFREGVALEX paSureRegs = NULL;
401#define ADD_REG_NAMED(a_Type, a_ValMemb, a_Value, a_pszName) do { \
402 if (paSureRegs) \
403 { \
404 paSureRegs[iReg].pszName = a_pszName;\
405 paSureRegs[iReg].enmReg = DBGFREG_END; \
406 paSureRegs[iReg].enmType = a_Type; \
407 paSureRegs[iReg].Value.a_ValMemb = (a_Value); \
408 } \
409 iReg++; \
410 } while (0)
411#define MAYBE_ADD_GREG(a_Value, a_enmReg, a_idxReg) do { \
412 if (!(pState->u.x86.Loaded.s.fRegs & RT_BIT(a_idxReg))) \
413 { \
414 if (paSureRegs) \
415 { \
416 pState->u.x86.Loaded.s.fRegs |= RT_BIT(a_idxReg); \
417 pState->u.x86.auRegs[a_idxReg] = (a_Value); \
418 paSureRegs[iReg].Value.u64 = (a_Value); \
419 paSureRegs[iReg].enmReg = a_enmReg; \
420 paSureRegs[iReg].enmType = DBGFREGVALTYPE_U64; \
421 paSureRegs[iReg].pszName = NULL; \
422 } \
423 iReg++; \
424 } \
425 } while (0)
426 for (unsigned iLoop = 0; iLoop < 2; iLoop++)
427 {
428 uint32_t iReg = pFrame->cSureRegs;
429 ADD_REG_NAMED(DBGFREGVALTYPE_U64, u64, uTrapFrameAddr, "TrapFrame");
430 ADD_REG_NAMED(DBGFREGVALTYPE_U8, u8, TrapFrame.ExceptionActive, "ExceptionActive");
431 if (TrapFrame.ExceptionActive == 0)
432 {
433 ADD_REG_NAMED(DBGFREGVALTYPE_U8, u8, TrapFrame.PreviousIrql, "PrevIrql");
434 ADD_REG_NAMED(DBGFREGVALTYPE_U8, u8, (uint8_t)TrapFrame.ErrCdOrXcptFrameOrS, "IntNo");
435 }
436 else if ( TrapFrame.ExceptionActive == 1
437 && TrapFrame.FaultIndicator == ((TrapFrame.ErrCdOrXcptFrameOrS >> 1) & 0x9))
438 ADD_REG_NAMED(DBGFREGVALTYPE_U64, u64, TrapFrame.FaultAddrOrCtxRecOrTS, "cr2-probably");
439 if (TrapFrame.SegCs & X86_SEL_RPL)
440 ADD_REG_NAMED(DBGFREGVALTYPE_U8, u8, 1, "UserMode");
441 else
442 ADD_REG_NAMED(DBGFREGVALTYPE_U8, u8, 1, "KernelMode");
443 if (TrapFrame.ExceptionActive <= 1)
444 {
445 MAYBE_ADD_GREG(TrapFrame.Rax, DBGFREG_RAX, X86_GREG_xAX);
446 MAYBE_ADD_GREG(TrapFrame.Rcx, DBGFREG_RCX, X86_GREG_xCX);
447 MAYBE_ADD_GREG(TrapFrame.Rdx, DBGFREG_RDX, X86_GREG_xDX);
448 MAYBE_ADD_GREG(TrapFrame.R8, DBGFREG_R8, X86_GREG_x8);
449 MAYBE_ADD_GREG(TrapFrame.R9, DBGFREG_R9, X86_GREG_x9);
450 MAYBE_ADD_GREG(TrapFrame.R10, DBGFREG_R10, X86_GREG_x10);
451 MAYBE_ADD_GREG(TrapFrame.R11, DBGFREG_R11, X86_GREG_x11);
452 }
453 else if (TrapFrame.ExceptionActive == 2)
454 {
455 MAYBE_ADD_GREG(TrapFrame.Rbx, DBGFREG_RBX, X86_GREG_xBX);
456 MAYBE_ADD_GREG(TrapFrame.Rsi, DBGFREG_RSI, X86_GREG_xSI);
457 MAYBE_ADD_GREG(TrapFrame.Rdi, DBGFREG_RDI, X86_GREG_xDI);
458 }
459 MAYBE_ADD_GREG(TrapFrame.Rbp, DBGFREG_RBP, X86_GREG_xBP);
460
461 /* Done? */
462 if (iLoop > 0)
463 {
464 Assert(cRegs == iReg);
465 break;
466 }
467
468 /* Resize the array, zeroing the extension. */
469 if (pFrame->cSureRegs)
470 paSureRegs = (PDBGFREGVALEX)MMR3HeapRealloc(pFrame->paSureRegs, iReg * sizeof(paSureRegs[0]));
471 else
472 paSureRegs = (PDBGFREGVALEX)MMR3HeapAllocU(pUVM, MM_TAG_DBGF_STACK, iReg * sizeof(paSureRegs[0]));
473 AssertReturn(paSureRegs, VERR_NO_MEMORY);
474
475 pFrame->paSureRegs = paSureRegs;
476 RT_BZERO(&paSureRegs[pFrame->cSureRegs], (iReg - pFrame->cSureRegs) * sizeof(paSureRegs[0]));
477 cRegs = iReg;
478 }
479#undef ADD_REG_NAMED
480#undef MAYBE_ADD_GREG
481
482 /* Commit the register update. */
483 pFrame->cSureRegs = cRegs;
484 }
485 }
486 }
487 }
488
489 RT_NOREF(pUVM, pvData, idCpu, hAs, pInitialCtx, puScratch);
490 return VINF_SUCCESS;
491}
492
493
494/**
495 * @copydoc DBGFOSREG::pfnQueryInterface
496 */
497static DECLCALLBACK(void *) dbgDiggerWinNtQueryInterface(PUVM pUVM, void *pvData, DBGFOSINTERFACE enmIf)
498{
499 RT_NOREF3(pUVM, pvData, enmIf);
500 return NULL;
501}
502
503
504/**
505 * @copydoc DBGFOSREG::pfnQueryVersion
506 */
507static DECLCALLBACK(int) dbgDiggerWinNtQueryVersion(PUVM pUVM, void *pvData, char *pszVersion, size_t cchVersion)
508{
509 RT_NOREF1(pUVM);
510 PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
511 Assert(pThis->fValid);
512 const char *pszNtProductType;
513 switch (pThis->NtProductType)
514 {
515 case kNtProductType_WinNt: pszNtProductType = "-WinNT"; break;
516 case kNtProductType_LanManNt: pszNtProductType = "-LanManNT"; break;
517 case kNtProductType_Server: pszNtProductType = "-Server"; break;
518 default: pszNtProductType = ""; break;
519 }
520 RTStrPrintf(pszVersion, cchVersion, "%u.%u-%s%s", pThis->NtMajorVersion, pThis->NtMinorVersion,
521 pThis->f32Bit ? "x86" : "AMD64", pszNtProductType);
522 return VINF_SUCCESS;
523}
524
525
526/**
527 * @copydoc DBGFOSREG::pfnTerm
528 */
529static DECLCALLBACK(void) dbgDiggerWinNtTerm(PUVM pUVM, void *pvData)
530{
531 RT_NOREF1(pUVM);
532 PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
533 Assert(pThis->fValid);
534
535 /*
536 * As long as we're using our private LDR reader implementation,
537 * we must unlink and ditch the modules we created.
538 */
539 RTDBGAS hDbgAs = DBGFR3AsResolveAndRetain(pUVM, DBGF_AS_KERNEL);
540 if (hDbgAs != NIL_RTDBGAS)
541 {
542 uint32_t iMod = RTDbgAsModuleCount(hDbgAs);
543 while (iMod-- > 0)
544 {
545 RTDBGMOD hMod = RTDbgAsModuleByIndex(hDbgAs, iMod);
546 if (hMod != NIL_RTDBGMOD)
547 {
548 if (RTDbgModGetTag(hMod) == DIG_WINNT_MOD_TAG)
549 {
550 int rc = RTDbgAsModuleUnlink(hDbgAs, hMod);
551 AssertRC(rc);
552 }
553 RTDbgModRelease(hMod);
554 }
555 }
556 RTDbgAsRelease(hDbgAs);
557 }
558
559 pThis->fValid = false;
560}
561
562
563/**
564 * @copydoc DBGFOSREG::pfnRefresh
565 */
566static DECLCALLBACK(int) dbgDiggerWinNtRefresh(PUVM pUVM, void *pvData)
567{
568 PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
569 NOREF(pThis);
570 Assert(pThis->fValid);
571
572 /*
573 * For now we'll flush and reload everything.
574 */
575 dbgDiggerWinNtTerm(pUVM, pvData);
576
577 return dbgDiggerWinNtInit(pUVM, pvData);
578}
579
580
581/**
582 * @copydoc DBGFOSREG::pfnInit
583 */
584static DECLCALLBACK(int) dbgDiggerWinNtInit(PUVM pUVM, void *pvData)
585{
586 PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
587 Assert(!pThis->fValid);
588
589 union
590 {
591 uint8_t au8[0x2000];
592 RTUTF16 wsz[0x2000/2];
593 NTKUSERSHAREDDATA UserSharedData;
594 } u;
595 DBGFADDRESS Addr;
596 int rc;
597
598 /*
599 * Figure the NT version.
600 */
601 DBGFR3AddrFromFlat(pUVM, &Addr, pThis->f32Bit ? NTKUSERSHAREDDATA_WINNT32 : NTKUSERSHAREDDATA_WINNT64);
602 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &Addr, &u, PAGE_SIZE);
603 if (RT_SUCCESS(rc))
604 {
605 pThis->NtProductType = u.UserSharedData.ProductTypeIsValid && u.UserSharedData.NtProductType <= kNtProductType_Server
606 ? (NTPRODUCTTYPE)u.UserSharedData.NtProductType
607 : kNtProductType_Invalid;
608 pThis->NtMajorVersion = u.UserSharedData.NtMajorVersion;
609 pThis->NtMinorVersion = u.UserSharedData.NtMinorVersion;
610 }
611 else if (pThis->fNt31)
612 {
613 pThis->NtProductType = kNtProductType_WinNt;
614 pThis->NtMajorVersion = 3;
615 pThis->NtMinorVersion = 1;
616 }
617 else
618 {
619 Log(("DigWinNt: Error reading KUSER_SHARED_DATA: %Rrc\n", rc));
620 return rc;
621 }
622
623 /*
624 * Dig out the module chain.
625 */
626 DBGFADDRESS AddrPrev = pThis->PsLoadedModuleListAddr;
627 Addr = pThis->KernelMteAddr;
628 do
629 {
630 /* Read the validate the MTE. */
631 NTMTE Mte;
632 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &Addr, &Mte, pThis->f32Bit ? sizeof(Mte.vX_32) : sizeof(Mte.vX_64));
633 if (RT_FAILURE(rc))
634 break;
635 if (WINNT_UNION(pThis, &Mte, InLoadOrderLinks.Blink) != AddrPrev.FlatPtr)
636 {
637 Log(("DigWinNt: Bad Mte At %RGv - backpointer\n", Addr.FlatPtr));
638 break;
639 }
640 if (!WINNT_VALID_ADDRESS(pThis, WINNT_UNION(pThis, &Mte, InLoadOrderLinks.Flink)) )
641 {
642 Log(("DigWinNt: Bad Mte at %RGv - forward pointer\n", Addr.FlatPtr));
643 break;
644 }
645 if (!WINNT_VALID_ADDRESS(pThis, WINNT_UNION(pThis, &Mte, BaseDllName.Buffer)))
646 {
647 Log(("DigWinNt: Bad Mte at %RGv - BaseDllName=%llx\n", Addr.FlatPtr, WINNT_UNION(pThis, &Mte, BaseDllName.Buffer)));
648 break;
649 }
650 if (!WINNT_VALID_ADDRESS(pThis, WINNT_UNION(pThis, &Mte, FullDllName.Buffer)))
651 {
652 Log(("DigWinNt: Bad Mte at %RGv - FullDllName=%llx\n", Addr.FlatPtr, WINNT_UNION(pThis, &Mte, FullDllName.Buffer)));
653 break;
654 }
655 if (!WINNT_VALID_ADDRESS(pThis, WINNT_UNION(pThis, &Mte, DllBase)))
656 {
657 Log(("DigWinNt: Bad Mte at %RGv - DllBase=%llx\n", Addr.FlatPtr, WINNT_UNION(pThis, &Mte, DllBase) ));
658 break;
659 }
660
661 uint32_t const cbImageMte = !pThis->fNt31 ? WINNT_UNION(pThis, &Mte, SizeOfImage) : 0;
662 if ( !pThis->fNt31
663 && ( cbImageMte > _256M
664 || WINNT_UNION(pThis, &Mte, EntryPoint) - WINNT_UNION(pThis, &Mte, DllBase) > cbImageMte) )
665 {
666 Log(("DigWinNt: Bad Mte at %RGv - EntryPoint=%llx SizeOfImage=%x DllBase=%llx\n",
667 Addr.FlatPtr, WINNT_UNION(pThis, &Mte, EntryPoint), cbImageMte, WINNT_UNION(pThis, &Mte, DllBase)));
668 break;
669 }
670
671 /* Read the full name. */
672 DBGFADDRESS AddrName;
673 DBGFR3AddrFromFlat(pUVM, &AddrName, WINNT_UNION(pThis, &Mte, FullDllName.Buffer));
674 uint16_t cbName = WINNT_UNION(pThis, &Mte, FullDllName.Length);
675 if (cbName < sizeof(u))
676 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &AddrName, &u, cbName);
677 else
678 rc = VERR_OUT_OF_RANGE;
679 if (RT_FAILURE(rc))
680 {
681 DBGFR3AddrFromFlat(pUVM, &AddrName, WINNT_UNION(pThis, &Mte, BaseDllName.Buffer));
682 cbName = WINNT_UNION(pThis, &Mte, BaseDllName.Length);
683 if (cbName < sizeof(u))
684 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &AddrName, &u, cbName);
685 else
686 rc = VERR_OUT_OF_RANGE;
687 }
688 if (RT_SUCCESS(rc))
689 {
690 u.wsz[cbName / 2] = '\0';
691
692 char *pszName;
693 rc = RTUtf16ToUtf8(u.wsz, &pszName);
694 if (RT_SUCCESS(rc))
695 {
696 /* Read the start of the PE image and pass it along to a worker. */
697 DBGFADDRESS ImageAddr;
698 DBGFR3AddrFromFlat(pUVM, &ImageAddr, WINNT_UNION(pThis, &Mte, DllBase));
699 dbgDiggerWinNtProcessImage(pThis, pUVM, pszName, &ImageAddr, cbImageMte);
700 RTStrFree(pszName);
701 }
702 }
703
704 /* next */
705 AddrPrev = Addr;
706 DBGFR3AddrFromFlat(pUVM, &Addr, WINNT_UNION(pThis, &Mte, InLoadOrderLinks.Flink));
707 } while ( Addr.FlatPtr != pThis->KernelMteAddr.FlatPtr
708 && Addr.FlatPtr != pThis->PsLoadedModuleListAddr.FlatPtr);
709
710 pThis->fValid = true;
711 return VINF_SUCCESS;
712}
713
714
715/**
716 * @copydoc DBGFOSREG::pfnProbe
717 */
718static DECLCALLBACK(bool) dbgDiggerWinNtProbe(PUVM pUVM, void *pvData)
719{
720 PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
721 DBGFADDRESS Addr;
722 union
723 {
724 uint8_t au8[8192];
725 uint16_t au16[8192/2];
726 uint32_t au32[8192/4];
727 IMAGE_DOS_HEADER MzHdr;
728 RTUTF16 wsz[8192/2];
729 X86DESC64GATE a32Gates[X86_XCPT_PF + 1];
730 X86DESC64GATE a64Gates[X86_XCPT_PF + 1];
731 } u;
732
733 union
734 {
735 NTMTE32 v32;
736 NTMTE64 v64;
737 } uMte, uMte2, uMte3;
738
739 /*
740 * NT only runs in protected or long mode.
741 */
742 CPUMMODE const enmMode = DBGFR3CpuGetMode(pUVM, 0 /*idCpu*/);
743 if (enmMode != CPUMMODE_PROTECTED && enmMode != CPUMMODE_LONG)
744 return false;
745 bool const f64Bit = enmMode == CPUMMODE_LONG;
746 uint64_t const uStart = f64Bit ? UINT64_C(0xffff080000000000) : UINT32_C(0x80001000);
747 uint64_t const uEnd = f64Bit ? UINT64_C(0xffffffffffff0000) : UINT32_C(0xffff0000);
748
749 /*
750 * To approximately locate the kernel we examine the IDTR handlers.
751 *
752 * The exception/trap/fault handlers are all in NT kernel image, we pick
753 * KiPageFault here.
754 */
755 uint64_t uIdtrBase = 0;
756 uint16_t uIdtrLimit = 0;
757 int rc = DBGFR3RegCpuQueryXdtr(pUVM, 0, DBGFREG_IDTR, &uIdtrBase, &uIdtrLimit);
758 AssertRCReturn(rc, false);
759
760 const uint16_t cbMinIdtr = (X86_XCPT_PF + 1) * (f64Bit ? sizeof(X86DESC64GATE) : sizeof(X86DESCGATE));
761 if (uIdtrLimit < cbMinIdtr)
762 return false;
763
764 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pUVM, &Addr, uIdtrBase), &u, cbMinIdtr);
765 if (RT_FAILURE(rc))
766 return false;
767
768 uint64_t uKrnlStart = uStart;
769 uint64_t uKrnlEnd = uEnd;
770 if (f64Bit)
771 {
772 uint64_t uHandler = u.a64Gates[X86_XCPT_PF].u16OffsetLow
773 | ((uint32_t)u.a64Gates[X86_XCPT_PF].u16OffsetHigh << 16)
774 | ((uint64_t)u.a64Gates[X86_XCPT_PF].u32OffsetTop << 32);
775 if (uHandler < uStart || uHandler > uEnd)
776 return false;
777 uKrnlStart = (uHandler & ~(uint64_t)_4M) - _512M;
778 uKrnlEnd = (uHandler + (uint64_t)_4M) & ~(uint64_t)_4M;
779 }
780 else
781 {
782 uint32_t uHandler = u.a32Gates[X86_XCPT_PF].u16OffsetLow
783 | ((uint32_t)u.a64Gates[X86_XCPT_PF].u16OffsetHigh << 16);
784 if (uHandler < uStart || uHandler > uEnd)
785 return false;
786 uKrnlStart = (uHandler & ~(uint64_t)_4M) - _64M;
787 uKrnlEnd = (uHandler + (uint64_t)_4M) & ~(uint64_t)_4M;
788 }
789
790 /*
791 * Look for the PAGELK section name that seems to be a part of all kernels.
792 * Then try find the module table entry for it. Since it's the first entry
793 * in the PsLoadedModuleList we can easily validate the list head and report
794 * success.
795 *
796 * Note! We ASSUME the section name is 8 byte aligned.
797 */
798 DBGFADDRESS KernelAddr;
799 for (DBGFR3AddrFromFlat(pUVM, &KernelAddr, uKrnlStart);
800 KernelAddr.FlatPtr < uKrnlEnd;
801 KernelAddr.FlatPtr += PAGE_SIZE)
802 {
803 bool fNt31 = false;
804 DBGFADDRESS const RetryAddress = KernelAddr;
805 rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &KernelAddr, uEnd - KernelAddr.FlatPtr,
806 8, "PAGELK\0", sizeof("PAGELK\0"), &KernelAddr);
807 if ( rc == VERR_DBGF_MEM_NOT_FOUND
808 && enmMode != CPUMMODE_LONG)
809 {
810 /* NT3.1 didn't have a PAGELK section, so look for _TEXT instead. The
811 following VirtualSize is zero, so check for that too. */
812 rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &RetryAddress, uEnd - RetryAddress.FlatPtr,
813 8, "_TEXT\0\0\0\0\0\0", sizeof("_TEXT\0\0\0\0\0\0"), &KernelAddr);
814 fNt31 = true;
815 }
816 if (RT_FAILURE(rc))
817 break;
818 DBGFR3AddrSub(&KernelAddr, KernelAddr.FlatPtr & PAGE_OFFSET_MASK);
819
820 /* MZ + PE header. */
821 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &KernelAddr, &u, sizeof(u));
822 if ( RT_SUCCESS(rc)
823 && u.MzHdr.e_magic == IMAGE_DOS_SIGNATURE
824 && !(u.MzHdr.e_lfanew & 0x7)
825 && u.MzHdr.e_lfanew >= 0x080
826 && u.MzHdr.e_lfanew <= 0x400) /* W8 is at 0x288*/
827 {
828 if (enmMode != CPUMMODE_LONG)
829 {
830 IMAGE_NT_HEADERS32 const *pHdrs = (IMAGE_NT_HEADERS32 const *)&u.au8[u.MzHdr.e_lfanew];
831 if ( pHdrs->Signature == IMAGE_NT_SIGNATURE
832 && pHdrs->FileHeader.Machine == IMAGE_FILE_MACHINE_I386
833 && pHdrs->FileHeader.SizeOfOptionalHeader == sizeof(pHdrs->OptionalHeader)
834 && pHdrs->FileHeader.NumberOfSections >= 10 /* the kernel has lots */
835 && (pHdrs->FileHeader.Characteristics & (IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL)) == IMAGE_FILE_EXECUTABLE_IMAGE
836 && pHdrs->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC
837 && pHdrs->OptionalHeader.NumberOfRvaAndSizes == IMAGE_NUMBEROF_DIRECTORY_ENTRIES
838 )
839 {
840 /* Find the MTE. */
841 RT_ZERO(uMte);
842 uMte.v32.DllBase = KernelAddr.FlatPtr;
843 uMte.v32.EntryPoint = KernelAddr.FlatPtr + pHdrs->OptionalHeader.AddressOfEntryPoint;
844 uMte.v32.SizeOfImage = !fNt31 ? pHdrs->OptionalHeader.SizeOfImage : 0; /* NT 3.1 didn't set the size. */
845 DBGFADDRESS HitAddr;
846 rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &KernelAddr, uEnd - KernelAddr.FlatPtr,
847 4 /*align*/, &uMte.v32.DllBase, 3 * sizeof(uint32_t), &HitAddr);
848 while (RT_SUCCESS(rc))
849 {
850 /* check the name. */
851 DBGFADDRESS MteAddr = HitAddr;
852 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrSub(&MteAddr, RT_OFFSETOF(NTMTE32, DllBase)),
853 &uMte2.v32, sizeof(uMte2.v32));
854 if ( RT_SUCCESS(rc)
855 && uMte2.v32.DllBase == uMte.v32.DllBase
856 && uMte2.v32.EntryPoint == uMte.v32.EntryPoint
857 && uMte2.v32.SizeOfImage == uMte.v32.SizeOfImage
858 && WINNT32_VALID_ADDRESS(uMte2.v32.InLoadOrderLinks.Flink)
859 && WINNT32_VALID_ADDRESS(uMte2.v32.BaseDllName.Buffer)
860 && WINNT32_VALID_ADDRESS(uMte2.v32.FullDllName.Buffer)
861 && uMte2.v32.BaseDllName.Length <= 128
862 && uMte2.v32.FullDllName.Length <= 260
863 )
864 {
865 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pUVM, &Addr, uMte2.v32.BaseDllName.Buffer),
866 u.wsz, uMte2.v32.BaseDllName.Length);
867 u.wsz[uMte2.v32.BaseDllName.Length / 2] = '\0';
868 if ( RT_SUCCESS(rc)
869 && ( !RTUtf16ICmp(u.wsz, g_wszKernelNames[0])
870 /* || !RTUtf16ICmp(u.wsz, g_wszKernelNames[1]) */
871 )
872 )
873 {
874 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/,
875 DBGFR3AddrFromFlat(pUVM, &Addr, uMte2.v32.InLoadOrderLinks.Blink),
876 &uMte3.v32, RT_SIZEOFMEMB(NTMTE32, InLoadOrderLinks));
877 if ( RT_SUCCESS(rc)
878 && uMte3.v32.InLoadOrderLinks.Flink == MteAddr.FlatPtr
879 && WINNT32_VALID_ADDRESS(uMte3.v32.InLoadOrderLinks.Blink) )
880 {
881 Log(("DigWinNt: MteAddr=%RGv KernelAddr=%RGv SizeOfImage=%x &PsLoadedModuleList=%RGv (32-bit)\n",
882 MteAddr.FlatPtr, KernelAddr.FlatPtr, uMte2.v32.SizeOfImage, Addr.FlatPtr));
883 pThis->KernelAddr = KernelAddr;
884 pThis->KernelMteAddr = MteAddr;
885 pThis->PsLoadedModuleListAddr = Addr;
886 pThis->f32Bit = true;
887 pThis->fNt31 = fNt31;
888 return true;
889 }
890 }
891 else if (RT_SUCCESS(rc))
892 {
893 Log2(("DigWinNt: Wrong module: MteAddr=%RGv ImageAddr=%RGv SizeOfImage=%#x '%ls'\n",
894 MteAddr.FlatPtr, KernelAddr.FlatPtr, uMte2.v32.SizeOfImage, u.wsz));
895 break; /* Not NT kernel */
896 }
897 }
898
899 /* next */
900 DBGFR3AddrAdd(&HitAddr, 4);
901 if (HitAddr.FlatPtr < uEnd)
902 rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &HitAddr, uEnd - HitAddr.FlatPtr,
903 4 /*align*/, &uMte.v32.DllBase, 3 * sizeof(uint32_t), &HitAddr);
904 else
905 rc = VERR_DBGF_MEM_NOT_FOUND;
906 }
907 }
908 }
909 else
910 {
911 IMAGE_NT_HEADERS64 const *pHdrs = (IMAGE_NT_HEADERS64 const *)&u.au8[u.MzHdr.e_lfanew];
912 if ( pHdrs->Signature == IMAGE_NT_SIGNATURE
913 && pHdrs->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64
914 && pHdrs->FileHeader.SizeOfOptionalHeader == sizeof(pHdrs->OptionalHeader)
915 && pHdrs->FileHeader.NumberOfSections >= 10 /* the kernel has lots */
916 && (pHdrs->FileHeader.Characteristics & (IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL))
917 == IMAGE_FILE_EXECUTABLE_IMAGE
918 && pHdrs->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC
919 && pHdrs->OptionalHeader.NumberOfRvaAndSizes == IMAGE_NUMBEROF_DIRECTORY_ENTRIES
920 )
921 {
922 /* Find the MTE. */
923 RT_ZERO(uMte.v64);
924 uMte.v64.DllBase = KernelAddr.FlatPtr;
925 uMte.v64.EntryPoint = KernelAddr.FlatPtr + pHdrs->OptionalHeader.AddressOfEntryPoint;
926 uMte.v64.SizeOfImage = pHdrs->OptionalHeader.SizeOfImage;
927 DBGFADDRESS ScanAddr;
928 DBGFADDRESS HitAddr;
929 rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pUVM, &ScanAddr, uStart),
930 uEnd - uStart, 8 /*align*/, &uMte.v64.DllBase, 5 * sizeof(uint32_t), &HitAddr);
931 while (RT_SUCCESS(rc))
932 {
933 /* Read the start of the MTE and check some basic members. */
934 DBGFADDRESS MteAddr = HitAddr;
935 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrSub(&MteAddr, RT_OFFSETOF(NTMTE64, DllBase)),
936 &uMte2.v64, sizeof(uMte2.v64));
937 if ( RT_SUCCESS(rc)
938 && uMte2.v64.DllBase == uMte.v64.DllBase
939 && uMte2.v64.EntryPoint == uMte.v64.EntryPoint
940 && uMte2.v64.SizeOfImage == uMte.v64.SizeOfImage
941 && WINNT64_VALID_ADDRESS(uMte2.v64.InLoadOrderLinks.Flink)
942 && WINNT64_VALID_ADDRESS(uMte2.v64.BaseDllName.Buffer)
943 && WINNT64_VALID_ADDRESS(uMte2.v64.FullDllName.Buffer)
944 && uMte2.v64.BaseDllName.Length <= 128
945 && uMte2.v64.FullDllName.Length <= 260
946 )
947 {
948 /* Try read the base name and compare with known NT kernel names. */
949 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pUVM, &Addr, uMte2.v64.BaseDllName.Buffer),
950 u.wsz, uMte2.v64.BaseDllName.Length);
951 u.wsz[uMte2.v64.BaseDllName.Length / 2] = '\0';
952 if ( RT_SUCCESS(rc)
953 && ( !RTUtf16ICmp(u.wsz, g_wszKernelNames[0])
954 /* || !RTUtf16ICmp(u.wsz, g_wszKernelNames[1]) */
955 )
956 )
957 {
958 /* Read the link entry of the previous entry in the list and check that its
959 forward pointer points at the MTE we've found. */
960 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/,
961 DBGFR3AddrFromFlat(pUVM, &Addr, uMte2.v64.InLoadOrderLinks.Blink),
962 &uMte3.v64, RT_SIZEOFMEMB(NTMTE64, InLoadOrderLinks));
963 if ( RT_SUCCESS(rc)
964 && uMte3.v64.InLoadOrderLinks.Flink == MteAddr.FlatPtr
965 && WINNT64_VALID_ADDRESS(uMte3.v64.InLoadOrderLinks.Blink) )
966 {
967 Log(("DigWinNt: MteAddr=%RGv KernelAddr=%RGv SizeOfImage=%x &PsLoadedModuleList=%RGv (32-bit)\n",
968 MteAddr.FlatPtr, KernelAddr.FlatPtr, uMte2.v64.SizeOfImage, Addr.FlatPtr));
969 pThis->KernelAddr = KernelAddr;
970 pThis->KernelMteAddr = MteAddr;
971 pThis->PsLoadedModuleListAddr = Addr;
972 pThis->f32Bit = false;
973 pThis->fNt31 = false;
974 return true;
975 }
976 }
977 else if (RT_SUCCESS(rc))
978 {
979 Log2(("DigWinNt: Wrong module: MteAddr=%RGv ImageAddr=%RGv SizeOfImage=%#x '%ls'\n",
980 MteAddr.FlatPtr, KernelAddr.FlatPtr, uMte2.v64.SizeOfImage, u.wsz));
981 break; /* Not NT kernel */
982 }
983 }
984
985 /* next */
986 DBGFR3AddrAdd(&HitAddr, 8);
987 if (HitAddr.FlatPtr < uEnd)
988 rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &HitAddr, uEnd - HitAddr.FlatPtr,
989 8 /*align*/, &uMte.v64.DllBase, 3 * sizeof(uint32_t), &HitAddr);
990 else
991 rc = VERR_DBGF_MEM_NOT_FOUND;
992 }
993 }
994 }
995 }
996 }
997 return false;
998}
999
1000
1001/**
1002 * @copydoc DBGFOSREG::pfnDestruct
1003 */
1004static DECLCALLBACK(void) dbgDiggerWinNtDestruct(PUVM pUVM, void *pvData)
1005{
1006 RT_NOREF2(pUVM, pvData);
1007}
1008
1009
1010/**
1011 * @copydoc DBGFOSREG::pfnConstruct
1012 */
1013static DECLCALLBACK(int) dbgDiggerWinNtConstruct(PUVM pUVM, void *pvData)
1014{
1015 RT_NOREF1(pUVM);
1016 PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
1017 pThis->fValid = false;
1018 pThis->f32Bit = false;
1019 pThis->enmVer = DBGDIGGERWINNTVER_UNKNOWN;
1020 return VINF_SUCCESS;
1021}
1022
1023
1024const DBGFOSREG g_DBGDiggerWinNt =
1025{
1026 /* .u32Magic = */ DBGFOSREG_MAGIC,
1027 /* .fFlags = */ 0,
1028 /* .cbData = */ sizeof(DBGDIGGERWINNT),
1029 /* .szName = */ "WinNT",
1030 /* .pfnConstruct = */ dbgDiggerWinNtConstruct,
1031 /* .pfnDestruct = */ dbgDiggerWinNtDestruct,
1032 /* .pfnProbe = */ dbgDiggerWinNtProbe,
1033 /* .pfnInit = */ dbgDiggerWinNtInit,
1034 /* .pfnRefresh = */ dbgDiggerWinNtRefresh,
1035 /* .pfnTerm = */ dbgDiggerWinNtTerm,
1036 /* .pfnQueryVersion = */ dbgDiggerWinNtQueryVersion,
1037 /* .pfnQueryInterface = */ dbgDiggerWinNtQueryInterface,
1038 /* .pfnStackUnwindAssist = */ dbgDiggerWinNtStackUnwindAssist,
1039 /* .u32EndMagic = */ DBGFOSREG_MAGIC
1040};
1041
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