VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/PDMLdr.cpp@ 107044

Last change on this file since 107044 was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 64.1 KB
Line 
1/* $Id: PDMLdr.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * PDM - Pluggable Device Manager, module loader.
4 */
5
6/*
7 * Copyright (C) 2006-2024 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 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28//#define PDMLDR_FAKE_MODE
29
30
31/*********************************************************************************************************************************
32* Header Files *
33*********************************************************************************************************************************/
34#define LOG_GROUP LOG_GROUP_PDM_LDR
35#include "PDMInternal.h"
36#include <VBox/vmm/pdm.h>
37#include <VBox/vmm/mm.h>
38#include <VBox/vmm/trpm.h>
39#include <VBox/vmm/vmm.h>
40#include <VBox/vmm/vm.h>
41#include <VBox/vmm/uvm.h>
42#include <VBox/sup.h>
43#include <VBox/param.h>
44#include <VBox/err.h>
45#include <VBox/vmm/hm.h>
46#include <VBox/VBoxTpG.h>
47
48#include <VBox/log.h>
49#include <iprt/assert.h>
50#include <iprt/ctype.h>
51#include <iprt/file.h>
52#include <iprt/ldr.h>
53#include <iprt/mem.h>
54#include <iprt/path.h>
55#include <iprt/string.h>
56
57#include <limits.h>
58
59
60/*********************************************************************************************************************************
61* Structures and Typedefs *
62*********************************************************************************************************************************/
63/**
64 * Structure which the user argument of the RTLdrGetBits() callback points to.
65 * @internal
66 */
67typedef struct PDMGETIMPORTARGS
68{
69 PVM pVM;
70 PPDMMOD pModule;
71} PDMGETIMPORTARGS, *PPDMGETIMPORTARGS;
72
73
74/*********************************************************************************************************************************
75* Internal Functions *
76*********************************************************************************************************************************/
77#ifdef VBOX_WITH_RAW_MODE_KEEP
78static DECLCALLBACK(int) pdmR3GetImportRC(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol, unsigned uSymbol, RTUINTPTR *pValue, void *pvUser);
79static char *pdmR3FileRC(const char *pszFile, const char *pszSearchPath);
80#endif
81static int pdmR3LoadR0U(PUVM pUVM, const char *pszFilename, const char *pszName, const char *pszSearchPath);
82static char *pdmR3FileR0(const char *pszFile, const char *pszSearchPath);
83static char *pdmR3File(const char *pszFile, const char *pszDefaultExt, const char *pszSearchPath, bool fShared);
84
85
86
87/**
88 * Loads the VMMR0.r0 module early in the init process.
89 *
90 * @returns VBox status code.
91 * @param pUVM Pointer to the user mode VM structure.
92 */
93VMMR3_INT_DECL(int) PDMR3LdrLoadVMMR0U(PUVM pUVM)
94{
95 return pdmR3LoadR0U(pUVM, NULL, VMMR0_MAIN_MODULE_NAME, NULL);
96}
97
98
99/**
100 * Init the module loader part of PDM.
101 *
102 * This routine will load the Host Context Ring-0 and Guest
103 * Context VMM modules.
104 *
105 * @returns VBox status code.
106 * @param pUVM The user mode VM structure.
107 */
108int pdmR3LdrInitU(PUVM pUVM)
109{
110#if !defined(PDMLDR_FAKE_MODE) && defined(VBOX_WITH_RAW_MODE_KEEP)
111 /*
112 * Load the mandatory RC module, the VMMR0.r0 is loaded before VM creation.
113 */
114 PVM pVM = pUVM->pVM; AssertPtr(pVM);
115 if (VM_IS_RAW_MODE_ENABLED(pVM))
116 {
117 int rc = PDMR3LdrLoadRC(pVM, NULL, VMMRC_MAIN_MODULE_NAME);
118 if (RT_FAILURE(rc))
119 return rc;
120 }
121#else
122 RT_NOREF(pUVM);
123#endif
124 return VINF_SUCCESS;
125}
126
127
128/**
129 * Terminate the module loader part of PDM.
130 *
131 * This will unload and free all modules.
132 *
133 * @param pUVM The user mode VM structure.
134 * @param fFinal This is clear when in the PDMR3Term/vmR3Destroy call
135 * chain, and set when called from PDMR3TermUVM.
136 *
137 * @remarks This is normally called twice during termination.
138 */
139void pdmR3LdrTermU(PUVM pUVM, bool fFinal)
140{
141 /*
142 * Free the modules.
143 */
144 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
145 PPDMMOD pModule = pUVM->pdm.s.pModules;
146 pUVM->pdm.s.pModules = NULL;
147 PPDMMOD *ppNext = &pUVM->pdm.s.pModules;
148 while (pModule)
149 {
150 /* free loader item. */
151 if (pModule->hLdrMod != NIL_RTLDRMOD)
152 {
153 int rc2 = RTLdrClose(pModule->hLdrMod);
154 AssertRC(rc2);
155 pModule->hLdrMod = NIL_RTLDRMOD;
156 }
157
158 /* free bits. */
159 switch (pModule->eType)
160 {
161 case PDMMOD_TYPE_R0:
162 {
163 if (fFinal)
164 {
165 Assert(pModule->ImageBase);
166 int rc2 = SUPR3FreeModule((void *)(uintptr_t)pModule->ImageBase);
167 AssertRC(rc2);
168 pModule->ImageBase = 0;
169 break;
170 }
171
172 /* Postpone ring-0 module till the PDMR3TermUVM() phase as VMMR0.r0 is still
173 busy when we're called the first time very very early in vmR3Destroy(). */
174 PPDMMOD pNextModule = pModule->pNext;
175
176 pModule->pNext = NULL;
177 *ppNext = pModule;
178 ppNext = &pModule->pNext;
179
180 pModule = pNextModule;
181 continue;
182 }
183
184#ifdef VBOX_WITH_RAW_MODE_KEEP
185 case PDMMOD_TYPE_RC:
186#endif
187 case PDMMOD_TYPE_R3:
188 /* MM will free this memory for us - it's alloc only memory. :-) */
189 break;
190
191 default:
192 AssertMsgFailed(("eType=%d\n", pModule->eType));
193 break;
194 }
195 pModule->pvBits = NULL;
196
197 void *pvFree = pModule;
198 pModule = pModule->pNext;
199 RTMemFree(pvFree);
200 }
201 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
202}
203
204
205/**
206 * Applies relocations to RC modules.
207 *
208 * This must be done very early in the relocation
209 * process so that components can resolve RC symbols during relocation.
210 *
211 * @param pUVM Pointer to the user mode VM structure.
212 * @param offDelta Relocation delta relative to old location.
213 */
214VMMR3_INT_DECL(void) PDMR3LdrRelocateU(PUVM pUVM, RTGCINTPTR offDelta)
215{
216#ifdef VBOX_WITH_RAW_MODE_KEEP
217 LogFlow(("PDMR3LdrRelocate: offDelta=%RGv\n", offDelta));
218 RT_NOREF1(offDelta);
219
220 /*
221 * RC Modules.
222 */
223 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
224 if (pUVM->pdm.s.pModules)
225 {
226 /*
227 * The relocation have to be done in two passes so imports
228 * can be correctly resolved. The first pass will update
229 * the ImageBase saving the current value in OldImageBase.
230 * The second pass will do the actual relocation.
231 */
232 /* pass 1 */
233 PPDMMOD pCur;
234 for (pCur = pUVM->pdm.s.pModules; pCur; pCur = pCur->pNext)
235 {
236 if (pCur->eType == PDMMOD_TYPE_RC)
237 {
238 pCur->OldImageBase = pCur->ImageBase;
239 pCur->ImageBase = MMHyperR3ToRC(pUVM->pVM, pCur->pvBits);
240 }
241 }
242
243 /* pass 2 */
244 for (pCur = pUVM->pdm.s.pModules; pCur; pCur = pCur->pNext)
245 {
246 if (pCur->eType == PDMMOD_TYPE_RC)
247 {
248 PDMGETIMPORTARGS Args;
249 Args.pVM = pUVM->pVM;
250 Args.pModule = pCur;
251 int rc = RTLdrRelocate(pCur->hLdrMod, pCur->pvBits, pCur->ImageBase, pCur->OldImageBase,
252 pdmR3GetImportRC, &Args);
253 AssertFatalMsgRC(rc, ("RTLdrRelocate failed, rc=%d\n", rc));
254 }
255 }
256 }
257 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
258#else
259 RT_NOREF2(pUVM, offDelta);
260#endif
261}
262
263
264/**
265 * Loads a module into the host context ring-3.
266 *
267 * This is used by the driver and device init functions to load modules
268 * containing the drivers and devices. The function can be extended to
269 * load modules which are not native to the environment we're running in,
270 * but at the moment this is not required.
271 *
272 * No reference counting is kept, since we don't implement any facilities
273 * for unloading the module. But the module will naturally be released
274 * when the VM terminates.
275 *
276 * @returns VBox status code.
277 * @param pUVM Pointer to the user mode VM structure.
278 * @param pszFilename Filename of the module binary.
279 * @param pszName Module name. Case sensitive and the length is limited!
280 */
281int pdmR3LoadR3U(PUVM pUVM, const char *pszFilename, const char *pszName)
282{
283 /*
284 * Validate input.
285 */
286 AssertMsg(RTCritSectIsInitialized(&pUVM->pdm.s.ListCritSect), ("bad init order!\n"));
287 Assert(pszFilename);
288 size_t cchFilename = strlen(pszFilename);
289 Assert(pszName);
290 size_t cchName = strlen(pszName);
291 PPDMMOD pCur;
292 if (cchName >= sizeof(pCur->szName))
293 {
294 AssertMsgFailed(("Name is too long, cchName=%d pszName='%s'\n", cchName, pszName));
295 return VERR_INVALID_PARAMETER;
296 }
297
298 /*
299 * Try lookup the name and see if the module exists.
300 */
301 int rc;
302 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
303 for (pCur = pUVM->pdm.s.pModules; pCur; pCur = pCur->pNext)
304 {
305 if (!strcmp(pCur->szName, pszName))
306 {
307 if (pCur->eType == PDMMOD_TYPE_R3)
308 rc = VINF_PDM_ALREADY_LOADED;
309 else
310 rc = VERR_PDM_MODULE_NAME_CLASH;
311 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
312
313 AssertMsgRC(rc, ("We've already got a module '%s' loaded!\n", pszName));
314 return rc;
315 }
316 }
317
318 /*
319 * Allocate the module list node and initialize it.
320 */
321 const char *pszSuff = RTLdrGetSuff();
322 size_t cchSuff = RTPathHasSuffix(pszFilename) ? 0 : strlen(pszSuff);
323 PPDMMOD pModule = (PPDMMOD)RTMemAllocZ(RT_UOFFSETOF_DYN(PDMMOD, szFilename[cchFilename + cchSuff + 1]));
324 if (pModule)
325 {
326 pModule->eType = PDMMOD_TYPE_R3;
327 memcpy(pModule->szName, pszName, cchName); /* memory is zero'd, no need to copy terminator :-) */
328 memcpy(pModule->szFilename, pszFilename, cchFilename);
329 memcpy(&pModule->szFilename[cchFilename], pszSuff, cchSuff);
330
331 /*
332 * Load the loader item.
333 */
334 RTERRINFOSTATIC ErrInfo;
335 RTErrInfoInitStatic(&ErrInfo);
336 rc = SUPR3HardenedLdrLoadPlugIn(pModule->szFilename, &pModule->hLdrMod, &ErrInfo.Core);
337 if (RT_SUCCESS(rc))
338 {
339 pModule->pNext = pUVM->pdm.s.pModules;
340 pUVM->pdm.s.pModules = pModule;
341 }
342 else
343 {
344 /* Something went wrong, most likely module not found. Don't consider other unlikely errors */
345 rc = VMSetError(pUVM->pVM, rc, RT_SRC_POS,
346 N_("Unable to load R3 module %s (%s): %s"), pModule->szFilename, pszName, ErrInfo.Core.pszMsg);
347 RTMemFree(pModule);
348 }
349 }
350 else
351 rc = VERR_NO_MEMORY;
352
353 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
354 return rc;
355}
356
357#ifdef VBOX_WITH_RAW_MODE_KEEP
358
359/**
360 * Resolve an external symbol during RTLdrGetBits() of a RC module.
361 *
362 * @returns VBox status code.
363 * @param hLdrMod The loader module handle.
364 * @param pszModule Module name.
365 * @param pszSymbol Symbol name, NULL if uSymbol should be used.
366 * @param uSymbol Symbol ordinal, ~0 if pszSymbol should be used.
367 * @param pValue Where to store the symbol value (address).
368 * @param pvUser User argument.
369 */
370static DECLCALLBACK(int) pdmR3GetImportRC(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol, unsigned uSymbol,
371 RTUINTPTR *pValue, void *pvUser)
372{
373 PVM pVM = ((PPDMGETIMPORTARGS)pvUser)->pVM;
374 PPDMMOD pModule = ((PPDMGETIMPORTARGS)pvUser)->pModule;
375 NOREF(hLdrMod); NOREF(uSymbol);
376
377 /*
378 * Adjust input.
379 */
380 if (pszModule && !*pszModule)
381 pszModule = NULL;
382
383 /*
384 * Builtin module.
385 */
386 if (!pszModule || !strcmp(pszModule, "VMMRCBuiltin.rc"))
387 {
388 int rc = VINF_SUCCESS;
389 if (!strcmp(pszSymbol, "g_VM"))
390 *pValue = pVM->pVMRC;
391 else if (!strcmp(pszSymbol, "g_VCpu0"))
392 *pValue = pVM->pVMRC + pVM->offVMCPU;
393 else if (!strcmp(pszSymbol, "g_CPUM"))
394 *pValue = VM_RC_ADDR(pVM, &pVM->cpum);
395 else if ( !strncmp(pszSymbol, "g_TRPM", 6)
396 || !strncmp(pszSymbol, "g_trpm", 6)
397 || !strncmp(pszSymbol, "TRPM", 4))
398 {
399 RTRCPTR RCPtr = 0;
400 rc = TRPMR3GetImportRC(pVM, pszSymbol, &RCPtr);
401 if (RT_SUCCESS(rc))
402 *pValue = RCPtr;
403 }
404 else if ( !strncmp(pszSymbol, "VMM", 3)
405 || !strcmp(pszSymbol, "g_Logger")
406 || !strcmp(pszSymbol, "g_RelLogger"))
407 {
408 RTRCPTR RCPtr = 0;
409 rc = VMMR3GetImportRC(pVM, pszSymbol, &RCPtr);
410 if (RT_SUCCESS(rc))
411 *pValue = RCPtr;
412 }
413 else
414 {
415 AssertMsg(!pszModule, ("Unknown builtin symbol '%s' for module '%s'!\n", pszSymbol, pModule->szName)); NOREF(pModule);
416 rc = VERR_SYMBOL_NOT_FOUND;
417 }
418 if (RT_SUCCESS(rc) || pszModule)
419 {
420 if (RT_FAILURE(rc))
421 LogRel(("PDMLdr: Couldn't find symbol '%s' in module '%s'!\n", pszSymbol, pszModule));
422 return rc;
423 }
424 }
425
426 /*
427 * Search for module.
428 */
429 PUVM pUVM = pVM->pUVM;
430 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
431 PPDMMOD pCur = pUVM->pdm.s.pModules;
432 while (pCur)
433 {
434 if ( pCur->eType == PDMMOD_TYPE_RC
435 && ( !pszModule
436 || !strcmp(pCur->szName, pszModule))
437 )
438 {
439 /* Search for the symbol. */
440 int rc = RTLdrGetSymbolEx(pCur->hLdrMod, pCur->pvBits, pCur->ImageBase, UINT32_MAX, pszSymbol, pValue);
441 if (RT_SUCCESS(rc))
442 {
443 AssertMsg(*pValue - pCur->ImageBase < RTLdrSize(pCur->hLdrMod),
444 ("%RRv-%RRv %s %RRv\n", (RTRCPTR)pCur->ImageBase,
445 (RTRCPTR)(pCur->ImageBase + RTLdrSize(pCur->hLdrMod) - 1),
446 pszSymbol, (RTRCPTR)*pValue));
447 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
448 return rc;
449 }
450 if (pszModule)
451 {
452 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
453 AssertLogRelMsgFailed(("PDMLdr: Couldn't find symbol '%s' in module '%s'!\n", pszSymbol, pszModule));
454 return VERR_SYMBOL_NOT_FOUND;
455 }
456 }
457
458 /* next */
459 pCur = pCur->pNext;
460 }
461
462 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
463 AssertLogRelMsgFailed(("Couldn't find module '%s' for resolving symbol '%s'!\n", pszModule, pszSymbol));
464 return VERR_SYMBOL_NOT_FOUND;
465}
466
467
468/**
469 * Loads a module into the raw-mode context (i.e. into the Hypervisor memory
470 * region).
471 *
472 * @returns VBox status code.
473 * @retval VINF_PDM_ALREADY_LOADED if the module is already loaded (name +
474 * filename match).
475 * @retval VERR_PDM_MODULE_NAME_CLASH if a different file has already been
476 * loaded with the name module name.
477 *
478 * @param pVM The cross context VM structure.
479 * @param pszFilename Filename of the module binary.
480 * @param pszName Module name. Case sensitive and the length is limited!
481 */
482VMMR3DECL(int) PDMR3LdrLoadRC(PVM pVM, const char *pszFilename, const char *pszName)
483{
484 /*
485 * Validate input.
486 */
487 AssertReturn(VM_IS_RAW_MODE_ENABLED(pVM), VERR_PDM_HM_IPE);
488
489 /*
490 * Find the file if not specified.
491 */
492 char *pszFile = NULL;
493 if (!pszFilename)
494 pszFilename = pszFile = pdmR3FileRC(pszName, NULL);
495
496 /*
497 * Check if a module by that name is already loaded.
498 */
499 int rc;
500 PUVM pUVM = pVM->pUVM;
501 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
502 PPDMMOD pCur = pUVM->pdm.s.pModules;
503 while (pCur)
504 {
505 if (!strcmp(pCur->szName, pszName))
506 {
507 /* Name clash. Hopefully due to it being the same file. */
508 if (!strcmp(pCur->szFilename, pszFilename))
509 rc = VINF_PDM_ALREADY_LOADED;
510 else
511 {
512 rc = VERR_PDM_MODULE_NAME_CLASH;
513 AssertMsgFailed(("We've already got a module '%s' loaded!\n", pszName));
514 }
515 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
516 RTMemTmpFree(pszFile);
517 return rc;
518 }
519 /* next */
520 pCur = pCur->pNext;
521 }
522
523 /*
524 * Allocate the module list node.
525 */
526 PPDMMOD pModule = (PPDMMOD)RTMemAllocZ(sizeof(*pModule) + strlen(pszFilename));
527 if (!pModule)
528 {
529 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
530 RTMemTmpFree(pszFile);
531 return VERR_NO_MEMORY;
532 }
533 AssertMsg(strlen(pszName) + 1 < sizeof(pModule->szName),
534 ("pazName is too long (%d chars) max is %d chars.\n", strlen(pszName), sizeof(pModule->szName) - 1));
535 strcpy(pModule->szName, pszName);
536 pModule->eType = PDMMOD_TYPE_RC;
537 strcpy(pModule->szFilename, pszFilename);
538
539
540 /*
541 * Open the loader item.
542 */
543 RTERRINFOSTATIC ErrInfo;
544 RTErrInfoInitStatic(&ErrInfo);
545 rc = SUPR3HardenedVerifyPlugIn(pszFilename, &ErrInfo.Core);
546 if (RT_SUCCESS(rc))
547 {
548 RTErrInfoClear(&ErrInfo.Core);
549 rc = RTLdrOpen(pszFilename, 0, RTLDRARCH_X86_32, &pModule->hLdrMod);
550 }
551 if (RT_SUCCESS(rc))
552 {
553 /*
554 * Allocate space in the hypervisor.
555 */
556 size_t cb = RTLdrSize(pModule->hLdrMod);
557 cb = RT_ALIGN_Z(cb, RT_MAX(GUEST_PAGE_SIZE, HOST_PAGE_SIZE));
558 uint32_t cPages = (uint32_t)(cb >> HOST_PAGE_SHIFT);
559 if (((size_t)cPages << HOST_PAGE_SHIFT) == cb)
560 {
561 PSUPPAGE paPages = (PSUPPAGE)RTMemTmpAlloc(cPages * sizeof(paPages[0]));
562 if (paPages)
563 {
564 rc = SUPR3PageAllocEx(cPages, 0 /*fFlags*/, &pModule->pvBits, NULL /*pR0Ptr*/, paPages);
565 if (RT_SUCCESS(rc))
566 {
567 RTGCPTR GCPtr;
568 rc = VERR_NOT_IMPLEMENTED; //MMR3HyperMapPages(pVM, pModule->pvBits, NIL_RTR0PTR, cPages, paPages, pModule->szName, &GCPtr);
569 if (RT_SUCCESS(rc))
570 {
571 //MMR3HyperReserveFence(pVM);
572
573 /*
574 * Get relocated image bits.
575 */
576 Assert(MMHyperR3ToRC(pVM, pModule->pvBits) == GCPtr);
577 pModule->ImageBase = GCPtr;
578 PDMGETIMPORTARGS Args;
579 Args.pVM = pVM;
580 Args.pModule = pModule;
581 rc = RTLdrGetBits(pModule->hLdrMod, pModule->pvBits, pModule->ImageBase, pdmR3GetImportRC, &Args);
582 if (RT_SUCCESS(rc))
583 {
584#ifdef VBOX_WITH_DTRACE_RC
585 /*
586 * Register the tracer bits if present.
587 */
588 RTLDRADDR uValue;
589 rc = RTLdrGetSymbolEx(pModule->hLdrMod, pModule->pvBits, pModule->ImageBase, UINT32_MAX,
590 "g_VTGObjHeader", &uValue);
591 if (RT_SUCCESS(rc))
592 {
593 PVTGOBJHDR pVtgHdr = (PVTGOBJHDR)MMHyperRCToCC(pVM, (RTRCPTR)uValue);
594 if ( pVtgHdr
595 && !memcmp(pVtgHdr->szMagic, VTGOBJHDR_MAGIC, sizeof(pVtgHdr->szMagic)))
596 rc = SUPR3TracerRegisterModule(~(uintptr_t)0, pModule->szName, pVtgHdr, uValue,
597 SUP_TRACER_UMOD_FLAGS_SHARED);
598 else
599 rc = pVtgHdr ? VERR_INVALID_MAGIC : VERR_INVALID_POINTER;
600 if (RT_FAILURE(rc))
601 LogRel(("PDMLdr: Failed to register tracepoints for '%s': %Rrc\n", pModule->szName, rc));
602 }
603#endif
604
605 /*
606 * Insert the module.
607 */
608 if (pUVM->pdm.s.pModules)
609 {
610 /* we don't expect this list to be very long, so rather save the tail pointer. */
611 pCur = pUVM->pdm.s.pModules;
612 while (pCur->pNext)
613 pCur = pCur->pNext;
614 pCur->pNext = pModule;
615 }
616 else
617 pUVM->pdm.s.pModules = pModule; /* (pNext is zeroed by alloc) */
618 Log(("PDM: RC Module at %RRv %s (%s)\n", (RTRCPTR)pModule->ImageBase, pszName, pszFilename));
619
620 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
621 RTMemTmpFree(pszFile);
622 RTMemTmpFree(paPages);
623
624 return VINF_SUCCESS;
625 }
626 }
627 else
628 {
629 AssertRC(rc);
630 SUPR3PageFreeEx(pModule->pvBits, cPages);
631 }
632 }
633 else
634 AssertMsgFailed(("SUPR3PageAlloc(%d,) -> %Rrc\n", cPages, rc));
635 RTMemTmpFree(paPages);
636 }
637 else
638 rc = VERR_NO_TMP_MEMORY;
639 }
640 else
641 rc = VERR_OUT_OF_RANGE;
642 int rc2 = RTLdrClose(pModule->hLdrMod);
643 AssertRC(rc2);
644 }
645 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
646
647 /* Don't consider VERR_PDM_MODULE_NAME_CLASH and VERR_NO_MEMORY above as these are very unlikely. */
648 if (RT_FAILURE(rc) && RTErrInfoIsSet(&ErrInfo.Core))
649 rc = VMSetError(pVM, rc, RT_SRC_POS, N_("Cannot load RC module %s: %s"), pszFilename, ErrInfo.Core.pszMsg);
650 else if (RT_FAILURE(rc))
651 rc = VMSetError(pVM, rc, RT_SRC_POS, N_("Cannot load RC module %s"), pszFilename);
652
653 RTMemFree(pModule);
654 RTMemTmpFree(pszFile);
655 return rc;
656}
657
658#endif /* VBOX_WITH_RAW_MODE_KEEP */
659
660/**
661 * Loads a module into the ring-0 context.
662 *
663 * @returns VBox status code.
664 * @param pUVM Pointer to the user mode VM structure.
665 * @param pszFilename Filename of the module binary.
666 * @param pszName Module name. Case sensitive and the length is limited!
667 * @param pszSearchPath List of directories to search if @a pszFilename is
668 * not specified. Can be NULL, in which case the arch
669 * dependent install dir is searched.
670 */
671static int pdmR3LoadR0U(PUVM pUVM, const char *pszFilename, const char *pszName, const char *pszSearchPath)
672{
673 /*
674 * Validate input.
675 */
676 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
677 PPDMMOD pCur = pUVM->pdm.s.pModules;
678 while (pCur)
679 {
680 if (!strcmp(pCur->szName, pszName))
681 {
682 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
683 AssertMsgFailed(("We've already got a module '%s' loaded!\n", pszName));
684 return VERR_PDM_MODULE_NAME_CLASH;
685 }
686 /* next */
687 pCur = pCur->pNext;
688 }
689
690 /*
691 * Find the file if not specified.
692 */
693 char *pszFile = NULL;
694 if (!pszFilename)
695 pszFilename = pszFile = pdmR3FileR0(pszName, pszSearchPath);
696
697 /*
698 * Allocate the module list node.
699 */
700 PPDMMOD pModule = (PPDMMOD)RTMemAllocZ(sizeof(*pModule) + strlen(pszFilename));
701 if (!pModule)
702 {
703 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
704 RTMemTmpFree(pszFile);
705 return VERR_NO_MEMORY;
706 }
707 AssertMsg(strlen(pszName) + 1 < sizeof(pModule->szName),
708 ("pazName is too long (%d chars) max is %d chars.\n", strlen(pszName), sizeof(pModule->szName) - 1));
709 strcpy(pModule->szName, pszName);
710 pModule->eType = PDMMOD_TYPE_R0;
711 strcpy(pModule->szFilename, pszFilename);
712
713 /*
714 * Ask the support library to load it.
715 */
716 RTERRINFOSTATIC ErrInfo;
717 void *pvImageBase = NULL;
718 int rc = SUPR3LoadModule(pszFilename, pszName, &pvImageBase, RTErrInfoInitStatic(&ErrInfo));
719 if (RT_SUCCESS(rc))
720 {
721 pModule->hLdrMod = NIL_RTLDRMOD;
722 pModule->ImageBase = (uintptr_t)pvImageBase;
723
724 /*
725 * Insert the module.
726 */
727 if (pUVM->pdm.s.pModules)
728 {
729 /* we don't expect this list to be very long, so rather save the tail pointer. */
730 pCur = pUVM->pdm.s.pModules;
731 while (pCur->pNext)
732 pCur = pCur->pNext;
733 pCur->pNext = pModule;
734 }
735 else
736 pUVM->pdm.s.pModules = pModule; /* (pNext is zeroed by alloc) */
737 Log(("PDM: R0 Module at %RHv %s (%s)\n", (RTR0PTR)pModule->ImageBase, pszName, pszFilename));
738 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
739 RTMemTmpFree(pszFile);
740 return VINF_SUCCESS;
741 }
742
743 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
744 RTMemFree(pModule);
745 LogRel(("PDMLdr: pdmR3LoadR0U: pszName=\"%s\" rc=%Rrc szErr=\"%s\"\n", pszName, rc, ErrInfo.Core.pszMsg));
746
747 /* Don't consider VERR_PDM_MODULE_NAME_CLASH and VERR_NO_MEMORY above as these are very unlikely. */
748 if (RT_FAILURE(rc))
749 rc = VMR3SetError(pUVM, rc, RT_SRC_POS, N_("Failed to load R0 module %s: %s"), pszFilename, ErrInfo.Core.pszMsg);
750
751 RTMemTmpFree(pszFile); /* might be reference thru pszFilename in the above VMSetError call. */
752 return rc;
753}
754
755
756/**
757 * Makes sure a ring-0 module is loaded.
758 *
759 * @returns VBox status code.
760 * @param pUVM Pointer to the user mode VM structure.
761 * @param pszModule Module name (no path).
762 * @param pszSearchPath List of directories to search for the module
763 * (assumes @a pszModule is also a filename).
764 */
765VMMR3_INT_DECL(int) PDMR3LdrLoadR0(PUVM pUVM, const char *pszModule, const char *pszSearchPath)
766{
767 /*
768 * Find the module.
769 */
770 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
771 for (PPDMMOD pModule = pUVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
772 {
773 if ( pModule->eType == PDMMOD_TYPE_R0
774 && !strcmp(pModule->szName, pszModule))
775 {
776 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
777 return VINF_SUCCESS;
778 }
779 }
780 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
781
782 /*
783 * Okay, load it.
784 */
785 return pdmR3LoadR0U(pUVM, NULL, pszModule, pszSearchPath);
786}
787
788
789/**
790 * Get the address of a symbol in a given HC ring 3 module.
791 *
792 * @returns VBox status code.
793 * @param pVM The cross context VM structure.
794 * @param pszModule Module name.
795 * @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
796 * ordinal value rather than a string pointer.
797 * @param ppvValue Where to store the symbol value.
798 */
799VMMR3_INT_DECL(int) PDMR3LdrGetSymbolR3(PVM pVM, const char *pszModule, const char *pszSymbol, void **ppvValue)
800{
801 /*
802 * Validate input.
803 */
804 AssertPtr(pVM);
805 AssertPtr(pszModule);
806 AssertPtr(ppvValue);
807 PUVM pUVM = pVM->pUVM;
808 AssertMsg(RTCritSectIsInitialized(&pUVM->pdm.s.ListCritSect), ("bad init order!\n"));
809
810 /*
811 * Find the module.
812 */
813 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
814 for (PPDMMOD pModule = pUVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
815 {
816 if ( pModule->eType == PDMMOD_TYPE_R3
817 && !strcmp(pModule->szName, pszModule))
818 {
819 RTUINTPTR Value = 0;
820 int rc = RTLdrGetSymbolEx(pModule->hLdrMod, pModule->pvBits, pModule->ImageBase, UINT32_MAX, pszSymbol, &Value);
821 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
822 if (RT_SUCCESS(rc))
823 {
824 *ppvValue = (void *)(uintptr_t)Value;
825 Assert((uintptr_t)*ppvValue == Value);
826 }
827 else
828 {
829 if ((uintptr_t)pszSymbol < 0x10000)
830 AssertMsg(rc, ("Couldn't symbol '%u' in module '%s'\n", (unsigned)(uintptr_t)pszSymbol, pszModule));
831 else
832 AssertMsg(rc, ("Couldn't symbol '%s' in module '%s'\n", pszSymbol, pszModule));
833 }
834 return rc;
835 }
836 }
837 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
838 AssertMsgFailed(("Couldn't locate module '%s'\n", pszModule));
839 return VERR_SYMBOL_NOT_FOUND;
840}
841
842
843/**
844 * Get the address of a symbol in a given HC ring 0 module.
845 *
846 * @returns VBox status code.
847 * @param pVM The cross context VM structure.
848 * @param pszModule Module name. If NULL the main R0 module (VMMR0.r0) is assumes.
849 * @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
850 * ordinal value rather than a string pointer.
851 * @param ppvValue Where to store the symbol value.
852 */
853VMMR3DECL(int) PDMR3LdrGetSymbolR0(PVM pVM, const char *pszModule, const char *pszSymbol, PRTR0PTR ppvValue)
854{
855#ifdef PDMLDR_FAKE_MODE
856 *ppvValue = 0xdeadbeef;
857 return VINF_SUCCESS;
858
859#else
860 /*
861 * Validate input.
862 */
863 AssertPtr(pVM);
864 AssertPtrNull(pszModule);
865 AssertPtr(ppvValue);
866 PUVM pUVM = pVM->pUVM;
867 AssertMsg(RTCritSectIsInitialized(&pUVM->pdm.s.ListCritSect), ("bad init order!\n"));
868
869 if (!pszModule)
870 pszModule = VMMR0_MAIN_MODULE_NAME;
871
872 /*
873 * Find the module.
874 */
875 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
876 for (PPDMMOD pModule = pUVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
877 {
878 if ( pModule->eType == PDMMOD_TYPE_R0
879 && !strcmp(pModule->szName, pszModule))
880 {
881 int rc = SUPR3GetSymbolR0((void *)(uintptr_t)pModule->ImageBase, pszSymbol, (void **)ppvValue);
882 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
883 if (RT_FAILURE(rc))
884 {
885 AssertMsgRC(rc, ("Couldn't find symbol '%s' in module '%s'\n", pszSymbol, pszModule));
886 LogRel(("PDMLdr: PDMGetSymbol: Couldn't find symbol '%s' in module '%s'\n", pszSymbol, pszModule));
887 }
888 return rc;
889 }
890 }
891 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
892 AssertMsgFailed(("Couldn't locate module '%s'\n", pszModule));
893 return VERR_SYMBOL_NOT_FOUND;
894#endif
895}
896
897
898/**
899 * Same as PDMR3LdrGetSymbolR0 except that the module will be attempted loaded if not found.
900 *
901 * @returns VBox status code.
902 * @param pVM The cross context VM structure.
903 * @param pszModule Module name. If NULL the main R0 module (VMMR0.r0) is assumed.
904 * @param pszSearchPath List of directories to search if @a pszFile is
905 * not qualified with a path. Can be NULL, in which
906 * case the arch dependent install dir is searched.
907 * @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
908 * ordinal value rather than a string pointer.
909 * @param ppvValue Where to store the symbol value.
910 */
911VMMR3DECL(int) PDMR3LdrGetSymbolR0Lazy(PVM pVM, const char *pszModule, const char *pszSearchPath, const char *pszSymbol,
912 PRTR0PTR ppvValue)
913{
914#ifdef PDMLDR_FAKE_MODE
915 *ppvValue = 0xdeadbeef;
916 return VINF_SUCCESS;
917
918#else
919 AssertPtr(pVM);
920 AssertPtrNull(pszModule);
921 AssertPtr(ppvValue);
922 PUVM pUVM = pVM->pUVM;
923 AssertMsg(RTCritSectIsInitialized(&pUVM->pdm.s.ListCritSect), ("bad init order!\n"));
924
925 if (pszModule) /* (We don't lazy load the main R0 module.) */
926 {
927 /*
928 * Since we're lazy, we'll only check if the module is present
929 * and hand it over to PDMR3LdrGetSymbolR0 when that's done.
930 */
931 AssertMsgReturn(!strpbrk(pszModule, "/\\:\n\r\t"), ("pszModule=%s\n", pszModule), VERR_INVALID_PARAMETER);
932 PPDMMOD pModule;
933 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
934 for (pModule = pUVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
935 if ( pModule->eType == PDMMOD_TYPE_R0
936 && !strcmp(pModule->szName, pszModule))
937 break;
938 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
939 if (!pModule)
940 {
941 int rc = pdmR3LoadR0U(pUVM, NULL, pszModule, pszSearchPath);
942 AssertMsgRCReturn(rc, ("pszModule=%s rc=%Rrc\n", pszModule, rc), VERR_MODULE_NOT_FOUND);
943 }
944 }
945
946 return PDMR3LdrGetSymbolR0(pVM, pszModule, pszSymbol, ppvValue);
947#endif
948}
949
950
951/**
952 * Get the address of a symbol in a given RC module.
953 *
954 * @returns VBox status code.
955 * @param pVM The cross context VM structure.
956 * @param pszModule Module name. If NULL the main R0 module (VMMRC.rc)
957 * is assumes.
958 * @param pszSymbol Symbol name. If it's value is less than 64k it's
959 * treated like a ordinal value rather than a string
960 * pointer.
961 * @param pRCPtrValue Where to store the symbol value.
962 */
963VMMR3DECL(int) PDMR3LdrGetSymbolRC(PVM pVM, const char *pszModule, const char *pszSymbol, PRTRCPTR pRCPtrValue)
964{
965#if defined(PDMLDR_FAKE_MODE) || !defined(VBOX_WITH_RAW_MODE_KEEP)
966 RT_NOREF(pVM, pszModule, pszSymbol);
967 *pRCPtrValue = NIL_RTRCPTR;
968 return VINF_SUCCESS;
969
970#else
971 /*
972 * Validate input.
973 */
974 AssertPtr(pVM);
975 AssertPtrNull(pszModule);
976 AssertPtr(pRCPtrValue);
977
978 if (!pszModule)
979 pszModule = VMMRC_MAIN_MODULE_NAME;
980
981 /*
982 * Find the module.
983 */
984 PUVM pUVM = pVM->pUVM;
985 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
986 for (PPDMMOD pModule = pUVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
987 {
988 if ( pModule->eType == PDMMOD_TYPE_RC
989 && !strcmp(pModule->szName, pszModule))
990 {
991 RTUINTPTR Value;
992 int rc = RTLdrGetSymbolEx(pModule->hLdrMod, pModule->pvBits, pModule->ImageBase, UINT32_MAX, pszSymbol, &Value);
993 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
994 if (RT_SUCCESS(rc))
995 {
996 *pRCPtrValue = (RTGCPTR)Value;
997 Assert(*pRCPtrValue == Value);
998 }
999 else
1000 {
1001 if ((uintptr_t)pszSymbol < 0x10000)
1002 AssertMsg(rc, ("Couldn't symbol '%u' in module '%s'\n", (unsigned)(uintptr_t)pszSymbol, pszModule));
1003 else
1004 AssertMsg(rc, ("Couldn't symbol '%s' in module '%s'\n", pszSymbol, pszModule));
1005 }
1006 return rc;
1007 }
1008 }
1009 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
1010 AssertMsgFailed(("Couldn't locate module '%s'\n", pszModule));
1011 return VERR_SYMBOL_NOT_FOUND;
1012#endif
1013}
1014
1015
1016/**
1017 * Same as PDMR3LdrGetSymbolRC except that the module will be attempted loaded if not found.
1018 *
1019 * @returns VBox status code.
1020 * @param pVM The cross context VM structure.
1021 * @param pszModule Module name. If NULL the main RC module (VMMRC.rc)
1022 * is assumed.
1023 * @param pszSearchPath List of directories to search if @a pszFile is
1024 * not qualified with a path. Can be NULL, in which
1025 * case the arch dependent install dir is searched.
1026 * @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
1027 * ordinal value rather than a string pointer.
1028 * @param pRCPtrValue Where to store the symbol value.
1029 */
1030VMMR3DECL(int) PDMR3LdrGetSymbolRCLazy(PVM pVM, const char *pszModule, const char *pszSearchPath, const char *pszSymbol,
1031 PRTRCPTR pRCPtrValue)
1032{
1033#if defined(PDMLDR_FAKE_MODE) || !defined(VBOX_WITH_RAW_MODE_KEEP)
1034 RT_NOREF(pVM, pszModule, pszSearchPath, pszSymbol);
1035 *pRCPtrValue = NIL_RTRCPTR;
1036 return VINF_SUCCESS;
1037
1038#else
1039 AssertPtr(pVM);
1040 if (!pszModule)
1041 pszModule = VMMRC_MAIN_MODULE_NAME;
1042 AssertPtr(pszModule);
1043 AssertPtr(pRCPtrValue);
1044
1045 /*
1046 * Since we're lazy, we'll only check if the module is present
1047 * and hand it over to PDMR3LdrGetSymbolRC when that's done.
1048 */
1049 AssertMsgReturn(!strpbrk(pszModule, "/\\:\n\r\t"), ("pszModule=%s\n", pszModule), VERR_INVALID_PARAMETER);
1050 PUVM pUVM = pVM->pUVM;
1051 PPDMMOD pModule;
1052 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
1053 for (pModule = pUVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
1054 if ( pModule->eType == PDMMOD_TYPE_RC
1055 && !strcmp(pModule->szName, pszModule))
1056 break;
1057 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
1058 if (!pModule)
1059 {
1060 char *pszFilename = pdmR3FileRC(pszModule, pszSearchPath);
1061 AssertMsgReturn(pszFilename, ("pszModule=%s\n", pszModule), VERR_MODULE_NOT_FOUND);
1062 int rc = PDMR3LdrLoadRC(pVM, pszFilename, pszModule);
1063 RTMemTmpFree(pszFilename);
1064 AssertMsgRCReturn(rc, ("pszModule=%s rc=%Rrc\n", pszModule, rc), VERR_MODULE_NOT_FOUND);
1065 }
1066
1067 return PDMR3LdrGetSymbolRC(pVM, pszModule, pszSymbol, pRCPtrValue);
1068#endif
1069}
1070
1071
1072/**
1073 * Constructs the full filename for a R3 image file.
1074 *
1075 * @returns Pointer to temporary memory containing the filename.
1076 * Caller must free this using RTMemTmpFree().
1077 * @returns NULL on failure.
1078 *
1079 * @param pszFile File name (no path).
1080 * @param fShared If true, search in the shared directory (/usr/lib on Unix), else
1081 * search in the private directory (/usr/lib/virtualbox on Unix).
1082 * Ignored if VBOX_PATH_SHARED_LIBS is not defined.
1083 */
1084char *pdmR3FileR3(const char *pszFile, bool fShared)
1085{
1086 return pdmR3File(pszFile, NULL, NULL, fShared);
1087}
1088
1089
1090/**
1091 * Constructs the full filename for a R0 image file.
1092 *
1093 * @returns Pointer to temporary memory containing the filename.
1094 * Caller must free this using RTMemTmpFree().
1095 * @returns NULL on failure.
1096 *
1097 * @param pszFile File name (no path).
1098 * @param pszSearchPath List of directories to search if @a pszFile is
1099 * not qualified with a path. Can be NULL, in which
1100 * case the arch dependent install dir is searched.
1101 */
1102static char *pdmR3FileR0(const char *pszFile, const char *pszSearchPath)
1103{
1104 return pdmR3File(pszFile, NULL, pszSearchPath, /*fShared=*/false);
1105}
1106
1107
1108#if 0 /* unused */
1109/**
1110 * Constructs the full filename for a RC image file.
1111 *
1112 * @returns Pointer to temporary memory containing the filename.
1113 * Caller must free this using RTMemTmpFree().
1114 * @returns NULL on failure.
1115 *
1116 * @param pszFile File name (no path).
1117 * @param pszSearchPath List of directories to search if @a pszFile is
1118 * not qualified with a path. Can be NULL, in which
1119 * case the arch dependent install dir is searched.
1120 */
1121static char *pdmR3FileRC(const char *pszFile, const char *pszSearchPath)
1122{
1123 return pdmR3File(pszFile, NULL, pszSearchPath, /*fShared=*/false);
1124}
1125#endif
1126
1127
1128/**
1129 * Worker for pdmR3File().
1130 *
1131 * @returns Pointer to temporary memory containing the filename.
1132 * Caller must free this using RTMemTmpFree().
1133 * @returns NULL on failure.
1134 *
1135 * @param pszDir Directory part
1136 * @param pszFile File name part
1137 * @param pszDefaultExt Extension part
1138 */
1139static char *pdmR3FileConstruct(const char *pszDir, const char *pszFile, const char *pszDefaultExt)
1140{
1141 /*
1142 * Allocate temp memory for return buffer.
1143 */
1144 size_t cchDir = strlen(pszDir);
1145 size_t cchFile = strlen(pszFile);
1146 size_t cchDefaultExt;
1147
1148 /*
1149 * Default extention?
1150 */
1151 if (!pszDefaultExt || strchr(pszFile, '.'))
1152 cchDefaultExt = 0;
1153 else
1154 cchDefaultExt = strlen(pszDefaultExt);
1155
1156 size_t cchPath = cchDir + 1 + cchFile + cchDefaultExt + 1;
1157 AssertMsgReturn(cchPath <= RTPATH_MAX, ("Path too long!\n"), NULL);
1158
1159 char *pszRet = (char *)RTMemTmpAlloc(cchDir + 1 + cchFile + cchDefaultExt + 1);
1160 AssertMsgReturn(pszRet, ("Out of temporary memory!\n"), NULL);
1161
1162 /*
1163 * Construct the filename.
1164 */
1165 memcpy(pszRet, pszDir, cchDir);
1166 pszRet[cchDir++] = '/'; /* this works everywhere */
1167 memcpy(pszRet + cchDir, pszFile, cchFile + 1);
1168 if (cchDefaultExt)
1169 memcpy(pszRet + cchDir + cchFile, pszDefaultExt, cchDefaultExt + 1);
1170
1171 return pszRet;
1172}
1173
1174
1175/**
1176 * Worker for pdmR3FileRC(), pdmR3FileR0() and pdmR3FileR3().
1177 *
1178 * @returns Pointer to temporary memory containing the filename.
1179 * Caller must free this using RTMemTmpFree().
1180 * @returns NULL on failure.
1181 * @param pszFile File name (no path).
1182 * @param pszDefaultExt The default extention, NULL if none.
1183 * @param pszSearchPath List of directories to search if @a pszFile is
1184 * not qualified with a path. Can be NULL, in which
1185 * case the arch dependent install dir is searched.
1186 * @param fShared If true, search in the shared directory (/usr/lib on Unix), else
1187 * search in the private directory (/usr/lib/virtualbox on Unix).
1188 * Ignored if VBOX_PATH_SHARED_LIBS is not defined.
1189 * @todo We'll have this elsewhere than in the root later!
1190 * @todo Remove the fShared hack again once we don't need to link against VBoxDD anymore!
1191 */
1192static char *pdmR3File(const char *pszFile, const char *pszDefaultExt, const char *pszSearchPath, bool fShared)
1193{
1194 char szPath[RTPATH_MAX];
1195 int rc;
1196
1197 AssertLogRelReturn(!fShared || !pszSearchPath, NULL);
1198 Assert(!RTPathHavePath(pszFile));
1199
1200 /*
1201 * If there is a path, search it.
1202 */
1203 if ( pszSearchPath
1204 && *pszSearchPath)
1205 {
1206 /* Check the filename length. */
1207 size_t const cchFile = strlen(pszFile);
1208 if (cchFile >= sizeof(szPath))
1209 return NULL;
1210
1211 /*
1212 * Walk the search path.
1213 */
1214 const char *psz = pszSearchPath;
1215 while (*psz)
1216 {
1217 /* Skip leading blanks - no directories with leading spaces, thank you. */
1218 while (RT_C_IS_BLANK(*psz))
1219 psz++;
1220
1221 /* Find the end of this element. */
1222 const char *pszNext;
1223 const char *pszEnd = strchr(psz, ';');
1224 if (!pszEnd)
1225 pszEnd = pszNext = strchr(psz, '\0');
1226 else
1227 pszNext = pszEnd + 1;
1228 if (pszEnd != psz)
1229 {
1230 rc = RTPathJoinEx(szPath, sizeof(szPath), psz, pszEnd - psz, pszFile, cchFile, RTPATH_STR_F_STYLE_HOST);
1231 if (RT_SUCCESS(rc))
1232 {
1233 if (RTFileExists(szPath))
1234 {
1235 size_t cchPath = strlen(szPath) + 1;
1236 char *pszRet = (char *)RTMemTmpAlloc(cchPath);
1237 if (pszRet)
1238 memcpy(pszRet, szPath, cchPath);
1239 return pszRet;
1240 }
1241 }
1242 }
1243
1244 /* advance */
1245 psz = pszNext;
1246 }
1247 }
1248
1249 /*
1250 * Use the default location.
1251 */
1252 rc = fShared
1253 ? RTPathSharedLibs( szPath, sizeof(szPath))
1254 : RTPathAppPrivateArch(szPath, sizeof(szPath));
1255 if (!RT_SUCCESS(rc))
1256 {
1257 AssertMsgFailed(("RTPath[SharedLibs|AppPrivateArch](,%d) failed rc=%d!\n", sizeof(szPath), rc));
1258 return NULL;
1259 }
1260
1261 return pdmR3FileConstruct(szPath, pszFile, pszDefaultExt);
1262}
1263
1264
1265/** @internal */
1266typedef struct QMFEIPARG
1267{
1268 RTINTPTR uPC;
1269
1270 char *pszNearSym1;
1271 size_t cchNearSym1;
1272 RTINTPTR offNearSym1;
1273
1274 char *pszNearSym2;
1275 size_t cchNearSym2;
1276 RTINTPTR offNearSym2;
1277} QMFEIPARG, *PQMFEIPARG;
1278
1279
1280/**
1281 * Enumeration callback function used by RTLdrEnumSymbols().
1282 *
1283 * @returns VBox status code. Failure will stop the enumeration.
1284 * @param hLdrMod The loader module handle.
1285 * @param pszSymbol Symbol name. NULL if ordinal only.
1286 * @param uSymbol Symbol ordinal, ~0 if not used.
1287 * @param Value Symbol value.
1288 * @param pvUser The user argument specified to RTLdrEnumSymbols().
1289 */
1290static DECLCALLBACK(int) pdmR3QueryModFromEIPEnumSymbols(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol,
1291 RTUINTPTR Value, void *pvUser)
1292{
1293 PQMFEIPARG pArgs = (PQMFEIPARG)pvUser;
1294 NOREF(hLdrMod);
1295
1296 RTINTPTR off = Value - pArgs->uPC;
1297 if (off <= 0) /* near1 is before or at same location. */
1298 {
1299 if (off > pArgs->offNearSym1)
1300 {
1301 pArgs->offNearSym1 = off;
1302 if (pArgs->pszNearSym1 && pArgs->cchNearSym1)
1303 {
1304 *pArgs->pszNearSym1 = '\0';
1305 if (pszSymbol)
1306 strncat(pArgs->pszNearSym1, pszSymbol, pArgs->cchNearSym1);
1307 else
1308 {
1309 char szOrd[32];
1310 RTStrPrintf(szOrd, sizeof(szOrd), "#%#x", uSymbol);
1311 strncat(pArgs->pszNearSym1, szOrd, pArgs->cchNearSym1);
1312 }
1313 }
1314 }
1315 }
1316 else /* near2 is after */
1317 {
1318 if (off < pArgs->offNearSym2)
1319 {
1320 pArgs->offNearSym2 = off;
1321 if (pArgs->pszNearSym2 && pArgs->cchNearSym2)
1322 {
1323 *pArgs->pszNearSym2 = '\0';
1324 if (pszSymbol)
1325 strncat(pArgs->pszNearSym2, pszSymbol, pArgs->cchNearSym2);
1326 else
1327 {
1328 char szOrd[32];
1329 RTStrPrintf(szOrd, sizeof(szOrd), "#%#x", uSymbol);
1330 strncat(pArgs->pszNearSym2, szOrd, pArgs->cchNearSym2);
1331 }
1332 }
1333 }
1334 }
1335
1336 return VINF_SUCCESS;
1337}
1338
1339
1340/**
1341 * Internal worker for PDMR3LdrQueryRCModFromPC and PDMR3LdrQueryR0ModFromPC.
1342 *
1343 * @returns VBox status code.
1344 *
1345 * @param pVM The cross context VM structure.
1346 * @param uPC The program counter (eip/rip) to locate the module for.
1347 * @param enmType The module type.
1348 * @param pszModName Where to store the module name.
1349 * @param cchModName Size of the module name buffer.
1350 * @param pMod Base address of the module.
1351 * @param pszNearSym1 Name of the closes symbol from below.
1352 * @param cchNearSym1 Size of the buffer pointed to by pszNearSym1.
1353 * @param pNearSym1 The address of pszNearSym1.
1354 * @param pszNearSym2 Name of the closes symbol from below.
1355 * @param cchNearSym2 Size of the buffer pointed to by pszNearSym2.
1356 * @param pNearSym2 The address of pszNearSym2.
1357 */
1358static int pdmR3LdrQueryModFromPC(PVM pVM, RTUINTPTR uPC, PDMMODTYPE enmType,
1359 char *pszModName, size_t cchModName, PRTUINTPTR pMod,
1360 char *pszNearSym1, size_t cchNearSym1, PRTUINTPTR pNearSym1,
1361 char *pszNearSym2, size_t cchNearSym2, PRTUINTPTR pNearSym2)
1362{
1363 PUVM pUVM = pVM->pUVM;
1364 int rc = VERR_MODULE_NOT_FOUND;
1365 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
1366 for (PPDMMOD pCur= pUVM->pdm.s.pModules; pCur; pCur = pCur->pNext)
1367 {
1368 if (pCur->eType != enmType)
1369 continue;
1370
1371 /* The following RTLdrOpen call is a dirty hack to get ring-0 module information. */
1372 RTLDRMOD hLdrMod = pCur->hLdrMod;
1373 if (hLdrMod == NIL_RTLDRMOD && uPC >= pCur->ImageBase)
1374 {
1375 int rc2 = RTLdrOpen(pCur->szFilename, 0 /*fFlags*/, RTLDRARCH_HOST, &hLdrMod);
1376 if (RT_FAILURE(rc2))
1377 hLdrMod = NIL_RTLDRMOD;
1378 }
1379
1380 if ( hLdrMod != NIL_RTLDRMOD
1381 && uPC - pCur->ImageBase < RTLdrSize(hLdrMod))
1382 {
1383 if (pMod)
1384 *pMod = pCur->ImageBase;
1385 if (pszModName && cchModName)
1386 {
1387 *pszModName = '\0';
1388 strncat(pszModName, pCur->szName, cchModName);
1389 }
1390 if (pNearSym1) *pNearSym1 = 0;
1391 if (pNearSym2) *pNearSym2 = 0;
1392 if (pszNearSym1) *pszNearSym1 = '\0';
1393 if (pszNearSym2) *pszNearSym2 = '\0';
1394
1395 /*
1396 * Locate the nearest symbols.
1397 */
1398 QMFEIPARG Args;
1399 Args.uPC = uPC;
1400 Args.pszNearSym1 = pszNearSym1;
1401 Args.cchNearSym1 = cchNearSym1;
1402 Args.offNearSym1 = RTINTPTR_MIN;
1403 Args.pszNearSym2 = pszNearSym2;
1404 Args.cchNearSym2 = cchNearSym2;
1405 Args.offNearSym2 = RTINTPTR_MAX;
1406
1407 rc = RTLdrEnumSymbols(hLdrMod, RTLDR_ENUM_SYMBOL_FLAGS_ALL, pCur->pvBits, pCur->ImageBase,
1408 pdmR3QueryModFromEIPEnumSymbols, &Args);
1409 if (pNearSym1 && Args.offNearSym1 != RTINTPTR_MIN)
1410 *pNearSym1 = Args.offNearSym1 + uPC;
1411 if (pNearSym2 && Args.offNearSym2 != RTINTPTR_MAX)
1412 *pNearSym2 = Args.offNearSym2 + uPC;
1413
1414 rc = VINF_SUCCESS;
1415 }
1416
1417 if (hLdrMod != pCur->hLdrMod && hLdrMod != NIL_RTLDRMOD)
1418 RTLdrClose(hLdrMod);
1419
1420 if (RT_SUCCESS(rc))
1421 break;
1422 }
1423 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
1424 return rc;
1425}
1426
1427
1428/**
1429 * Queries raw-mode context module information from an PC (eip/rip).
1430 *
1431 * This is typically used to locate a crash address.
1432 *
1433 * @returns VBox status code.
1434 *
1435 * @param pVM The cross context VM structure.
1436 * @param uPC The program counter (eip/rip) to locate the module for.
1437 * @param pszModName Where to store the module name.
1438 * @param cchModName Size of the module name buffer.
1439 * @param pMod Base address of the module.
1440 * @param pszNearSym1 Name of the closes symbol from below.
1441 * @param cchNearSym1 Size of the buffer pointed to by pszNearSym1.
1442 * @param pNearSym1 The address of pszNearSym1.
1443 * @param pszNearSym2 Name of the closes symbol from below.
1444 * @param cchNearSym2 Size of the buffer pointed to by pszNearSym2.
1445 * @param pNearSym2 The address of pszNearSym2.
1446 */
1447VMMR3_INT_DECL(int) PDMR3LdrQueryRCModFromPC(PVM pVM, RTRCPTR uPC,
1448 char *pszModName, size_t cchModName, PRTRCPTR pMod,
1449 char *pszNearSym1, size_t cchNearSym1, PRTRCPTR pNearSym1,
1450 char *pszNearSym2, size_t cchNearSym2, PRTRCPTR pNearSym2)
1451{
1452 RTUINTPTR AddrMod = 0;
1453 RTUINTPTR AddrNear1 = 0;
1454 RTUINTPTR AddrNear2 = 0;
1455 int rc = pdmR3LdrQueryModFromPC(pVM, uPC, PDMMOD_TYPE_RC,
1456 pszModName, cchModName, &AddrMod,
1457 pszNearSym1, cchNearSym1, &AddrNear1,
1458 pszNearSym2, cchNearSym2, &AddrNear2);
1459 if (RT_SUCCESS(rc))
1460 {
1461 if (pMod)
1462 *pMod = (RTRCPTR)AddrMod;
1463 if (pNearSym1)
1464 *pNearSym1 = (RTRCPTR)AddrNear1;
1465 if (pNearSym2)
1466 *pNearSym2 = (RTRCPTR)AddrNear2;
1467 }
1468 return rc;
1469}
1470
1471
1472/**
1473 * Queries ring-0 context module information from an PC (eip/rip).
1474 *
1475 * This is typically used to locate a crash address.
1476 *
1477 * @returns VBox status code.
1478 *
1479 * @param pVM The cross context VM structure.
1480 * @param uPC The program counter (eip/rip) to locate the module for.
1481 * @param pszModName Where to store the module name.
1482 * @param cchModName Size of the module name buffer.
1483 * @param pMod Base address of the module.
1484 * @param pszNearSym1 Name of the closes symbol from below.
1485 * @param cchNearSym1 Size of the buffer pointed to by pszNearSym1.
1486 * @param pNearSym1 The address of pszNearSym1.
1487 * @param pszNearSym2 Name of the closes symbol from below.
1488 * @param cchNearSym2 Size of the buffer pointed to by pszNearSym2. Optional.
1489 * @param pNearSym2 The address of pszNearSym2. Optional.
1490 */
1491VMMR3_INT_DECL(int) PDMR3LdrQueryR0ModFromPC(PVM pVM, RTR0PTR uPC,
1492 char *pszModName, size_t cchModName, PRTR0PTR pMod,
1493 char *pszNearSym1, size_t cchNearSym1, PRTR0PTR pNearSym1,
1494 char *pszNearSym2, size_t cchNearSym2, PRTR0PTR pNearSym2)
1495{
1496 RTUINTPTR AddrMod = 0;
1497 RTUINTPTR AddrNear1 = 0;
1498 RTUINTPTR AddrNear2 = 0;
1499 int rc = pdmR3LdrQueryModFromPC(pVM, uPC, PDMMOD_TYPE_R0,
1500 pszModName, cchModName, &AddrMod,
1501 pszNearSym1, cchNearSym1, &AddrNear1,
1502 pszNearSym2, cchNearSym2, &AddrNear2);
1503 if (RT_SUCCESS(rc))
1504 {
1505 if (pMod)
1506 *pMod = (RTR0PTR)AddrMod;
1507 if (pNearSym1)
1508 *pNearSym1 = (RTR0PTR)AddrNear1;
1509 if (pNearSym2)
1510 *pNearSym2 = (RTR0PTR)AddrNear2;
1511 }
1512 return rc;
1513}
1514
1515
1516/**
1517 * Enumerate all PDM modules.
1518 *
1519 * @returns VBox status code.
1520 * @param pVM The cross context VM structure.
1521 * @param pfnCallback Function to call back for each of the modules.
1522 * @param pvArg User argument.
1523 */
1524VMMR3DECL(int) PDMR3LdrEnumModules(PVM pVM, PFNPDMR3ENUM pfnCallback, void *pvArg)
1525{
1526 PUVM pUVM = pVM->pUVM;
1527 int rc = VINF_SUCCESS;
1528 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
1529 for (PPDMMOD pCur = pUVM->pdm.s.pModules; pCur; pCur = pCur->pNext)
1530 {
1531 rc = pfnCallback(pVM,
1532 pCur->szFilename,
1533 pCur->szName,
1534 pCur->ImageBase,
1535 pCur->eType == PDMMOD_TYPE_RC ? RTLdrSize(pCur->hLdrMod) : 0,
1536 pCur->eType == PDMMOD_TYPE_RC ? PDMLDRCTX_RAW_MODE
1537 : pCur->eType == PDMMOD_TYPE_R0 ? PDMLDRCTX_RING_0
1538 : pCur->eType == PDMMOD_TYPE_R3 ? PDMLDRCTX_RING_3
1539 : PDMLDRCTX_INVALID,
1540 pvArg);
1541 if (RT_FAILURE(rc))
1542 break;
1543 }
1544 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
1545 return rc;
1546}
1547
1548
1549/**
1550 * Locates a module.
1551 *
1552 * @returns Pointer to the module if found.
1553 * @param pUVM Pointer to the user mode VM structure.
1554 * @param pszModule The module name.
1555 * @param enmType The module type.
1556 * @param fLazy Lazy loading the module if set.
1557 * @param pszSearchPath Search path for use when lazy loading.
1558 */
1559static PPDMMOD pdmR3LdrFindModule(PUVM pUVM, const char *pszModule, PDMMODTYPE enmType,
1560 bool fLazy, const char *pszSearchPath)
1561{
1562 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
1563 for (PPDMMOD pModule = pUVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
1564 if ( pModule->eType == enmType
1565 && !strcmp(pModule->szName, pszModule))
1566 {
1567 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
1568 return pModule;
1569 }
1570 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
1571 if (fLazy)
1572 {
1573 switch (enmType)
1574 {
1575#ifdef VBOX_WITH_RAW_MODE_KEEP
1576 case PDMMOD_TYPE_RC:
1577 {
1578 char *pszFilename = pdmR3FileRC(pszModule, pszSearchPath);
1579 if (pszFilename)
1580 {
1581 int rc = PDMR3LdrLoadRC(pUVM->pVM, pszFilename, pszModule);
1582 RTMemTmpFree(pszFilename);
1583 if (RT_SUCCESS(rc))
1584 return pdmR3LdrFindModule(pUVM, pszModule, enmType, false, NULL);
1585 }
1586 break;
1587 }
1588#endif
1589
1590 case PDMMOD_TYPE_R0:
1591 {
1592 int rc = pdmR3LoadR0U(pUVM, NULL, pszModule, pszSearchPath);
1593 if (RT_SUCCESS(rc))
1594 return pdmR3LdrFindModule(pUVM, pszModule, enmType, false, NULL);
1595 break;
1596 }
1597
1598 default:
1599 AssertFailed();
1600 }
1601 }
1602 return NULL;
1603}
1604
1605
1606/**
1607 * Resolves a ring-0 or raw-mode context interface.
1608 *
1609 * @returns VBox status code.
1610 * @param pVM The cross context VM structure.
1611 * @param pvInterface Pointer to the interface structure. The symbol list
1612 * describes the layout.
1613 * @param cbInterface The size of the structure pvInterface is pointing
1614 * to. For bounds checking.
1615 * @param pszModule The module name. If NULL we assume it's the default
1616 * R0 or RC module (@a fRing0OrRC). We'll attempt to
1617 * load the module if it isn't found in the module
1618 * list.
1619 * @param pszSearchPath The module search path. If NULL, search the
1620 * architecture dependent install directory.
1621 * @param pszSymPrefix What to prefix the symbols in the list with. The
1622 * idea is that you define a list that goes with an
1623 * interface (INTERFACE_SYM_LIST) and reuse it with
1624 * each implementation.
1625 * @param pszSymList The symbol list for the interface. This is a
1626 * semi-colon separated list of symbol base names. As
1627 * mentioned above, each is prefixed with @a
1628 * pszSymPrefix before resolving. There are a couple
1629 * of special symbol names that will cause us to skip
1630 * ahead a little bit:
1631 * - U8:whatever,
1632 * - U16:whatever,
1633 * - U32:whatever,
1634 * - U64:whatever,
1635 * - RCPTR:whatever,
1636 * - R3PTR:whatever,
1637 * - R0PTR:whatever,
1638 * - GCPHYS:whatever,
1639 * - HCPHYS:whatever.
1640 * @param fRing0 Set if it's a ring-0 context interface, clear if
1641 * it's raw-mode context interface.
1642 */
1643VMMR3_INT_DECL(int) PDMR3LdrGetInterfaceSymbols(PVM pVM, void *pvInterface, size_t cbInterface,
1644 const char *pszModule, const char *pszSearchPath,
1645 const char *pszSymPrefix, const char *pszSymList,
1646 bool fRing0)
1647{
1648 bool const fNullRun = !fRing0;
1649
1650 /*
1651 * Find the module.
1652 */
1653 int rc = VINF_SUCCESS;
1654 PPDMMOD pModule = NULL;
1655 if (!fNullRun)
1656 pModule = pdmR3LdrFindModule(pVM->pUVM,
1657 pszModule ? pszModule : fRing0 ? "VMMR0.r0" : "VMMRC.rc",
1658 fRing0 ? PDMMOD_TYPE_R0 : PDMMOD_TYPE_RC,
1659 true /*fLazy*/, pszSearchPath);
1660 if (pModule || fNullRun)
1661 {
1662 /* Prep the symbol name. */
1663 char szSymbol[256];
1664 size_t const cchSymPrefix = strlen(pszSymPrefix);
1665 AssertReturn(cchSymPrefix + 5 < sizeof(szSymbol), VERR_SYMBOL_NOT_FOUND);
1666 memcpy(szSymbol, pszSymPrefix, cchSymPrefix);
1667
1668 /*
1669 * Iterate the symbol list.
1670 */
1671 uint32_t offInterface = 0;
1672 const char *pszCur = pszSymList;
1673 while (pszCur)
1674 {
1675 /*
1676 * Find the end of the current symbol name.
1677 */
1678 size_t cchSym;
1679 const char *pszNext = strchr(pszCur, ';');
1680 if (pszNext)
1681 {
1682 cchSym = pszNext - pszCur;
1683 pszNext++;
1684 }
1685 else
1686 cchSym = strlen(pszCur);
1687 AssertBreakStmt(cchSym > 0, rc = VERR_INVALID_PARAMETER);
1688
1689 /* Is it a skip instruction? */
1690 const char *pszColon = (const char *)memchr(pszCur, ':', cchSym);
1691 if (pszColon)
1692 {
1693 /*
1694 * String switch on the instruction and execute it, checking
1695 * that we didn't overshoot the interface structure.
1696 */
1697#define IS_SKIP_INSTR(szInstr) \
1698 ( cchSkip == sizeof(szInstr) - 1 \
1699 && !memcmp(pszCur, szInstr, sizeof(szInstr) - 1) )
1700
1701 size_t const cchSkip = pszColon - pszCur;
1702 if (IS_SKIP_INSTR("U8"))
1703 offInterface += sizeof(uint8_t);
1704 else if (IS_SKIP_INSTR("U16"))
1705 offInterface += sizeof(uint16_t);
1706 else if (IS_SKIP_INSTR("U32"))
1707 offInterface += sizeof(uint32_t);
1708 else if (IS_SKIP_INSTR("U64"))
1709 offInterface += sizeof(uint64_t);
1710 else if (IS_SKIP_INSTR("RCPTR"))
1711 offInterface += sizeof(RTRCPTR);
1712 else if (IS_SKIP_INSTR("R3PTR"))
1713 offInterface += sizeof(RTR3PTR);
1714 else if (IS_SKIP_INSTR("R0PTR"))
1715 offInterface += sizeof(RTR0PTR);
1716 else if (IS_SKIP_INSTR("HCPHYS"))
1717 offInterface += sizeof(RTHCPHYS);
1718 else if (IS_SKIP_INSTR("GCPHYS"))
1719 offInterface += sizeof(RTGCPHYS);
1720 else
1721 AssertMsgFailedBreakStmt(("Invalid skip instruction %.*s (prefix=%s)\n", cchSym, pszCur, pszSymPrefix),
1722 rc = VERR_INVALID_PARAMETER);
1723 AssertMsgBreakStmt(offInterface <= cbInterface,
1724 ("off=%#x cb=%#x (sym=%.*s prefix=%s)\n", offInterface, cbInterface, cchSym, pszCur, pszSymPrefix),
1725 rc = VERR_BUFFER_OVERFLOW);
1726#undef IS_SKIP_INSTR
1727 }
1728 else
1729 {
1730 /*
1731 * Construct the symbol name, get its value, store it and
1732 * advance the interface cursor.
1733 */
1734 AssertReturn(cchSymPrefix + cchSym < sizeof(szSymbol), VERR_SYMBOL_NOT_FOUND);
1735 memcpy(&szSymbol[cchSymPrefix], pszCur, cchSym);
1736 szSymbol[cchSymPrefix + cchSym] = '\0';
1737
1738 if (fRing0)
1739 {
1740 void *pvValue = NULL;
1741 if (!fNullRun)
1742 {
1743 rc = SUPR3GetSymbolR0((void *)(RTR0PTR)pModule->ImageBase, szSymbol, &pvValue);
1744 AssertMsgRCBreak(rc, ("Couldn't find symbol '%s' in module '%s'\n", szSymbol, pModule->szName));
1745 }
1746
1747 PRTR0PTR pValue = (PRTR0PTR)((uintptr_t)pvInterface + offInterface);
1748 AssertMsgBreakStmt(offInterface + sizeof(*pValue) <= cbInterface,
1749 ("off=%#x cb=%#x sym=%s\n", offInterface, cbInterface, szSymbol),
1750 rc = VERR_BUFFER_OVERFLOW);
1751 *pValue = (RTR0PTR)pvValue;
1752 Assert((void *)*pValue == pvValue);
1753 offInterface += sizeof(*pValue);
1754 }
1755 else
1756 {
1757 RTUINTPTR Value = 0;
1758 if (!fNullRun)
1759 {
1760 rc = RTLdrGetSymbolEx(pModule->hLdrMod, pModule->pvBits, pModule->ImageBase, UINT32_MAX, szSymbol, &Value);
1761 AssertMsgRCBreak(rc, ("Couldn't find symbol '%s' in module '%s'\n", szSymbol, pModule->szName));
1762 }
1763
1764 PRTRCPTR pValue = (PRTRCPTR)((uintptr_t)pvInterface + offInterface);
1765 AssertMsgBreakStmt(offInterface + sizeof(*pValue) <= cbInterface,
1766 ("off=%#x cb=%#x sym=%s\n", offInterface, cbInterface, szSymbol),
1767 rc = VERR_BUFFER_OVERFLOW);
1768 *pValue = (RTRCPTR)Value;
1769 Assert(*pValue == Value);
1770 offInterface += sizeof(*pValue);
1771 }
1772 }
1773
1774 /* advance */
1775 pszCur = pszNext;
1776 }
1777
1778 }
1779 else
1780 rc = VERR_MODULE_NOT_FOUND;
1781 return rc;
1782}
1783
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