VirtualBox

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

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

TRPM: Save state directly to the CPUMCPU context member instead of putting on the stack. this avoid copying the state around before returning to host context to service an IRQ, or before using IEM.

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