VirtualBox

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

Last change on this file since 50653 was 49039, checked in by vboxsync, 11 years ago

IPRT: Filename extension versus suffix cleanup, long overdue.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use