VirtualBox

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

Last change on this file since 31510 was 31510, checked in by vboxsync, 14 years ago

The debugger is back in the OSE.

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