VirtualBox

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

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

VMM: More refactoring of GVM & VM structures for bugref:9217

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

© 2023 Oracle
ContactPrivacy policyTerms of Use