VirtualBox

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

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

string.h & stdio.h + header cleanups.

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