VirtualBox

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

Last change on this file since 5999 was 5999, checked in by vboxsync, 17 years ago

The Giant CDDL Dual-License Header Change.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 39.0 KB
Line 
1/* $Id: PDMLdr.cpp 5999 2007-12-07 15:05:06Z vboxsync $ */
2/** @file
3 * PDM - Pluggable Device Manager, module loader.
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
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/pdm.h>
26#include <VBox/mm.h>
27#include <VBox/vmm.h>
28#include <VBox/vm.h>
29#include <VBox/sup.h>
30#include <VBox/param.h>
31#include <VBox/err.h>
32#include <VBox/hwaccm.h>
33
34#include <VBox/log.h>
35#include <iprt/assert.h>
36#include <iprt/alloc.h>
37#include <iprt/ldr.h>
38#include <iprt/path.h>
39#include <iprt/string.h>
40
41#include <limits.h>
42
43
44/*******************************************************************************
45* Structures and Typedefs *
46*******************************************************************************/
47/**
48 * Structure which the user argument of the RTLdrGetBits() callback points to.
49 * @internal
50 */
51typedef struct PDMGETIMPORTARGS
52{
53 PVM pVM;
54 PPDMMOD pModule;
55} PDMGETIMPORTARGS, *PPDMGETIMPORTARGS;
56
57
58/*******************************************************************************
59* Internal Functions *
60*******************************************************************************/
61static DECLCALLBACK(int) pdmr3GetImportGC(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol, unsigned uSymbol, RTUINTPTR *pValue, void *pvUser);
62static int pdmR3LoadR0(PVM pVM, const char *pszFilename, const char *pszName);
63static char * pdmR3FileGC(const char *pszFile);
64static char * pdmR3FileR0(const char *pszFile);
65static char * pdmR3File(const char *pszFile, const char *pszDefaultExt, bool fShared);
66static DECLCALLBACK(int) pdmR3QueryModFromEIPEnumSymbols(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser);
67
68
69
70/**
71 * Loads the VMMR0.r0 module before the VM is created.
72 *
73 * The opqaue VMMR0 module pointer is passed on to PDMR3Init later in
74 * the init process or PDMR3LdrUnloadVMMR0 in case of some init failure before PDMR3Init.
75 *
76 * @returns VBox status code.
77 * @param ppvOpaque Where to return the opaque VMMR0.r0 module handle one success.
78 *
79 * @remarks Yes, this is a kind of hacky and should go away. See @todo in VMR3Create.
80 */
81PDMR3DECL(int) PDMR3LdrLoadVMMR0(void **ppvOpaque)
82{
83 *ppvOpaque = NULL;
84
85 /*
86 * Resolve the filename and allocate the module list node.
87 */
88 char *pszFilename = pdmR3FileR0(VMMR0_MAIN_MODULE_NAME);
89 PPDMMOD pModule = (PPDMMOD)RTMemAllocZ(sizeof(*pModule) + strlen(pszFilename));
90 if (!pModule)
91 {
92 RTMemTmpFree(pszFilename);
93 return VERR_NO_MEMORY;
94 }
95 strcpy(pModule->szName, VMMR0_MAIN_MODULE_NAME);
96 pModule->eType = PDMMOD_TYPE_R0;
97 strcpy(pModule->szFilename, pszFilename);
98 RTMemTmpFree(pszFilename);
99
100 /*
101 * Ask the support library to load it.
102 */
103 void *pvImageBase;
104 int rc = SUPLoadModule(pModule->szFilename, pModule->szName, &pvImageBase);
105 if (RT_SUCCESS(rc))
106 {
107 pModule->hLdrMod = NIL_RTLDRMOD;
108 pModule->ImageBase = (uintptr_t)pvImageBase;
109 *ppvOpaque = pModule;
110
111 Log(("PDMR3LdrLoadVMMR0: Loaded %s at %VGvx (%s)\n", pModule->szName, (RTGCPTR)pModule->ImageBase, pModule->szFilename));
112 return VINF_SUCCESS;
113 }
114
115 LogRel(("PDMR3LdrLoadVMMR0: rc=%Vrc szName=%s szFilename=%s\n", rc, pModule->szName, pModule->szFilename));
116 RTMemFree(pModule);
117 return rc;
118}
119
120
121/**
122 * Register the VMMR0.r0 module with the created VM or unload it if
123 * we failed to create the VM (pVM == NULL).
124 *
125 * @param pVM The VM pointer. NULL if we failed to create the VM and
126 * the module should be unloaded and freed.
127 * @param pvOpaque The value returned by PDMR3LDrLoadVMMR0().
128 *
129 * @remarks Yes, this is a kind of hacky and should go away. See @todo in VMR3Create.
130 */
131PDMR3DECL(void) PDMR3LdrLoadVMMR0Part2(PVM pVM, void *pvOpaque)
132{
133 PPDMMOD pModule = (PPDMMOD)pvOpaque;
134 AssertPtrReturnVoid(pModule);
135
136 if (pVM)
137 {
138 /*
139 * Register the R0 module loaded by PDMR3LdrLoadVMMR0
140 */
141 Assert(!pVM->pdm.s.pModules);
142 pModule->pNext = pVM->pdm.s.pModules;
143 pVM->pdm.s.pModules = pModule;
144 }
145 else
146 {
147 /*
148 * Failed, unload the module.
149 */
150 int rc2 = SUPFreeModule((void *)(uintptr_t)pModule->ImageBase);
151 AssertRC(rc2);
152 pModule->ImageBase = 0;
153 RTMemFree(pvOpaque);
154 }
155}
156
157
158/**
159 * Init the module loader part of PDM.
160 *
161 * This routine will load the Host Context Ring-0 and Guest
162 * Context VMM modules.
163 *
164 * @returns VBox stutus code.
165 * @param pVM VM handle.
166 * @param pvVMMR0Mod The opqaue returned by PDMR3LdrLoadVMMR0.
167 */
168int pdmR3LdrInit(PVM pVM)
169{
170#ifdef PDMLDR_FAKE_MODE
171 return VINF_SUCCESS;
172
173#else
174
175 /*
176 * Load the mandatory GC module, the VMMR0.r0 is loaded before VM creation.
177 */
178 return PDMR3LoadGC(pVM, NULL, VMMGC_MAIN_MODULE_NAME);
179#endif
180}
181
182
183/**
184 * Terminate the module loader part of PDM.
185 *
186 * This will unload and free all modules.
187 *
188 * @param pVM The VM handle.
189 */
190void pdmR3LdrTerm(PVM pVM)
191{
192 /*
193 * Free the modules.
194 */
195 PPDMMOD pModule = pVM->pdm.s.pModules;
196 while (pModule)
197 {
198 /* free loader item. */
199 if (pModule->hLdrMod != NIL_RTLDRMOD)
200 {
201 int rc2 = RTLdrClose(pModule->hLdrMod);
202 AssertRC(rc2);
203 pModule->hLdrMod = NIL_RTLDRMOD;
204 }
205
206 /* free bits. */
207 switch (pModule->eType)
208 {
209 case PDMMOD_TYPE_R0:
210 {
211 Assert(pModule->ImageBase);
212 int rc2 = SUPFreeModule((void *)(uintptr_t)pModule->ImageBase);
213 AssertRC(rc2);
214 pModule->ImageBase = 0;
215 break;
216 }
217
218 case PDMMOD_TYPE_GC:
219 case PDMMOD_TYPE_R3:
220 /* MM will free this memory for us - it's alloc only memory. :-) */
221 break;
222
223 default:
224 AssertMsgFailed(("eType=%d\n", pModule->eType));
225 break;
226 }
227 pModule->pvBits = NULL;
228
229 void *pvFree = pModule;
230 pModule = pModule->pNext;
231 RTMemFree(pvFree);
232 }
233}
234
235
236/**
237 * Applies relocations to GC modules.
238 *
239 * This must be done very early in the relocation
240 * process so that components can resolve GC symbols during relocation.
241 *
242 * @param pVM VM handle.
243 * @param offDelta Relocation delta relative to old location.
244 */
245PDMR3DECL(void) PDMR3LdrRelocate(PVM pVM, RTGCINTPTR offDelta)
246{
247 LogFlow(("PDMR3LdrRelocate: offDelta=%VGv\n", offDelta));
248
249 /*
250 * GC Modules.
251 */
252 if (pVM->pdm.s.pModules)
253 {
254 /*
255 * The relocation have to be done in two passes so imports
256 * can be correctely resolved. The first pass will update
257 * the ImageBase saving the current value in OldImageBase.
258 * The second pass will do the actual relocation.
259 */
260 /* pass 1 */
261 PPDMMOD pCur;
262 for (pCur = pVM->pdm.s.pModules; pCur; pCur = pCur->pNext)
263 {
264 if (pCur->eType == PDMMOD_TYPE_GC)
265 {
266 pCur->OldImageBase = pCur->ImageBase;
267 pCur->ImageBase = MMHyperHC2GC(pVM, pCur->pvBits);
268 }
269 }
270
271 /* pass 2 */
272 for (pCur = pVM->pdm.s.pModules; pCur; pCur = pCur->pNext)
273 {
274 if (pCur->eType == PDMMOD_TYPE_GC)
275 {
276 PDMGETIMPORTARGS Args;
277 Args.pVM = pVM;
278 Args.pModule = pCur;
279 int rc = RTLdrRelocate(pCur->hLdrMod, pCur->pvBits, pCur->ImageBase, pCur->OldImageBase,
280 pdmr3GetImportGC, &Args);
281 AssertFatalMsgRC(rc, ("RTLdrRelocate failed, rc=%d\n", rc));
282 DBGFR3ModuleRelocate(pVM, pCur->OldImageBase, pCur->ImageBase, RTLdrSize(pCur->hLdrMod),
283 pCur->szFilename, pCur->szName);
284 }
285 }
286 }
287}
288
289
290/**
291 * Loads a module into the host context ring-3.
292 *
293 * This is used by the driver and device init functions to load modules
294 * containing the drivers and devices. The function can be extended to
295 * load modules which are not native to the environment we're running in,
296 * but at the moment this is not required.
297 *
298 * No reference counting is kept, since we don't implement any facilities
299 * for unloading the module. But the module will naturally be released
300 * when the VM terminates.
301 *
302 * @returns VBox status code.
303 * @param pVM The VM to load it into.
304 * @param pszFilename Filename of the module binary.
305 * @param pszName Module name. Case sensitive and the length is limited!
306 */
307int pdmR3LoadR3(PVM pVM, const char *pszFilename, const char *pszName)
308{
309 /*
310 * Validate input.
311 */
312 AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
313 Assert(pszFilename);
314 size_t cchFilename = strlen(pszFilename);
315 Assert(pszName);
316 size_t cchName = strlen(pszName);
317 PPDMMOD pCur;
318 if (cchName >= sizeof(pCur->szName))
319 {
320 AssertMsgFailed(("Name is too long, cchName=%d pszName='%s'\n", cchName, pszName));
321 return VERR_INVALID_PARAMETER;
322 }
323
324 /*
325 * Try lookup the name and see if the module exists.
326 */
327 for (pCur = pVM->pdm.s.pModules; pCur; pCur = pCur->pNext)
328 {
329 if (!strcmp(pCur->szName, pszName))
330 {
331 if (pCur->eType == PDMMOD_TYPE_R3)
332 return VINF_PDM_ALREADY_LOADED;
333 AssertMsgFailed(("We've already got a module '%s' loaded!\n", pszName));
334 return VERR_PDM_MODULE_NAME_CLASH;
335 }
336 }
337
338 /*
339 * Allocate the module list node and initialize it.
340 */
341 PPDMMOD pModule = (PPDMMOD)RTMemAllocZ(sizeof(*pModule) + cchFilename);
342 if (!pModule)
343 return VERR_NO_MEMORY;
344
345 pModule->eType = PDMMOD_TYPE_R3;
346 memcpy(pModule->szName, pszName, cchName); /* memory is zero'ed, no need to copy terminator :-) */
347 memcpy(pModule->szFilename, pszFilename, cchFilename);
348
349 /*
350 * Load the loader item.
351 */
352 int rc = RTLdrLoad(pszFilename, &pModule->hLdrMod);
353 if (VBOX_SUCCESS(rc))
354 {
355 pModule->pNext = pVM->pdm.s.pModules;
356 pVM->pdm.s.pModules = pModule;
357 return rc;
358 }
359
360 /* Something went wrong, most likely module not found. Don't consider other unlikely errors */
361 RTMemFree(pModule);
362 return VMSetError(pVM, rc, RT_SRC_POS, N_("Unable to load R3 module %s"), pszFilename);
363}
364
365
366/**
367 * Resolve an external symbol during RTLdrGetBits() of a GC module.
368 *
369 * @returns VBox status code.
370 * @param hLdrMod The loader module handle.
371 * @param pszModule Module name.
372 * @param pszSymbol Symbol name, NULL if uSymbol should be used.
373 * @param uSymbol Symbol ordinal, ~0 if pszSymbol should be used.
374 * @param pValue Where to store the symbol value (address).
375 * @param pvUser User argument.
376 */
377static DECLCALLBACK(int) pdmr3GetImportGC(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol, unsigned uSymbol, RTUINTPTR *pValue, void *pvUser)
378{
379 PVM pVM = ((PPDMGETIMPORTARGS)pvUser)->pVM;
380 PPDMMOD pModule = ((PPDMGETIMPORTARGS)pvUser)->pModule;
381
382 /*
383 * Adjust input.
384 */
385 if (pszModule && !*pszModule)
386 pszModule = NULL;
387
388 /*
389 * Builtin module.
390 */
391 if (!pszModule || !strcmp(pszModule, "VMMGCBuiltin.gc"))
392 {
393 int rc = VINF_SUCCESS;
394 if (!strcmp(pszSymbol, "g_VM"))
395 *pValue = pVM->pVMGC;
396 else if (!strcmp(pszSymbol, "g_CPUM"))
397 *pValue = VM_GUEST_ADDR(pVM, &pVM->cpum);
398 else if (!strcmp(pszSymbol, "g_TRPM"))
399 *pValue = VM_GUEST_ADDR(pVM, &pVM->trpm);
400 else if ( !strncmp(pszSymbol, "VMM", 3)
401 || !strcmp(pszSymbol, "g_Logger")
402 || !strcmp(pszSymbol, "g_RelLogger"))
403 {
404 RTGCPTR GCPtr = 0;
405 rc = VMMR3GetImportGC(pVM, pszSymbol, &GCPtr);
406 if (VBOX_SUCCESS(rc))
407 *pValue = GCPtr;
408 }
409 else if ( !strncmp(pszSymbol, "TM", 2)
410 || !strcmp(pszSymbol, "g_pSUPGlobalInfoPage"))
411 {
412 RTGCPTR GCPtr = 0;
413 rc = TMR3GetImportGC(pVM, pszSymbol, &GCPtr);
414 if (VBOX_SUCCESS(rc))
415 *pValue = GCPtr;
416 }
417 else
418 {
419 AssertMsg(!pszModule, ("Unknown builtin symbol '%s' for module '%s'!\n", pszSymbol, pModule->szName)); NOREF(pModule);
420 rc = VERR_SYMBOL_NOT_FOUND;
421 }
422 if (VBOX_SUCCESS(rc) || pszModule)
423 return rc;
424 }
425
426 /*
427 * Search for module.
428 */
429 PPDMMOD pCur = pVM->pdm.s.pModules;
430 while (pCur)
431 {
432 if ( pCur->eType == PDMMOD_TYPE_GC
433 && ( !pszModule
434 || !strcmp(pCur->szName, pszModule))
435 )
436 {
437 /* Search for the symbol. */
438 int rc = RTLdrGetSymbolEx(pCur->hLdrMod, pCur->pvBits, pCur->ImageBase, pszSymbol, pValue);
439 if (VBOX_SUCCESS(rc))
440 {
441 AssertMsg(*pValue - pCur->ImageBase < RTLdrSize(pCur->hLdrMod),
442 ("%VGv-%VGv %s %VGv\n", (RTGCPTR)pCur->ImageBase,
443 (RTGCPTR)(pCur->ImageBase + RTLdrSize(pCur->hLdrMod) - 1),
444 pszSymbol, (RTGCPTR)*pValue));
445 return rc;
446 }
447 if (pszModule)
448 {
449 AssertMsgFailed(("Couldn't find symbol '%s' in module '%s'!\n", pszSymbol, pszModule));
450 LogRel(("PDMLdr: Couldn't find symbol '%s' in module '%s'!\n", pszSymbol, pszModule));
451 return VERR_SYMBOL_NOT_FOUND;
452 }
453 }
454
455 /* next */
456 pCur = pCur->pNext;
457 }
458
459 AssertMsgFailed(("Couldn't find module '%s' for resolving symbol '%s'!\n", pszModule, pszSymbol));
460 return VERR_SYMBOL_NOT_FOUND;
461}
462
463
464/**
465 * Loads a module into the guest context (i.e. into the Hypervisor memory region).
466 *
467 * The external (to PDM) use of this interface is to load VMMGC.gc.
468 *
469 * @returns VBox status code.
470 * @param pVM The VM to load it into.
471 * @param pszFilename Filename of the module binary.
472 * @param pszName Module name. Case sensitive and the length is limited!
473 */
474PDMR3DECL(int) PDMR3LoadGC(PVM pVM, const char *pszFilename, const char *pszName)
475{
476 /*
477 * Validate input.
478 */
479 AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
480 PPDMMOD pCur = pVM->pdm.s.pModules;
481 while (pCur)
482 {
483 if (!strcmp(pCur->szName, pszName))
484 {
485 AssertMsgFailed(("We've already got a module '%s' loaded!\n", pszName));
486 return VERR_PDM_MODULE_NAME_CLASH;
487 }
488 /* next */
489 pCur = pCur->pNext;
490 }
491
492 /*
493 * Find the file if not specified.
494 */
495 char *pszFile = NULL;
496 if (!pszFilename)
497 pszFilename = pszFile = pdmR3FileGC(pszName);
498
499 /*
500 * Allocate the module list node.
501 */
502 PPDMMOD pModule = (PPDMMOD)RTMemAllocZ(sizeof(*pModule) + strlen(pszFilename));
503 if (!pModule)
504 {
505 RTMemTmpFree(pszFile);
506 return VERR_NO_MEMORY;
507 }
508 AssertMsg(strlen(pszName) + 1 < sizeof(pModule->szName),
509 ("pazName is too long (%d chars) max is %d chars.\n", strlen(pszName), sizeof(pModule->szName) - 1));
510 strcpy(pModule->szName, pszName);
511 pModule->eType = PDMMOD_TYPE_GC;
512 strcpy(pModule->szFilename, pszFilename);
513
514
515 /*
516 * Open the loader item.
517 */
518 int rc = RTLdrOpen(pszFilename, &pModule->hLdrMod);
519 if (VBOX_SUCCESS(rc))
520 {
521 /*
522 * Allocate space in the hypervisor.
523 */
524 size_t cb = RTLdrSize(pModule->hLdrMod);
525 cb = RT_ALIGN_Z(cb, PAGE_SIZE);
526 rc = SUPPageAlloc(cb >> PAGE_SHIFT, &pModule->pvBits);
527 if (VBOX_SUCCESS(rc))
528 {
529 RTGCPTR GCPtr;
530 rc = MMR3HyperMapHCRam(pVM, pModule->pvBits, cb, true, pModule->szName, &GCPtr);
531 if (VBOX_SUCCESS(rc))
532 {
533 MMR3HyperReserve(pVM, PAGE_SIZE, "fence", NULL);
534
535 /*
536 * Get relocated image bits.
537 */
538 Assert(MMHyperHC2GC(pVM, pModule->pvBits) == GCPtr);
539 pModule->ImageBase = GCPtr;
540 PDMGETIMPORTARGS Args;
541 Args.pVM = pVM;
542 Args.pModule = pModule;
543 rc = RTLdrGetBits(pModule->hLdrMod, pModule->pvBits, pModule->ImageBase, pdmr3GetImportGC, &Args);
544 if (VBOX_SUCCESS(rc))
545 {
546 /*
547 * Insert the module.
548 */
549 if (pVM->pdm.s.pModules)
550 {
551 /* we don't expect this list to be very long, so rather save the tail pointer. */
552 PPDMMOD pCur = pVM->pdm.s.pModules;
553 while (pCur->pNext)
554 pCur = pCur->pNext;
555 pCur->pNext = pModule;
556 }
557 else
558 pVM->pdm.s.pModules = pModule; /* (pNext is zeroed by alloc) */
559 Log(("PDM: GC Module at %VGvx %s (%s)\n", (RTGCPTR)pModule->ImageBase, pszName, pszFilename));
560 RTMemTmpFree(pszFile);
561 return VINF_SUCCESS;
562 }
563 }
564 else
565 {
566 AssertRC(rc);
567 SUPPageFree(pModule->pvBits, cb >> PAGE_SHIFT);
568 }
569 }
570 else
571 AssertMsgFailed(("SUPPageAlloc(%d,) -> %Vrc\n", cb >> PAGE_SHIFT, rc));
572 int rc2 = RTLdrClose(pModule->hLdrMod);
573 AssertRC(rc2);
574 }
575 RTMemFree(pModule);
576 RTMemTmpFree(pszFile);
577
578 /* Don't consider VERR_PDM_MODULE_NAME_CLASH and VERR_NO_MEMORY above as these are very unlikely. */
579 if (VBOX_FAILURE(rc))
580 return VMSetError(pVM, rc, RT_SRC_POS, N_("Cannot load GC module %s"), pszFilename);
581 return rc;
582}
583
584
585/**
586 * Loads a module into the ring-0 context.
587 *
588 * @returns VBox status code.
589 * @param pVM The VM to load it into.
590 * @param pszFilename Filename of the module binary.
591 * @param pszName Module name. Case sensitive and the length is limited!
592 */
593static int pdmR3LoadR0(PVM pVM, const char *pszFilename, const char *pszName)
594{
595 /*
596 * Validate input.
597 */
598 AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
599 PPDMMOD pCur = pVM->pdm.s.pModules;
600 while (pCur)
601 {
602 if (!strcmp(pCur->szName, pszName))
603 {
604 AssertMsgFailed(("We've already got a module '%s' loaded!\n", pszName));
605 return VERR_PDM_MODULE_NAME_CLASH;
606 }
607 /* next */
608 pCur = pCur->pNext;
609 }
610 AssertReturn(strcmp(pszName, VMMR0_MAIN_MODULE_NAME), VERR_INTERNAL_ERROR);
611
612 /*
613 * Find the file if not specified.
614 */
615 char *pszFile = NULL;
616 if (!pszFilename)
617 pszFilename = pszFile = pdmR3FileR0(pszName);
618
619 /*
620 * Allocate the module list node.
621 */
622 PPDMMOD pModule = (PPDMMOD)RTMemAllocZ(sizeof(*pModule) + strlen(pszFilename));
623 if (!pModule)
624 {
625 RTMemTmpFree(pszFile);
626 return VERR_NO_MEMORY;
627 }
628 AssertMsg(strlen(pszName) + 1 < sizeof(pModule->szName),
629 ("pazName is too long (%d chars) max is %d chars.\n", strlen(pszName), sizeof(pModule->szName) - 1));
630 strcpy(pModule->szName, pszName);
631 pModule->eType = PDMMOD_TYPE_R0;
632 strcpy(pModule->szFilename, pszFilename);
633
634 /*
635 * Ask the support library to load it.
636 */
637 void *pvImageBase;
638 int rc = SUPLoadModule(pszFilename, pszName, &pvImageBase);
639 if (VBOX_SUCCESS(rc))
640 {
641 pModule->hLdrMod = NIL_RTLDRMOD;
642 pModule->ImageBase = (uintptr_t)pvImageBase;
643
644 /*
645 * Insert the module.
646 */
647 if (pVM->pdm.s.pModules)
648 {
649 /* we don't expect this list to be very long, so rather save the tail pointer. */
650 PPDMMOD pCur = pVM->pdm.s.pModules;
651 while (pCur->pNext)
652 pCur = pCur->pNext;
653 pCur->pNext = pModule;
654 }
655 else
656 pVM->pdm.s.pModules = pModule; /* (pNext is zeroed by alloc) */
657 Log(("PDM: GC Module at %VGvx %s (%s)\n", (RTGCPTR)pModule->ImageBase, pszName, pszFilename));
658 RTMemTmpFree(pszFile);
659 return VINF_SUCCESS;
660 }
661
662 RTMemFree(pModule);
663 RTMemTmpFree(pszFile);
664 LogRel(("pdmR3LoadR0: pszName=\"%s\" rc=%Vrc\n", pszName, rc));
665
666 /* Don't consider VERR_PDM_MODULE_NAME_CLASH and VERR_NO_MEMORY above as these are very unlikely. */
667 if (VBOX_FAILURE(rc))
668 return VMSetError(pVM, rc, RT_SRC_POS, N_("Cannot load R0 module %s"), pszFilename);
669 return rc;
670}
671
672
673
674/**
675 * Get the address of a symbol in a given HC ring 3 module.
676 *
677 * @returns VBox status code.
678 * @param pVM VM handle.
679 * @param pszModule Module name.
680 * @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
681 * ordinal value rather than a string pointer.
682 * @param ppvValue Where to store the symbol value.
683 */
684PDMR3DECL(int) PDMR3GetSymbolR3(PVM pVM, const char *pszModule, const char *pszSymbol, void **ppvValue)
685{
686 /*
687 * Validate input.
688 */
689 AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
690
691 /*
692 * Find the module.
693 */
694 for (PPDMMOD pModule = pVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
695 {
696 if ( pModule->eType == PDMMOD_TYPE_R3
697 && !strcmp(pModule->szName, pszModule))
698 {
699 RTUINTPTR Value = 0;
700 int rc = RTLdrGetSymbolEx(pModule->hLdrMod, pModule->pvBits, pModule->ImageBase, pszSymbol, &Value);
701 if (VBOX_SUCCESS(rc))
702 {
703 *ppvValue = (void *)(uintptr_t)Value;
704 Assert((uintptr_t)*ppvValue == Value);
705 }
706 else
707 {
708 if (pszSymbol < (const char*)(void*)0x10000)
709 AssertMsg(rc, ("Couldn't symbol '%u' in module '%s'\n", (unsigned)(uintptr_t)pszSymbol, pszModule));
710 else
711 AssertMsg(rc, ("Couldn't symbol '%s' in module '%s'\n", pszSymbol, pszModule));
712 }
713 return rc;
714 }
715 }
716
717 AssertMsgFailed(("Couldn't locate module '%s'\n", pszModule));
718 return VERR_SYMBOL_NOT_FOUND;
719}
720
721
722/**
723 * Get the address of a symbol in a given HC ring 0 module.
724 *
725 * @returns VBox status code.
726 * @param pVM VM handle.
727 * @param pszModule Module name. If NULL the main R0 module (VMMR0.r0) is assumes.
728 * @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
729 * ordinal value rather than a string pointer.
730 * @param ppvValue Where to store the symbol value.
731 */
732PDMR3DECL(int) PDMR3GetSymbolR0(PVM pVM, const char *pszModule, const char *pszSymbol, PRTR0PTR ppvValue)
733{
734#ifdef PDMLDR_FAKE_MODE
735 *ppvValue = 0xdeadbeef;
736 return VINF_SUCCESS;
737
738#else
739 /*
740 * Validate input.
741 */
742 AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
743 if (!pszModule)
744 pszModule = "VMMR0.r0";
745
746 /*
747 * Find the module.
748 */
749 for (PPDMMOD pModule = pVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
750 {
751 if ( pModule->eType == PDMMOD_TYPE_R0
752 && !strcmp(pModule->szName, pszModule))
753 {
754 int rc = SUPGetSymbolR0((void *)(uintptr_t)pModule->ImageBase, pszSymbol, (void **)ppvValue);
755 if (VBOX_FAILURE(rc))
756 {
757 AssertMsgRC(rc, ("Couldn't find symbol '%s' in module '%s'\n", pszSymbol, pszModule));
758 LogRel(("PDMGetSymbol: Couldn't find symbol '%s' in module '%s'\n", pszSymbol, pszModule));
759 }
760 return rc;
761 }
762 }
763
764 AssertMsgFailed(("Couldn't locate module '%s'\n", pszModule));
765 return VERR_SYMBOL_NOT_FOUND;
766#endif
767}
768
769
770/**
771 * Same as PDMR3GetSymbolR0 except that the module will be attempted loaded if not found.
772 *
773 * @returns VBox status code.
774 * @param pVM VM handle.
775 * @param pszModule Module name. If NULL the main R0 module (VMMR0.r0) is assumed.
776 * @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
777 * ordinal value rather than a string pointer.
778 * @param ppvValue Where to store the symbol value.
779 */
780PDMR3DECL(int) PDMR3GetSymbolR0Lazy(PVM pVM, const char *pszModule, const char *pszSymbol, PRTR0PTR ppvValue)
781{
782#ifdef PDMLDR_FAKE_MODE
783 *ppvValue = 0xdeadbeef;
784 return VINF_SUCCESS;
785
786#else
787 /*
788 * Since we're lazy, we'll only check if the module is present
789 * and hand it over to PDMR3GetSymbolR0 when that's done.
790 */
791 AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
792 if (pszModule)
793 {
794 AssertMsgReturn(!strpbrk(pszModule, "/\\:\n\r\t"), ("pszModule=%s\n", pszModule), VERR_INVALID_PARAMETER);
795 PPDMMOD pModule;
796 for (pModule = pVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
797 if ( pModule->eType == PDMMOD_TYPE_R0
798 && !strcmp(pModule->szName, pszModule))
799 break;
800 if (!pModule)
801 {
802 int rc = pdmR3LoadR0(pVM, NULL, pszModule);
803 AssertMsgRCReturn(rc, ("pszModule=%s rc=%Vrc\n", pszModule, rc), VERR_MODULE_NOT_FOUND);
804 }
805 }
806 return PDMR3GetSymbolR0(pVM, pszModule, pszSymbol, ppvValue);
807#endif
808}
809
810
811/**
812 * Get the address of a symbol in a given GC module.
813 *
814 * @returns VBox status code.
815 * @param pVM VM handle.
816 * @param pszModule Module name. If NULL the main R0 module (VMMGC.gc) is assumes.
817 * @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
818 * ordinal value rather than a string pointer.
819 * @param pGCPtrValue Where to store the symbol value.
820 */
821PDMR3DECL(int) PDMR3GetSymbolGC(PVM pVM, const char *pszModule, const char *pszSymbol, PRTGCPTR pGCPtrValue)
822{
823#ifdef PDMLDR_FAKE_MODE
824 *pGCPtrValue = 0xfeedf00d;
825 return VINF_SUCCESS;
826
827#else
828 /*
829 * Validate input.
830 */
831 AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
832 if (!pszModule)
833 pszModule = "VMMGC.gc";
834
835 /*
836 * Find the module.
837 */
838 for (PPDMMOD pModule = pVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
839 {
840 if ( pModule->eType == PDMMOD_TYPE_GC
841 && !strcmp(pModule->szName, pszModule))
842 {
843 RTUINTPTR Value;
844 int rc = RTLdrGetSymbolEx(pModule->hLdrMod, pModule->pvBits, pModule->ImageBase, pszSymbol, &Value);
845 if (VBOX_SUCCESS(rc))
846 {
847 *pGCPtrValue = (RTGCPTR)Value;
848 Assert(*pGCPtrValue == Value);
849 }
850 else
851 {
852 if (pszSymbol < (const char*)(void*)0x10000)
853 AssertMsg(rc, ("Couldn't symbol '%u' in module '%s'\n", (unsigned)(uintptr_t)pszSymbol, pszModule));
854 else
855 AssertMsg(rc, ("Couldn't symbol '%s' in module '%s'\n", pszSymbol, pszModule));
856 }
857 return rc;
858 }
859 }
860
861 AssertMsgFailed(("Couldn't locate module '%s'\n", pszModule));
862 return VERR_SYMBOL_NOT_FOUND;
863#endif
864}
865
866
867/**
868 * Same as PDMR3GetSymbolGC except that the module will be attempted loaded if not found.
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 pGCPtrValue Where to store the symbol value.
876 */
877PDMR3DECL(int) PDMR3GetSymbolGCLazy(PVM pVM, const char *pszModule, const char *pszSymbol, PRTGCPTR pGCPtrValue)
878{
879#ifdef PDMLDR_FAKE_MODE
880 *pGCPtrValue = 0xfeedf00d;
881 return VINF_SUCCESS;
882
883#else
884 /*
885 * Since we're lazy, we'll only check if the module is present
886 * and hand it over to PDMR3GetSymbolGC when that's done.
887 */
888 AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
889 if (pszModule)
890 {
891 AssertMsgReturn(!strpbrk(pszModule, "/\\:\n\r\t"), ("pszModule=%s\n", pszModule), VERR_INVALID_PARAMETER);
892 PPDMMOD pModule;
893 for (pModule = pVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
894 if ( pModule->eType == PDMMOD_TYPE_GC
895 && !strcmp(pModule->szName, pszModule))
896 break;
897 if (!pModule)
898 {
899 char *pszFilename = pdmR3FileGC(pszModule);
900 AssertMsgReturn(pszFilename, ("pszModule=%s\n", pszModule), VERR_MODULE_NOT_FOUND);
901 int rc = PDMR3LoadGC(pVM, pszFilename, pszModule);
902 RTMemTmpFree(pszFilename);
903 AssertMsgRCReturn(rc, ("pszModule=%s rc=%Vrc\n", pszModule, rc), VERR_MODULE_NOT_FOUND);
904 }
905 }
906 return PDMR3GetSymbolGC(pVM, pszModule, pszSymbol, pGCPtrValue);
907#endif
908}
909
910
911/**
912 * Constructs the full filename for a R3 image file.
913 *
914 * @returns Pointer to temporary memory containing the filename.
915 * Caller must free this using RTMemTmpFree().
916 * @returns NULL on failure.
917 * @param pszFile File name (no path).
918 * @todo We'll have this elsewhere than in the root later!
919 */
920char *pdmR3FileR3(const char *pszFile, bool fShared)
921{
922 return pdmR3File(pszFile, NULL, fShared);
923}
924
925
926/**
927 * Constructs the full filename for a R0 image file.
928 *
929 * @returns Pointer to temporary memory containing the filename.
930 * Caller must free this using RTMemTmpFree().
931 * @returns NULL on failure.
932 * @param pszFile File name (no path).
933 * @todo We'll have this elsewhere than in the root later!
934 */
935char * pdmR3FileR0(const char *pszFile)
936{
937 return pdmR3File(pszFile, NULL, /*fShared=*/false);
938}
939
940
941/**
942 * Constructs the full filename for a GC image file.
943 *
944 * @returns Pointer to temporary memory containing the filename.
945 * Caller must free this using RTMemTmpFree().
946 * @returns NULL on failure.
947 * @param pszFile File name (no path).
948 * @todo We'll have this elsewhere than in the root later!
949 */
950char * pdmR3FileGC(const char *pszFile)
951{
952 return pdmR3File(pszFile, NULL, /*fShared=*/false);
953}
954
955
956/**
957 * Worker for pdmR3File().
958 *
959 * @returns Pointer to temporary memory containing the filename.
960 * Caller must free this using RTMemTmpFree().
961 * @returns NULL on failure.
962 * @param pszDir Directory part
963 * @param pszFile File name part
964 * @param pszDefaultExt Extension part
965 */
966static char * pdmR3FileConstruct(const char *pszDir, const char *pszFile, const char *pszDefaultExt)
967{
968 /*
969 * Allocate temp memory for return buffer.
970 */
971 unsigned cchDir = strlen(pszDir);
972 unsigned cchFile = strlen(pszFile);
973 unsigned cchDefaultExt;
974
975 /*
976 * Default extention?
977 */
978 if (!pszDefaultExt || strchr(pszFile, '.'))
979 cchDefaultExt = 0;
980 else
981 cchDefaultExt = strlen(pszDefaultExt);
982
983 unsigned cchPath = cchDir + 1 + cchFile + cchDefaultExt + 1;
984 if (cchPath > RTPATH_MAX)
985 {
986 AssertMsgFailed(("Path too long!\n"));
987 return NULL;
988 }
989
990 char *pszRet = (char *)RTMemTmpAlloc(cchDir + 1 + cchFile + cchDefaultExt + 1);
991 if (!pszRet)
992 {
993 AssertMsgFailed(("Out of temporary memory!\n"));
994 return NULL;
995 }
996
997 /*
998 * Construct the filename.
999 */
1000 memcpy(pszRet, pszDir, cchDir);
1001 pszRet[cchDir++] = '/'; /* this works everywhere */
1002 memcpy(pszRet + cchDir, pszFile, cchFile + 1);
1003 if (cchDefaultExt)
1004 memcpy(pszRet + cchDir + cchFile, pszDefaultExt, cchDefaultExt + 1);
1005
1006 return pszRet;
1007}
1008
1009
1010/**
1011 * Worker for pdmR3FileGC(), pdmR3FileR0() and pdmR3FileR3().
1012 *
1013 * @returns Pointer to temporary memory containing the filename.
1014 * Caller must free this using RTMemTmpFree().
1015 * @returns NULL on failure.
1016 * @param pszFile File name (no path).
1017 * @param pszDefaultExt The default extention, NULL if none.
1018 * @param fShared If true, search in the shared directory (/usr/lib on Unix), else
1019 * search in the private directory (/usr/lib/virtualbox on Unix).
1020 * Ignored if VBOX_PATH_SHARED_LIBS is not defined.
1021 * @todo We'll have this elsewhere than in the root later!
1022 * @todo Remove the fShared hack again once we don't need to link against VBoxDD anymore!
1023 */
1024static char * pdmR3File(const char *pszFile, const char *pszDefaultExt, bool fShared)
1025{
1026 char szPath[RTPATH_MAX];
1027 int rc;
1028
1029 rc = fShared ? RTPathSharedLibs(szPath, sizeof(szPath))
1030 : RTPathAppPrivateArch(szPath, sizeof(szPath));
1031 if (!VBOX_SUCCESS(rc))
1032 {
1033 AssertMsgFailed(("RTPathProgram(,%d) failed rc=%d!\n", sizeof(szPath), rc));
1034 return NULL;
1035 }
1036
1037 return pdmR3FileConstruct(szPath, pszFile, pszDefaultExt);
1038}
1039
1040
1041/** @internal */
1042typedef struct QMFEIPARG
1043{
1044 uint32_t uEIP;
1045
1046 char *pszNearSym1;
1047 unsigned cchNearSym1;
1048 RTINTPTR offNearSym1;
1049
1050 char *pszNearSym2;
1051 unsigned cchNearSym2;
1052 RTINTPTR offNearSym2;
1053} QMFEIPARG, *PQMFEIPARG;
1054
1055/**
1056 * Queries module information from an EIP.
1057 *
1058 * This is typically used to locate a crash address.
1059 *
1060 * @returns VBox status code.
1061 * @param pVM VM handle
1062 * @param uEIP EIP to locate.
1063 * @param pszModName Where to store the module name.
1064 * @param cchModName Size of the module name buffer.
1065 * @param pMod Base address of the module.
1066 * @param pszNearSym1 Name of the closes symbol from below.
1067 * @param cchNearSym1 Size of the buffer pointed to by pszNearSym1.
1068 * @param pNearSym1 The address of pszNearSym1.
1069 * @param pszNearSym2 Name of the closes symbol from below.
1070 * @param cchNearSym2 Size of the buffer pointed to by pszNearSym2.
1071 * @param pNearSym2 The address of pszNearSym2.
1072 */
1073PDMR3DECL(int) PDMR3QueryModFromEIP(PVM pVM, uint32_t uEIP,
1074 char *pszModName, unsigned cchModName, RTGCPTR *pMod,
1075 char *pszNearSym1, unsigned cchNearSym1, RTGCPTR *pNearSym1,
1076 char *pszNearSym2, unsigned cchNearSym2, RTGCPTR *pNearSym2)
1077{
1078 int rc = VERR_MODULE_NOT_FOUND;
1079 PPDMMOD pCur;
1080 for (pCur = pVM->pdm.s.pModules; pCur; pCur = pCur->pNext)
1081 {
1082 /* Skip anything which isn't in GC. */
1083 if (pCur->eType != PDMMOD_TYPE_GC)
1084 continue;
1085 if ((RTUINTPTR)uEIP - pCur->ImageBase < RTLdrSize(pCur->hLdrMod))
1086 {
1087 if (pMod)
1088 *pMod = pCur->ImageBase;
1089 if (pszModName && cchModName)
1090 {
1091 *pszModName = '\0';
1092 strncat(pszModName, pCur->szName, cchModName);
1093 }
1094 if (pNearSym1) *pNearSym1 = 0;
1095 if (pNearSym2) *pNearSym2 = 0;
1096 if (pszNearSym1) *pszNearSym1 = '\0';
1097 if (pszNearSym2) *pszNearSym2 = '\0';
1098
1099 /*
1100 * Locate the nearest symbols.
1101 */
1102 QMFEIPARG Args;
1103 Args.uEIP = uEIP;
1104 Args.pszNearSym1 = pszNearSym1;
1105 Args.cchNearSym1 = cchNearSym1;
1106 Args.offNearSym1 = INT_MIN; /** @todo fix INT_MIN/MAX! */
1107 Args.pszNearSym2 = pszNearSym2;
1108 Args.cchNearSym2 = cchNearSym2;
1109 Args.offNearSym2 = INT_MAX;
1110
1111 rc = RTLdrEnumSymbols(pCur->hLdrMod, RTLDR_ENUM_SYMBOL_FLAGS_ALL, pCur->pvBits, pCur->ImageBase,
1112 pdmR3QueryModFromEIPEnumSymbols, &Args);
1113 if (pNearSym1 && Args.offNearSym1 != INT_MIN)
1114 *pNearSym1 = Args.offNearSym1 + uEIP;
1115 if (pNearSym2 && Args.offNearSym2 != INT_MAX)
1116 *pNearSym2 = Args.offNearSym2 + uEIP;
1117
1118 rc = VINF_SUCCESS;
1119 if (pCur->eType == PDMMOD_TYPE_GC)
1120 break;
1121 }
1122
1123 }
1124 return rc;
1125}
1126
1127
1128/**
1129 * Enumeration callback function used by RTLdrEnumSymbols().
1130 *
1131 * @returns VBox status code. Failure will stop the enumeration.
1132 * @param hLdrMod The loader module handle.
1133 * @param pszSymbol Symbol name. NULL if ordinal only.
1134 * @param uSymbol Symbol ordinal, ~0 if not used.
1135 * @param Value Symbol value.
1136 * @param pvUser The user argument specified to RTLdrEnumSymbols().
1137 */
1138static DECLCALLBACK(int) pdmR3QueryModFromEIPEnumSymbols(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser)
1139{
1140 PQMFEIPARG pArgs = (PQMFEIPARG)pvUser;
1141
1142 RTINTPTR off = Value - pArgs->uEIP;
1143 if (off <= 0) /* near1 is before or at same location. */
1144 {
1145 if (off > pArgs->offNearSym1)
1146 {
1147 pArgs->offNearSym1 = off;
1148 if (pArgs->pszNearSym1 && pArgs->cchNearSym1)
1149 {
1150 *pArgs->pszNearSym1 = '\0';
1151 if (pszSymbol)
1152 strncat(pArgs->pszNearSym1, pszSymbol, pArgs->cchNearSym1);
1153 else
1154 {
1155 char szOrd[32];
1156 RTStrPrintf(szOrd, sizeof(szOrd), "#%#x", uSymbol);
1157 strncat(pArgs->pszNearSym1, szOrd, pArgs->cchNearSym1);
1158 }
1159 }
1160 }
1161 }
1162 else /* near2 is after */
1163 {
1164 if (off < pArgs->offNearSym2)
1165 {
1166 pArgs->offNearSym2 = off;
1167 if (pArgs->pszNearSym2 && pArgs->cchNearSym2)
1168 {
1169 *pArgs->pszNearSym2 = '\0';
1170 if (pszSymbol)
1171 strncat(pArgs->pszNearSym2, pszSymbol, pArgs->cchNearSym2);
1172 else
1173 {
1174 char szOrd[32];
1175 RTStrPrintf(szOrd, sizeof(szOrd), "#%#x", uSymbol);
1176 strncat(pArgs->pszNearSym2, szOrd, pArgs->cchNearSym2);
1177 }
1178 }
1179 }
1180 }
1181
1182 return VINF_SUCCESS;
1183}
1184
1185
1186/**
1187 * Enumerate all PDM modules.
1188 *
1189 * @returns VBox status.
1190 * @param pVM VM Handle.
1191 * @param pfnCallback Function to call back for each of the modules.
1192 * @param pvArg User argument.
1193 */
1194PDMR3DECL(int) PDMR3EnumModules(PVM pVM, PFNPDMR3ENUM pfnCallback, void *pvArg)
1195{
1196 PPDMMOD pCur;
1197 for (pCur = pVM->pdm.s.pModules; pCur; pCur = pCur->pNext)
1198 {
1199 int rc = pfnCallback(pVM,
1200 pCur->szFilename,
1201 pCur->szName,
1202 pCur->ImageBase,
1203 pCur->eType == PDMMOD_TYPE_GC ? RTLdrSize(pCur->hLdrMod) : 0,
1204 pCur->eType == PDMMOD_TYPE_GC);
1205 if (VBOX_FAILURE(rc))
1206 return rc;
1207 }
1208 return VINF_SUCCESS;
1209}
1210
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