VirtualBox

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

Last change on this file since 2230 was 1890, checked in by vboxsync, 18 years ago

Attempt to fix ALSA on Linux kernels <= 2.6.17: use mmap not memalign for allocating pages. Use madvise or mprotect to separater VM area structs inside the kernel. Most SUP* functions work on cPages now (not cBytes anymore). The free functions take a cPages parameter which is used for munmap on Linux.

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