VirtualBox

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

Last change on this file since 19 was 1, checked in by vboxsync, 55 years ago

import

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