VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/nt/dbgkrnlinfo-r0drv-nt.cpp@ 91633

最後變更 在這個檔案從91633是 91633,由 vboxsync 提交於 3 年 前

IPRT/dbg.h,dbgkrnlinfo-r0drv-nt.cpp: Added a few pseudo symbols to the NT kernel debug info provider to expose some basic module info (simpler than adding dedicated APIs for each of them). bugref:10118

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 37.5 KB
 
1/* $Id: dbgkrnlinfo-r0drv-nt.cpp 91633 2021-10-08 08:42:00Z vboxsync $ */
2/** @file
3 * IPRT - Kernel Debug Information, R0 Driver, NT.
4 */
5
6/*
7 * Copyright (C) 2006-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.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 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#define IMAGE_NT_HEADERS NT_IMAGE_NT_HEADERS
32#define IMAGE_NT_HEADERS32 NT_IMAGE_NT_HEADERS32
33#define IMAGE_NT_HEADERS64 NT_IMAGE_NT_HEADERS64
34#define PIMAGE_NT_HEADERS NT_PIMAGE_NT_HEADERS
35#define PIMAGE_NT_HEADERS32 NT_PIMAGE_NT_HEADERS32
36#define PIMAGE_NT_HEADERS64 NT_PIMAGE_NT_HEADERS64
37#ifndef IPRT_NT_MAP_TO_ZW
38# define IPRT_NT_MAP_TO_ZW
39#endif
40#include "the-nt-kernel.h"
41#include <iprt/dbg.h>
42
43#include <iprt/err.h>
44#include <iprt/log.h>
45#include <iprt/mem.h>
46#include <iprt/string.h>
47#include <iprt/utf16.h>
48#include "internal-r0drv-nt.h"
49#include "internal/magics.h"
50
51#undef IMAGE_NT_HEADERS
52#undef IMAGE_NT_HEADERS32
53#undef IMAGE_NT_HEADERS64
54#undef PIMAGE_NT_HEADERS
55#undef PIMAGE_NT_HEADERS32
56#undef PIMAGE_NT_HEADERS64
57#include <iprt/formats/pecoff.h>
58#include <iprt/formats/mz.h>
59
60
61/*********************************************************************************************************************************
62* Defined Constants And Macros *
63*********************************************************************************************************************************/
64/** Private logging macro, will use DbgPrint! */
65#ifdef IN_GUEST
66# define RTR0DBG_NT_ERROR_LOG(a) do { RTLogBackdoorPrintf a; DbgPrint a; } while (0)
67# define RTR0DBG_NT_DEBUG_LOG(a) do { RTLogBackdoorPrintf a; DbgPrint a; } while (0)
68#else
69# define RTR0DBG_NT_ERROR_LOG(a) do { DbgPrint a; } while (0)
70# define RTR0DBG_NT_DEBUG_LOG(a) do { DbgPrint a; } while (0)
71#endif
72#ifndef LOG_ENABLED
73# undef RTR0DBG_NT_DEBUG_LOG
74# define RTR0DBG_NT_DEBUG_LOG(a) do { } while (0)
75#endif
76
77
78/*********************************************************************************************************************************
79* Structures and Typedefs *
80*********************************************************************************************************************************/
81#define PIMAGE_NT_HEADERS RT_CONCAT(PIMAGE_NT_HEADERS, ARCH_BITS)
82
83/**
84 * Information we cache for a kernel module.
85 */
86typedef struct RTDBGNTKRNLMODINFO
87{
88 /** The module name. */
89 char szName[32];
90
91 /** The image base. */
92 uint8_t const *pbImageBase;
93 /** The NT headers. */
94 PIMAGE_NT_HEADERS pNtHdrs;
95 /** Set if this module parsed okay and all fields are valid. */
96 bool fOkay;
97 /** The NT header offset/RVA. */
98 uint32_t offNtHdrs;
99 /** The end of the section headers. */
100 uint32_t offEndSectHdrs;
101 /** The end of the image. */
102 uint32_t cbImage;
103 /** Offset of the export directory. */
104 uint32_t offExportDir;
105 /** Size of the export directory. */
106 uint32_t cbExportDir;
107
108 /** Exported functions and data by ordinal (RVAs). */
109 uint32_t const *paoffExports;
110 /** The number of exports. */
111 uint32_t cExports;
112 /** The number of exported names. */
113 uint32_t cNamedExports;
114 /** Pointer to the array of exported names (RVAs to strings). */
115 uint32_t const *paoffNamedExports;
116 /** Array parallel to paoffNamedExports with the corresponding ordinals
117 * (indexes into paoffExports). */
118 uint16_t const *pau16NameOrdinals;
119} RTDBGNTKRNLMODINFO;
120/** Pointer to kernel module info. */
121typedef RTDBGNTKRNLMODINFO *PRTDBGNTKRNLMODINFO;
122/** Pointer to const kernel module info. */
123typedef RTDBGNTKRNLMODINFO const *PCRTDBGNTKRNLMODINFO;
124
125
126/**
127 * NT kernel info instance.
128 */
129typedef struct RTDBGKRNLINFOINT
130{
131 /** Magic value (RTDBGKRNLINFO_MAGIC). */
132 uint32_t u32Magic;
133 /** Reference counter. */
134 uint32_t volatile cRefs;
135 /** Number of additional modules in the cache. */
136 uint32_t cModules;
137 /** Additional modules. */
138 RTDBGNTKRNLMODINFO aModules[3];
139} RTDBGKRNLINFOINT;
140
141
142
143/*********************************************************************************************************************************
144* Global Variables *
145*********************************************************************************************************************************/
146/** Pointer to MmGetSystemRoutineAddress.
147 * @note Added in NT v5.0. */
148static decltype(MmGetSystemRoutineAddress) *g_pfnMmGetSystemRoutineAddress = NULL;
149/** Info about the ntoskrnl.exe mapping. */
150static RTDBGNTKRNLMODINFO g_NtOsKrnlInfo = { "ntoskrnl.exe", NULL, NULL, false, 0, 0, 0, 0, 0, NULL, 0, 0, NULL, NULL };
151/** Info about the hal.dll mapping. */
152static RTDBGNTKRNLMODINFO g_HalInfo = { "hal.dll", NULL, NULL, false, 0, 0, 0, 0, 0, NULL, 0, 0, NULL, NULL };
153
154
155
156/**
157 * Looks up an symbol int the export table.
158 *
159 * @returns VINF_SUCCESS or VERR_SYMBOL_NOT_FOUND.
160 * @param pModInfo The module info.
161 * @param pszSymbol The symbol to find.
162 * @param cForwarders Forwarder nesting depth.
163 * @param ppvSymbol Where to put the symbol address.
164 *
165 * @note Support library has similar code for in the importless area.
166 */
167static int rtR0DbgKrnlInfoLookupSymbol(PCRTDBGNTKRNLMODINFO pModInfo, const char *pszSymbol, unsigned cForwarders,
168 void **ppvSymbol)
169{
170 if (pModInfo->fOkay)
171 {
172 /*
173 * Pseudo symbols:
174 */
175 if ( pszSymbol[0] == '_'
176 && pszSymbol[1] == '_'
177 && pszSymbol[2] == 'I')
178 {
179 if (strcmp(pszSymbol, "__ImageBase") == 0)
180 {
181 *ppvSymbol = (void *)pModInfo->pbImageBase;
182 return VINF_SUCCESS;
183 }
184 if (strcmp(pszSymbol, "__ImageSize") == 0)
185 {
186 *ppvSymbol = (void *)(uintptr_t)pModInfo->cbImage;
187 return VINF_SUCCESS;
188 }
189 if (strcmp(pszSymbol, "__ImageNtHdrs") == 0)
190 {
191 *ppvSymbol = pModInfo->pNtHdrs;
192 return VINF_SUCCESS;
193 }
194 }
195
196 /*
197 * Binary search.
198 */
199 __try
200 {
201 uint32_t iStart = 0;
202 uint32_t iEnd = pModInfo->cNamedExports;
203 while (iStart < iEnd)
204 {
205 uint32_t iCur = iStart + (iEnd - iStart) / 2;
206 uint32_t offExpName = pModInfo->paoffNamedExports[iCur];
207 if (offExpName >= pModInfo->offEndSectHdrs && offExpName < pModInfo->cbImage)
208 { /* likely */ }
209 else
210 {
211 RTR0DBG_NT_ERROR_LOG(("rtR0DbgKrnlInfoLookupSymbol: %s: Bad export name entry: %#x (iCur=%#x)\n",
212 pModInfo->szName, offExpName, iCur));
213 break;
214 }
215
216 const char *pszExpName = (const char *)&pModInfo->pbImageBase[offExpName];
217 int iDiff = strcmp(pszExpName, pszSymbol);
218 if (iDiff > 0) /* pszExpName > pszSymbol: search chunck before i */
219 iEnd = iCur;
220 else if (iDiff < 0) /* pszExpName < pszSymbol: search chunk after i */
221 iStart = iCur + 1;
222 else /* pszExpName == pszSymbol */
223 {
224 uint16_t iExpOrdinal = pModInfo->pau16NameOrdinals[iCur];
225 if (iExpOrdinal < pModInfo->cExports)
226 {
227 uint32_t offExport = pModInfo->paoffExports[iExpOrdinal];
228 if (offExport - pModInfo->offExportDir >= pModInfo->cbExportDir)
229 {
230 *ppvSymbol = (void *)&pModInfo->pbImageBase[offExport];
231 return VINF_SUCCESS;
232 }
233
234 /*
235 * Deal with forwarders to NT and HAL. No ordinals.
236 */
237 const char *pszForwarder = (const char *)&pModInfo->pbImageBase[offExport];
238 uint32_t cbMax = pModInfo->cbImage - offExpName;
239 size_t cchForwarder = RTStrNLen(pszForwarder, cbMax);
240 if (cchForwarder < cbMax)
241 {
242 if ( cchForwarder > 9
243 && pModInfo != &g_NtOsKrnlInfo
244 && g_NtOsKrnlInfo.pbImageBase != NULL
245 && cForwarders < 2
246 && (pszForwarder[0] == 'n' || pszForwarder[0] == 'N')
247 && (pszForwarder[1] == 't' || pszForwarder[1] == 'T')
248 && (pszForwarder[2] == 'o' || pszForwarder[2] == 'O')
249 && (pszForwarder[3] == 's' || pszForwarder[3] == 'S')
250 && (pszForwarder[4] == 'k' || pszForwarder[4] == 'K')
251 && (pszForwarder[5] == 'r' || pszForwarder[5] == 'R')
252 && (pszForwarder[6] == 'n' || pszForwarder[6] == 'N')
253 && (pszForwarder[7] == 'l' || pszForwarder[7] == 'L')
254 && pszForwarder[8] == '.')
255 return rtR0DbgKrnlInfoLookupSymbol(&g_NtOsKrnlInfo, pszForwarder + 9, cForwarders + 1, ppvSymbol);
256
257 if ( cchForwarder > 4
258 && pModInfo != &g_HalInfo
259 && g_HalInfo.pbImageBase != NULL
260 && cForwarders < 2
261 && (pszForwarder[0] == 'h' || pszForwarder[0] == 'H')
262 && (pszForwarder[1] == 'a' || pszForwarder[1] == 'A')
263 && (pszForwarder[2] == 'l' || pszForwarder[2] == 'L')
264 && pszForwarder[3] == '.')
265 return rtR0DbgKrnlInfoLookupSymbol(&g_HalInfo, pszForwarder + 4, cForwarders + 1, ppvSymbol);
266 }
267
268 RTR0DBG_NT_ERROR_LOG(("rtR0DbgKrnlInfoLookupSymbol: %s: Forwarded symbol '%s': offExport=%#x (dir %#x LB %#x)\n",
269 pModInfo->szName, pszSymbol, offExport, pModInfo->offExportDir, pModInfo->cbExportDir));
270 }
271 else
272 RTR0DBG_NT_ERROR_LOG(("rtR0DbgKrnlInfoLookupSymbol: %s: Name ordinal for '%s' is out of bounds: %#x (max %#x)\n",
273 pModInfo->szName, iExpOrdinal, pModInfo->cExports));
274 break;
275 }
276 }
277 }
278 __except(EXCEPTION_EXECUTE_HANDLER)
279 {
280 RTR0DBG_NT_ERROR_LOG(("rtR0DbgKrnlInfoLookupSymbol: Exception searching '%s' for '%s'...\n",
281 pModInfo->szName, pszSymbol));
282 }
283 }
284
285 *ppvSymbol = NULL;
286 return VERR_SYMBOL_NOT_FOUND;
287}
288
289
290/**
291 * Parses (PE) module headers and fills in the coresponding module info struct.
292 *
293 * @returns true on if success, false if not.
294 * @param pModInfo The module info structure to fill in with parsed
295 * data. The szName and fOkay are set by the
296 * caller, this function does the rest.
297 * @param pbMapping The image mapping address
298 * @param cbMapping The image mapping size.
299 *
300 * @note Support library has similar code for in the importless area.
301 */
302static bool rtR0DbgKrnlNtParseModule(PRTDBGNTKRNLMODINFO pModInfo, uint8_t const *pbMapping, size_t cbMapping)
303{
304#define MODERR_RETURN(a_LogMsg, ...) \
305 do { RTR0DBG_NT_ERROR_LOG(("rtR0DbgKrnlNtParseModule: " a_LogMsg, __VA_ARGS__)); return false; } while (0)
306
307 pModInfo->pbImageBase = pbMapping;
308
309 /*
310 * Locate the PE header, do some basic validations.
311 */
312 IMAGE_DOS_HEADER const *pMzHdr = (IMAGE_DOS_HEADER const *)pbMapping;
313 uint32_t offNtHdrs = 0;
314 PIMAGE_NT_HEADERS pNtHdrs;
315 if (pMzHdr->e_magic == IMAGE_DOS_SIGNATURE)
316 {
317 offNtHdrs = pMzHdr->e_lfanew;
318 if (offNtHdrs > _2K)
319 MODERR_RETURN("%s: e_lfanew=%#x, expected a lower value\n", pModInfo->szName, offNtHdrs);
320 }
321 pModInfo->pNtHdrs = pNtHdrs = (PIMAGE_NT_HEADERS)&pbMapping[offNtHdrs];
322
323 if (pNtHdrs->Signature != IMAGE_NT_SIGNATURE)
324 MODERR_RETURN("%s: Invalid PE signature: %#x", pModInfo->szName, pNtHdrs->Signature);
325 if (pNtHdrs->FileHeader.SizeOfOptionalHeader != sizeof(pNtHdrs->OptionalHeader))
326 MODERR_RETURN("%s: Unexpected optional header size: %#x\n", pModInfo->szName, pNtHdrs->FileHeader.SizeOfOptionalHeader);
327 if (pNtHdrs->OptionalHeader.Magic != RT_CONCAT3(IMAGE_NT_OPTIONAL_HDR,ARCH_BITS,_MAGIC))
328 MODERR_RETURN("%s: Unexpected optional header magic: %#x\n", pModInfo->szName, pNtHdrs->OptionalHeader.Magic);
329 if (pNtHdrs->OptionalHeader.NumberOfRvaAndSizes != IMAGE_NUMBEROF_DIRECTORY_ENTRIES)
330 MODERR_RETURN("%s: Unexpected number of RVA and sizes: %#x\n", pModInfo->szName, pNtHdrs->OptionalHeader.NumberOfRvaAndSizes);
331
332 pModInfo->offNtHdrs = offNtHdrs;
333 pModInfo->offEndSectHdrs = offNtHdrs
334 + sizeof(*pNtHdrs)
335 + pNtHdrs->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
336 pModInfo->cbImage = pNtHdrs->OptionalHeader.SizeOfImage;
337 if (pModInfo->cbImage > cbMapping)
338 MODERR_RETURN("%s: The image size %#x is larger than the mapping: %#x\n",
339 pModInfo->szName, pModInfo->cbImage, cbMapping);
340
341 /*
342 * Find the export directory.
343 */
344 IMAGE_DATA_DIRECTORY ExpDir = pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
345 if ( ExpDir.Size < sizeof(IMAGE_EXPORT_DIRECTORY)
346 || ExpDir.VirtualAddress < pModInfo->offEndSectHdrs
347 || ExpDir.VirtualAddress >= pModInfo->cbImage
348 || ExpDir.VirtualAddress + ExpDir.Size > pModInfo->cbImage)
349 MODERR_RETURN("%s: Missing or invalid export directory: %#lx LB %#x\n", pModInfo->szName, ExpDir.VirtualAddress, ExpDir.Size);
350 pModInfo->offExportDir = ExpDir.VirtualAddress;
351 pModInfo->cbExportDir = ExpDir.Size;
352
353 IMAGE_EXPORT_DIRECTORY const *pExpDir = (IMAGE_EXPORT_DIRECTORY const *)&pbMapping[ExpDir.VirtualAddress];
354
355 if ( pExpDir->NumberOfFunctions >= _1M
356 || pExpDir->NumberOfFunctions < 1
357 || pExpDir->NumberOfNames >= _1M
358 || pExpDir->NumberOfNames < 1)
359 MODERR_RETURN("%s: NumberOfNames or/and NumberOfFunctions are outside the expected range: nof=%#x non=%#x\n",
360 pModInfo->szName, pExpDir->NumberOfFunctions, pExpDir->NumberOfNames);
361 pModInfo->cNamedExports = pExpDir->NumberOfNames;
362 pModInfo->cExports = RT_MAX(pExpDir->NumberOfNames, pExpDir->NumberOfFunctions);
363
364 if ( pExpDir->AddressOfFunctions < pModInfo->offEndSectHdrs
365 || pExpDir->AddressOfFunctions >= pModInfo->cbImage
366 || pExpDir->AddressOfFunctions + pModInfo->cExports * sizeof(uint32_t) > pModInfo->cbImage)
367 MODERR_RETURN("%s: Bad AddressOfFunctions: %#x\n", pModInfo->szName, pExpDir->AddressOfFunctions);
368 pModInfo->paoffExports = (uint32_t const *)&pbMapping[pExpDir->AddressOfFunctions];
369
370 if ( pExpDir->AddressOfNames < pModInfo->offEndSectHdrs
371 || pExpDir->AddressOfNames >= pModInfo->cbImage
372 || pExpDir->AddressOfNames + pExpDir->NumberOfNames * sizeof(uint32_t) > pModInfo->cbImage)
373 MODERR_RETURN("%s: Bad AddressOfNames: %#x\n", pModInfo->szName, pExpDir->AddressOfNames);
374 pModInfo->paoffNamedExports = (uint32_t const *)&pbMapping[pExpDir->AddressOfNames];
375
376 if ( pExpDir->AddressOfNameOrdinals < pModInfo->offEndSectHdrs
377 || pExpDir->AddressOfNameOrdinals >= pModInfo->cbImage
378 || pExpDir->AddressOfNameOrdinals + pExpDir->NumberOfNames * sizeof(uint32_t) > pModInfo->cbImage)
379 MODERR_RETURN("%s: Bad AddressOfNameOrdinals: %#x\n", pModInfo->szName, pExpDir->AddressOfNameOrdinals);
380 pModInfo->pau16NameOrdinals = (uint16_t const *)&pbMapping[pExpDir->AddressOfNameOrdinals];
381
382 /*
383 * Success.
384 */
385 return true;
386#undef MODERR_RETURN
387}
388
389
390/**
391 * Searches the given module information from the kernel for the NT kernel module, the
392 * HAL module, and optionally one more module.
393 *
394 * If the NT kernel or HAL modules have already been found, they'll be skipped.
395 *
396 * @returns IPRT status code.
397 * @retval VERR_LDR_GENERAL_FAILURE if we failed to parse the NT kernel or HAL.
398 * @retval VERR_BAD_EXE_FORMAT if we failed to parse @a pModInfo.
399 * @retval VERR_MODULE_NOT_FOUND if @a pModInfo wasn't found.
400 *
401 * @param pInfo Pointer to the module information.
402 * @param cModules Number of valid module entries in the module information pointer.
403 * @param pModInfo Custom module to search for. Optional.
404 */
405static int rtR0DbgKrnlNtSearchForModuleWorker(PRTL_PROCESS_MODULES pInfo, uint32_t cModules, PRTDBGNTKRNLMODINFO pModInfo)
406{
407 AssertPtrReturn(pInfo, VERR_INVALID_PARAMETER);
408 AssertReturn(cModules >= 2, VERR_INVALID_PARAMETER);
409
410 /*
411 * Search the info. The information is ordered with the kernel bits first,
412 * we expect aleast two modules to be returned to us (kernel + hal)!
413 */
414 int rc = VINF_SUCCESS;
415#if ARCH_BITS == 32
416 uintptr_t const uMinKernelAddr = _2G; /** @todo resolve MmSystemRangeStart */
417#else
418 uintptr_t const uMinKernelAddr = (uintptr_t)MM_SYSTEM_RANGE_START;
419#endif
420
421 for (uint32_t iModule = 0; iModule < cModules; iModule++)
422 RTR0DBG_NT_DEBUG_LOG(("rtR0DbgKrnlNtInit: [%u]= %p LB %#x %s\n", iModule, pInfo->Modules[iModule].ImageBase,
423 pInfo->Modules[iModule].ImageSize, pInfo->Modules[iModule].FullPathName));
424
425 /*
426 * First time around we serch for the NT kernel and HAL. We'll look for NT
427 * kerneland HAL in the first 16 entries, and if not found, use the first
428 * and second entry respectively.
429 */
430 if ( !g_NtOsKrnlInfo.pbImageBase
431 && !g_HalInfo.pbImageBase)
432 {
433 /* Find them. */
434 RTR0DBG_NT_DEBUG_LOG(("rtR0DbgKrnlNtInit: Looking for kernel and hal...\n"));
435 uint32_t const cMaxModules = RT_MIN(cModules, 16);
436 uint32_t idxNtOsKrnl = UINT32_MAX;
437 uint32_t idxHal = UINT32_MAX;
438 for (uint32_t iModule = 0; iModule < cMaxModules; iModule++)
439 {
440 RTL_PROCESS_MODULE_INFORMATION const * const pModule = &pInfo->Modules[iModule];
441 if ( (uintptr_t)pModule->ImageBase >= uMinKernelAddr
442 && (uintptr_t)pModule->ImageSize >= _4K)
443 {
444 const char *pszName = (const char *)&pModule->FullPathName[pModule->OffsetToFileName];
445 if ( idxNtOsKrnl == UINT32_MAX
446 && RTStrICmpAscii(pszName, g_NtOsKrnlInfo.szName) == 0)
447 {
448 idxNtOsKrnl = iModule;
449 if (idxHal != UINT32_MAX)
450 break;
451 }
452 else if ( idxHal == UINT32_MAX
453 && RTStrICmpAscii(pszName, g_HalInfo.szName) == 0)
454 {
455 idxHal = iModule;
456 if (idxHal != UINT32_MAX)
457 break;
458 }
459 }
460 }
461 RTR0DBG_NT_DEBUG_LOG(("rtR0DbgKrnlNtInit: idxNtOsKrnl=%#x idxHal=%#x\n", idxNtOsKrnl, idxHal));
462 if (idxNtOsKrnl == UINT32_MAX)
463 {
464 idxNtOsKrnl = 0;
465 RTR0DBG_NT_ERROR_LOG(("rtR0DbgKrnlNtInit: 'ntoskrnl.exe' not found, picking '%s' instead\n",
466 pInfo->Modules[idxNtOsKrnl].FullPathName));
467 }
468 if (idxHal == UINT32_MAX)
469 {
470 idxHal = 1;
471 RTR0DBG_NT_ERROR_LOG(("rtR0DbgKrnlNtInit: 'hal.dll' not found, picking '%s' instead\n",
472 pInfo->Modules[idxHal].FullPathName));
473 }
474
475 /* Parse them. */
476 //RTR0DBG_NT_DEBUG_LOG(("rtR0DbgKrnlNtInit: Parsing NT kernel...\n"));
477 __try
478 {
479 g_NtOsKrnlInfo.fOkay = rtR0DbgKrnlNtParseModule(&g_NtOsKrnlInfo,
480 (uint8_t const *)pInfo->Modules[idxNtOsKrnl].ImageBase,
481 pInfo->Modules[idxNtOsKrnl].ImageSize);
482 }
483 __except(EXCEPTION_EXECUTE_HANDLER)
484 {
485 g_NtOsKrnlInfo.fOkay = false;
486 RTR0DBG_NT_ERROR_LOG(("rtR0DbgKrnlNtInit: Exception in rtR0DbgKrnlNtParseModule parsing ntoskrnl.exe...\n"));
487 }
488
489 //RTR0DBG_NT_DEBUG_LOG(("rtR0DbgKrnlNtInit: Parsing HAL...\n"));
490 __try
491 {
492 g_HalInfo.fOkay = rtR0DbgKrnlNtParseModule(&g_HalInfo, (uint8_t const *)pInfo->Modules[idxHal].ImageBase,
493 pInfo->Modules[idxHal].ImageSize);
494 }
495 __except(EXCEPTION_EXECUTE_HANDLER)
496 {
497 g_HalInfo.fOkay = false;
498 RTR0DBG_NT_ERROR_LOG(("rtR0DbgKrnlNtInit: Exception in rtR0DbgKrnlNtParseModule parsing hal.dll...\n"));
499 }
500 if (!g_NtOsKrnlInfo.fOkay || !g_HalInfo.fOkay)
501 rc = VERR_LDR_GENERAL_FAILURE;
502
503 /*
504 * Resolve symbols we may need in the NT kernel (provided it parsed successfully)
505 */
506 if (g_NtOsKrnlInfo.fOkay)
507 {
508 if (!g_pfnMmGetSystemRoutineAddress)
509 {
510 //RTR0DBG_NT_DEBUG_LOG(("rtR0DbgKrnlNtInit: Looking up 'MmGetSystemRoutineAddress'...\n"));
511 rtR0DbgKrnlInfoLookupSymbol(&g_NtOsKrnlInfo, "MmGetSystemRoutineAddress", 0,
512 (void **)&g_pfnMmGetSystemRoutineAddress);
513 }
514 }
515 }
516
517 /*
518 * If we're still good, search for the given module (optional).
519 */
520 if (RT_SUCCESS(rc) && pModInfo)
521 {
522 RTR0DBG_NT_DEBUG_LOG(("rtR0DbgKrnlNtInit: Locating module '%s'...\n", pModInfo->szName));
523 rc = VERR_MODULE_NOT_FOUND;
524 for (uint32_t iModule = 0; iModule < cModules; iModule++)
525 {
526 RTL_PROCESS_MODULE_INFORMATION const * const pModule = &pInfo->Modules[iModule];
527 if ( (uintptr_t)pModule->ImageBase >= uMinKernelAddr
528 && (uintptr_t)pModule->ImageSize >= _4K)
529 {
530 const char *pszName = (const char *)&pModule->FullPathName[pModule->OffsetToFileName];
531 if ( pModInfo->pbImageBase == NULL
532 && RTStrICmpAscii(pszName, pModInfo->szName) == 0)
533 {
534 /*
535 * Found the module, try parse it.
536 */
537 __try
538 {
539 pModInfo->fOkay = rtR0DbgKrnlNtParseModule(pModInfo, (uint8_t const *)pModule->ImageBase,
540 pModule->ImageSize);
541 rc = VINF_SUCCESS;
542 }
543 __except(EXCEPTION_EXECUTE_HANDLER)
544 {
545 pModInfo->fOkay = false;
546 rc = VERR_BAD_EXE_FORMAT;
547 }
548 break;
549 }
550 }
551 }
552 }
553
554 return rc;
555}
556
557
558/**
559 * Queries the given maximum amount of modules and returns a pointer to the
560 * allocation holding the modules.
561 *
562 * @returns IPRT status code.
563 * @param ppInfo Where to store the pointer to the module information structure on success.
564 * Free with RTMemFree() when done.
565 * @param cModulesMax Maximum number of modules to return.
566 * @param pcModules Where to store the amount of modules returned upon success,
567 * can be lower than the requested maximum.
568 */
569static int rtR0DbgKrnlNtQueryModules(PRTL_PROCESS_MODULES *ppInfo, uint32_t cModulesMax, uint32_t *pcModules)
570{
571 *ppInfo = NULL;
572 *pcModules = 0;
573
574 ULONG cbInfo = RT_UOFFSETOF_DYN(RTL_PROCESS_MODULES, Modules[cModulesMax]);
575 PRTL_PROCESS_MODULES pInfo = (PRTL_PROCESS_MODULES)RTMemAllocZ(cbInfo);
576 if (!pInfo)
577 {
578 cModulesMax = cModulesMax / 4;
579 cbInfo = RT_UOFFSETOF_DYN(RTL_PROCESS_MODULES, Modules[cModulesMax]);
580 pInfo = (PRTL_PROCESS_MODULES)RTMemAllocZ(cbInfo);
581 if (!pInfo)
582 {
583 RTR0DBG_NT_ERROR_LOG(("rtR0DbgKrnlNtQueryModules: Out of memory!\n"));
584 return VERR_NO_MEMORY;
585 }
586 }
587
588 int rc;
589 ULONG cbActual = 0;
590 NTSTATUS rcNt = ZwQuerySystemInformation(SystemModuleInformation, pInfo, cbInfo, &cbActual);
591 RTR0DBG_NT_DEBUG_LOG(("rtR0DbgKrnlNtQueryModules: ZwQuerySystemInformation returned %#x and NumberOfModules=%#x\n",
592 rcNt, pInfo->NumberOfModules));
593 if ( NT_SUCCESS(rcNt)
594 || rcNt == STATUS_INFO_LENGTH_MISMATCH)
595 {
596 *ppInfo = pInfo;
597 *pcModules = RT_MIN(cModulesMax, pInfo->NumberOfModules);
598 rc = VINF_SUCCESS;
599 }
600 else
601 {
602 RTMemFree(pInfo);
603 RTR0DBG_NT_ERROR_LOG(("rtR0DbgKrnlNtQueryModules: ZwQuerySystemInformation failed: %#x\n", rcNt));
604 rc = RTErrConvertFromNtStatus(rcNt);
605 }
606
607 return rc;
608}
609
610
611/**
612 * Searches the module information from the kernel for the NT kernel module, the
613 * HAL module, and optionally one more module.
614 *
615 * If the NT kernel or HAL modules have already been found, they'll be skipped.
616 *
617 * @returns IPRT status code.
618 * @retval VERR_LDR_GENERAL_FAILURE if we failed to parse the NT kernel or HAL.
619 * @retval VERR_BAD_EXE_FORMAT if we failed to parse @a pModInfo.
620 * @retval VERR_MODULE_NOT_FOUND if @a pModInfo wasn't found.
621 * @retval VERR_BUFFER_UNDERFLOW if less that two modules was returned by the
622 * system.
623 *
624 * @param pModInfo Custom module to search for. Optional.
625 */
626static int rtR0DbgKrnlNtInit(PRTDBGNTKRNLMODINFO pModInfo)
627{
628 RTR0DBG_NT_DEBUG_LOG(("rtR0DbgKrnlNtInit: pModInfo=%p\n", pModInfo));
629
630#ifndef IPRT_TARGET_NT4
631 /*
632 * Must manually initialize g_pfnMmGetSystemRoutineAddress, otherwise compiler
633 * generates its own dynamic init code that might not necessarily be called.
634 */
635 g_pfnMmGetSystemRoutineAddress = MmGetSystemRoutineAddress;
636#endif
637
638 /*
639 * Allocate a reasonably large buffer and get the information we need. We don't
640 * need everything since the result starts off with the kernel bits in load order.
641 *
642 * Note! ZwQuerySystemInformation requires NT4. For 3.51 we could possibly emit
643 * the syscall ourselves, if we cared.
644 */
645 uint32_t cModules = 0;
646 PRTL_PROCESS_MODULES pInfo = NULL;
647 int rc = rtR0DbgKrnlNtQueryModules(&pInfo, pModInfo ? 110 /*32KB*/ : 27 /*8KB*/, &cModules);
648 if (RT_SUCCESS(rc))
649 {
650 if (cModules >= 2)
651 {
652 rc = rtR0DbgKrnlNtSearchForModuleWorker(pInfo, cModules, pModInfo);
653 if ( rc == VERR_MODULE_NOT_FOUND
654 && pInfo->NumberOfModules > cModules
655 && pModInfo)
656 {
657 /* Module not found in the first round, reallocate array to maximum size and rerun. */
658 cModules = pInfo->NumberOfModules;
659
660 RTMemFree(pInfo);
661 pInfo = NULL;
662
663 rc = rtR0DbgKrnlNtQueryModules(&pInfo, cModules, &cModules);
664 if (RT_SUCCESS(rc))
665 {
666 rc = rtR0DbgKrnlNtSearchForModuleWorker(pInfo, cModules, pModInfo);
667 RTMemFree(pInfo);
668 }
669 }
670 }
671 else
672 {
673 RTMemFree(pInfo);
674 RTR0DBG_NT_ERROR_LOG(("rtR0DbgKrnlNtInit: Error! Only %u module(s) returned!\n", cModules));
675 rc = VERR_BUFFER_UNDERFLOW;
676 }
677 }
678
679 RTR0DBG_NT_DEBUG_LOG(("rtR0DbgKrnlNtInit: returns %d\n", rc));
680 return rc;
681}
682
683
684
685RTR0DECL(int) RTR0DbgKrnlInfoOpen(PRTDBGKRNLINFO phKrnlInfo, uint32_t fFlags)
686{
687 AssertReturn(!fFlags, VERR_INVALID_FLAGS);
688
689 RTDBGKRNLINFOINT *pThis = (RTDBGKRNLINFOINT *)RTMemAllocZ(sizeof(*pThis));
690 if (pThis)
691 {
692 pThis->u32Magic = RTDBGKRNLINFO_MAGIC;
693 pThis->cRefs = 1;
694 *phKrnlInfo = pThis;
695 return VINF_SUCCESS;
696 }
697 return VERR_NO_MEMORY;
698}
699
700
701RTR0DECL(uint32_t) RTR0DbgKrnlInfoRetain(RTDBGKRNLINFO hKrnlInfo)
702{
703 RTDBGKRNLINFOINT *pThis = hKrnlInfo;
704 AssertPtrReturn(pThis, UINT32_MAX);
705 AssertMsgReturn(pThis->u32Magic == RTDBGKRNLINFO_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), UINT32_MAX);
706
707 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
708 Assert(cRefs && cRefs < 100000);
709 return cRefs;
710}
711
712
713static void rtR0DbgKrnlNtDtor(RTDBGKRNLINFOINT *pThis)
714{
715 pThis->u32Magic = ~RTDBGKRNLINFO_MAGIC;
716 RTMemFree(pThis);
717}
718
719
720RTR0DECL(uint32_t) RTR0DbgKrnlInfoRelease(RTDBGKRNLINFO hKrnlInfo)
721{
722 RTDBGKRNLINFOINT *pThis = hKrnlInfo;
723 if (pThis == NIL_RTDBGKRNLINFO)
724 return 0;
725 AssertPtrReturn(pThis, UINT32_MAX);
726 AssertMsgReturn(pThis->u32Magic == RTDBGKRNLINFO_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), UINT32_MAX);
727
728 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
729 if (cRefs == 0)
730 rtR0DbgKrnlNtDtor(pThis);
731 return cRefs;
732}
733
734
735RTR0DECL(int) RTR0DbgKrnlInfoQueryMember(RTDBGKRNLINFO hKrnlInfo, const char *pszModule, const char *pszStructure,
736 const char *pszMember, size_t *poffMember)
737{
738 RTDBGKRNLINFOINT *pThis = hKrnlInfo;
739 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
740 AssertMsgReturn(pThis->u32Magic == RTDBGKRNLINFO_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
741 AssertPtrReturn(pszMember, VERR_INVALID_POINTER);
742 AssertPtrNullReturn(pszModule, VERR_INVALID_POINTER);
743 AssertPtrReturn(pszStructure, VERR_INVALID_POINTER);
744 AssertPtrReturn(poffMember, VERR_INVALID_POINTER);
745 return VERR_NOT_FOUND;
746}
747
748
749RTR0DECL(int) RTR0DbgKrnlInfoQuerySymbol(RTDBGKRNLINFO hKrnlInfo, const char *pszModule, const char *pszSymbol, void **ppvSymbol)
750{
751 RTDBGKRNLINFOINT *pThis = hKrnlInfo;
752 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
753 AssertMsgReturn(pThis->u32Magic == RTDBGKRNLINFO_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
754 AssertPtrReturn(pszSymbol, VERR_INVALID_PARAMETER);
755 AssertPtrNullReturn(ppvSymbol, VERR_INVALID_PARAMETER);
756
757 RTR0DBG_NT_DEBUG_LOG(("RTR0DbgKrnlInfoQuerySymbol: pszModule=%s pszSymbol=%s\n", pszModule ? pszModule : "<null>", pszSymbol));
758
759 void *pvTmpSymbol = NULL;
760 if (!ppvSymbol)
761 ppvSymbol = &pvTmpSymbol;
762
763 int rc;
764 if (!pszModule)
765 {
766 /*
767 * Search both ntoskrnl and hal, may use MmGetSystemRoutineAddress as fallback.
768 * Note! MmGetSystemRoutineAddress was buggy before XP SP2 according to Geoff Chappell.
769 */
770 if (g_NtOsKrnlInfo.pbImageBase)
771 rc = VINF_SUCCESS;
772 else
773 rc = rtR0DbgKrnlNtInit(NULL);
774 if (RT_SUCCESS(rc))
775 {
776 Assert(g_NtOsKrnlInfo.fOkay);
777 Assert(g_HalInfo.fOkay);
778 //RTR0DBG_NT_DEBUG_LOG(("RTR0DbgKrnlInfoQuerySymbol: Calling RTR0DbgKrnlInfoQuerySymbol on NT kernel...\n"));
779 rc = rtR0DbgKrnlInfoLookupSymbol(&g_NtOsKrnlInfo, pszSymbol, 0, ppvSymbol);
780 if (RT_FAILURE(rc))
781 {
782 //RTR0DBG_NT_DEBUG_LOG(("RTR0DbgKrnlInfoQuerySymbol: Calling RTR0DbgKrnlInfoQuerySymbol on HAL kernel...\n"));
783 rc = rtR0DbgKrnlInfoLookupSymbol(&g_HalInfo, pszSymbol, 0, ppvSymbol);
784 }
785 RTR0DBG_NT_DEBUG_LOG(("RTR0DbgKrnlInfoQuerySymbol: #1 returns %d *ppvSymbol=%p\n", rc, *ppvSymbol));
786 }
787 else
788 {
789 /* Init failed. Try resolve symbol, but preserve the status code up to a point. */
790 int rc2 = VERR_SYMBOL_NOT_FOUND;
791 if (g_NtOsKrnlInfo.fOkay)
792 rc2 = rtR0DbgKrnlInfoLookupSymbol(&g_NtOsKrnlInfo, pszSymbol, 0, ppvSymbol);
793 if (g_HalInfo.fOkay && rc2 == VERR_SYMBOL_NOT_FOUND)
794 rc2 = rtR0DbgKrnlInfoLookupSymbol(&g_HalInfo, pszSymbol, 0, ppvSymbol);
795 if ( rc2 == VERR_SYMBOL_NOT_FOUND
796 && g_pfnMmGetSystemRoutineAddress)
797 {
798 /* We'll overwrite init failure status code here since
799 MmGetSystemRoutineAddress will do the job for us. */
800 size_t cwcSymbol;
801 PRTUTF16 pwszSymbol = NULL;
802 rc = RTStrToUtf16Ex(pszSymbol, RTSTR_MAX, &pwszSymbol, 0, &cwcSymbol);
803 if (RT_SUCCESS(rc))
804 {
805 UNICODE_STRING UniStr;
806 UniStr.Buffer = pwszSymbol;
807 UniStr.Length = (uint16_t)(cwcSymbol * sizeof(RTUTF16));
808 UniStr.MaximumLength = UniStr.Length + sizeof(RTUTF16);
809 *ppvSymbol = g_pfnMmGetSystemRoutineAddress(&UniStr);
810 if (*ppvSymbol)
811 rc = VINF_SUCCESS;
812 else
813 rc = VERR_SYMBOL_NOT_FOUND;
814 RTUtf16Free(pwszSymbol);
815 RTR0DBG_NT_DEBUG_LOG(("RTR0DbgKrnlInfoQuerySymbol: #2 returns %d *ppvSymbol=%p\n", rc, *ppvSymbol));
816 }
817 }
818 }
819 }
820 else
821 {
822 /*
823 * Search specified module.
824 */
825 rc = VERR_MODULE_NOT_FOUND;
826 PRTDBGNTKRNLMODINFO pModInfo;
827 if (RTStrICmpAscii(pszModule, g_NtOsKrnlInfo.szName) == 0)
828 pModInfo = &g_NtOsKrnlInfo;
829 else if (RTStrICmpAscii(pszModule, g_HalInfo.szName) == 0)
830 pModInfo = &g_NtOsKrnlInfo;
831 else
832 {
833 pModInfo = NULL;
834 for (unsigned i = 0; i < pThis->cModules; i++)
835 if (RTStrICmpAscii(pszModule, pThis->aModules[i].szName) == 0)
836 {
837 pModInfo = &pThis->aModules[i];
838 break;
839 }
840 if (!pModInfo)
841 {
842 /*
843 * Not found, try load it. If module table is full, drop the first
844 * entry and shuffle the other up to make space.
845 */
846 size_t const cchModule = strlen(pszModule);
847 RTDBGNTKRNLMODINFO NewModInfo;
848 if (cchModule < sizeof(NewModInfo.szName))
849 {
850 RT_ZERO(NewModInfo);
851 memcpy(NewModInfo.szName, pszModule, cchModule);
852 NewModInfo.szName[cchModule] = '\0';
853
854 rc = rtR0DbgKrnlNtInit(&NewModInfo);
855 if (RT_SUCCESS(rc))
856 {
857 Assert(NewModInfo.fOkay);
858 uint32_t iModule = pThis->cModules;
859 if (iModule >= RT_ELEMENTS(pThis->aModules))
860 {
861 iModule = RT_ELEMENTS(pThis->aModules) - 1;
862 memmove(&pThis->aModules[0], &pThis->aModules[1], iModule * sizeof(pThis->aModules[0]));
863 }
864 pThis->aModules[iModule] = NewModInfo;
865 pThis->cModules = iModule + 1;
866 pModInfo = &pThis->aModules[iModule];
867 rc = VINF_SUCCESS;
868 }
869 }
870 else
871 {
872 AssertMsgFailed(("cchModule=%zu pszModule=%s\n", cchModule, pszModule));
873 rc = VERR_FILENAME_TOO_LONG;
874 }
875 }
876 }
877 if (pModInfo)
878 {
879 rc = rtR0DbgKrnlInfoLookupSymbol(pModInfo, pszSymbol, 0, ppvSymbol);
880 RTR0DBG_NT_DEBUG_LOG(("RTR0DbgKrnlInfoQuerySymbol: #3 returns %d *ppvSymbol=%p\n", rc, *ppvSymbol));
881 }
882 }
883 return rc;
884}
885
886
887RTR0DECL(int) RTR0DbgKrnlInfoQuerySize(RTDBGKRNLINFO hKrnlInfo, const char *pszModule, const char *pszType, size_t *pcbType)
888{
889 RTDBGKRNLINFOINT *pThis = hKrnlInfo;
890 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
891 AssertMsgReturn(pThis->u32Magic == RTDBGKRNLINFO_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
892 AssertPtrNullReturn(pszModule, VERR_INVALID_POINTER);
893 AssertPtrReturn(pszType, VERR_INVALID_POINTER);
894 AssertPtrReturn(pcbType, VERR_INVALID_POINTER);
895 return VERR_NOT_FOUND;
896}
897
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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