VirtualBox

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

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

RTDbgModCreateFromPeImage: Mostly implemented.

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