VirtualBox

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

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

Removed incorrect assertion (breaks VT-x)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 39.0 KB
Line 
1/* $Id: PDMLdr.cpp 5045 2007-09-26 11:41:28Z 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 as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * 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#if 0 /* breaks VT-x */
611 AssertReturn(!strcmp(pszName, VMMR0_MAIN_MODULE_NAME), VERR_INTERNAL_ERROR);
612#endif
613
614 /*
615 * Find the file if not specified.
616 */
617 char *pszFile = NULL;
618 if (!pszFilename)
619 pszFilename = pszFile = pdmR3FileR0(pszName);
620
621 /*
622 * Allocate the module list node.
623 */
624 PPDMMOD pModule = (PPDMMOD)RTMemAllocZ(sizeof(*pModule) + strlen(pszFilename));
625 if (!pModule)
626 {
627 RTMemTmpFree(pszFile);
628 return VERR_NO_MEMORY;
629 }
630 AssertMsg(strlen(pszName) + 1 < sizeof(pModule->szName),
631 ("pazName is too long (%d chars) max is %d chars.\n", strlen(pszName), sizeof(pModule->szName) - 1));
632 strcpy(pModule->szName, pszName);
633 pModule->eType = PDMMOD_TYPE_R0;
634 strcpy(pModule->szFilename, pszFilename);
635
636 /*
637 * Ask the support library to load it.
638 */
639 void *pvImageBase;
640 int rc = SUPLoadModule(pszFilename, pszName, &pvImageBase);
641 if (VBOX_SUCCESS(rc))
642 {
643 pModule->hLdrMod = NIL_RTLDRMOD;
644 pModule->ImageBase = (uintptr_t)pvImageBase;
645
646 /*
647 * Insert the module.
648 */
649 if (pVM->pdm.s.pModules)
650 {
651 /* we don't expect this list to be very long, so rather save the tail pointer. */
652 PPDMMOD pCur = pVM->pdm.s.pModules;
653 while (pCur->pNext)
654 pCur = pCur->pNext;
655 pCur->pNext = pModule;
656 }
657 else
658 pVM->pdm.s.pModules = pModule; /* (pNext is zeroed by alloc) */
659 Log(("PDM: GC Module at %VGvx %s (%s)\n", (RTGCPTR)pModule->ImageBase, pszName, pszFilename));
660 RTMemTmpFree(pszFile);
661 return VINF_SUCCESS;
662 }
663
664 RTMemFree(pModule);
665 RTMemTmpFree(pszFile);
666 LogRel(("pdmR3LoadR0: pszName=\"%s\" rc=%Vrc\n", pszName, rc));
667
668 /* Don't consider VERR_PDM_MODULE_NAME_CLASH and VERR_NO_MEMORY above as these are very unlikely. */
669 if (VBOX_FAILURE(rc))
670 return VMSetError(pVM, rc, RT_SRC_POS, N_("Cannot load R0 module %s"), pszFilename);
671 return rc;
672}
673
674
675
676/**
677 * Get the address of a symbol in a given HC ring 3 module.
678 *
679 * @returns VBox status code.
680 * @param pVM VM handle.
681 * @param pszModule Module name.
682 * @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
683 * ordinal value rather than a string pointer.
684 * @param ppvValue Where to store the symbol value.
685 */
686PDMR3DECL(int) PDMR3GetSymbolR3(PVM pVM, const char *pszModule, const char *pszSymbol, void **ppvValue)
687{
688 /*
689 * Validate input.
690 */
691 AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
692
693 /*
694 * Find the module.
695 */
696 for (PPDMMOD pModule = pVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
697 {
698 if ( pModule->eType == PDMMOD_TYPE_R3
699 && !strcmp(pModule->szName, pszModule))
700 {
701 RTUINTPTR Value = 0;
702 int rc = RTLdrGetSymbolEx(pModule->hLdrMod, pModule->pvBits, pModule->ImageBase, pszSymbol, &Value);
703 if (VBOX_SUCCESS(rc))
704 {
705 *ppvValue = (void *)(uintptr_t)Value;
706 Assert((uintptr_t)*ppvValue == Value);
707 }
708 else
709 {
710 if (pszSymbol < (const char*)(void*)0x10000)
711 AssertMsg(rc, ("Couldn't symbol '%u' in module '%s'\n", (unsigned)(uintptr_t)pszSymbol, pszModule));
712 else
713 AssertMsg(rc, ("Couldn't symbol '%s' in module '%s'\n", pszSymbol, pszModule));
714 }
715 return rc;
716 }
717 }
718
719 AssertMsgFailed(("Couldn't locate module '%s'\n", pszModule));
720 return VERR_SYMBOL_NOT_FOUND;
721}
722
723
724/**
725 * Get the address of a symbol in a given HC ring 0 module.
726 *
727 * @returns VBox status code.
728 * @param pVM VM handle.
729 * @param pszModule Module name. If NULL the main R0 module (VMMR0.r0) is assumes.
730 * @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
731 * ordinal value rather than a string pointer.
732 * @param ppvValue Where to store the symbol value.
733 */
734PDMR3DECL(int) PDMR3GetSymbolR0(PVM pVM, const char *pszModule, const char *pszSymbol, PRTR0PTR ppvValue)
735{
736#ifdef PDMLDR_FAKE_MODE
737 *ppvValue = 0xdeadbeef;
738 return VINF_SUCCESS;
739
740#else
741 /*
742 * Validate input.
743 */
744 AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
745 if (!pszModule)
746 pszModule = "VMMR0.r0";
747
748 /*
749 * Find the module.
750 */
751 for (PPDMMOD pModule = pVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
752 {
753 if ( pModule->eType == PDMMOD_TYPE_R0
754 && !strcmp(pModule->szName, pszModule))
755 {
756 int rc = SUPGetSymbolR0((void *)(uintptr_t)pModule->ImageBase, pszSymbol, (void **)ppvValue);
757 if (VBOX_FAILURE(rc))
758 {
759 AssertMsgRC(rc, ("Couldn't find symbol '%s' in module '%s'\n", pszSymbol, pszModule));
760 LogRel(("PDMGetSymbol: Couldn't find symbol '%s' in module '%s'\n", pszSymbol, pszModule));
761 }
762 return rc;
763 }
764 }
765
766 AssertMsgFailed(("Couldn't locate module '%s'\n", pszModule));
767 return VERR_SYMBOL_NOT_FOUND;
768#endif
769}
770
771
772/**
773 * Same as PDMR3GetSymbolR0 except that the module will be attempted loaded if not found.
774 *
775 * @returns VBox status code.
776 * @param pVM VM handle.
777 * @param pszModule Module name. If NULL the main R0 module (VMMR0.r0) is assumed.
778 * @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
779 * ordinal value rather than a string pointer.
780 * @param ppvValue Where to store the symbol value.
781 */
782PDMR3DECL(int) PDMR3GetSymbolR0Lazy(PVM pVM, const char *pszModule, const char *pszSymbol, PRTR0PTR ppvValue)
783{
784#ifdef PDMLDR_FAKE_MODE
785 *ppvValue = 0xdeadbeef;
786 return VINF_SUCCESS;
787
788#else
789 /*
790 * Since we're lazy, we'll only check if the module is present
791 * and hand it over to PDMR3GetSymbolR0 when that's done.
792 */
793 AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
794 if (pszModule)
795 {
796 AssertMsgReturn(!strpbrk(pszModule, "/\\:\n\r\t"), ("pszModule=%s\n", pszModule), VERR_INVALID_PARAMETER);
797 PPDMMOD pModule;
798 for (pModule = pVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
799 if ( pModule->eType == PDMMOD_TYPE_R0
800 && !strcmp(pModule->szName, pszModule))
801 break;
802 if (!pModule)
803 {
804 int rc = pdmR3LoadR0(pVM, NULL, pszModule);
805 AssertMsgRCReturn(rc, ("pszModule=%s rc=%Vrc\n", pszModule, rc), VERR_MODULE_NOT_FOUND);
806 }
807 }
808 return PDMR3GetSymbolR0(pVM, pszModule, pszSymbol, ppvValue);
809#endif
810}
811
812
813/**
814 * Get the address of a symbol in a given GC module.
815 *
816 * @returns VBox status code.
817 * @param pVM VM handle.
818 * @param pszModule Module name. If NULL the main R0 module (VMMGC.gc) is assumes.
819 * @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
820 * ordinal value rather than a string pointer.
821 * @param pGCPtrValue Where to store the symbol value.
822 */
823PDMR3DECL(int) PDMR3GetSymbolGC(PVM pVM, const char *pszModule, const char *pszSymbol, PRTGCPTR pGCPtrValue)
824{
825#ifdef PDMLDR_FAKE_MODE
826 *pGCPtrValue = 0xfeedf00d;
827 return VINF_SUCCESS;
828
829#else
830 /*
831 * Validate input.
832 */
833 AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
834 if (!pszModule)
835 pszModule = "VMMGC.gc";
836
837 /*
838 * Find the module.
839 */
840 for (PPDMMOD pModule = pVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
841 {
842 if ( pModule->eType == PDMMOD_TYPE_GC
843 && !strcmp(pModule->szName, pszModule))
844 {
845 RTUINTPTR Value;
846 int rc = RTLdrGetSymbolEx(pModule->hLdrMod, pModule->pvBits, pModule->ImageBase, pszSymbol, &Value);
847 if (VBOX_SUCCESS(rc))
848 {
849 *pGCPtrValue = (RTGCPTR)Value;
850 Assert(*pGCPtrValue == Value);
851 }
852 else
853 {
854 if (pszSymbol < (const char*)(void*)0x10000)
855 AssertMsg(rc, ("Couldn't symbol '%u' in module '%s'\n", (unsigned)(uintptr_t)pszSymbol, pszModule));
856 else
857 AssertMsg(rc, ("Couldn't symbol '%s' in module '%s'\n", pszSymbol, pszModule));
858 }
859 return rc;
860 }
861 }
862
863 AssertMsgFailed(("Couldn't locate module '%s'\n", pszModule));
864 return VERR_SYMBOL_NOT_FOUND;
865#endif
866}
867
868
869/**
870 * Same as PDMR3GetSymbolGC except that the module will be attempted loaded if not found.
871 *
872 * @returns VBox status code.
873 * @param pVM VM handle.
874 * @param pszModule Module name. If NULL the main R0 module (VMMGC.gc) is assumes.
875 * @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
876 * ordinal value rather than a string pointer.
877 * @param pGCPtrValue Where to store the symbol value.
878 */
879PDMR3DECL(int) PDMR3GetSymbolGCLazy(PVM pVM, const char *pszModule, const char *pszSymbol, PRTGCPTR pGCPtrValue)
880{
881#ifdef PDMLDR_FAKE_MODE
882 *pGCPtrValue = 0xfeedf00d;
883 return VINF_SUCCESS;
884
885#else
886 /*
887 * Since we're lazy, we'll only check if the module is present
888 * and hand it over to PDMR3GetSymbolGC when that's done.
889 */
890 AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
891 if (pszModule)
892 {
893 AssertMsgReturn(!strpbrk(pszModule, "/\\:\n\r\t"), ("pszModule=%s\n", pszModule), VERR_INVALID_PARAMETER);
894 PPDMMOD pModule;
895 for (pModule = pVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
896 if ( pModule->eType == PDMMOD_TYPE_GC
897 && !strcmp(pModule->szName, pszModule))
898 break;
899 if (!pModule)
900 {
901 char *pszFilename = pdmR3FileGC(pszModule);
902 AssertMsgReturn(pszFilename, ("pszModule=%s\n", pszModule), VERR_MODULE_NOT_FOUND);
903 int rc = PDMR3LoadGC(pVM, pszFilename, pszModule);
904 RTMemTmpFree(pszFilename);
905 AssertMsgRCReturn(rc, ("pszModule=%s rc=%Vrc\n", pszModule, rc), VERR_MODULE_NOT_FOUND);
906 }
907 }
908 return PDMR3GetSymbolGC(pVM, pszModule, pszSymbol, pGCPtrValue);
909#endif
910}
911
912
913/**
914 * Constructs the full filename for a R3 image file.
915 *
916 * @returns Pointer to temporary memory containing the filename.
917 * Caller must free this using RTMemTmpFree().
918 * @returns NULL on failure.
919 * @param pszFile File name (no path).
920 * @todo We'll have this elsewhere than in the root later!
921 */
922char *pdmR3FileR3(const char *pszFile, bool fShared)
923{
924 return pdmR3File(pszFile, NULL, fShared);
925}
926
927
928/**
929 * Constructs the full filename for a R0 image file.
930 *
931 * @returns Pointer to temporary memory containing the filename.
932 * Caller must free this using RTMemTmpFree().
933 * @returns NULL on failure.
934 * @param pszFile File name (no path).
935 * @todo We'll have this elsewhere than in the root later!
936 */
937char * pdmR3FileR0(const char *pszFile)
938{
939 return pdmR3File(pszFile, NULL, /*fShared=*/false);
940}
941
942
943/**
944 * Constructs the full filename for a GC image file.
945 *
946 * @returns Pointer to temporary memory containing the filename.
947 * Caller must free this using RTMemTmpFree().
948 * @returns NULL on failure.
949 * @param pszFile File name (no path).
950 * @todo We'll have this elsewhere than in the root later!
951 */
952char * pdmR3FileGC(const char *pszFile)
953{
954 return pdmR3File(pszFile, NULL, /*fShared=*/false);
955}
956
957
958/**
959 * Worker for pdmR3File().
960 *
961 * @returns Pointer to temporary memory containing the filename.
962 * Caller must free this using RTMemTmpFree().
963 * @returns NULL on failure.
964 * @param pszDir Directory part
965 * @param pszFile File name part
966 * @param pszDefaultExt Extension part
967 */
968static char * pdmR3FileConstruct(const char *pszDir, const char *pszFile, const char *pszDefaultExt)
969{
970 /*
971 * Allocate temp memory for return buffer.
972 */
973 unsigned cchDir = strlen(pszDir);
974 unsigned cchFile = strlen(pszFile);
975 unsigned cchDefaultExt;
976
977 /*
978 * Default extention?
979 */
980 if (!pszDefaultExt || strchr(pszFile, '.'))
981 cchDefaultExt = 0;
982 else
983 cchDefaultExt = strlen(pszDefaultExt);
984
985 unsigned cchPath = cchDir + 1 + cchFile + cchDefaultExt + 1;
986 if (cchPath > RTPATH_MAX)
987 {
988 AssertMsgFailed(("Path too long!\n"));
989 return NULL;
990 }
991
992 char *pszRet = (char *)RTMemTmpAlloc(cchDir + 1 + cchFile + cchDefaultExt + 1);
993 if (!pszRet)
994 {
995 AssertMsgFailed(("Out of temporary memory!\n"));
996 return NULL;
997 }
998
999 /*
1000 * Construct the filename.
1001 */
1002 memcpy(pszRet, pszDir, cchDir);
1003 pszRet[cchDir++] = '/'; /* this works everywhere */
1004 memcpy(pszRet + cchDir, pszFile, cchFile + 1);
1005 if (cchDefaultExt)
1006 memcpy(pszRet + cchDir + cchFile, pszDefaultExt, cchDefaultExt + 1);
1007
1008 return pszRet;
1009}
1010
1011
1012/**
1013 * Worker for pdmR3FileGC(), pdmR3FileR0() and pdmR3FileR3().
1014 *
1015 * @returns Pointer to temporary memory containing the filename.
1016 * Caller must free this using RTMemTmpFree().
1017 * @returns NULL on failure.
1018 * @param pszFile File name (no path).
1019 * @param pszDefaultExt The default extention, NULL if none.
1020 * @param fShared If true, search in the shared directory (/usr/lib on Unix), else
1021 * search in the private directory (/usr/lib/virtualbox on Unix).
1022 * Ignored if VBOX_PATH_SHARED_LIBS is not defined.
1023 * @todo We'll have this elsewhere than in the root later!
1024 * @todo Remove the fShared hack again once we don't need to link against VBoxDD anymore!
1025 */
1026static char * pdmR3File(const char *pszFile, const char *pszDefaultExt, bool fShared)
1027{
1028 char szPath[RTPATH_MAX];
1029 int rc;
1030
1031 rc = fShared ? RTPathSharedLibs(szPath, sizeof(szPath))
1032 : RTPathAppPrivateArch(szPath, sizeof(szPath));
1033 if (!VBOX_SUCCESS(rc))
1034 {
1035 AssertMsgFailed(("RTPathProgram(,%d) failed rc=%d!\n", sizeof(szPath), rc));
1036 return NULL;
1037 }
1038
1039 return pdmR3FileConstruct(szPath, pszFile, pszDefaultExt);
1040}
1041
1042
1043/** @internal */
1044typedef struct QMFEIPARG
1045{
1046 uint32_t uEIP;
1047
1048 char *pszNearSym1;
1049 unsigned cchNearSym1;
1050 RTINTPTR offNearSym1;
1051
1052 char *pszNearSym2;
1053 unsigned cchNearSym2;
1054 RTINTPTR offNearSym2;
1055} QMFEIPARG, *PQMFEIPARG;
1056
1057/**
1058 * Queries module information from an EIP.
1059 *
1060 * This is typically used to locate a crash address.
1061 *
1062 * @returns VBox status code.
1063 * @param pVM VM handle
1064 * @param uEIP EIP to locate.
1065 * @param pszModName Where to store the module name.
1066 * @param cchModName Size of the module name buffer.
1067 * @param pMod Base address of the module.
1068 * @param pszNearSym1 Name of the closes symbol from below.
1069 * @param cchNearSym1 Size of the buffer pointed to by pszNearSym1.
1070 * @param pNearSym1 The address of pszNearSym1.
1071 * @param pszNearSym2 Name of the closes symbol from below.
1072 * @param cchNearSym2 Size of the buffer pointed to by pszNearSym2.
1073 * @param pNearSym2 The address of pszNearSym2.
1074 */
1075PDMR3DECL(int) PDMR3QueryModFromEIP(PVM pVM, uint32_t uEIP,
1076 char *pszModName, unsigned cchModName, RTGCPTR *pMod,
1077 char *pszNearSym1, unsigned cchNearSym1, RTGCPTR *pNearSym1,
1078 char *pszNearSym2, unsigned cchNearSym2, RTGCPTR *pNearSym2)
1079{
1080 int rc = VERR_MODULE_NOT_FOUND;
1081 PPDMMOD pCur;
1082 for (pCur = pVM->pdm.s.pModules; pCur; pCur = pCur->pNext)
1083 {
1084 /* Skip anything which isn't in GC. */
1085 if (pCur->eType != PDMMOD_TYPE_GC)
1086 continue;
1087 if ((RTUINTPTR)uEIP - pCur->ImageBase < RTLdrSize(pCur->hLdrMod))
1088 {
1089 if (pMod)
1090 *pMod = pCur->ImageBase;
1091 if (pszModName && cchModName)
1092 {
1093 *pszModName = '\0';
1094 strncat(pszModName, pCur->szName, cchModName);
1095 }
1096 if (pNearSym1) *pNearSym1 = 0;
1097 if (pNearSym2) *pNearSym2 = 0;
1098 if (pszNearSym1) *pszNearSym1 = '\0';
1099 if (pszNearSym2) *pszNearSym2 = '\0';
1100
1101 /*
1102 * Locate the nearest symbols.
1103 */
1104 QMFEIPARG Args;
1105 Args.uEIP = uEIP;
1106 Args.pszNearSym1 = pszNearSym1;
1107 Args.cchNearSym1 = cchNearSym1;
1108 Args.offNearSym1 = INT_MIN; /** @todo fix INT_MIN/MAX! */
1109 Args.pszNearSym2 = pszNearSym2;
1110 Args.cchNearSym2 = cchNearSym2;
1111 Args.offNearSym2 = INT_MAX;
1112
1113 rc = RTLdrEnumSymbols(pCur->hLdrMod, RTLDR_ENUM_SYMBOL_FLAGS_ALL, pCur->pvBits, pCur->ImageBase,
1114 pdmR3QueryModFromEIPEnumSymbols, &Args);
1115 if (pNearSym1 && Args.offNearSym1 != INT_MIN)
1116 *pNearSym1 = Args.offNearSym1 + uEIP;
1117 if (pNearSym2 && Args.offNearSym2 != INT_MAX)
1118 *pNearSym2 = Args.offNearSym2 + uEIP;
1119
1120 rc = VINF_SUCCESS;
1121 if (pCur->eType == PDMMOD_TYPE_GC)
1122 break;
1123 }
1124
1125 }
1126 return rc;
1127}
1128
1129
1130/**
1131 * Enumeration callback function used by RTLdrEnumSymbols().
1132 *
1133 * @returns VBox status code. Failure will stop the enumeration.
1134 * @param hLdrMod The loader module handle.
1135 * @param pszSymbol Symbol name. NULL if ordinal only.
1136 * @param uSymbol Symbol ordinal, ~0 if not used.
1137 * @param Value Symbol value.
1138 * @param pvUser The user argument specified to RTLdrEnumSymbols().
1139 */
1140static DECLCALLBACK(int) pdmR3QueryModFromEIPEnumSymbols(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser)
1141{
1142 PQMFEIPARG pArgs = (PQMFEIPARG)pvUser;
1143
1144 RTINTPTR off = Value - pArgs->uEIP;
1145 if (off <= 0) /* near1 is before or at same location. */
1146 {
1147 if (off > pArgs->offNearSym1)
1148 {
1149 pArgs->offNearSym1 = off;
1150 if (pArgs->pszNearSym1 && pArgs->cchNearSym1)
1151 {
1152 *pArgs->pszNearSym1 = '\0';
1153 if (pszSymbol)
1154 strncat(pArgs->pszNearSym1, pszSymbol, pArgs->cchNearSym1);
1155 else
1156 {
1157 char szOrd[32];
1158 RTStrPrintf(szOrd, sizeof(szOrd), "#%#x", uSymbol);
1159 strncat(pArgs->pszNearSym1, szOrd, pArgs->cchNearSym1);
1160 }
1161 }
1162 }
1163 }
1164 else /* near2 is after */
1165 {
1166 if (off < pArgs->offNearSym2)
1167 {
1168 pArgs->offNearSym2 = off;
1169 if (pArgs->pszNearSym2 && pArgs->cchNearSym2)
1170 {
1171 *pArgs->pszNearSym2 = '\0';
1172 if (pszSymbol)
1173 strncat(pArgs->pszNearSym2, pszSymbol, pArgs->cchNearSym2);
1174 else
1175 {
1176 char szOrd[32];
1177 RTStrPrintf(szOrd, sizeof(szOrd), "#%#x", uSymbol);
1178 strncat(pArgs->pszNearSym2, szOrd, pArgs->cchNearSym2);
1179 }
1180 }
1181 }
1182 }
1183
1184 return VINF_SUCCESS;
1185}
1186
1187
1188/**
1189 * Enumerate all PDM modules.
1190 *
1191 * @returns VBox status.
1192 * @param pVM VM Handle.
1193 * @param pfnCallback Function to call back for each of the modules.
1194 * @param pvArg User argument.
1195 */
1196PDMR3DECL(int) PDMR3EnumModules(PVM pVM, PFNPDMR3ENUM pfnCallback, void *pvArg)
1197{
1198 PPDMMOD pCur;
1199 for (pCur = pVM->pdm.s.pModules; pCur; pCur = pCur->pNext)
1200 {
1201 int rc = pfnCallback(pVM,
1202 pCur->szFilename,
1203 pCur->szName,
1204 pCur->ImageBase,
1205 pCur->eType == PDMMOD_TYPE_GC ? RTLdrSize(pCur->hLdrMod) : 0,
1206 pCur->eType == PDMMOD_TYPE_GC);
1207 if (VBOX_FAILURE(rc))
1208 return rc;
1209 }
1210 return VINF_SUCCESS;
1211}
1212
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