VirtualBox

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

Last change on this file since 84044 was 82968, checked in by vboxsync, 4 years ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use