VirtualBox

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

Last change on this file since 98969 was 98103, checked in by vboxsync, 23 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 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * PDM - Pluggable Device Manager, module loader.
4 */
5
6/*
7 * Copyright (C) 2006-2023 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 void *pvImageBase;
717 RTERRINFOSTATIC ErrInfo;
718 RTErrInfoInitStatic(&ErrInfo);
719 int rc = SUPR3LoadModule(pszFilename, pszName, &pvImageBase, &ErrInfo.Core);
720 if (RT_SUCCESS(rc))
721 {
722 pModule->hLdrMod = NIL_RTLDRMOD;
723 pModule->ImageBase = (uintptr_t)pvImageBase;
724
725 /*
726 * Insert the module.
727 */
728 if (pUVM->pdm.s.pModules)
729 {
730 /* we don't expect this list to be very long, so rather save the tail pointer. */
731 pCur = pUVM->pdm.s.pModules;
732 while (pCur->pNext)
733 pCur = pCur->pNext;
734 pCur->pNext = pModule;
735 }
736 else
737 pUVM->pdm.s.pModules = pModule; /* (pNext is zeroed by alloc) */
738 Log(("PDM: R0 Module at %RHv %s (%s)\n", (RTR0PTR)pModule->ImageBase, pszName, pszFilename));
739 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
740 RTMemTmpFree(pszFile);
741 return VINF_SUCCESS;
742 }
743
744 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
745 RTMemFree(pModule);
746 LogRel(("PDMLdr: pdmR3LoadR0U: pszName=\"%s\" rc=%Rrc szErr=\"%s\"\n", pszName, rc, ErrInfo.Core.pszMsg));
747
748 /* Don't consider VERR_PDM_MODULE_NAME_CLASH and VERR_NO_MEMORY above as these are very unlikely. */
749 if (RT_FAILURE(rc))
750 rc = VMR3SetError(pUVM, rc, RT_SRC_POS, N_("Failed to load R0 module %s: %s"), pszFilename, ErrInfo.Core.pszMsg);
751
752 RTMemTmpFree(pszFile); /* might be reference thru pszFilename in the above VMSetError call. */
753 return rc;
754}
755
756
757/**
758 * Makes sure a ring-0 module is loaded.
759 *
760 * @returns VBox status code.
761 * @param pUVM Pointer to the user mode VM structure.
762 * @param pszModule Module name (no path).
763 * @param pszSearchPath List of directories to search for the module
764 * (assumes @a pszModule is also a filename).
765 */
766VMMR3_INT_DECL(int) PDMR3LdrLoadR0(PUVM pUVM, const char *pszModule, const char *pszSearchPath)
767{
768 /*
769 * Find the module.
770 */
771 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
772 for (PPDMMOD pModule = pUVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
773 {
774 if ( pModule->eType == PDMMOD_TYPE_R0
775 && !strcmp(pModule->szName, pszModule))
776 {
777 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
778 return VINF_SUCCESS;
779 }
780 }
781 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
782
783 /*
784 * Okay, load it.
785 */
786 return pdmR3LoadR0U(pUVM, NULL, pszModule, pszSearchPath);
787}
788
789
790/**
791 * Get the address of a symbol in a given HC ring 3 module.
792 *
793 * @returns VBox status code.
794 * @param pVM The cross context VM structure.
795 * @param pszModule Module name.
796 * @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
797 * ordinal value rather than a string pointer.
798 * @param ppvValue Where to store the symbol value.
799 */
800VMMR3_INT_DECL(int) PDMR3LdrGetSymbolR3(PVM pVM, const char *pszModule, const char *pszSymbol, void **ppvValue)
801{
802 /*
803 * Validate input.
804 */
805 AssertPtr(pVM);
806 AssertPtr(pszModule);
807 AssertPtr(ppvValue);
808 PUVM pUVM = pVM->pUVM;
809 AssertMsg(RTCritSectIsInitialized(&pUVM->pdm.s.ListCritSect), ("bad init order!\n"));
810
811 /*
812 * Find the module.
813 */
814 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
815 for (PPDMMOD pModule = pUVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
816 {
817 if ( pModule->eType == PDMMOD_TYPE_R3
818 && !strcmp(pModule->szName, pszModule))
819 {
820 RTUINTPTR Value = 0;
821 int rc = RTLdrGetSymbolEx(pModule->hLdrMod, pModule->pvBits, pModule->ImageBase, UINT32_MAX, pszSymbol, &Value);
822 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
823 if (RT_SUCCESS(rc))
824 {
825 *ppvValue = (void *)(uintptr_t)Value;
826 Assert((uintptr_t)*ppvValue == Value);
827 }
828 else
829 {
830 if ((uintptr_t)pszSymbol < 0x10000)
831 AssertMsg(rc, ("Couldn't symbol '%u' in module '%s'\n", (unsigned)(uintptr_t)pszSymbol, pszModule));
832 else
833 AssertMsg(rc, ("Couldn't symbol '%s' in module '%s'\n", pszSymbol, pszModule));
834 }
835 return rc;
836 }
837 }
838 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
839 AssertMsgFailed(("Couldn't locate module '%s'\n", pszModule));
840 return VERR_SYMBOL_NOT_FOUND;
841}
842
843
844/**
845 * Get the address of a symbol in a given HC ring 0 module.
846 *
847 * @returns VBox status code.
848 * @param pVM The cross context VM structure.
849 * @param pszModule Module name. If NULL the main R0 module (VMMR0.r0) is assumes.
850 * @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
851 * ordinal value rather than a string pointer.
852 * @param ppvValue Where to store the symbol value.
853 */
854VMMR3DECL(int) PDMR3LdrGetSymbolR0(PVM pVM, const char *pszModule, const char *pszSymbol, PRTR0PTR ppvValue)
855{
856#ifdef PDMLDR_FAKE_MODE
857 *ppvValue = 0xdeadbeef;
858 return VINF_SUCCESS;
859
860#else
861 /*
862 * Validate input.
863 */
864 AssertPtr(pVM);
865 AssertPtrNull(pszModule);
866 AssertPtr(ppvValue);
867 PUVM pUVM = pVM->pUVM;
868 AssertMsg(RTCritSectIsInitialized(&pUVM->pdm.s.ListCritSect), ("bad init order!\n"));
869
870 if (!pszModule)
871 pszModule = VMMR0_MAIN_MODULE_NAME;
872
873 /*
874 * Find the module.
875 */
876 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
877 for (PPDMMOD pModule = pUVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
878 {
879 if ( pModule->eType == PDMMOD_TYPE_R0
880 && !strcmp(pModule->szName, pszModule))
881 {
882 int rc = SUPR3GetSymbolR0((void *)(uintptr_t)pModule->ImageBase, pszSymbol, (void **)ppvValue);
883 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
884 if (RT_FAILURE(rc))
885 {
886 AssertMsgRC(rc, ("Couldn't find symbol '%s' in module '%s'\n", pszSymbol, pszModule));
887 LogRel(("PDMLdr: PDMGetSymbol: Couldn't find symbol '%s' in module '%s'\n", pszSymbol, pszModule));
888 }
889 return rc;
890 }
891 }
892 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
893 AssertMsgFailed(("Couldn't locate module '%s'\n", pszModule));
894 return VERR_SYMBOL_NOT_FOUND;
895#endif
896}
897
898
899/**
900 * Same as PDMR3LdrGetSymbolR0 except that the module will be attempted loaded if not found.
901 *
902 * @returns VBox status code.
903 * @param pVM The cross context VM structure.
904 * @param pszModule Module name. If NULL the main R0 module (VMMR0.r0) is assumed.
905 * @param pszSearchPath List of directories to search if @a pszFile is
906 * not qualified with a path. Can be NULL, in which
907 * case the arch dependent install dir is searched.
908 * @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
909 * ordinal value rather than a string pointer.
910 * @param ppvValue Where to store the symbol value.
911 */
912VMMR3DECL(int) PDMR3LdrGetSymbolR0Lazy(PVM pVM, const char *pszModule, const char *pszSearchPath, const char *pszSymbol,
913 PRTR0PTR ppvValue)
914{
915#ifdef PDMLDR_FAKE_MODE
916 *ppvValue = 0xdeadbeef;
917 return VINF_SUCCESS;
918
919#else
920 AssertPtr(pVM);
921 AssertPtrNull(pszModule);
922 AssertPtr(ppvValue);
923 PUVM pUVM = pVM->pUVM;
924 AssertMsg(RTCritSectIsInitialized(&pUVM->pdm.s.ListCritSect), ("bad init order!\n"));
925
926 if (pszModule) /* (We don't lazy load the main R0 module.) */
927 {
928 /*
929 * Since we're lazy, we'll only check if the module is present
930 * and hand it over to PDMR3LdrGetSymbolR0 when that's done.
931 */
932 AssertMsgReturn(!strpbrk(pszModule, "/\\:\n\r\t"), ("pszModule=%s\n", pszModule), VERR_INVALID_PARAMETER);
933 PPDMMOD pModule;
934 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
935 for (pModule = pUVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
936 if ( pModule->eType == PDMMOD_TYPE_R0
937 && !strcmp(pModule->szName, pszModule))
938 break;
939 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
940 if (!pModule)
941 {
942 int rc = pdmR3LoadR0U(pUVM, NULL, pszModule, pszSearchPath);
943 AssertMsgRCReturn(rc, ("pszModule=%s rc=%Rrc\n", pszModule, rc), VERR_MODULE_NOT_FOUND);
944 }
945 }
946
947 return PDMR3LdrGetSymbolR0(pVM, pszModule, pszSymbol, ppvValue);
948#endif
949}
950
951
952/**
953 * Get the address of a symbol in a given RC module.
954 *
955 * @returns VBox status code.
956 * @param pVM The cross context VM structure.
957 * @param pszModule Module name. If NULL the main R0 module (VMMRC.rc)
958 * is assumes.
959 * @param pszSymbol Symbol name. If it's value is less than 64k it's
960 * treated like a ordinal value rather than a string
961 * pointer.
962 * @param pRCPtrValue Where to store the symbol value.
963 */
964VMMR3DECL(int) PDMR3LdrGetSymbolRC(PVM pVM, const char *pszModule, const char *pszSymbol, PRTRCPTR pRCPtrValue)
965{
966#if defined(PDMLDR_FAKE_MODE) || !defined(VBOX_WITH_RAW_MODE_KEEP)
967 RT_NOREF(pVM, pszModule, pszSymbol);
968 *pRCPtrValue = NIL_RTRCPTR;
969 return VINF_SUCCESS;
970
971#else
972 /*
973 * Validate input.
974 */
975 AssertPtr(pVM);
976 AssertPtrNull(pszModule);
977 AssertPtr(pRCPtrValue);
978
979 if (!pszModule)
980 pszModule = VMMRC_MAIN_MODULE_NAME;
981
982 /*
983 * Find the module.
984 */
985 PUVM pUVM = pVM->pUVM;
986 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
987 for (PPDMMOD pModule = pUVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
988 {
989 if ( pModule->eType == PDMMOD_TYPE_RC
990 && !strcmp(pModule->szName, pszModule))
991 {
992 RTUINTPTR Value;
993 int rc = RTLdrGetSymbolEx(pModule->hLdrMod, pModule->pvBits, pModule->ImageBase, UINT32_MAX, pszSymbol, &Value);
994 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
995 if (RT_SUCCESS(rc))
996 {
997 *pRCPtrValue = (RTGCPTR)Value;
998 Assert(*pRCPtrValue == Value);
999 }
1000 else
1001 {
1002 if ((uintptr_t)pszSymbol < 0x10000)
1003 AssertMsg(rc, ("Couldn't symbol '%u' in module '%s'\n", (unsigned)(uintptr_t)pszSymbol, pszModule));
1004 else
1005 AssertMsg(rc, ("Couldn't symbol '%s' in module '%s'\n", pszSymbol, pszModule));
1006 }
1007 return rc;
1008 }
1009 }
1010 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
1011 AssertMsgFailed(("Couldn't locate module '%s'\n", pszModule));
1012 return VERR_SYMBOL_NOT_FOUND;
1013#endif
1014}
1015
1016
1017/**
1018 * Same as PDMR3LdrGetSymbolRC except that the module will be attempted loaded if not found.
1019 *
1020 * @returns VBox status code.
1021 * @param pVM The cross context VM structure.
1022 * @param pszModule Module name. If NULL the main RC module (VMMRC.rc)
1023 * is assumed.
1024 * @param pszSearchPath List of directories to search if @a pszFile is
1025 * not qualified with a path. Can be NULL, in which
1026 * case the arch dependent install dir is searched.
1027 * @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
1028 * ordinal value rather than a string pointer.
1029 * @param pRCPtrValue Where to store the symbol value.
1030 */
1031VMMR3DECL(int) PDMR3LdrGetSymbolRCLazy(PVM pVM, const char *pszModule, const char *pszSearchPath, const char *pszSymbol,
1032 PRTRCPTR pRCPtrValue)
1033{
1034#if defined(PDMLDR_FAKE_MODE) || !defined(VBOX_WITH_RAW_MODE_KEEP)
1035 RT_NOREF(pVM, pszModule, pszSearchPath, pszSymbol);
1036 *pRCPtrValue = NIL_RTRCPTR;
1037 return VINF_SUCCESS;
1038
1039#else
1040 AssertPtr(pVM);
1041 if (!pszModule)
1042 pszModule = VMMRC_MAIN_MODULE_NAME;
1043 AssertPtr(pszModule);
1044 AssertPtr(pRCPtrValue);
1045
1046 /*
1047 * Since we're lazy, we'll only check if the module is present
1048 * and hand it over to PDMR3LdrGetSymbolRC when that's done.
1049 */
1050 AssertMsgReturn(!strpbrk(pszModule, "/\\:\n\r\t"), ("pszModule=%s\n", pszModule), VERR_INVALID_PARAMETER);
1051 PUVM pUVM = pVM->pUVM;
1052 PPDMMOD pModule;
1053 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
1054 for (pModule = pUVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
1055 if ( pModule->eType == PDMMOD_TYPE_RC
1056 && !strcmp(pModule->szName, pszModule))
1057 break;
1058 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
1059 if (!pModule)
1060 {
1061 char *pszFilename = pdmR3FileRC(pszModule, pszSearchPath);
1062 AssertMsgReturn(pszFilename, ("pszModule=%s\n", pszModule), VERR_MODULE_NOT_FOUND);
1063 int rc = PDMR3LdrLoadRC(pVM, pszFilename, pszModule);
1064 RTMemTmpFree(pszFilename);
1065 AssertMsgRCReturn(rc, ("pszModule=%s rc=%Rrc\n", pszModule, rc), VERR_MODULE_NOT_FOUND);
1066 }
1067
1068 return PDMR3LdrGetSymbolRC(pVM, pszModule, pszSymbol, pRCPtrValue);
1069#endif
1070}
1071
1072
1073/**
1074 * Constructs the full filename for a R3 image file.
1075 *
1076 * @returns Pointer to temporary memory containing the filename.
1077 * Caller must free this using RTMemTmpFree().
1078 * @returns NULL on failure.
1079 *
1080 * @param pszFile File name (no path).
1081 * @param fShared If true, search in the shared directory (/usr/lib on Unix), else
1082 * search in the private directory (/usr/lib/virtualbox on Unix).
1083 * Ignored if VBOX_PATH_SHARED_LIBS is not defined.
1084 */
1085char *pdmR3FileR3(const char *pszFile, bool fShared)
1086{
1087 return pdmR3File(pszFile, NULL, NULL, fShared);
1088}
1089
1090
1091/**
1092 * Constructs the full filename for a R0 image file.
1093 *
1094 * @returns Pointer to temporary memory containing the filename.
1095 * Caller must free this using RTMemTmpFree().
1096 * @returns NULL on failure.
1097 *
1098 * @param pszFile File name (no path).
1099 * @param pszSearchPath List of directories to search if @a pszFile is
1100 * not qualified with a path. Can be NULL, in which
1101 * case the arch dependent install dir is searched.
1102 */
1103char *pdmR3FileR0(const char *pszFile, const char *pszSearchPath)
1104{
1105 return pdmR3File(pszFile, NULL, pszSearchPath, /*fShared=*/false);
1106}
1107
1108
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 */
1121char *pdmR3FileRC(const char *pszFile, const char *pszSearchPath)
1122{
1123 return pdmR3File(pszFile, NULL, pszSearchPath, /*fShared=*/false);
1124}
1125
1126
1127/**
1128 * Worker for pdmR3File().
1129 *
1130 * @returns Pointer to temporary memory containing the filename.
1131 * Caller must free this using RTMemTmpFree().
1132 * @returns NULL on failure.
1133 *
1134 * @param pszDir Directory part
1135 * @param pszFile File name part
1136 * @param pszDefaultExt Extension part
1137 */
1138static char *pdmR3FileConstruct(const char *pszDir, const char *pszFile, const char *pszDefaultExt)
1139{
1140 /*
1141 * Allocate temp memory for return buffer.
1142 */
1143 size_t cchDir = strlen(pszDir);
1144 size_t cchFile = strlen(pszFile);
1145 size_t cchDefaultExt;
1146
1147 /*
1148 * Default extention?
1149 */
1150 if (!pszDefaultExt || strchr(pszFile, '.'))
1151 cchDefaultExt = 0;
1152 else
1153 cchDefaultExt = strlen(pszDefaultExt);
1154
1155 size_t cchPath = cchDir + 1 + cchFile + cchDefaultExt + 1;
1156 AssertMsgReturn(cchPath <= RTPATH_MAX, ("Path too long!\n"), NULL);
1157
1158 char *pszRet = (char *)RTMemTmpAlloc(cchDir + 1 + cchFile + cchDefaultExt + 1);
1159 AssertMsgReturn(pszRet, ("Out of temporary memory!\n"), NULL);
1160
1161 /*
1162 * Construct the filename.
1163 */
1164 memcpy(pszRet, pszDir, cchDir);
1165 pszRet[cchDir++] = '/'; /* this works everywhere */
1166 memcpy(pszRet + cchDir, pszFile, cchFile + 1);
1167 if (cchDefaultExt)
1168 memcpy(pszRet + cchDir + cchFile, pszDefaultExt, cchDefaultExt + 1);
1169
1170 return pszRet;
1171}
1172
1173
1174/**
1175 * Worker for pdmR3FileRC(), pdmR3FileR0() and pdmR3FileR3().
1176 *
1177 * @returns Pointer to temporary memory containing the filename.
1178 * Caller must free this using RTMemTmpFree().
1179 * @returns NULL on failure.
1180 * @param pszFile File name (no path).
1181 * @param pszDefaultExt The default extention, NULL if none.
1182 * @param pszSearchPath List of directories to search if @a pszFile is
1183 * not qualified with a path. Can be NULL, in which
1184 * case the arch dependent install dir is searched.
1185 * @param fShared If true, search in the shared directory (/usr/lib on Unix), else
1186 * search in the private directory (/usr/lib/virtualbox on Unix).
1187 * Ignored if VBOX_PATH_SHARED_LIBS is not defined.
1188 * @todo We'll have this elsewhere than in the root later!
1189 * @todo Remove the fShared hack again once we don't need to link against VBoxDD anymore!
1190 */
1191static char *pdmR3File(const char *pszFile, const char *pszDefaultExt, const char *pszSearchPath, bool fShared)
1192{
1193 char szPath[RTPATH_MAX];
1194 int rc;
1195
1196 AssertLogRelReturn(!fShared || !pszSearchPath, NULL);
1197 Assert(!RTPathHavePath(pszFile));
1198
1199 /*
1200 * If there is a path, search it.
1201 */
1202 if ( pszSearchPath
1203 && *pszSearchPath)
1204 {
1205 /* Check the filename length. */
1206 size_t const cchFile = strlen(pszFile);
1207 if (cchFile >= sizeof(szPath))
1208 return NULL;
1209
1210 /*
1211 * Walk the search path.
1212 */
1213 const char *psz = pszSearchPath;
1214 while (*psz)
1215 {
1216 /* Skip leading blanks - no directories with leading spaces, thank you. */
1217 while (RT_C_IS_BLANK(*psz))
1218 psz++;
1219
1220 /* Find the end of this element. */
1221 const char *pszNext;
1222 const char *pszEnd = strchr(psz, ';');
1223 if (!pszEnd)
1224 pszEnd = pszNext = strchr(psz, '\0');
1225 else
1226 pszNext = pszEnd + 1;
1227 if (pszEnd != psz)
1228 {
1229 rc = RTPathJoinEx(szPath, sizeof(szPath), psz, pszEnd - psz, pszFile, cchFile, RTPATH_STR_F_STYLE_HOST);
1230 if (RT_SUCCESS(rc))
1231 {
1232 if (RTFileExists(szPath))
1233 {
1234 size_t cchPath = strlen(szPath) + 1;
1235 char *pszRet = (char *)RTMemTmpAlloc(cchPath);
1236 if (pszRet)
1237 memcpy(pszRet, szPath, cchPath);
1238 return pszRet;
1239 }
1240 }
1241 }
1242
1243 /* advance */
1244 psz = pszNext;
1245 }
1246 }
1247
1248 /*
1249 * Use the default location.
1250 */
1251 rc = fShared
1252 ? RTPathSharedLibs( szPath, sizeof(szPath))
1253 : RTPathAppPrivateArch(szPath, sizeof(szPath));
1254 if (!RT_SUCCESS(rc))
1255 {
1256 AssertMsgFailed(("RTPath[SharedLibs|AppPrivateArch](,%d) failed rc=%d!\n", sizeof(szPath), rc));
1257 return NULL;
1258 }
1259
1260 return pdmR3FileConstruct(szPath, pszFile, pszDefaultExt);
1261}
1262
1263
1264/** @internal */
1265typedef struct QMFEIPARG
1266{
1267 RTINTPTR uPC;
1268
1269 char *pszNearSym1;
1270 size_t cchNearSym1;
1271 RTINTPTR offNearSym1;
1272
1273 char *pszNearSym2;
1274 size_t cchNearSym2;
1275 RTINTPTR offNearSym2;
1276} QMFEIPARG, *PQMFEIPARG;
1277
1278
1279/**
1280 * Enumeration callback function used by RTLdrEnumSymbols().
1281 *
1282 * @returns VBox status code. Failure will stop the enumeration.
1283 * @param hLdrMod The loader module handle.
1284 * @param pszSymbol Symbol name. NULL if ordinal only.
1285 * @param uSymbol Symbol ordinal, ~0 if not used.
1286 * @param Value Symbol value.
1287 * @param pvUser The user argument specified to RTLdrEnumSymbols().
1288 */
1289static DECLCALLBACK(int) pdmR3QueryModFromEIPEnumSymbols(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol,
1290 RTUINTPTR Value, void *pvUser)
1291{
1292 PQMFEIPARG pArgs = (PQMFEIPARG)pvUser;
1293 NOREF(hLdrMod);
1294
1295 RTINTPTR off = Value - pArgs->uPC;
1296 if (off <= 0) /* near1 is before or at same location. */
1297 {
1298 if (off > pArgs->offNearSym1)
1299 {
1300 pArgs->offNearSym1 = off;
1301 if (pArgs->pszNearSym1 && pArgs->cchNearSym1)
1302 {
1303 *pArgs->pszNearSym1 = '\0';
1304 if (pszSymbol)
1305 strncat(pArgs->pszNearSym1, pszSymbol, pArgs->cchNearSym1);
1306 else
1307 {
1308 char szOrd[32];
1309 RTStrPrintf(szOrd, sizeof(szOrd), "#%#x", uSymbol);
1310 strncat(pArgs->pszNearSym1, szOrd, pArgs->cchNearSym1);
1311 }
1312 }
1313 }
1314 }
1315 else /* near2 is after */
1316 {
1317 if (off < pArgs->offNearSym2)
1318 {
1319 pArgs->offNearSym2 = off;
1320 if (pArgs->pszNearSym2 && pArgs->cchNearSym2)
1321 {
1322 *pArgs->pszNearSym2 = '\0';
1323 if (pszSymbol)
1324 strncat(pArgs->pszNearSym2, pszSymbol, pArgs->cchNearSym2);
1325 else
1326 {
1327 char szOrd[32];
1328 RTStrPrintf(szOrd, sizeof(szOrd), "#%#x", uSymbol);
1329 strncat(pArgs->pszNearSym2, szOrd, pArgs->cchNearSym2);
1330 }
1331 }
1332 }
1333 }
1334
1335 return VINF_SUCCESS;
1336}
1337
1338
1339/**
1340 * Internal worker for PDMR3LdrQueryRCModFromPC and PDMR3LdrQueryR0ModFromPC.
1341 *
1342 * @returns VBox status code.
1343 *
1344 * @param pVM The cross context VM structure.
1345 * @param uPC The program counter (eip/rip) to locate the module for.
1346 * @param enmType The module type.
1347 * @param pszModName Where to store the module name.
1348 * @param cchModName Size of the module name buffer.
1349 * @param pMod Base address of the module.
1350 * @param pszNearSym1 Name of the closes symbol from below.
1351 * @param cchNearSym1 Size of the buffer pointed to by pszNearSym1.
1352 * @param pNearSym1 The address of pszNearSym1.
1353 * @param pszNearSym2 Name of the closes symbol from below.
1354 * @param cchNearSym2 Size of the buffer pointed to by pszNearSym2.
1355 * @param pNearSym2 The address of pszNearSym2.
1356 */
1357static int pdmR3LdrQueryModFromPC(PVM pVM, RTUINTPTR uPC, PDMMODTYPE enmType,
1358 char *pszModName, size_t cchModName, PRTUINTPTR pMod,
1359 char *pszNearSym1, size_t cchNearSym1, PRTUINTPTR pNearSym1,
1360 char *pszNearSym2, size_t cchNearSym2, PRTUINTPTR pNearSym2)
1361{
1362 PUVM pUVM = pVM->pUVM;
1363 int rc = VERR_MODULE_NOT_FOUND;
1364 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
1365 for (PPDMMOD pCur= pUVM->pdm.s.pModules; pCur; pCur = pCur->pNext)
1366 {
1367 if (pCur->eType != enmType)
1368 continue;
1369
1370 /* The following RTLdrOpen call is a dirty hack to get ring-0 module information. */
1371 RTLDRMOD hLdrMod = pCur->hLdrMod;
1372 if (hLdrMod == NIL_RTLDRMOD && uPC >= pCur->ImageBase)
1373 {
1374 int rc2 = RTLdrOpen(pCur->szFilename, 0 /*fFlags*/, RTLDRARCH_HOST, &hLdrMod);
1375 if (RT_FAILURE(rc2))
1376 hLdrMod = NIL_RTLDRMOD;
1377 }
1378
1379 if ( hLdrMod != NIL_RTLDRMOD
1380 && uPC - pCur->ImageBase < RTLdrSize(hLdrMod))
1381 {
1382 if (pMod)
1383 *pMod = pCur->ImageBase;
1384 if (pszModName && cchModName)
1385 {
1386 *pszModName = '\0';
1387 strncat(pszModName, pCur->szName, cchModName);
1388 }
1389 if (pNearSym1) *pNearSym1 = 0;
1390 if (pNearSym2) *pNearSym2 = 0;
1391 if (pszNearSym1) *pszNearSym1 = '\0';
1392 if (pszNearSym2) *pszNearSym2 = '\0';
1393
1394 /*
1395 * Locate the nearest symbols.
1396 */
1397 QMFEIPARG Args;
1398 Args.uPC = uPC;
1399 Args.pszNearSym1 = pszNearSym1;
1400 Args.cchNearSym1 = cchNearSym1;
1401 Args.offNearSym1 = RTINTPTR_MIN;
1402 Args.pszNearSym2 = pszNearSym2;
1403 Args.cchNearSym2 = cchNearSym2;
1404 Args.offNearSym2 = RTINTPTR_MAX;
1405
1406 rc = RTLdrEnumSymbols(hLdrMod, RTLDR_ENUM_SYMBOL_FLAGS_ALL, pCur->pvBits, pCur->ImageBase,
1407 pdmR3QueryModFromEIPEnumSymbols, &Args);
1408 if (pNearSym1 && Args.offNearSym1 != RTINTPTR_MIN)
1409 *pNearSym1 = Args.offNearSym1 + uPC;
1410 if (pNearSym2 && Args.offNearSym2 != RTINTPTR_MAX)
1411 *pNearSym2 = Args.offNearSym2 + uPC;
1412
1413 rc = VINF_SUCCESS;
1414 }
1415
1416 if (hLdrMod != pCur->hLdrMod && hLdrMod != NIL_RTLDRMOD)
1417 RTLdrClose(hLdrMod);
1418
1419 if (RT_SUCCESS(rc))
1420 break;
1421 }
1422 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
1423 return rc;
1424}
1425
1426
1427/**
1428 * Queries raw-mode context module information from an PC (eip/rip).
1429 *
1430 * This is typically used to locate a crash address.
1431 *
1432 * @returns VBox status code.
1433 *
1434 * @param pVM The cross context VM structure.
1435 * @param uPC The program counter (eip/rip) to locate the module for.
1436 * @param pszModName Where to store the module name.
1437 * @param cchModName Size of the module name buffer.
1438 * @param pMod Base address of the module.
1439 * @param pszNearSym1 Name of the closes symbol from below.
1440 * @param cchNearSym1 Size of the buffer pointed to by pszNearSym1.
1441 * @param pNearSym1 The address of pszNearSym1.
1442 * @param pszNearSym2 Name of the closes symbol from below.
1443 * @param cchNearSym2 Size of the buffer pointed to by pszNearSym2.
1444 * @param pNearSym2 The address of pszNearSym2.
1445 */
1446VMMR3_INT_DECL(int) PDMR3LdrQueryRCModFromPC(PVM pVM, RTRCPTR uPC,
1447 char *pszModName, size_t cchModName, PRTRCPTR pMod,
1448 char *pszNearSym1, size_t cchNearSym1, PRTRCPTR pNearSym1,
1449 char *pszNearSym2, size_t cchNearSym2, PRTRCPTR pNearSym2)
1450{
1451 RTUINTPTR AddrMod = 0;
1452 RTUINTPTR AddrNear1 = 0;
1453 RTUINTPTR AddrNear2 = 0;
1454 int rc = pdmR3LdrQueryModFromPC(pVM, uPC, PDMMOD_TYPE_RC,
1455 pszModName, cchModName, &AddrMod,
1456 pszNearSym1, cchNearSym1, &AddrNear1,
1457 pszNearSym2, cchNearSym2, &AddrNear2);
1458 if (RT_SUCCESS(rc))
1459 {
1460 if (pMod)
1461 *pMod = (RTRCPTR)AddrMod;
1462 if (pNearSym1)
1463 *pNearSym1 = (RTRCPTR)AddrNear1;
1464 if (pNearSym2)
1465 *pNearSym2 = (RTRCPTR)AddrNear2;
1466 }
1467 return rc;
1468}
1469
1470
1471/**
1472 * Queries ring-0 context module information from an PC (eip/rip).
1473 *
1474 * This is typically used to locate a crash address.
1475 *
1476 * @returns VBox status code.
1477 *
1478 * @param pVM The cross context VM structure.
1479 * @param uPC The program counter (eip/rip) to locate the module for.
1480 * @param pszModName Where to store the module name.
1481 * @param cchModName Size of the module name buffer.
1482 * @param pMod Base address of the module.
1483 * @param pszNearSym1 Name of the closes symbol from below.
1484 * @param cchNearSym1 Size of the buffer pointed to by pszNearSym1.
1485 * @param pNearSym1 The address of pszNearSym1.
1486 * @param pszNearSym2 Name of the closes symbol from below.
1487 * @param cchNearSym2 Size of the buffer pointed to by pszNearSym2. Optional.
1488 * @param pNearSym2 The address of pszNearSym2. Optional.
1489 */
1490VMMR3_INT_DECL(int) PDMR3LdrQueryR0ModFromPC(PVM pVM, RTR0PTR uPC,
1491 char *pszModName, size_t cchModName, PRTR0PTR pMod,
1492 char *pszNearSym1, size_t cchNearSym1, PRTR0PTR pNearSym1,
1493 char *pszNearSym2, size_t cchNearSym2, PRTR0PTR pNearSym2)
1494{
1495 RTUINTPTR AddrMod = 0;
1496 RTUINTPTR AddrNear1 = 0;
1497 RTUINTPTR AddrNear2 = 0;
1498 int rc = pdmR3LdrQueryModFromPC(pVM, uPC, PDMMOD_TYPE_R0,
1499 pszModName, cchModName, &AddrMod,
1500 pszNearSym1, cchNearSym1, &AddrNear1,
1501 pszNearSym2, cchNearSym2, &AddrNear2);
1502 if (RT_SUCCESS(rc))
1503 {
1504 if (pMod)
1505 *pMod = (RTR0PTR)AddrMod;
1506 if (pNearSym1)
1507 *pNearSym1 = (RTR0PTR)AddrNear1;
1508 if (pNearSym2)
1509 *pNearSym2 = (RTR0PTR)AddrNear2;
1510 }
1511 return rc;
1512}
1513
1514
1515/**
1516 * Enumerate all PDM modules.
1517 *
1518 * @returns VBox status code.
1519 * @param pVM The cross context VM structure.
1520 * @param pfnCallback Function to call back for each of the modules.
1521 * @param pvArg User argument.
1522 */
1523VMMR3DECL(int) PDMR3LdrEnumModules(PVM pVM, PFNPDMR3ENUM pfnCallback, void *pvArg)
1524{
1525 PUVM pUVM = pVM->pUVM;
1526 int rc = VINF_SUCCESS;
1527 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
1528 for (PPDMMOD pCur = pUVM->pdm.s.pModules; pCur; pCur = pCur->pNext)
1529 {
1530 rc = pfnCallback(pVM,
1531 pCur->szFilename,
1532 pCur->szName,
1533 pCur->ImageBase,
1534 pCur->eType == PDMMOD_TYPE_RC ? RTLdrSize(pCur->hLdrMod) : 0,
1535 pCur->eType == PDMMOD_TYPE_RC ? PDMLDRCTX_RAW_MODE
1536 : pCur->eType == PDMMOD_TYPE_R0 ? PDMLDRCTX_RING_0
1537 : pCur->eType == PDMMOD_TYPE_R3 ? PDMLDRCTX_RING_3
1538 : PDMLDRCTX_INVALID,
1539 pvArg);
1540 if (RT_FAILURE(rc))
1541 break;
1542 }
1543 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
1544 return rc;
1545}
1546
1547
1548/**
1549 * Locates a module.
1550 *
1551 * @returns Pointer to the module if found.
1552 * @param pUVM Pointer to the user mode VM structure.
1553 * @param pszModule The module name.
1554 * @param enmType The module type.
1555 * @param fLazy Lazy loading the module if set.
1556 * @param pszSearchPath Search path for use when lazy loading.
1557 */
1558static PPDMMOD pdmR3LdrFindModule(PUVM pUVM, const char *pszModule, PDMMODTYPE enmType,
1559 bool fLazy, const char *pszSearchPath)
1560{
1561 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
1562 for (PPDMMOD pModule = pUVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
1563 if ( pModule->eType == enmType
1564 && !strcmp(pModule->szName, pszModule))
1565 {
1566 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
1567 return pModule;
1568 }
1569 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
1570 if (fLazy)
1571 {
1572 switch (enmType)
1573 {
1574#ifdef VBOX_WITH_RAW_MODE_KEEP
1575 case PDMMOD_TYPE_RC:
1576 {
1577 char *pszFilename = pdmR3FileRC(pszModule, pszSearchPath);
1578 if (pszFilename)
1579 {
1580 int rc = PDMR3LdrLoadRC(pUVM->pVM, pszFilename, pszModule);
1581 RTMemTmpFree(pszFilename);
1582 if (RT_SUCCESS(rc))
1583 return pdmR3LdrFindModule(pUVM, pszModule, enmType, false, NULL);
1584 }
1585 break;
1586 }
1587#endif
1588
1589 case PDMMOD_TYPE_R0:
1590 {
1591 int rc = pdmR3LoadR0U(pUVM, NULL, pszModule, pszSearchPath);
1592 if (RT_SUCCESS(rc))
1593 return pdmR3LdrFindModule(pUVM, pszModule, enmType, false, NULL);
1594 break;
1595 }
1596
1597 default:
1598 AssertFailed();
1599 }
1600 }
1601 return NULL;
1602}
1603
1604
1605/**
1606 * Resolves a ring-0 or raw-mode context interface.
1607 *
1608 * @returns VBox status code.
1609 * @param pVM The cross context VM structure.
1610 * @param pvInterface Pointer to the interface structure. The symbol list
1611 * describes the layout.
1612 * @param cbInterface The size of the structure pvInterface is pointing
1613 * to. For bounds checking.
1614 * @param pszModule The module name. If NULL we assume it's the default
1615 * R0 or RC module (@a fRing0OrRC). We'll attempt to
1616 * load the module if it isn't found in the module
1617 * list.
1618 * @param pszSearchPath The module search path. If NULL, search the
1619 * architecture dependent install directory.
1620 * @param pszSymPrefix What to prefix the symbols in the list with. The
1621 * idea is that you define a list that goes with an
1622 * interface (INTERFACE_SYM_LIST) and reuse it with
1623 * each implementation.
1624 * @param pszSymList The symbol list for the interface. This is a
1625 * semi-colon separated list of symbol base names. As
1626 * mentioned above, each is prefixed with @a
1627 * pszSymPrefix before resolving. There are a couple
1628 * of special symbol names that will cause us to skip
1629 * ahead a little bit:
1630 * - U8:whatever,
1631 * - U16:whatever,
1632 * - U32:whatever,
1633 * - U64:whatever,
1634 * - RCPTR:whatever,
1635 * - R3PTR:whatever,
1636 * - R0PTR:whatever,
1637 * - GCPHYS:whatever,
1638 * - HCPHYS:whatever.
1639 * @param fRing0 Set if it's a ring-0 context interface, clear if
1640 * it's raw-mode context interface.
1641 */
1642VMMR3_INT_DECL(int) PDMR3LdrGetInterfaceSymbols(PVM pVM, void *pvInterface, size_t cbInterface,
1643 const char *pszModule, const char *pszSearchPath,
1644 const char *pszSymPrefix, const char *pszSymList,
1645 bool fRing0)
1646{
1647 bool const fNullRun = !fRing0;
1648
1649 /*
1650 * Find the module.
1651 */
1652 int rc = VINF_SUCCESS;
1653 PPDMMOD pModule = NULL;
1654 if (!fNullRun)
1655 pModule = pdmR3LdrFindModule(pVM->pUVM,
1656 pszModule ? pszModule : fRing0 ? "VMMR0.r0" : "VMMRC.rc",
1657 fRing0 ? PDMMOD_TYPE_R0 : PDMMOD_TYPE_RC,
1658 true /*fLazy*/, pszSearchPath);
1659 if (pModule || fNullRun)
1660 {
1661 /* Prep the symbol name. */
1662 char szSymbol[256];
1663 size_t const cchSymPrefix = strlen(pszSymPrefix);
1664 AssertReturn(cchSymPrefix + 5 < sizeof(szSymbol), VERR_SYMBOL_NOT_FOUND);
1665 memcpy(szSymbol, pszSymPrefix, cchSymPrefix);
1666
1667 /*
1668 * Iterate the symbol list.
1669 */
1670 uint32_t offInterface = 0;
1671 const char *pszCur = pszSymList;
1672 while (pszCur)
1673 {
1674 /*
1675 * Find the end of the current symbol name.
1676 */
1677 size_t cchSym;
1678 const char *pszNext = strchr(pszCur, ';');
1679 if (pszNext)
1680 {
1681 cchSym = pszNext - pszCur;
1682 pszNext++;
1683 }
1684 else
1685 cchSym = strlen(pszCur);
1686 AssertBreakStmt(cchSym > 0, rc = VERR_INVALID_PARAMETER);
1687
1688 /* Is it a skip instruction? */
1689 const char *pszColon = (const char *)memchr(pszCur, ':', cchSym);
1690 if (pszColon)
1691 {
1692 /*
1693 * String switch on the instruction and execute it, checking
1694 * that we didn't overshoot the interface structure.
1695 */
1696#define IS_SKIP_INSTR(szInstr) \
1697 ( cchSkip == sizeof(szInstr) - 1 \
1698 && !memcmp(pszCur, szInstr, sizeof(szInstr) - 1) )
1699
1700 size_t const cchSkip = pszColon - pszCur;
1701 if (IS_SKIP_INSTR("U8"))
1702 offInterface += sizeof(uint8_t);
1703 else if (IS_SKIP_INSTR("U16"))
1704 offInterface += sizeof(uint16_t);
1705 else if (IS_SKIP_INSTR("U32"))
1706 offInterface += sizeof(uint32_t);
1707 else if (IS_SKIP_INSTR("U64"))
1708 offInterface += sizeof(uint64_t);
1709 else if (IS_SKIP_INSTR("RCPTR"))
1710 offInterface += sizeof(RTRCPTR);
1711 else if (IS_SKIP_INSTR("R3PTR"))
1712 offInterface += sizeof(RTR3PTR);
1713 else if (IS_SKIP_INSTR("R0PTR"))
1714 offInterface += sizeof(RTR0PTR);
1715 else if (IS_SKIP_INSTR("HCPHYS"))
1716 offInterface += sizeof(RTHCPHYS);
1717 else if (IS_SKIP_INSTR("GCPHYS"))
1718 offInterface += sizeof(RTGCPHYS);
1719 else
1720 AssertMsgFailedBreakStmt(("Invalid skip instruction %.*s (prefix=%s)\n", cchSym, pszCur, pszSymPrefix),
1721 rc = VERR_INVALID_PARAMETER);
1722 AssertMsgBreakStmt(offInterface <= cbInterface,
1723 ("off=%#x cb=%#x (sym=%.*s prefix=%s)\n", offInterface, cbInterface, cchSym, pszCur, pszSymPrefix),
1724 rc = VERR_BUFFER_OVERFLOW);
1725#undef IS_SKIP_INSTR
1726 }
1727 else
1728 {
1729 /*
1730 * Construct the symbol name, get its value, store it and
1731 * advance the interface cursor.
1732 */
1733 AssertReturn(cchSymPrefix + cchSym < sizeof(szSymbol), VERR_SYMBOL_NOT_FOUND);
1734 memcpy(&szSymbol[cchSymPrefix], pszCur, cchSym);
1735 szSymbol[cchSymPrefix + cchSym] = '\0';
1736
1737 if (fRing0)
1738 {
1739 void *pvValue = NULL;
1740 if (!fNullRun)
1741 {
1742 rc = SUPR3GetSymbolR0((void *)(RTR0PTR)pModule->ImageBase, szSymbol, &pvValue);
1743 AssertMsgRCBreak(rc, ("Couldn't find symbol '%s' in module '%s'\n", szSymbol, pModule->szName));
1744 }
1745
1746 PRTR0PTR pValue = (PRTR0PTR)((uintptr_t)pvInterface + offInterface);
1747 AssertMsgBreakStmt(offInterface + sizeof(*pValue) <= cbInterface,
1748 ("off=%#x cb=%#x sym=%s\n", offInterface, cbInterface, szSymbol),
1749 rc = VERR_BUFFER_OVERFLOW);
1750 *pValue = (RTR0PTR)pvValue;
1751 Assert((void *)*pValue == pvValue);
1752 offInterface += sizeof(*pValue);
1753 }
1754 else
1755 {
1756 RTUINTPTR Value = 0;
1757 if (!fNullRun)
1758 {
1759 rc = RTLdrGetSymbolEx(pModule->hLdrMod, pModule->pvBits, pModule->ImageBase, UINT32_MAX, szSymbol, &Value);
1760 AssertMsgRCBreak(rc, ("Couldn't find symbol '%s' in module '%s'\n", szSymbol, pModule->szName));
1761 }
1762
1763 PRTRCPTR pValue = (PRTRCPTR)((uintptr_t)pvInterface + offInterface);
1764 AssertMsgBreakStmt(offInterface + sizeof(*pValue) <= cbInterface,
1765 ("off=%#x cb=%#x sym=%s\n", offInterface, cbInterface, szSymbol),
1766 rc = VERR_BUFFER_OVERFLOW);
1767 *pValue = (RTRCPTR)Value;
1768 Assert(*pValue == Value);
1769 offInterface += sizeof(*pValue);
1770 }
1771 }
1772
1773 /* advance */
1774 pszCur = pszNext;
1775 }
1776
1777 }
1778 else
1779 rc = VERR_MODULE_NOT_FOUND;
1780 return rc;
1781}
1782
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