VirtualBox

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

Last change on this file since 97698 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

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