VirtualBox

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

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

PDM,++: Change APIs used by Main from PVM to PUVM.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 60.3 KB
Line 
1/* $Id: PDMLdr.cpp 44351 2013-01-24 12:04:39Z 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/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 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 */
180VMMR3_INT_DECL(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 */
722VMMR3_INT_DECL(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 */
1361VMMR3_INT_DECL(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 */
1405VMMR3_INT_DECL(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 */
1554VMMR3_INT_DECL(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