VirtualBox

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

Last change on this file since 45809 was 45809, checked in by vboxsync, 12 years ago

VMM,DevVGA: Don't resolve RC symbols when HM is enabled (part 2).

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