VirtualBox

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

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

The Big Sun Rebranding Header Change

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