VirtualBox

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

Last change on this file since 95126 was 95126, checked in by vboxsync, 3 years ago

IPRT/dbgkrnlinfo-r0drv-nt.cpp: cleanup. bugref:9845

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 37.9 KB
Line 
1/* $Id: dbgkrnlinfo-r0drv-nt.cpp 95126 2022-05-27 06:59:25Z vboxsync $ */
2/** @file
3 * IPRT - Kernel Debug Information, R0 Driver, NT.
4 */
5
6/*
7 * Copyright (C) 2006-2022 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 * 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. It's okay if none is present too.
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 {
350 if (ExpDir.Size == 0 && ExpDir.VirtualAddress == 0)
351 {
352 pModInfo->offExportDir = 0;
353 pModInfo->cbExportDir = 0;
354 pModInfo->cNamedExports = 0;
355 pModInfo->cExports = 0;
356 pModInfo->paoffExports = NULL;
357 pModInfo->paoffNamedExports = NULL;
358 pModInfo->pau16NameOrdinals = NULL;
359 return true;
360 }
361 MODERR_RETURN("%s: Missing or invalid export directory: %#lx LB %#x\n", pModInfo->szName, ExpDir.VirtualAddress, ExpDir.Size);
362 }
363 pModInfo->offExportDir = ExpDir.VirtualAddress;
364 pModInfo->cbExportDir = ExpDir.Size;
365
366 IMAGE_EXPORT_DIRECTORY const *pExpDir = (IMAGE_EXPORT_DIRECTORY const *)&pbMapping[ExpDir.VirtualAddress];
367
368 if ( pExpDir->NumberOfFunctions >= _1M
369 || pExpDir->NumberOfFunctions < 1
370 || pExpDir->NumberOfNames >= _1M
371 || pExpDir->NumberOfNames < 1)
372 MODERR_RETURN("%s: NumberOfNames or/and NumberOfFunctions are outside the expected range: nof=%#x non=%#x\n",
373 pModInfo->szName, pExpDir->NumberOfFunctions, pExpDir->NumberOfNames);
374 pModInfo->cNamedExports = pExpDir->NumberOfNames;
375 pModInfo->cExports = RT_MAX(pExpDir->NumberOfNames, pExpDir->NumberOfFunctions);
376
377 if ( pExpDir->AddressOfFunctions < pModInfo->offEndSectHdrs
378 || pExpDir->AddressOfFunctions >= pModInfo->cbImage
379 || pExpDir->AddressOfFunctions + pModInfo->cExports * sizeof(uint32_t) > pModInfo->cbImage)
380 MODERR_RETURN("%s: Bad AddressOfFunctions: %#x\n", pModInfo->szName, pExpDir->AddressOfFunctions);
381 pModInfo->paoffExports = (uint32_t const *)&pbMapping[pExpDir->AddressOfFunctions];
382
383 if ( pExpDir->AddressOfNames < pModInfo->offEndSectHdrs
384 || pExpDir->AddressOfNames >= pModInfo->cbImage
385 || pExpDir->AddressOfNames + pExpDir->NumberOfNames * sizeof(uint32_t) > pModInfo->cbImage)
386 MODERR_RETURN("%s: Bad AddressOfNames: %#x\n", pModInfo->szName, pExpDir->AddressOfNames);
387 pModInfo->paoffNamedExports = (uint32_t const *)&pbMapping[pExpDir->AddressOfNames];
388
389 if ( pExpDir->AddressOfNameOrdinals < pModInfo->offEndSectHdrs
390 || pExpDir->AddressOfNameOrdinals >= pModInfo->cbImage
391 || pExpDir->AddressOfNameOrdinals + pExpDir->NumberOfNames * sizeof(uint32_t) > pModInfo->cbImage)
392 MODERR_RETURN("%s: Bad AddressOfNameOrdinals: %#x\n", pModInfo->szName, pExpDir->AddressOfNameOrdinals);
393 pModInfo->pau16NameOrdinals = (uint16_t const *)&pbMapping[pExpDir->AddressOfNameOrdinals];
394
395 /*
396 * Success.
397 */
398 return true;
399#undef MODERR_RETURN
400}
401
402
403/**
404 * Searches the given module information from the kernel for the NT kernel module, the
405 * HAL module, and optionally one more module.
406 *
407 * If the NT kernel or HAL modules have already been found, they'll be skipped.
408 *
409 * @returns IPRT status code.
410 * @retval VERR_LDR_GENERAL_FAILURE if we failed to parse the NT kernel or HAL.
411 * @retval VERR_BAD_EXE_FORMAT if we failed to parse @a pModInfo.
412 * @retval VERR_MODULE_NOT_FOUND if @a pModInfo wasn't found.
413 *
414 * @param pInfo Pointer to the module information.
415 * @param cModules Number of valid module entries in the module information pointer.
416 * @param pModInfo Custom module to search for. Optional.
417 */
418static int rtR0DbgKrnlNtSearchForModuleWorker(PRTL_PROCESS_MODULES pInfo, uint32_t cModules, PRTDBGNTKRNLMODINFO pModInfo)
419{
420 AssertPtrReturn(pInfo, VERR_INVALID_PARAMETER);
421 AssertReturn(cModules >= 2, VERR_INVALID_PARAMETER);
422
423 /*
424 * Search the info. The information is ordered with the kernel bits first,
425 * we expect aleast two modules to be returned to us (kernel + hal)!
426 */
427 int rc = VINF_SUCCESS;
428#if ARCH_BITS == 32
429 uintptr_t const uMinKernelAddr = _2G; /** @todo resolve MmSystemRangeStart */
430#else
431 uintptr_t const uMinKernelAddr = (uintptr_t)MM_SYSTEM_RANGE_START;
432#endif
433
434 for (uint32_t iModule = 0; iModule < cModules; iModule++)
435 RTR0DBG_NT_DEBUG_LOG(("rtR0DbgKrnlNtInit: [%u]= %p LB %#x %s\n", iModule, pInfo->Modules[iModule].ImageBase,
436 pInfo->Modules[iModule].ImageSize, pInfo->Modules[iModule].FullPathName));
437
438 /*
439 * First time around we serch for the NT kernel and HAL. We'll look for NT
440 * kerneland HAL in the first 16 entries, and if not found, use the first
441 * and second entry respectively.
442 */
443 if ( !g_NtOsKrnlInfo.pbImageBase
444 && !g_HalInfo.pbImageBase)
445 {
446 /* Find them. */
447 RTR0DBG_NT_DEBUG_LOG(("rtR0DbgKrnlNtInit: Looking for kernel and hal...\n"));
448 uint32_t const cMaxModules = RT_MIN(cModules, 16);
449 uint32_t idxNtOsKrnl = UINT32_MAX;
450 uint32_t idxHal = UINT32_MAX;
451 for (uint32_t iModule = 0; iModule < cMaxModules; iModule++)
452 {
453 RTL_PROCESS_MODULE_INFORMATION const * const pModule = &pInfo->Modules[iModule];
454 if ( (uintptr_t)pModule->ImageBase >= uMinKernelAddr
455 && (uintptr_t)pModule->ImageSize >= _4K)
456 {
457 const char *pszName = (const char *)&pModule->FullPathName[pModule->OffsetToFileName];
458 if ( idxNtOsKrnl == UINT32_MAX
459 && RTStrICmpAscii(pszName, g_NtOsKrnlInfo.szName) == 0)
460 {
461 idxNtOsKrnl = iModule;
462 if (idxHal != UINT32_MAX)
463 break;
464 }
465 else if ( idxHal == UINT32_MAX
466 && RTStrICmpAscii(pszName, g_HalInfo.szName) == 0)
467 {
468 idxHal = iModule;
469 if (idxHal != UINT32_MAX)
470 break;
471 }
472 }
473 }
474 RTR0DBG_NT_DEBUG_LOG(("rtR0DbgKrnlNtInit: idxNtOsKrnl=%#x idxHal=%#x\n", idxNtOsKrnl, idxHal));
475 if (idxNtOsKrnl == UINT32_MAX)
476 {
477 idxNtOsKrnl = 0;
478 RTR0DBG_NT_ERROR_LOG(("rtR0DbgKrnlNtInit: 'ntoskrnl.exe' not found, picking '%s' instead\n",
479 pInfo->Modules[idxNtOsKrnl].FullPathName));
480 }
481 if (idxHal == UINT32_MAX)
482 {
483 idxHal = 1;
484 RTR0DBG_NT_ERROR_LOG(("rtR0DbgKrnlNtInit: 'hal.dll' not found, picking '%s' instead\n",
485 pInfo->Modules[idxHal].FullPathName));
486 }
487
488 /* Parse them. */
489 //RTR0DBG_NT_DEBUG_LOG(("rtR0DbgKrnlNtInit: Parsing NT kernel...\n"));
490 __try
491 {
492 g_NtOsKrnlInfo.fOkay = rtR0DbgKrnlNtParseModule(&g_NtOsKrnlInfo,
493 (uint8_t const *)pInfo->Modules[idxNtOsKrnl].ImageBase,
494 pInfo->Modules[idxNtOsKrnl].ImageSize);
495 }
496 __except(EXCEPTION_EXECUTE_HANDLER)
497 {
498 g_NtOsKrnlInfo.fOkay = false;
499 RTR0DBG_NT_ERROR_LOG(("rtR0DbgKrnlNtInit: Exception in rtR0DbgKrnlNtParseModule parsing ntoskrnl.exe...\n"));
500 }
501
502 //RTR0DBG_NT_DEBUG_LOG(("rtR0DbgKrnlNtInit: Parsing HAL...\n"));
503 __try
504 {
505 g_HalInfo.fOkay = rtR0DbgKrnlNtParseModule(&g_HalInfo, (uint8_t const *)pInfo->Modules[idxHal].ImageBase,
506 pInfo->Modules[idxHal].ImageSize);
507 }
508 __except(EXCEPTION_EXECUTE_HANDLER)
509 {
510 g_HalInfo.fOkay = false;
511 RTR0DBG_NT_ERROR_LOG(("rtR0DbgKrnlNtInit: Exception in rtR0DbgKrnlNtParseModule parsing hal.dll...\n"));
512 }
513 if (!g_NtOsKrnlInfo.fOkay || !g_HalInfo.fOkay)
514 rc = VERR_LDR_GENERAL_FAILURE;
515
516 /*
517 * Resolve symbols we may need in the NT kernel (provided it parsed successfully)
518 */
519 if (g_NtOsKrnlInfo.fOkay)
520 {
521 if (!g_pfnMmGetSystemRoutineAddress)
522 {
523 //RTR0DBG_NT_DEBUG_LOG(("rtR0DbgKrnlNtInit: Looking up 'MmGetSystemRoutineAddress'...\n"));
524 rtR0DbgKrnlInfoLookupSymbol(&g_NtOsKrnlInfo, "MmGetSystemRoutineAddress", 0,
525 (void **)&g_pfnMmGetSystemRoutineAddress);
526 }
527 }
528 }
529
530 /*
531 * If we're still good, search for the given module (optional).
532 */
533 if (RT_SUCCESS(rc) && pModInfo)
534 {
535 RTR0DBG_NT_DEBUG_LOG(("rtR0DbgKrnlNtInit: Locating module '%s'...\n", pModInfo->szName));
536 rc = VERR_MODULE_NOT_FOUND;
537 for (uint32_t iModule = 0; iModule < cModules; iModule++)
538 {
539 RTL_PROCESS_MODULE_INFORMATION const * const pModule = &pInfo->Modules[iModule];
540 if ( (uintptr_t)pModule->ImageBase >= uMinKernelAddr
541 && (uintptr_t)pModule->ImageSize >= _4K)
542 {
543 const char *pszName = (const char *)&pModule->FullPathName[pModule->OffsetToFileName];
544 if ( pModInfo->pbImageBase == NULL
545 && RTStrICmpAscii(pszName, pModInfo->szName) == 0)
546 {
547 /*
548 * Found the module, try parse it.
549 */
550 __try
551 {
552 pModInfo->fOkay = rtR0DbgKrnlNtParseModule(pModInfo, (uint8_t const *)pModule->ImageBase,
553 pModule->ImageSize);
554 rc = VINF_SUCCESS;
555 }
556 __except(EXCEPTION_EXECUTE_HANDLER)
557 {
558 pModInfo->fOkay = false;
559 rc = VERR_BAD_EXE_FORMAT;
560 }
561 break;
562 }
563 }
564 }
565 }
566
567 return rc;
568}
569
570
571/**
572 * Queries the given maximum amount of modules and returns a pointer to the
573 * allocation holding the modules.
574 *
575 * @returns IPRT status code.
576 * @param ppInfo Where to store the pointer to the module information structure on success.
577 * Free with RTMemFree() when done.
578 * @param cModulesMax Maximum number of modules to return.
579 * @param pcModules Where to store the amount of modules returned upon success,
580 * can be lower than the requested maximum.
581 */
582static int rtR0DbgKrnlNtQueryModules(PRTL_PROCESS_MODULES *ppInfo, uint32_t cModulesMax, uint32_t *pcModules)
583{
584 *ppInfo = NULL;
585 *pcModules = 0;
586
587 ULONG cbInfo = RT_UOFFSETOF_DYN(RTL_PROCESS_MODULES, Modules[cModulesMax]);
588 PRTL_PROCESS_MODULES pInfo = (PRTL_PROCESS_MODULES)RTMemAllocZ(cbInfo);
589 if (!pInfo)
590 {
591 cModulesMax = cModulesMax / 4;
592 cbInfo = RT_UOFFSETOF_DYN(RTL_PROCESS_MODULES, Modules[cModulesMax]);
593 pInfo = (PRTL_PROCESS_MODULES)RTMemAllocZ(cbInfo);
594 if (!pInfo)
595 {
596 RTR0DBG_NT_ERROR_LOG(("rtR0DbgKrnlNtQueryModules: Out of memory!\n"));
597 return VERR_NO_MEMORY;
598 }
599 }
600
601 int rc;
602 ULONG cbActual = 0;
603 NTSTATUS rcNt = ZwQuerySystemInformation(SystemModuleInformation, pInfo, cbInfo, &cbActual);
604 RTR0DBG_NT_DEBUG_LOG(("rtR0DbgKrnlNtQueryModules: ZwQuerySystemInformation returned %#x and NumberOfModules=%#x\n",
605 rcNt, pInfo->NumberOfModules));
606 if ( NT_SUCCESS(rcNt)
607 || rcNt == STATUS_INFO_LENGTH_MISMATCH)
608 {
609 *ppInfo = pInfo;
610 *pcModules = RT_MIN(cModulesMax, pInfo->NumberOfModules);
611 rc = VINF_SUCCESS;
612 }
613 else
614 {
615 RTMemFree(pInfo);
616 RTR0DBG_NT_ERROR_LOG(("rtR0DbgKrnlNtQueryModules: ZwQuerySystemInformation failed: %#x\n", rcNt));
617 rc = RTErrConvertFromNtStatus(rcNt);
618 }
619
620 return rc;
621}
622
623
624/**
625 * Searches the module information from the kernel for the NT kernel module, the
626 * HAL module, and optionally one more module.
627 *
628 * If the NT kernel or HAL modules have already been found, they'll be skipped.
629 *
630 * @returns IPRT status code.
631 * @retval VERR_LDR_GENERAL_FAILURE if we failed to parse the NT kernel or HAL.
632 * @retval VERR_BAD_EXE_FORMAT if we failed to parse @a pModInfo.
633 * @retval VERR_MODULE_NOT_FOUND if @a pModInfo wasn't found.
634 * @retval VERR_BUFFER_UNDERFLOW if less that two modules was returned by the
635 * system.
636 *
637 * @param pModInfo Custom module to search for. Optional.
638 */
639static int rtR0DbgKrnlNtInit(PRTDBGNTKRNLMODINFO pModInfo)
640{
641 RTR0DBG_NT_DEBUG_LOG(("rtR0DbgKrnlNtInit: pModInfo=%p\n", pModInfo));
642
643#ifndef IPRT_TARGET_NT4
644 /*
645 * Must manually initialize g_pfnMmGetSystemRoutineAddress, otherwise compiler
646 * generates its own dynamic init code that might not necessarily be called.
647 */
648 g_pfnMmGetSystemRoutineAddress = MmGetSystemRoutineAddress;
649#endif
650
651 /*
652 * Allocate a reasonably large buffer and get the information we need. We don't
653 * need everything since the result starts off with the kernel bits in load order.
654 *
655 * Note! ZwQuerySystemInformation requires NT4. For 3.51 we could possibly emit
656 * the syscall ourselves, if we cared.
657 */
658 uint32_t cModules = 0;
659 PRTL_PROCESS_MODULES pInfo = NULL;
660 int rc = rtR0DbgKrnlNtQueryModules(&pInfo, pModInfo ? 110 /*32KB*/ : 27 /*8KB*/, &cModules);
661 if (RT_SUCCESS(rc))
662 {
663 if (cModules >= 2)
664 {
665 rc = rtR0DbgKrnlNtSearchForModuleWorker(pInfo, cModules, pModInfo);
666 if ( rc == VERR_MODULE_NOT_FOUND
667 && pInfo->NumberOfModules > cModules
668 && pModInfo)
669 {
670 /* Module not found in the first round, reallocate array to maximum size and rerun. */
671 cModules = pInfo->NumberOfModules;
672
673 RTMemFree(pInfo);
674 pInfo = NULL;
675
676 rc = rtR0DbgKrnlNtQueryModules(&pInfo, cModules, &cModules);
677 if (RT_SUCCESS(rc))
678 rc = rtR0DbgKrnlNtSearchForModuleWorker(pInfo, cModules, pModInfo);
679 }
680 }
681 else
682 {
683 RTR0DBG_NT_ERROR_LOG(("rtR0DbgKrnlNtInit: Error! Only %u module(s) returned!\n", cModules));
684 rc = VERR_BUFFER_UNDERFLOW;
685 }
686
687 RTMemFree(pInfo);
688 }
689
690 RTR0DBG_NT_DEBUG_LOG(("rtR0DbgKrnlNtInit: returns %d\n", rc));
691 return rc;
692}
693
694
695
696RTR0DECL(int) RTR0DbgKrnlInfoOpen(PRTDBGKRNLINFO phKrnlInfo, uint32_t fFlags)
697{
698 AssertReturn(!fFlags, VERR_INVALID_FLAGS);
699
700 RTDBGKRNLINFOINT *pThis = (RTDBGKRNLINFOINT *)RTMemAllocZ(sizeof(*pThis));
701 if (pThis)
702 {
703 pThis->u32Magic = RTDBGKRNLINFO_MAGIC;
704 pThis->cRefs = 1;
705 *phKrnlInfo = pThis;
706 return VINF_SUCCESS;
707 }
708 return VERR_NO_MEMORY;
709}
710
711
712RTR0DECL(uint32_t) RTR0DbgKrnlInfoRetain(RTDBGKRNLINFO hKrnlInfo)
713{
714 RTDBGKRNLINFOINT *pThis = hKrnlInfo;
715 AssertPtrReturn(pThis, UINT32_MAX);
716 AssertMsgReturn(pThis->u32Magic == RTDBGKRNLINFO_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), UINT32_MAX);
717
718 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
719 Assert(cRefs && cRefs < 100000);
720 return cRefs;
721}
722
723
724static void rtR0DbgKrnlNtDtor(RTDBGKRNLINFOINT *pThis)
725{
726 pThis->u32Magic = ~RTDBGKRNLINFO_MAGIC;
727 RTMemFree(pThis);
728}
729
730
731RTR0DECL(uint32_t) RTR0DbgKrnlInfoRelease(RTDBGKRNLINFO hKrnlInfo)
732{
733 RTDBGKRNLINFOINT *pThis = hKrnlInfo;
734 if (pThis == NIL_RTDBGKRNLINFO)
735 return 0;
736 AssertPtrReturn(pThis, UINT32_MAX);
737 AssertMsgReturn(pThis->u32Magic == RTDBGKRNLINFO_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), UINT32_MAX);
738
739 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
740 if (cRefs == 0)
741 rtR0DbgKrnlNtDtor(pThis);
742 return cRefs;
743}
744
745
746RTR0DECL(int) RTR0DbgKrnlInfoQueryMember(RTDBGKRNLINFO hKrnlInfo, const char *pszModule, const char *pszStructure,
747 const char *pszMember, size_t *poffMember)
748{
749 RTDBGKRNLINFOINT *pThis = hKrnlInfo;
750 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
751 AssertMsgReturn(pThis->u32Magic == RTDBGKRNLINFO_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
752 AssertPtrReturn(pszMember, VERR_INVALID_POINTER);
753 AssertPtrNullReturn(pszModule, VERR_INVALID_POINTER);
754 AssertPtrReturn(pszStructure, VERR_INVALID_POINTER);
755 AssertPtrReturn(poffMember, VERR_INVALID_POINTER);
756 return VERR_NOT_FOUND;
757}
758
759
760RTR0DECL(int) RTR0DbgKrnlInfoQuerySymbol(RTDBGKRNLINFO hKrnlInfo, const char *pszModule, const char *pszSymbol, void **ppvSymbol)
761{
762 RTDBGKRNLINFOINT *pThis = hKrnlInfo;
763 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
764 AssertMsgReturn(pThis->u32Magic == RTDBGKRNLINFO_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
765 AssertPtrReturn(pszSymbol, VERR_INVALID_PARAMETER);
766 AssertPtrNullReturn(ppvSymbol, VERR_INVALID_PARAMETER);
767
768 RTR0DBG_NT_DEBUG_LOG(("RTR0DbgKrnlInfoQuerySymbol: pszModule=%s pszSymbol=%s\n", pszModule ? pszModule : "<null>", pszSymbol));
769
770 void *pvTmpSymbol = NULL;
771 if (!ppvSymbol)
772 ppvSymbol = &pvTmpSymbol;
773
774 int rc;
775 if (!pszModule)
776 {
777 /*
778 * Search both ntoskrnl and hal, may use MmGetSystemRoutineAddress as fallback.
779 * Note! MmGetSystemRoutineAddress was buggy before XP SP2 according to Geoff Chappell.
780 */
781 if (g_NtOsKrnlInfo.pbImageBase)
782 rc = VINF_SUCCESS;
783 else
784 rc = rtR0DbgKrnlNtInit(NULL);
785 if (RT_SUCCESS(rc))
786 {
787 Assert(g_NtOsKrnlInfo.fOkay);
788 Assert(g_HalInfo.fOkay);
789 //RTR0DBG_NT_DEBUG_LOG(("RTR0DbgKrnlInfoQuerySymbol: Calling RTR0DbgKrnlInfoQuerySymbol on NT kernel...\n"));
790 rc = rtR0DbgKrnlInfoLookupSymbol(&g_NtOsKrnlInfo, pszSymbol, 0, ppvSymbol);
791 if (RT_FAILURE(rc))
792 {
793 //RTR0DBG_NT_DEBUG_LOG(("RTR0DbgKrnlInfoQuerySymbol: Calling RTR0DbgKrnlInfoQuerySymbol on HAL kernel...\n"));
794 rc = rtR0DbgKrnlInfoLookupSymbol(&g_HalInfo, pszSymbol, 0, ppvSymbol);
795 }
796 RTR0DBG_NT_DEBUG_LOG(("RTR0DbgKrnlInfoQuerySymbol: #1 returns %d *ppvSymbol=%p\n", rc, *ppvSymbol));
797 }
798 else
799 {
800 /* Init failed. Try resolve symbol, but preserve the status code up to a point. */
801 int rc2 = VERR_SYMBOL_NOT_FOUND;
802 if (g_NtOsKrnlInfo.fOkay)
803 rc2 = rtR0DbgKrnlInfoLookupSymbol(&g_NtOsKrnlInfo, pszSymbol, 0, ppvSymbol);
804 if (g_HalInfo.fOkay && rc2 == VERR_SYMBOL_NOT_FOUND)
805 rc2 = rtR0DbgKrnlInfoLookupSymbol(&g_HalInfo, pszSymbol, 0, ppvSymbol);
806 if ( rc2 == VERR_SYMBOL_NOT_FOUND
807 && g_pfnMmGetSystemRoutineAddress)
808 {
809 /* We'll overwrite init failure status code here since
810 MmGetSystemRoutineAddress will do the job for us. */
811 size_t cwcSymbol;
812 PRTUTF16 pwszSymbol = NULL;
813 rc = RTStrToUtf16Ex(pszSymbol, RTSTR_MAX, &pwszSymbol, 0, &cwcSymbol);
814 if (RT_SUCCESS(rc))
815 {
816 UNICODE_STRING UniStr;
817 UniStr.Buffer = pwszSymbol;
818 UniStr.Length = (uint16_t)(cwcSymbol * sizeof(RTUTF16));
819 UniStr.MaximumLength = UniStr.Length + sizeof(RTUTF16);
820 *ppvSymbol = g_pfnMmGetSystemRoutineAddress(&UniStr);
821 if (*ppvSymbol)
822 rc = VINF_SUCCESS;
823 else
824 rc = VERR_SYMBOL_NOT_FOUND;
825 RTUtf16Free(pwszSymbol);
826 RTR0DBG_NT_DEBUG_LOG(("RTR0DbgKrnlInfoQuerySymbol: #2 returns %d *ppvSymbol=%p\n", rc, *ppvSymbol));
827 }
828 }
829 }
830 }
831 else
832 {
833 /*
834 * Search specified module.
835 */
836 rc = VERR_MODULE_NOT_FOUND;
837 PRTDBGNTKRNLMODINFO pModInfo;
838 if (RTStrICmpAscii(pszModule, g_NtOsKrnlInfo.szName) == 0)
839 pModInfo = &g_NtOsKrnlInfo;
840 else if (RTStrICmpAscii(pszModule, g_HalInfo.szName) == 0)
841 pModInfo = &g_NtOsKrnlInfo;
842 else
843 {
844 pModInfo = NULL;
845 for (unsigned i = 0; i < pThis->cModules; i++)
846 if (RTStrICmpAscii(pszModule, pThis->aModules[i].szName) == 0)
847 {
848 pModInfo = &pThis->aModules[i];
849 break;
850 }
851 if (!pModInfo)
852 {
853 /*
854 * Not found, try load it. If module table is full, drop the first
855 * entry and shuffle the other up to make space.
856 */
857 size_t const cchModule = strlen(pszModule);
858 RTDBGNTKRNLMODINFO NewModInfo;
859 if (cchModule < sizeof(NewModInfo.szName))
860 {
861 RT_ZERO(NewModInfo);
862 memcpy(NewModInfo.szName, pszModule, cchModule);
863 NewModInfo.szName[cchModule] = '\0';
864
865 rc = rtR0DbgKrnlNtInit(&NewModInfo);
866 if (RT_SUCCESS(rc))
867 {
868 Assert(NewModInfo.fOkay);
869 uint32_t iModule = pThis->cModules;
870 if (iModule >= RT_ELEMENTS(pThis->aModules))
871 {
872 iModule = RT_ELEMENTS(pThis->aModules) - 1;
873 memmove(&pThis->aModules[0], &pThis->aModules[1], iModule * sizeof(pThis->aModules[0]));
874 }
875 pThis->aModules[iModule] = NewModInfo;
876 pThis->cModules = iModule + 1;
877 pModInfo = &pThis->aModules[iModule];
878 rc = VINF_SUCCESS;
879 }
880 }
881 else
882 {
883 AssertMsgFailed(("cchModule=%zu pszModule=%s\n", cchModule, pszModule));
884 rc = VERR_FILENAME_TOO_LONG;
885 }
886 }
887 }
888 if (pModInfo)
889 {
890 rc = rtR0DbgKrnlInfoLookupSymbol(pModInfo, pszSymbol, 0, ppvSymbol);
891 RTR0DBG_NT_DEBUG_LOG(("RTR0DbgKrnlInfoQuerySymbol: #3 returns %d *ppvSymbol=%p\n", rc, *ppvSymbol));
892 }
893 }
894 return rc;
895}
896
897
898RTR0DECL(int) RTR0DbgKrnlInfoQuerySize(RTDBGKRNLINFO hKrnlInfo, const char *pszModule, const char *pszType, size_t *pcbType)
899{
900 RTDBGKRNLINFOINT *pThis = hKrnlInfo;
901 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
902 AssertMsgReturn(pThis->u32Magic == RTDBGKRNLINFO_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
903 AssertPtrNullReturn(pszModule, VERR_INVALID_POINTER);
904 AssertPtrReturn(pszType, VERR_INVALID_POINTER);
905 AssertPtrReturn(pcbType, VERR_INVALID_POINTER);
906 return VERR_NOT_FOUND;
907}
908
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