VirtualBox

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

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

VMM/PDMLdr: Don't try release .r0 objects till PDMR3TermUVM is called, then the VM structure + ring-0 object will be freed and VMMR0.r0 no longer in use. [order fix] bugref:9841

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