VirtualBox

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

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

DBGFStack,DBGPlugInWinNt.cpp: Heed the frame pointer; don't corrupt RBP with invalid trapframe info.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 43.7 KB
Line 
1/* $Id: DBGPlugInWinNt.cpp 73486 2018-08-03 13:59:46Z 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); - KiInterrupt[Sub]Dispatch* may leave this invalid.
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