VirtualBox

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

Last change on this file since 80239 was 80191, checked in by vboxsync, 5 years ago

VMM/r3: Refactored VMCPU enumeration in preparation that aCpus will be replaced with a pointer array. Removed two raw-mode offset members from the CPUM and CPUMCPU sub-structures. bugref:9217 bugref:9517

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