VirtualBox

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

Last change on this file since 86669 was 85906, checked in by vboxsync, 4 years ago

Runtime/dbgkrnlinfo-r0drv-nt.cpp: Split up rtR0DbgKrnlNtInit() and make it reallocate the module information to the maximum and search again for a module symbol when not being found on the first try, fixes VERR_NEM_MISSING_KERNEL_API_2 when using Hyper-V on systems with a lot of loaded kernel modules, bugref:9044 comment 66 until 68 [scm fix]

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.8 KB
Line 
1/* $Id: dbgkrnlinfo-r0drv-nt.cpp 85906 2020-08-27 13:46:55Z 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.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 * Binary search.
174 */
175 __try
176 {
177 uint32_t iStart = 0;
178 uint32_t iEnd = pModInfo->cNamedExports;
179 while (iStart < iEnd)
180 {
181 uint32_t iCur = iStart + (iEnd - iStart) / 2;
182 uint32_t offExpName = pModInfo->paoffNamedExports[iCur];
183 if (offExpName >= pModInfo->offEndSectHdrs && offExpName < pModInfo->cbImage)
184 { /* likely */ }
185 else
186 {
187 RTR0DBG_NT_ERROR_LOG(("rtR0DbgKrnlInfoLookupSymbol: %s: Bad export name entry: %#x (iCur=%#x)\n",
188 pModInfo->szName, offExpName, iCur));
189 break;
190 }
191
192 const char *pszExpName = (const char *)&pModInfo->pbImageBase[offExpName];
193 int iDiff = strcmp(pszExpName, pszSymbol);
194 if (iDiff > 0) /* pszExpName > pszSymbol: search chunck before i */
195 iEnd = iCur;
196 else if (iDiff < 0) /* pszExpName < pszSymbol: search chunk after i */
197 iStart = iCur + 1;
198 else /* pszExpName == pszSymbol */
199 {
200 uint16_t iExpOrdinal = pModInfo->pau16NameOrdinals[iCur];
201 if (iExpOrdinal < pModInfo->cExports)
202 {
203 uint32_t offExport = pModInfo->paoffExports[iExpOrdinal];
204 if (offExport - pModInfo->offExportDir >= pModInfo->cbExportDir)
205 {
206 *ppvSymbol = (void *)&pModInfo->pbImageBase[offExport];
207 return VINF_SUCCESS;
208 }
209
210 /*
211 * Deal with forwarders to NT and HAL. No ordinals.
212 */
213 const char *pszForwarder = (const char *)&pModInfo->pbImageBase[offExport];
214 uint32_t cbMax = pModInfo->cbImage - offExpName;
215 size_t cchForwarder = RTStrNLen(pszForwarder, cbMax);
216 if (cchForwarder < cbMax)
217 {
218 if ( cchForwarder > 9
219 && pModInfo != &g_NtOsKrnlInfo
220 && g_NtOsKrnlInfo.pbImageBase != NULL
221 && cForwarders < 2
222 && (pszForwarder[0] == 'n' || pszForwarder[0] == 'N')
223 && (pszForwarder[1] == 't' || pszForwarder[1] == 'T')
224 && (pszForwarder[2] == 'o' || pszForwarder[2] == 'O')
225 && (pszForwarder[3] == 's' || pszForwarder[3] == 'S')
226 && (pszForwarder[4] == 'k' || pszForwarder[4] == 'K')
227 && (pszForwarder[5] == 'r' || pszForwarder[5] == 'R')
228 && (pszForwarder[6] == 'n' || pszForwarder[6] == 'N')
229 && (pszForwarder[7] == 'l' || pszForwarder[7] == 'L')
230 && pszForwarder[8] == '.')
231 return rtR0DbgKrnlInfoLookupSymbol(&g_NtOsKrnlInfo, pszForwarder + 9, cForwarders + 1, ppvSymbol);
232
233 if ( cchForwarder > 4
234 && pModInfo != &g_HalInfo
235 && g_HalInfo.pbImageBase != NULL
236 && cForwarders < 2
237 && (pszForwarder[0] == 'h' || pszForwarder[0] == 'H')
238 && (pszForwarder[1] == 'a' || pszForwarder[1] == 'A')
239 && (pszForwarder[2] == 'l' || pszForwarder[2] == 'L')
240 && pszForwarder[3] == '.')
241 return rtR0DbgKrnlInfoLookupSymbol(&g_HalInfo, pszForwarder + 4, cForwarders + 1, ppvSymbol);
242 }
243
244 RTR0DBG_NT_ERROR_LOG(("rtR0DbgKrnlInfoLookupSymbol: %s: Forwarded symbol '%s': offExport=%#x (dir %#x LB %#x)\n",
245 pModInfo->szName, pszSymbol, offExport, pModInfo->offExportDir, pModInfo->cbExportDir));
246 }
247 else
248 RTR0DBG_NT_ERROR_LOG(("rtR0DbgKrnlInfoLookupSymbol: %s: Name ordinal for '%s' is out of bounds: %#x (max %#x)\n",
249 pModInfo->szName, iExpOrdinal, pModInfo->cExports));
250 break;
251 }
252 }
253 }
254 __except(EXCEPTION_EXECUTE_HANDLER)
255 {
256 RTR0DBG_NT_ERROR_LOG(("rtR0DbgKrnlInfoLookupSymbol: Exception searching '%s' for '%s'...\n",
257 pModInfo->szName, pszSymbol));
258 }
259 }
260
261 *ppvSymbol = NULL;
262 return VERR_SYMBOL_NOT_FOUND;
263}
264
265
266/**
267 * Parses (PE) module headers and fills in the coresponding module info struct.
268 *
269 * @returns true on if success, false if not.
270 * @param pModInfo The module info structure to fill in with parsed
271 * data. The szName and fOkay are set by the
272 * caller, this function does the rest.
273 * @param pbMapping The image mapping address
274 * @param cbMapping The image mapping size.
275 *
276 * @note Support library has similar code for in the importless area.
277 */
278static bool rtR0DbgKrnlNtParseModule(PRTDBGNTKRNLMODINFO pModInfo, uint8_t const *pbMapping, size_t cbMapping)
279{
280#define MODERR_RETURN(a_LogMsg, ...) \
281 do { RTR0DBG_NT_ERROR_LOG(("rtR0DbgKrnlNtParseModule: " a_LogMsg, __VA_ARGS__)); return false; } while (0)
282
283 pModInfo->pbImageBase = pbMapping;
284
285 /*
286 * Locate the PE header, do some basic validations.
287 */
288 IMAGE_DOS_HEADER const *pMzHdr = (IMAGE_DOS_HEADER const *)pbMapping;
289 uint32_t offNtHdrs = 0;
290 PIMAGE_NT_HEADERS pNtHdrs;
291 if (pMzHdr->e_magic == IMAGE_DOS_SIGNATURE)
292 {
293 offNtHdrs = pMzHdr->e_lfanew;
294 if (offNtHdrs > _2K)
295 MODERR_RETURN("%s: e_lfanew=%#x, expected a lower value\n", pModInfo->szName, offNtHdrs);
296 }
297 pModInfo->pNtHdrs = pNtHdrs = (PIMAGE_NT_HEADERS)&pbMapping[offNtHdrs];
298
299 if (pNtHdrs->Signature != IMAGE_NT_SIGNATURE)
300 MODERR_RETURN("%s: Invalid PE signature: %#x", pModInfo->szName, pNtHdrs->Signature);
301 if (pNtHdrs->FileHeader.SizeOfOptionalHeader != sizeof(pNtHdrs->OptionalHeader))
302 MODERR_RETURN("%s: Unexpected optional header size: %#x\n", pModInfo->szName, pNtHdrs->FileHeader.SizeOfOptionalHeader);
303 if (pNtHdrs->OptionalHeader.Magic != RT_CONCAT3(IMAGE_NT_OPTIONAL_HDR,ARCH_BITS,_MAGIC))
304 MODERR_RETURN("%s: Unexpected optional header magic: %#x\n", pModInfo->szName, pNtHdrs->OptionalHeader.Magic);
305 if (pNtHdrs->OptionalHeader.NumberOfRvaAndSizes != IMAGE_NUMBEROF_DIRECTORY_ENTRIES)
306 MODERR_RETURN("%s: Unexpected number of RVA and sizes: %#x\n", pModInfo->szName, pNtHdrs->OptionalHeader.NumberOfRvaAndSizes);
307
308 pModInfo->offNtHdrs = offNtHdrs;
309 pModInfo->offEndSectHdrs = offNtHdrs
310 + sizeof(*pNtHdrs)
311 + pNtHdrs->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
312 pModInfo->cbImage = pNtHdrs->OptionalHeader.SizeOfImage;
313 if (pModInfo->cbImage > cbMapping)
314 MODERR_RETURN("%s: The image size %#x is larger than the mapping: %#x\n",
315 pModInfo->szName, pModInfo->cbImage, cbMapping);
316
317 /*
318 * Find the export directory.
319 */
320 IMAGE_DATA_DIRECTORY ExpDir = pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
321 if ( ExpDir.Size < sizeof(IMAGE_EXPORT_DIRECTORY)
322 || ExpDir.VirtualAddress < pModInfo->offEndSectHdrs
323 || ExpDir.VirtualAddress >= pModInfo->cbImage
324 || ExpDir.VirtualAddress + ExpDir.Size > pModInfo->cbImage)
325 MODERR_RETURN("%s: Missing or invalid export directory: %#lx LB %#x\n", pModInfo->szName, ExpDir.VirtualAddress, ExpDir.Size);
326 pModInfo->offExportDir = ExpDir.VirtualAddress;
327 pModInfo->cbExportDir = ExpDir.Size;
328
329 IMAGE_EXPORT_DIRECTORY const *pExpDir = (IMAGE_EXPORT_DIRECTORY const *)&pbMapping[ExpDir.VirtualAddress];
330
331 if ( pExpDir->NumberOfFunctions >= _1M
332 || pExpDir->NumberOfFunctions < 1
333 || pExpDir->NumberOfNames >= _1M
334 || pExpDir->NumberOfNames < 1)
335 MODERR_RETURN("%s: NumberOfNames or/and NumberOfFunctions are outside the expected range: nof=%#x non=%#x\n",
336 pModInfo->szName, pExpDir->NumberOfFunctions, pExpDir->NumberOfNames);
337 pModInfo->cNamedExports = pExpDir->NumberOfNames;
338 pModInfo->cExports = RT_MAX(pExpDir->NumberOfNames, pExpDir->NumberOfFunctions);
339
340 if ( pExpDir->AddressOfFunctions < pModInfo->offEndSectHdrs
341 || pExpDir->AddressOfFunctions >= pModInfo->cbImage
342 || pExpDir->AddressOfFunctions + pModInfo->cExports * sizeof(uint32_t) > pModInfo->cbImage)
343 MODERR_RETURN("%s: Bad AddressOfFunctions: %#x\n", pModInfo->szName, pExpDir->AddressOfFunctions);
344 pModInfo->paoffExports = (uint32_t const *)&pbMapping[pExpDir->AddressOfFunctions];
345
346 if ( pExpDir->AddressOfNames < pModInfo->offEndSectHdrs
347 || pExpDir->AddressOfNames >= pModInfo->cbImage
348 || pExpDir->AddressOfNames + pExpDir->NumberOfNames * sizeof(uint32_t) > pModInfo->cbImage)
349 MODERR_RETURN("%s: Bad AddressOfNames: %#x\n", pModInfo->szName, pExpDir->AddressOfNames);
350 pModInfo->paoffNamedExports = (uint32_t const *)&pbMapping[pExpDir->AddressOfNames];
351
352 if ( pExpDir->AddressOfNameOrdinals < pModInfo->offEndSectHdrs
353 || pExpDir->AddressOfNameOrdinals >= pModInfo->cbImage
354 || pExpDir->AddressOfNameOrdinals + pExpDir->NumberOfNames * sizeof(uint32_t) > pModInfo->cbImage)
355 MODERR_RETURN("%s: Bad AddressOfNameOrdinals: %#x\n", pModInfo->szName, pExpDir->AddressOfNameOrdinals);
356 pModInfo->pau16NameOrdinals = (uint16_t const *)&pbMapping[pExpDir->AddressOfNameOrdinals];
357
358 /*
359 * Success.
360 */
361 return true;
362#undef MODERR_RETURN
363}
364
365
366/**
367 * Searches the given module information from the kernel for the NT kernel module, the
368 * HAL module, and optionally one more module.
369 *
370 * If the NT kernel or HAL modules have already been found, they'll be skipped.
371 *
372 * @returns IPRT status code.
373 * @retval VERR_LDR_GENERAL_FAILURE if we failed to parse the NT kernel or HAL.
374 * @retval VERR_BAD_EXE_FORMAT if we failed to parse @a pModInfo.
375 * @retval VERR_MODULE_NOT_FOUND if @a pModInfo wasn't found.
376 *
377 * @param pInfo Pointer to the module information.
378 * @param cModules Number of valid module entries in the module information pointer.
379 * @param pModInfo Custom module to search for. Optional.
380 */
381static int rtR0DbgKrnlNtSearchForModuleWorker(PRTL_PROCESS_MODULES pInfo, uint32_t cModules, PRTDBGNTKRNLMODINFO pModInfo)
382{
383 AssertPtrReturn(pInfo, VERR_INVALID_PARAMETER);
384 AssertReturn(cModules >= 2, VERR_INVALID_PARAMETER);
385
386 /*
387 * Search the info. The information is ordered with the kernel bits first,
388 * we expect aleast two modules to be returned to us (kernel + hal)!
389 */
390 int rc = VINF_SUCCESS;
391#if ARCH_BITS == 32
392 uintptr_t const uMinKernelAddr = _2G; /** @todo resolve MmSystemRangeStart */
393#else
394 uintptr_t const uMinKernelAddr = (uintptr_t)MM_SYSTEM_RANGE_START;
395#endif
396
397 for (uint32_t iModule = 0; iModule < cModules; iModule++)
398 RTR0DBG_NT_DEBUG_LOG(("rtR0DbgKrnlNtInit: [%u]= %p LB %#x %s\n", iModule, pInfo->Modules[iModule].ImageBase,
399 pInfo->Modules[iModule].ImageSize, pInfo->Modules[iModule].FullPathName));
400
401 /*
402 * First time around we serch for the NT kernel and HAL. We'll look for NT
403 * kerneland HAL in the first 16 entries, and if not found, use the first
404 * and second entry respectively.
405 */
406 if ( !g_NtOsKrnlInfo.pbImageBase
407 && !g_HalInfo.pbImageBase)
408 {
409 /* Find them. */
410 RTR0DBG_NT_DEBUG_LOG(("rtR0DbgKrnlNtInit: Looking for kernel and hal...\n"));
411 uint32_t const cMaxModules = RT_MIN(cModules, 16);
412 uint32_t idxNtOsKrnl = UINT32_MAX;
413 uint32_t idxHal = UINT32_MAX;
414 for (uint32_t iModule = 0; iModule < cMaxModules; iModule++)
415 {
416 RTL_PROCESS_MODULE_INFORMATION const * const pModule = &pInfo->Modules[iModule];
417 if ( (uintptr_t)pModule->ImageBase >= uMinKernelAddr
418 && (uintptr_t)pModule->ImageSize >= _4K)
419 {
420 const char *pszName = (const char *)&pModule->FullPathName[pModule->OffsetToFileName];
421 if ( idxNtOsKrnl == UINT32_MAX
422 && RTStrICmpAscii(pszName, g_NtOsKrnlInfo.szName) == 0)
423 {
424 idxNtOsKrnl = iModule;
425 if (idxHal != UINT32_MAX)
426 break;
427 }
428 else if ( idxHal == UINT32_MAX
429 && RTStrICmpAscii(pszName, g_HalInfo.szName) == 0)
430 {
431 idxHal = iModule;
432 if (idxHal != UINT32_MAX)
433 break;
434 }
435 }
436 }
437 RTR0DBG_NT_DEBUG_LOG(("rtR0DbgKrnlNtInit: idxNtOsKrnl=%#x idxHal=%#x\n", idxNtOsKrnl, idxHal));
438 if (idxNtOsKrnl == UINT32_MAX)
439 {
440 idxNtOsKrnl = 0;
441 RTR0DBG_NT_ERROR_LOG(("rtR0DbgKrnlNtInit: 'ntoskrnl.exe' not found, picking '%s' instead\n",
442 pInfo->Modules[idxNtOsKrnl].FullPathName));
443 }
444 if (idxHal == UINT32_MAX)
445 {
446 idxHal = 1;
447 RTR0DBG_NT_ERROR_LOG(("rtR0DbgKrnlNtInit: 'hal.dll' not found, picking '%s' instead\n",
448 pInfo->Modules[idxHal].FullPathName));
449 }
450
451 /* Parse them. */
452 //RTR0DBG_NT_DEBUG_LOG(("rtR0DbgKrnlNtInit: Parsing NT kernel...\n"));
453 __try
454 {
455 g_NtOsKrnlInfo.fOkay = rtR0DbgKrnlNtParseModule(&g_NtOsKrnlInfo,
456 (uint8_t const *)pInfo->Modules[idxNtOsKrnl].ImageBase,
457 pInfo->Modules[idxNtOsKrnl].ImageSize);
458 }
459 __except(EXCEPTION_EXECUTE_HANDLER)
460 {
461 g_NtOsKrnlInfo.fOkay = false;
462 RTR0DBG_NT_ERROR_LOG(("rtR0DbgKrnlNtInit: Exception in rtR0DbgKrnlNtParseModule parsing ntoskrnl.exe...\n"));
463 }
464
465 //RTR0DBG_NT_DEBUG_LOG(("rtR0DbgKrnlNtInit: Parsing HAL...\n"));
466 __try
467 {
468 g_HalInfo.fOkay = rtR0DbgKrnlNtParseModule(&g_HalInfo, (uint8_t const *)pInfo->Modules[idxHal].ImageBase,
469 pInfo->Modules[idxHal].ImageSize);
470 }
471 __except(EXCEPTION_EXECUTE_HANDLER)
472 {
473 g_HalInfo.fOkay = false;
474 RTR0DBG_NT_ERROR_LOG(("rtR0DbgKrnlNtInit: Exception in rtR0DbgKrnlNtParseModule parsing hal.dll...\n"));
475 }
476 if (!g_NtOsKrnlInfo.fOkay || !g_HalInfo.fOkay)
477 rc = VERR_LDR_GENERAL_FAILURE;
478
479 /*
480 * Resolve symbols we may need in the NT kernel (provided it parsed successfully)
481 */
482 if (g_NtOsKrnlInfo.fOkay)
483 {
484 if (!g_pfnMmGetSystemRoutineAddress)
485 {
486 //RTR0DBG_NT_DEBUG_LOG(("rtR0DbgKrnlNtInit: Looking up 'MmGetSystemRoutineAddress'...\n"));
487 rtR0DbgKrnlInfoLookupSymbol(&g_NtOsKrnlInfo, "MmGetSystemRoutineAddress", 0,
488 (void **)&g_pfnMmGetSystemRoutineAddress);
489 }
490 }
491 }
492
493 /*
494 * If we're still good, search for the given module (optional).
495 */
496 if (RT_SUCCESS(rc) && pModInfo)
497 {
498 RTR0DBG_NT_DEBUG_LOG(("rtR0DbgKrnlNtInit: Locating module '%s'...\n", pModInfo->szName));
499 rc = VERR_MODULE_NOT_FOUND;
500 for (uint32_t iModule = 0; iModule < cModules; iModule++)
501 {
502 RTL_PROCESS_MODULE_INFORMATION const * const pModule = &pInfo->Modules[iModule];
503 if ( (uintptr_t)pModule->ImageBase >= uMinKernelAddr
504 && (uintptr_t)pModule->ImageSize >= _4K)
505 {
506 const char *pszName = (const char *)&pModule->FullPathName[pModule->OffsetToFileName];
507 if ( pModInfo->pbImageBase == NULL
508 && RTStrICmpAscii(pszName, pModInfo->szName) == 0)
509 {
510 /*
511 * Found the module, try parse it.
512 */
513 __try
514 {
515 pModInfo->fOkay = rtR0DbgKrnlNtParseModule(pModInfo, (uint8_t const *)pModule->ImageBase,
516 pModule->ImageSize);
517 rc = VINF_SUCCESS;
518 }
519 __except(EXCEPTION_EXECUTE_HANDLER)
520 {
521 pModInfo->fOkay = false;
522 rc = VERR_BAD_EXE_FORMAT;
523 }
524 break;
525 }
526 }
527 }
528 }
529
530 return rc;
531}
532
533
534/**
535 * Queries the given maximum amount of modules and returns a pointer to the
536 * allocation holding the modules.
537 *
538 * @returns IPRT status code.
539 * @param ppInfo Where to store the pointer to the module information structure on success.
540 * Free with RTMemFree() when done.
541 * @param cModulesMax Maximum number of modules to return.
542 * @param pcModules Where to store the amount of modules returned upon success,
543 * can be lower than the requested maximum.
544 */
545static int rtR0DbgKrnlNtQueryModules(PRTL_PROCESS_MODULES *ppInfo, uint32_t cModulesMax, uint32_t *pcModules)
546{
547 *ppInfo = NULL;
548 *pcModules = 0;
549
550 ULONG cbInfo = RT_UOFFSETOF_DYN(RTL_PROCESS_MODULES, Modules[cModulesMax]);
551 PRTL_PROCESS_MODULES pInfo = (PRTL_PROCESS_MODULES)RTMemAllocZ(cbInfo);
552 if (!pInfo)
553 {
554 cModulesMax = cModulesMax / 4;
555 cbInfo = RT_UOFFSETOF_DYN(RTL_PROCESS_MODULES, Modules[cModulesMax]);
556 pInfo = (PRTL_PROCESS_MODULES)RTMemAllocZ(cbInfo);
557 if (!pInfo)
558 {
559 RTR0DBG_NT_ERROR_LOG(("rtR0DbgKrnlNtQueryModules: Out of memory!\n"));
560 return VERR_NO_MEMORY;
561 }
562 }
563
564 int rc;
565 ULONG cbActual = 0;
566 NTSTATUS rcNt = ZwQuerySystemInformation(SystemModuleInformation, pInfo, cbInfo, &cbActual);
567 RTR0DBG_NT_DEBUG_LOG(("rtR0DbgKrnlNtQueryModules: ZwQuerySystemInformation returned %#x and NumberOfModules=%#x\n",
568 rcNt, pInfo->NumberOfModules));
569 if ( NT_SUCCESS(rcNt)
570 || rcNt == STATUS_INFO_LENGTH_MISMATCH)
571 {
572 *ppInfo = pInfo;
573 *pcModules = RT_MIN(cModulesMax, pInfo->NumberOfModules);
574 rc = VINF_SUCCESS;
575 }
576 else
577 {
578 RTMemFree(pInfo);
579 RTR0DBG_NT_ERROR_LOG(("rtR0DbgKrnlNtQueryModules: ZwQuerySystemInformation failed: %#x\n", rcNt));
580 rc = RTErrConvertFromNtStatus(rcNt);
581 }
582
583 return rc;
584}
585
586
587/**
588 * Searches the module information from the kernel for the NT kernel module, the
589 * HAL module, and optionally one more module.
590 *
591 * If the NT kernel or HAL modules have already been found, they'll be skipped.
592 *
593 * @returns IPRT status code.
594 * @retval VERR_LDR_GENERAL_FAILURE if we failed to parse the NT kernel or HAL.
595 * @retval VERR_BAD_EXE_FORMAT if we failed to parse @a pModInfo.
596 * @retval VERR_MODULE_NOT_FOUND if @a pModInfo wasn't found.
597 * @retval VERR_BUFFER_UNDERFLOW if less that two modules was returned by the
598 * system.
599 *
600 * @param pModInfo Custom module to search for. Optional.
601 */
602static int rtR0DbgKrnlNtInit(PRTDBGNTKRNLMODINFO pModInfo)
603{
604 RTR0DBG_NT_DEBUG_LOG(("rtR0DbgKrnlNtInit: pModInfo=%p\n", pModInfo));
605
606#ifndef IPRT_TARGET_NT4
607 /*
608 * Must manually initialize g_pfnMmGetSystemRoutineAddress, otherwise compiler
609 * generates its own dynamic init code that might not necessarily be called.
610 */
611 g_pfnMmGetSystemRoutineAddress = MmGetSystemRoutineAddress;
612#endif
613
614 /*
615 * Allocate a reasonably large buffer and get the information we need. We don't
616 * need everything since the result starts off with the kernel bits in load order.
617 *
618 * Note! ZwQuerySystemInformation requires NT4. For 3.51 we could possibly emit
619 * the syscall ourselves, if we cared.
620 */
621 uint32_t cModules = 0;
622 PRTL_PROCESS_MODULES pInfo = NULL;
623 int rc = rtR0DbgKrnlNtQueryModules(&pInfo, pModInfo ? 110 /*32KB*/ : 27 /*8KB*/, &cModules);
624 if (RT_SUCCESS(rc))
625 {
626 if (cModules >= 2)
627 {
628 rc = rtR0DbgKrnlNtSearchForModuleWorker(pInfo, cModules, pModInfo);
629 if ( rc == VERR_MODULE_NOT_FOUND
630 && pInfo->NumberOfModules > cModules
631 && pModInfo)
632 {
633 /* Module not found in the first round, reallocate array to maximum size and rerun. */
634 cModules = pInfo->NumberOfModules;
635
636 RTMemFree(pInfo);
637 pInfo = NULL;
638
639 rc = rtR0DbgKrnlNtQueryModules(&pInfo, cModules, &cModules);
640 if (RT_SUCCESS(rc))
641 {
642 rc = rtR0DbgKrnlNtSearchForModuleWorker(pInfo, cModules, pModInfo);
643 RTMemFree(pInfo);
644 }
645 }
646 }
647 else
648 {
649 RTMemFree(pInfo);
650 RTR0DBG_NT_ERROR_LOG(("rtR0DbgKrnlNtInit: Error! Only %u module(s) returned!\n", cModules));
651 rc = VERR_BUFFER_UNDERFLOW;
652 }
653 }
654
655 RTR0DBG_NT_DEBUG_LOG(("rtR0DbgKrnlNtInit: returns %d\n", rc));
656 return rc;
657}
658
659
660
661RTR0DECL(int) RTR0DbgKrnlInfoOpen(PRTDBGKRNLINFO phKrnlInfo, uint32_t fFlags)
662{
663 AssertReturn(!fFlags, VERR_INVALID_FLAGS);
664
665 RTDBGKRNLINFOINT *pThis = (RTDBGKRNLINFOINT *)RTMemAllocZ(sizeof(*pThis));
666 if (pThis)
667 {
668 pThis->u32Magic = RTDBGKRNLINFO_MAGIC;
669 pThis->cRefs = 1;
670 *phKrnlInfo = pThis;
671 return VINF_SUCCESS;
672 }
673 return VERR_NO_MEMORY;
674}
675
676
677RTR0DECL(uint32_t) RTR0DbgKrnlInfoRetain(RTDBGKRNLINFO hKrnlInfo)
678{
679 RTDBGKRNLINFOINT *pThis = hKrnlInfo;
680 AssertPtrReturn(pThis, UINT32_MAX);
681 AssertMsgReturn(pThis->u32Magic == RTDBGKRNLINFO_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), UINT32_MAX);
682
683 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
684 Assert(cRefs && cRefs < 100000);
685 return cRefs;
686}
687
688
689static void rtR0DbgKrnlNtDtor(RTDBGKRNLINFOINT *pThis)
690{
691 pThis->u32Magic = ~RTDBGKRNLINFO_MAGIC;
692 RTMemFree(pThis);
693}
694
695
696RTR0DECL(uint32_t) RTR0DbgKrnlInfoRelease(RTDBGKRNLINFO hKrnlInfo)
697{
698 RTDBGKRNLINFOINT *pThis = hKrnlInfo;
699 if (pThis == NIL_RTDBGKRNLINFO)
700 return 0;
701 AssertPtrReturn(pThis, UINT32_MAX);
702 AssertMsgReturn(pThis->u32Magic == RTDBGKRNLINFO_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), UINT32_MAX);
703
704 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
705 if (cRefs == 0)
706 rtR0DbgKrnlNtDtor(pThis);
707 return cRefs;
708}
709
710
711RTR0DECL(int) RTR0DbgKrnlInfoQueryMember(RTDBGKRNLINFO hKrnlInfo, const char *pszModule, const char *pszStructure,
712 const char *pszMember, size_t *poffMember)
713{
714 RTDBGKRNLINFOINT *pThis = hKrnlInfo;
715 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
716 AssertMsgReturn(pThis->u32Magic == RTDBGKRNLINFO_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
717 AssertPtrReturn(pszMember, VERR_INVALID_POINTER);
718 AssertPtrNullReturn(pszModule, VERR_INVALID_POINTER);
719 AssertPtrReturn(pszStructure, VERR_INVALID_POINTER);
720 AssertPtrReturn(poffMember, VERR_INVALID_POINTER);
721 return VERR_NOT_FOUND;
722}
723
724
725RTR0DECL(int) RTR0DbgKrnlInfoQuerySymbol(RTDBGKRNLINFO hKrnlInfo, const char *pszModule, const char *pszSymbol, void **ppvSymbol)
726{
727 RTDBGKRNLINFOINT *pThis = hKrnlInfo;
728 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
729 AssertMsgReturn(pThis->u32Magic == RTDBGKRNLINFO_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
730 AssertPtrReturn(pszSymbol, VERR_INVALID_PARAMETER);
731 AssertPtrNullReturn(ppvSymbol, VERR_INVALID_PARAMETER);
732
733 RTR0DBG_NT_DEBUG_LOG(("RTR0DbgKrnlInfoQuerySymbol: pszModule=%s pszSymbol=%s\n", pszModule ? pszModule : "<null>", pszSymbol));
734
735 void *pvTmpSymbol = NULL;
736 if (!ppvSymbol)
737 ppvSymbol = &pvTmpSymbol;
738
739 int rc;
740 if (!pszModule)
741 {
742 /*
743 * Search both ntoskrnl and hal, may use MmGetSystemRoutineAddress as fallback.
744 * Note! MmGetSystemRoutineAddress was buggy before XP SP2 according to Geoff Chappell.
745 */
746 if (g_NtOsKrnlInfo.pbImageBase)
747 rc = VINF_SUCCESS;
748 else
749 rc = rtR0DbgKrnlNtInit(NULL);
750 if (RT_SUCCESS(rc))
751 {
752 Assert(g_NtOsKrnlInfo.fOkay);
753 Assert(g_HalInfo.fOkay);
754 //RTR0DBG_NT_DEBUG_LOG(("RTR0DbgKrnlInfoQuerySymbol: Calling RTR0DbgKrnlInfoQuerySymbol on NT kernel...\n"));
755 rc = rtR0DbgKrnlInfoLookupSymbol(&g_NtOsKrnlInfo, pszSymbol, 0, ppvSymbol);
756 if (RT_FAILURE(rc))
757 {
758 //RTR0DBG_NT_DEBUG_LOG(("RTR0DbgKrnlInfoQuerySymbol: Calling RTR0DbgKrnlInfoQuerySymbol on HAL kernel...\n"));
759 rc = rtR0DbgKrnlInfoLookupSymbol(&g_HalInfo, pszSymbol, 0, ppvSymbol);
760 }
761 RTR0DBG_NT_DEBUG_LOG(("RTR0DbgKrnlInfoQuerySymbol: #1 returns %d *ppvSymbol=%p\n", rc, *ppvSymbol));
762 }
763 else
764 {
765 /* Init failed. Try resolve symbol, but preserve the status code up to a point. */
766 int rc2 = VERR_SYMBOL_NOT_FOUND;
767 if (g_NtOsKrnlInfo.fOkay)
768 rc2 = rtR0DbgKrnlInfoLookupSymbol(&g_NtOsKrnlInfo, pszSymbol, 0, ppvSymbol);
769 if (g_HalInfo.fOkay && rc2 == VERR_SYMBOL_NOT_FOUND)
770 rc2 = rtR0DbgKrnlInfoLookupSymbol(&g_HalInfo, pszSymbol, 0, ppvSymbol);
771 if ( rc2 == VERR_SYMBOL_NOT_FOUND
772 && g_pfnMmGetSystemRoutineAddress)
773 {
774 /* We'll overwrite init failure status code here since
775 MmGetSystemRoutineAddress will do the job for us. */
776 size_t cwcSymbol;
777 PRTUTF16 pwszSymbol = NULL;
778 rc = RTStrToUtf16Ex(pszSymbol, RTSTR_MAX, &pwszSymbol, 0, &cwcSymbol);
779 if (RT_SUCCESS(rc))
780 {
781 UNICODE_STRING UniStr;
782 UniStr.Buffer = pwszSymbol;
783 UniStr.Length = (uint16_t)(cwcSymbol * sizeof(RTUTF16));
784 UniStr.MaximumLength = UniStr.Length + sizeof(RTUTF16);
785 *ppvSymbol = g_pfnMmGetSystemRoutineAddress(&UniStr);
786 if (*ppvSymbol)
787 rc = VINF_SUCCESS;
788 else
789 rc = VERR_SYMBOL_NOT_FOUND;
790 RTUtf16Free(pwszSymbol);
791 RTR0DBG_NT_DEBUG_LOG(("RTR0DbgKrnlInfoQuerySymbol: #2 returns %d *ppvSymbol=%p\n", rc, *ppvSymbol));
792 }
793 }
794 }
795 }
796 else
797 {
798 /*
799 * Search specified module.
800 */
801 rc = VERR_MODULE_NOT_FOUND;
802 PRTDBGNTKRNLMODINFO pModInfo;
803 if (RTStrICmpAscii(pszModule, g_NtOsKrnlInfo.szName) == 0)
804 pModInfo = &g_NtOsKrnlInfo;
805 else if (RTStrICmpAscii(pszModule, g_HalInfo.szName) == 0)
806 pModInfo = &g_NtOsKrnlInfo;
807 else
808 {
809 pModInfo = NULL;
810 for (unsigned i = 0; i < pThis->cModules; i++)
811 if (RTStrICmpAscii(pszModule, pThis->aModules[i].szName) == 0)
812 {
813 pModInfo = &pThis->aModules[i];
814 break;
815 }
816 if (!pModInfo)
817 {
818 /*
819 * Not found, try load it. If module table is full, drop the first
820 * entry and shuffle the other up to make space.
821 */
822 size_t const cchModule = strlen(pszModule);
823 RTDBGNTKRNLMODINFO NewModInfo;
824 if (cchModule < sizeof(NewModInfo.szName))
825 {
826 RT_ZERO(NewModInfo);
827 memcpy(NewModInfo.szName, pszModule, cchModule);
828 NewModInfo.szName[cchModule] = '\0';
829
830 rc = rtR0DbgKrnlNtInit(&NewModInfo);
831 if (RT_SUCCESS(rc))
832 {
833 Assert(NewModInfo.fOkay);
834 uint32_t iModule = pThis->cModules;
835 if (iModule >= RT_ELEMENTS(pThis->aModules))
836 {
837 iModule = RT_ELEMENTS(pThis->aModules) - 1;
838 memmove(&pThis->aModules[0], &pThis->aModules[1], iModule * sizeof(pThis->aModules[0]));
839 }
840 pThis->aModules[iModule] = NewModInfo;
841 pThis->cModules = iModule + 1;
842 pModInfo = &pThis->aModules[iModule];
843 rc = VINF_SUCCESS;
844 }
845 }
846 else
847 {
848 AssertMsgFailed(("cchModule=%zu pszModule=%s\n", cchModule, pszModule));
849 rc = VERR_FILENAME_TOO_LONG;
850 }
851 }
852 }
853 if (pModInfo)
854 {
855 rc = rtR0DbgKrnlInfoLookupSymbol(pModInfo, pszSymbol, 0, ppvSymbol);
856 RTR0DBG_NT_DEBUG_LOG(("RTR0DbgKrnlInfoQuerySymbol: #3 returns %d *ppvSymbol=%p\n", rc, *ppvSymbol));
857 }
858 }
859 return rc;
860}
861
862
863RTR0DECL(int) RTR0DbgKrnlInfoQuerySize(RTDBGKRNLINFO hKrnlInfo, const char *pszModule, const char *pszType, size_t *pcbType)
864{
865 RTDBGKRNLINFOINT *pThis = hKrnlInfo;
866 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
867 AssertMsgReturn(pThis->u32Magic == RTDBGKRNLINFO_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
868 AssertPtrNullReturn(pszModule, VERR_INVALID_POINTER);
869 AssertPtrReturn(pszType, VERR_INVALID_POINTER);
870 AssertPtrReturn(pcbType, VERR_INVALID_POINTER);
871 return VERR_NOT_FOUND;
872}
873
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