VirtualBox

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

Last change on this file since 102828 was 99775, checked in by vboxsync, 20 months ago

*: Mark functions as static if not used outside of a given compilation unit. Enables the compiler to optimize inlining, reduces the symbol tables, exposes unused functions and in some rare cases exposes mismtaches between function declarations and definitions, but most importantly reduces the number of parfait reports for the extern-function-no-forward-declaration category. This should not result in any functional changes, bugref:3409

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 64.1 KB
Line 
1/* $Id: PDMLdr.cpp 99775 2023-05-12 12:21:58Z 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 */
1103static char *pdmR3FileR0(const char *pszFile, const char *pszSearchPath)
1104{
1105 return pdmR3File(pszFile, NULL, pszSearchPath, /*fShared=*/false);
1106}
1107
1108
1109#if 0 /* unused */
1110/**
1111 * Constructs the full filename for a RC image file.
1112 *
1113 * @returns Pointer to temporary memory containing the filename.
1114 * Caller must free this using RTMemTmpFree().
1115 * @returns NULL on failure.
1116 *
1117 * @param pszFile File name (no path).
1118 * @param pszSearchPath List of directories to search if @a pszFile is
1119 * not qualified with a path. Can be NULL, in which
1120 * case the arch dependent install dir is searched.
1121 */
1122static char *pdmR3FileRC(const char *pszFile, const char *pszSearchPath)
1123{
1124 return pdmR3File(pszFile, NULL, pszSearchPath, /*fShared=*/false);
1125}
1126#endif
1127
1128
1129/**
1130 * Worker for pdmR3File().
1131 *
1132 * @returns Pointer to temporary memory containing the filename.
1133 * Caller must free this using RTMemTmpFree().
1134 * @returns NULL on failure.
1135 *
1136 * @param pszDir Directory part
1137 * @param pszFile File name part
1138 * @param pszDefaultExt Extension part
1139 */
1140static char *pdmR3FileConstruct(const char *pszDir, const char *pszFile, const char *pszDefaultExt)
1141{
1142 /*
1143 * Allocate temp memory for return buffer.
1144 */
1145 size_t cchDir = strlen(pszDir);
1146 size_t cchFile = strlen(pszFile);
1147 size_t cchDefaultExt;
1148
1149 /*
1150 * Default extention?
1151 */
1152 if (!pszDefaultExt || strchr(pszFile, '.'))
1153 cchDefaultExt = 0;
1154 else
1155 cchDefaultExt = strlen(pszDefaultExt);
1156
1157 size_t cchPath = cchDir + 1 + cchFile + cchDefaultExt + 1;
1158 AssertMsgReturn(cchPath <= RTPATH_MAX, ("Path too long!\n"), NULL);
1159
1160 char *pszRet = (char *)RTMemTmpAlloc(cchDir + 1 + cchFile + cchDefaultExt + 1);
1161 AssertMsgReturn(pszRet, ("Out of temporary memory!\n"), NULL);
1162
1163 /*
1164 * Construct the filename.
1165 */
1166 memcpy(pszRet, pszDir, cchDir);
1167 pszRet[cchDir++] = '/'; /* this works everywhere */
1168 memcpy(pszRet + cchDir, pszFile, cchFile + 1);
1169 if (cchDefaultExt)
1170 memcpy(pszRet + cchDir + cchFile, pszDefaultExt, cchDefaultExt + 1);
1171
1172 return pszRet;
1173}
1174
1175
1176/**
1177 * Worker for pdmR3FileRC(), pdmR3FileR0() and pdmR3FileR3().
1178 *
1179 * @returns Pointer to temporary memory containing the filename.
1180 * Caller must free this using RTMemTmpFree().
1181 * @returns NULL on failure.
1182 * @param pszFile File name (no path).
1183 * @param pszDefaultExt The default extention, NULL if none.
1184 * @param pszSearchPath List of directories to search if @a pszFile is
1185 * not qualified with a path. Can be NULL, in which
1186 * case the arch dependent install dir is searched.
1187 * @param fShared If true, search in the shared directory (/usr/lib on Unix), else
1188 * search in the private directory (/usr/lib/virtualbox on Unix).
1189 * Ignored if VBOX_PATH_SHARED_LIBS is not defined.
1190 * @todo We'll have this elsewhere than in the root later!
1191 * @todo Remove the fShared hack again once we don't need to link against VBoxDD anymore!
1192 */
1193static char *pdmR3File(const char *pszFile, const char *pszDefaultExt, const char *pszSearchPath, bool fShared)
1194{
1195 char szPath[RTPATH_MAX];
1196 int rc;
1197
1198 AssertLogRelReturn(!fShared || !pszSearchPath, NULL);
1199 Assert(!RTPathHavePath(pszFile));
1200
1201 /*
1202 * If there is a path, search it.
1203 */
1204 if ( pszSearchPath
1205 && *pszSearchPath)
1206 {
1207 /* Check the filename length. */
1208 size_t const cchFile = strlen(pszFile);
1209 if (cchFile >= sizeof(szPath))
1210 return NULL;
1211
1212 /*
1213 * Walk the search path.
1214 */
1215 const char *psz = pszSearchPath;
1216 while (*psz)
1217 {
1218 /* Skip leading blanks - no directories with leading spaces, thank you. */
1219 while (RT_C_IS_BLANK(*psz))
1220 psz++;
1221
1222 /* Find the end of this element. */
1223 const char *pszNext;
1224 const char *pszEnd = strchr(psz, ';');
1225 if (!pszEnd)
1226 pszEnd = pszNext = strchr(psz, '\0');
1227 else
1228 pszNext = pszEnd + 1;
1229 if (pszEnd != psz)
1230 {
1231 rc = RTPathJoinEx(szPath, sizeof(szPath), psz, pszEnd - psz, pszFile, cchFile, RTPATH_STR_F_STYLE_HOST);
1232 if (RT_SUCCESS(rc))
1233 {
1234 if (RTFileExists(szPath))
1235 {
1236 size_t cchPath = strlen(szPath) + 1;
1237 char *pszRet = (char *)RTMemTmpAlloc(cchPath);
1238 if (pszRet)
1239 memcpy(pszRet, szPath, cchPath);
1240 return pszRet;
1241 }
1242 }
1243 }
1244
1245 /* advance */
1246 psz = pszNext;
1247 }
1248 }
1249
1250 /*
1251 * Use the default location.
1252 */
1253 rc = fShared
1254 ? RTPathSharedLibs( szPath, sizeof(szPath))
1255 : RTPathAppPrivateArch(szPath, sizeof(szPath));
1256 if (!RT_SUCCESS(rc))
1257 {
1258 AssertMsgFailed(("RTPath[SharedLibs|AppPrivateArch](,%d) failed rc=%d!\n", sizeof(szPath), rc));
1259 return NULL;
1260 }
1261
1262 return pdmR3FileConstruct(szPath, pszFile, pszDefaultExt);
1263}
1264
1265
1266/** @internal */
1267typedef struct QMFEIPARG
1268{
1269 RTINTPTR uPC;
1270
1271 char *pszNearSym1;
1272 size_t cchNearSym1;
1273 RTINTPTR offNearSym1;
1274
1275 char *pszNearSym2;
1276 size_t cchNearSym2;
1277 RTINTPTR offNearSym2;
1278} QMFEIPARG, *PQMFEIPARG;
1279
1280
1281/**
1282 * Enumeration callback function used by RTLdrEnumSymbols().
1283 *
1284 * @returns VBox status code. Failure will stop the enumeration.
1285 * @param hLdrMod The loader module handle.
1286 * @param pszSymbol Symbol name. NULL if ordinal only.
1287 * @param uSymbol Symbol ordinal, ~0 if not used.
1288 * @param Value Symbol value.
1289 * @param pvUser The user argument specified to RTLdrEnumSymbols().
1290 */
1291static DECLCALLBACK(int) pdmR3QueryModFromEIPEnumSymbols(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol,
1292 RTUINTPTR Value, void *pvUser)
1293{
1294 PQMFEIPARG pArgs = (PQMFEIPARG)pvUser;
1295 NOREF(hLdrMod);
1296
1297 RTINTPTR off = Value - pArgs->uPC;
1298 if (off <= 0) /* near1 is before or at same location. */
1299 {
1300 if (off > pArgs->offNearSym1)
1301 {
1302 pArgs->offNearSym1 = off;
1303 if (pArgs->pszNearSym1 && pArgs->cchNearSym1)
1304 {
1305 *pArgs->pszNearSym1 = '\0';
1306 if (pszSymbol)
1307 strncat(pArgs->pszNearSym1, pszSymbol, pArgs->cchNearSym1);
1308 else
1309 {
1310 char szOrd[32];
1311 RTStrPrintf(szOrd, sizeof(szOrd), "#%#x", uSymbol);
1312 strncat(pArgs->pszNearSym1, szOrd, pArgs->cchNearSym1);
1313 }
1314 }
1315 }
1316 }
1317 else /* near2 is after */
1318 {
1319 if (off < pArgs->offNearSym2)
1320 {
1321 pArgs->offNearSym2 = off;
1322 if (pArgs->pszNearSym2 && pArgs->cchNearSym2)
1323 {
1324 *pArgs->pszNearSym2 = '\0';
1325 if (pszSymbol)
1326 strncat(pArgs->pszNearSym2, pszSymbol, pArgs->cchNearSym2);
1327 else
1328 {
1329 char szOrd[32];
1330 RTStrPrintf(szOrd, sizeof(szOrd), "#%#x", uSymbol);
1331 strncat(pArgs->pszNearSym2, szOrd, pArgs->cchNearSym2);
1332 }
1333 }
1334 }
1335 }
1336
1337 return VINF_SUCCESS;
1338}
1339
1340
1341/**
1342 * Internal worker for PDMR3LdrQueryRCModFromPC and PDMR3LdrQueryR0ModFromPC.
1343 *
1344 * @returns VBox status code.
1345 *
1346 * @param pVM The cross context VM structure.
1347 * @param uPC The program counter (eip/rip) to locate the module for.
1348 * @param enmType The module type.
1349 * @param pszModName Where to store the module name.
1350 * @param cchModName Size of the module name buffer.
1351 * @param pMod Base address of the module.
1352 * @param pszNearSym1 Name of the closes symbol from below.
1353 * @param cchNearSym1 Size of the buffer pointed to by pszNearSym1.
1354 * @param pNearSym1 The address of pszNearSym1.
1355 * @param pszNearSym2 Name of the closes symbol from below.
1356 * @param cchNearSym2 Size of the buffer pointed to by pszNearSym2.
1357 * @param pNearSym2 The address of pszNearSym2.
1358 */
1359static int pdmR3LdrQueryModFromPC(PVM pVM, RTUINTPTR uPC, PDMMODTYPE enmType,
1360 char *pszModName, size_t cchModName, PRTUINTPTR pMod,
1361 char *pszNearSym1, size_t cchNearSym1, PRTUINTPTR pNearSym1,
1362 char *pszNearSym2, size_t cchNearSym2, PRTUINTPTR pNearSym2)
1363{
1364 PUVM pUVM = pVM->pUVM;
1365 int rc = VERR_MODULE_NOT_FOUND;
1366 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
1367 for (PPDMMOD pCur= pUVM->pdm.s.pModules; pCur; pCur = pCur->pNext)
1368 {
1369 if (pCur->eType != enmType)
1370 continue;
1371
1372 /* The following RTLdrOpen call is a dirty hack to get ring-0 module information. */
1373 RTLDRMOD hLdrMod = pCur->hLdrMod;
1374 if (hLdrMod == NIL_RTLDRMOD && uPC >= pCur->ImageBase)
1375 {
1376 int rc2 = RTLdrOpen(pCur->szFilename, 0 /*fFlags*/, RTLDRARCH_HOST, &hLdrMod);
1377 if (RT_FAILURE(rc2))
1378 hLdrMod = NIL_RTLDRMOD;
1379 }
1380
1381 if ( hLdrMod != NIL_RTLDRMOD
1382 && uPC - pCur->ImageBase < RTLdrSize(hLdrMod))
1383 {
1384 if (pMod)
1385 *pMod = pCur->ImageBase;
1386 if (pszModName && cchModName)
1387 {
1388 *pszModName = '\0';
1389 strncat(pszModName, pCur->szName, cchModName);
1390 }
1391 if (pNearSym1) *pNearSym1 = 0;
1392 if (pNearSym2) *pNearSym2 = 0;
1393 if (pszNearSym1) *pszNearSym1 = '\0';
1394 if (pszNearSym2) *pszNearSym2 = '\0';
1395
1396 /*
1397 * Locate the nearest symbols.
1398 */
1399 QMFEIPARG Args;
1400 Args.uPC = uPC;
1401 Args.pszNearSym1 = pszNearSym1;
1402 Args.cchNearSym1 = cchNearSym1;
1403 Args.offNearSym1 = RTINTPTR_MIN;
1404 Args.pszNearSym2 = pszNearSym2;
1405 Args.cchNearSym2 = cchNearSym2;
1406 Args.offNearSym2 = RTINTPTR_MAX;
1407
1408 rc = RTLdrEnumSymbols(hLdrMod, RTLDR_ENUM_SYMBOL_FLAGS_ALL, pCur->pvBits, pCur->ImageBase,
1409 pdmR3QueryModFromEIPEnumSymbols, &Args);
1410 if (pNearSym1 && Args.offNearSym1 != RTINTPTR_MIN)
1411 *pNearSym1 = Args.offNearSym1 + uPC;
1412 if (pNearSym2 && Args.offNearSym2 != RTINTPTR_MAX)
1413 *pNearSym2 = Args.offNearSym2 + uPC;
1414
1415 rc = VINF_SUCCESS;
1416 }
1417
1418 if (hLdrMod != pCur->hLdrMod && hLdrMod != NIL_RTLDRMOD)
1419 RTLdrClose(hLdrMod);
1420
1421 if (RT_SUCCESS(rc))
1422 break;
1423 }
1424 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
1425 return rc;
1426}
1427
1428
1429/**
1430 * Queries raw-mode context module information from an PC (eip/rip).
1431 *
1432 * This is typically used to locate a crash address.
1433 *
1434 * @returns VBox status code.
1435 *
1436 * @param pVM The cross context VM structure.
1437 * @param uPC The program counter (eip/rip) to locate the module for.
1438 * @param pszModName Where to store the module name.
1439 * @param cchModName Size of the module name buffer.
1440 * @param pMod Base address of the module.
1441 * @param pszNearSym1 Name of the closes symbol from below.
1442 * @param cchNearSym1 Size of the buffer pointed to by pszNearSym1.
1443 * @param pNearSym1 The address of pszNearSym1.
1444 * @param pszNearSym2 Name of the closes symbol from below.
1445 * @param cchNearSym2 Size of the buffer pointed to by pszNearSym2.
1446 * @param pNearSym2 The address of pszNearSym2.
1447 */
1448VMMR3_INT_DECL(int) PDMR3LdrQueryRCModFromPC(PVM pVM, RTRCPTR uPC,
1449 char *pszModName, size_t cchModName, PRTRCPTR pMod,
1450 char *pszNearSym1, size_t cchNearSym1, PRTRCPTR pNearSym1,
1451 char *pszNearSym2, size_t cchNearSym2, PRTRCPTR pNearSym2)
1452{
1453 RTUINTPTR AddrMod = 0;
1454 RTUINTPTR AddrNear1 = 0;
1455 RTUINTPTR AddrNear2 = 0;
1456 int rc = pdmR3LdrQueryModFromPC(pVM, uPC, PDMMOD_TYPE_RC,
1457 pszModName, cchModName, &AddrMod,
1458 pszNearSym1, cchNearSym1, &AddrNear1,
1459 pszNearSym2, cchNearSym2, &AddrNear2);
1460 if (RT_SUCCESS(rc))
1461 {
1462 if (pMod)
1463 *pMod = (RTRCPTR)AddrMod;
1464 if (pNearSym1)
1465 *pNearSym1 = (RTRCPTR)AddrNear1;
1466 if (pNearSym2)
1467 *pNearSym2 = (RTRCPTR)AddrNear2;
1468 }
1469 return rc;
1470}
1471
1472
1473/**
1474 * Queries ring-0 context module information from an PC (eip/rip).
1475 *
1476 * This is typically used to locate a crash address.
1477 *
1478 * @returns VBox status code.
1479 *
1480 * @param pVM The cross context VM structure.
1481 * @param uPC The program counter (eip/rip) to locate the module for.
1482 * @param pszModName Where to store the module name.
1483 * @param cchModName Size of the module name buffer.
1484 * @param pMod Base address of the module.
1485 * @param pszNearSym1 Name of the closes symbol from below.
1486 * @param cchNearSym1 Size of the buffer pointed to by pszNearSym1.
1487 * @param pNearSym1 The address of pszNearSym1.
1488 * @param pszNearSym2 Name of the closes symbol from below.
1489 * @param cchNearSym2 Size of the buffer pointed to by pszNearSym2. Optional.
1490 * @param pNearSym2 The address of pszNearSym2. Optional.
1491 */
1492VMMR3_INT_DECL(int) PDMR3LdrQueryR0ModFromPC(PVM pVM, RTR0PTR uPC,
1493 char *pszModName, size_t cchModName, PRTR0PTR pMod,
1494 char *pszNearSym1, size_t cchNearSym1, PRTR0PTR pNearSym1,
1495 char *pszNearSym2, size_t cchNearSym2, PRTR0PTR pNearSym2)
1496{
1497 RTUINTPTR AddrMod = 0;
1498 RTUINTPTR AddrNear1 = 0;
1499 RTUINTPTR AddrNear2 = 0;
1500 int rc = pdmR3LdrQueryModFromPC(pVM, uPC, PDMMOD_TYPE_R0,
1501 pszModName, cchModName, &AddrMod,
1502 pszNearSym1, cchNearSym1, &AddrNear1,
1503 pszNearSym2, cchNearSym2, &AddrNear2);
1504 if (RT_SUCCESS(rc))
1505 {
1506 if (pMod)
1507 *pMod = (RTR0PTR)AddrMod;
1508 if (pNearSym1)
1509 *pNearSym1 = (RTR0PTR)AddrNear1;
1510 if (pNearSym2)
1511 *pNearSym2 = (RTR0PTR)AddrNear2;
1512 }
1513 return rc;
1514}
1515
1516
1517/**
1518 * Enumerate all PDM modules.
1519 *
1520 * @returns VBox status code.
1521 * @param pVM The cross context VM structure.
1522 * @param pfnCallback Function to call back for each of the modules.
1523 * @param pvArg User argument.
1524 */
1525VMMR3DECL(int) PDMR3LdrEnumModules(PVM pVM, PFNPDMR3ENUM pfnCallback, void *pvArg)
1526{
1527 PUVM pUVM = pVM->pUVM;
1528 int rc = VINF_SUCCESS;
1529 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
1530 for (PPDMMOD pCur = pUVM->pdm.s.pModules; pCur; pCur = pCur->pNext)
1531 {
1532 rc = pfnCallback(pVM,
1533 pCur->szFilename,
1534 pCur->szName,
1535 pCur->ImageBase,
1536 pCur->eType == PDMMOD_TYPE_RC ? RTLdrSize(pCur->hLdrMod) : 0,
1537 pCur->eType == PDMMOD_TYPE_RC ? PDMLDRCTX_RAW_MODE
1538 : pCur->eType == PDMMOD_TYPE_R0 ? PDMLDRCTX_RING_0
1539 : pCur->eType == PDMMOD_TYPE_R3 ? PDMLDRCTX_RING_3
1540 : PDMLDRCTX_INVALID,
1541 pvArg);
1542 if (RT_FAILURE(rc))
1543 break;
1544 }
1545 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
1546 return rc;
1547}
1548
1549
1550/**
1551 * Locates a module.
1552 *
1553 * @returns Pointer to the module if found.
1554 * @param pUVM Pointer to the user mode VM structure.
1555 * @param pszModule The module name.
1556 * @param enmType The module type.
1557 * @param fLazy Lazy loading the module if set.
1558 * @param pszSearchPath Search path for use when lazy loading.
1559 */
1560static PPDMMOD pdmR3LdrFindModule(PUVM pUVM, const char *pszModule, PDMMODTYPE enmType,
1561 bool fLazy, const char *pszSearchPath)
1562{
1563 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
1564 for (PPDMMOD pModule = pUVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
1565 if ( pModule->eType == enmType
1566 && !strcmp(pModule->szName, pszModule))
1567 {
1568 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
1569 return pModule;
1570 }
1571 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
1572 if (fLazy)
1573 {
1574 switch (enmType)
1575 {
1576#ifdef VBOX_WITH_RAW_MODE_KEEP
1577 case PDMMOD_TYPE_RC:
1578 {
1579 char *pszFilename = pdmR3FileRC(pszModule, pszSearchPath);
1580 if (pszFilename)
1581 {
1582 int rc = PDMR3LdrLoadRC(pUVM->pVM, pszFilename, pszModule);
1583 RTMemTmpFree(pszFilename);
1584 if (RT_SUCCESS(rc))
1585 return pdmR3LdrFindModule(pUVM, pszModule, enmType, false, NULL);
1586 }
1587 break;
1588 }
1589#endif
1590
1591 case PDMMOD_TYPE_R0:
1592 {
1593 int rc = pdmR3LoadR0U(pUVM, NULL, pszModule, pszSearchPath);
1594 if (RT_SUCCESS(rc))
1595 return pdmR3LdrFindModule(pUVM, pszModule, enmType, false, NULL);
1596 break;
1597 }
1598
1599 default:
1600 AssertFailed();
1601 }
1602 }
1603 return NULL;
1604}
1605
1606
1607/**
1608 * Resolves a ring-0 or raw-mode context interface.
1609 *
1610 * @returns VBox status code.
1611 * @param pVM The cross context VM structure.
1612 * @param pvInterface Pointer to the interface structure. The symbol list
1613 * describes the layout.
1614 * @param cbInterface The size of the structure pvInterface is pointing
1615 * to. For bounds checking.
1616 * @param pszModule The module name. If NULL we assume it's the default
1617 * R0 or RC module (@a fRing0OrRC). We'll attempt to
1618 * load the module if it isn't found in the module
1619 * list.
1620 * @param pszSearchPath The module search path. If NULL, search the
1621 * architecture dependent install directory.
1622 * @param pszSymPrefix What to prefix the symbols in the list with. The
1623 * idea is that you define a list that goes with an
1624 * interface (INTERFACE_SYM_LIST) and reuse it with
1625 * each implementation.
1626 * @param pszSymList The symbol list for the interface. This is a
1627 * semi-colon separated list of symbol base names. As
1628 * mentioned above, each is prefixed with @a
1629 * pszSymPrefix before resolving. There are a couple
1630 * of special symbol names that will cause us to skip
1631 * ahead a little bit:
1632 * - U8:whatever,
1633 * - U16:whatever,
1634 * - U32:whatever,
1635 * - U64:whatever,
1636 * - RCPTR:whatever,
1637 * - R3PTR:whatever,
1638 * - R0PTR:whatever,
1639 * - GCPHYS:whatever,
1640 * - HCPHYS:whatever.
1641 * @param fRing0 Set if it's a ring-0 context interface, clear if
1642 * it's raw-mode context interface.
1643 */
1644VMMR3_INT_DECL(int) PDMR3LdrGetInterfaceSymbols(PVM pVM, void *pvInterface, size_t cbInterface,
1645 const char *pszModule, const char *pszSearchPath,
1646 const char *pszSymPrefix, const char *pszSymList,
1647 bool fRing0)
1648{
1649 bool const fNullRun = !fRing0;
1650
1651 /*
1652 * Find the module.
1653 */
1654 int rc = VINF_SUCCESS;
1655 PPDMMOD pModule = NULL;
1656 if (!fNullRun)
1657 pModule = pdmR3LdrFindModule(pVM->pUVM,
1658 pszModule ? pszModule : fRing0 ? "VMMR0.r0" : "VMMRC.rc",
1659 fRing0 ? PDMMOD_TYPE_R0 : PDMMOD_TYPE_RC,
1660 true /*fLazy*/, pszSearchPath);
1661 if (pModule || fNullRun)
1662 {
1663 /* Prep the symbol name. */
1664 char szSymbol[256];
1665 size_t const cchSymPrefix = strlen(pszSymPrefix);
1666 AssertReturn(cchSymPrefix + 5 < sizeof(szSymbol), VERR_SYMBOL_NOT_FOUND);
1667 memcpy(szSymbol, pszSymPrefix, cchSymPrefix);
1668
1669 /*
1670 * Iterate the symbol list.
1671 */
1672 uint32_t offInterface = 0;
1673 const char *pszCur = pszSymList;
1674 while (pszCur)
1675 {
1676 /*
1677 * Find the end of the current symbol name.
1678 */
1679 size_t cchSym;
1680 const char *pszNext = strchr(pszCur, ';');
1681 if (pszNext)
1682 {
1683 cchSym = pszNext - pszCur;
1684 pszNext++;
1685 }
1686 else
1687 cchSym = strlen(pszCur);
1688 AssertBreakStmt(cchSym > 0, rc = VERR_INVALID_PARAMETER);
1689
1690 /* Is it a skip instruction? */
1691 const char *pszColon = (const char *)memchr(pszCur, ':', cchSym);
1692 if (pszColon)
1693 {
1694 /*
1695 * String switch on the instruction and execute it, checking
1696 * that we didn't overshoot the interface structure.
1697 */
1698#define IS_SKIP_INSTR(szInstr) \
1699 ( cchSkip == sizeof(szInstr) - 1 \
1700 && !memcmp(pszCur, szInstr, sizeof(szInstr) - 1) )
1701
1702 size_t const cchSkip = pszColon - pszCur;
1703 if (IS_SKIP_INSTR("U8"))
1704 offInterface += sizeof(uint8_t);
1705 else if (IS_SKIP_INSTR("U16"))
1706 offInterface += sizeof(uint16_t);
1707 else if (IS_SKIP_INSTR("U32"))
1708 offInterface += sizeof(uint32_t);
1709 else if (IS_SKIP_INSTR("U64"))
1710 offInterface += sizeof(uint64_t);
1711 else if (IS_SKIP_INSTR("RCPTR"))
1712 offInterface += sizeof(RTRCPTR);
1713 else if (IS_SKIP_INSTR("R3PTR"))
1714 offInterface += sizeof(RTR3PTR);
1715 else if (IS_SKIP_INSTR("R0PTR"))
1716 offInterface += sizeof(RTR0PTR);
1717 else if (IS_SKIP_INSTR("HCPHYS"))
1718 offInterface += sizeof(RTHCPHYS);
1719 else if (IS_SKIP_INSTR("GCPHYS"))
1720 offInterface += sizeof(RTGCPHYS);
1721 else
1722 AssertMsgFailedBreakStmt(("Invalid skip instruction %.*s (prefix=%s)\n", cchSym, pszCur, pszSymPrefix),
1723 rc = VERR_INVALID_PARAMETER);
1724 AssertMsgBreakStmt(offInterface <= cbInterface,
1725 ("off=%#x cb=%#x (sym=%.*s prefix=%s)\n", offInterface, cbInterface, cchSym, pszCur, pszSymPrefix),
1726 rc = VERR_BUFFER_OVERFLOW);
1727#undef IS_SKIP_INSTR
1728 }
1729 else
1730 {
1731 /*
1732 * Construct the symbol name, get its value, store it and
1733 * advance the interface cursor.
1734 */
1735 AssertReturn(cchSymPrefix + cchSym < sizeof(szSymbol), VERR_SYMBOL_NOT_FOUND);
1736 memcpy(&szSymbol[cchSymPrefix], pszCur, cchSym);
1737 szSymbol[cchSymPrefix + cchSym] = '\0';
1738
1739 if (fRing0)
1740 {
1741 void *pvValue = NULL;
1742 if (!fNullRun)
1743 {
1744 rc = SUPR3GetSymbolR0((void *)(RTR0PTR)pModule->ImageBase, szSymbol, &pvValue);
1745 AssertMsgRCBreak(rc, ("Couldn't find symbol '%s' in module '%s'\n", szSymbol, pModule->szName));
1746 }
1747
1748 PRTR0PTR pValue = (PRTR0PTR)((uintptr_t)pvInterface + offInterface);
1749 AssertMsgBreakStmt(offInterface + sizeof(*pValue) <= cbInterface,
1750 ("off=%#x cb=%#x sym=%s\n", offInterface, cbInterface, szSymbol),
1751 rc = VERR_BUFFER_OVERFLOW);
1752 *pValue = (RTR0PTR)pvValue;
1753 Assert((void *)*pValue == pvValue);
1754 offInterface += sizeof(*pValue);
1755 }
1756 else
1757 {
1758 RTUINTPTR Value = 0;
1759 if (!fNullRun)
1760 {
1761 rc = RTLdrGetSymbolEx(pModule->hLdrMod, pModule->pvBits, pModule->ImageBase, UINT32_MAX, szSymbol, &Value);
1762 AssertMsgRCBreak(rc, ("Couldn't find symbol '%s' in module '%s'\n", szSymbol, pModule->szName));
1763 }
1764
1765 PRTRCPTR pValue = (PRTRCPTR)((uintptr_t)pvInterface + offInterface);
1766 AssertMsgBreakStmt(offInterface + sizeof(*pValue) <= cbInterface,
1767 ("off=%#x cb=%#x sym=%s\n", offInterface, cbInterface, szSymbol),
1768 rc = VERR_BUFFER_OVERFLOW);
1769 *pValue = (RTRCPTR)Value;
1770 Assert(*pValue == Value);
1771 offInterface += sizeof(*pValue);
1772 }
1773 }
1774
1775 /* advance */
1776 pszCur = pszNext;
1777 }
1778
1779 }
1780 else
1781 rc = VERR_MODULE_NOT_FOUND;
1782 return rc;
1783}
1784
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