VirtualBox

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

Last change on this file since 41466 was 41147, checked in by vboxsync, 13 years ago

SUPDrv,VMM: Tracepoints in raw-mode.

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