VirtualBox

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

Last change on this file since 80533 was 80533, checked in by vboxsync, 6 years ago

VMM,Devices: Some PDM device model refactoring. [doxyfix] bugref:9218

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