VirtualBox

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

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

Don't need to fake loader operations on OS/2.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 34.7 KB
Line 
1/* $Id: PDMLdr.cpp 1194 2007-03-04 20:56: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);
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 RTMemFree(pModule);
278 return rc;
279}
280
281
282/**
283 * Resolve an external symbol during RTLdrGetBits() of a GC module.
284 *
285 * @returns VBox status code.
286 * @param hLdrMod The loader module handle.
287 * @param pszModule Module name.
288 * @param pszSymbol Symbol name, NULL if uSymbol should be used.
289 * @param uSymbol Symbol ordinal, ~0 if pszSymbol should be used.
290 * @param pValue Where to store the symbol value (address).
291 * @param pvUser User argument.
292 */
293static DECLCALLBACK(int) pdmr3GetImportGC(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol, unsigned uSymbol, RTUINTPTR *pValue, void *pvUser)
294{
295 PVM pVM = ((PPDMGETIMPORTARGS)pvUser)->pVM;
296 PPDMMOD pModule = ((PPDMGETIMPORTARGS)pvUser)->pModule;
297
298 /*
299 * Adjust input.
300 */
301 if (pszModule && !*pszModule)
302 pszModule = NULL;
303
304 /*
305 * Builtin module.
306 */
307 if (!pszModule || !strcmp(pszModule, "VMMGCBuiltin.gc"))
308 {
309 int rc = VINF_SUCCESS;
310 if (!strcmp(pszSymbol, "g_VM"))
311 *pValue = pVM->pVMGC;
312 else if (!strcmp(pszSymbol, "g_CPUM"))
313 *pValue = VM_GUEST_ADDR(pVM, &pVM->cpum);
314 else if (!strcmp(pszSymbol, "g_TRPM"))
315 *pValue = VM_GUEST_ADDR(pVM, &pVM->trpm);
316 else if ( !strncmp(pszSymbol, "VMM", 3)
317 || !strcmp(pszSymbol, "g_Logger")
318 || !strcmp(pszSymbol, "g_RelLogger"))
319 {
320 RTGCPTR GCPtr = 0;
321 rc = VMMR3GetImportGC(pVM, pszSymbol, &GCPtr);
322 if (VBOX_SUCCESS(rc))
323 *pValue = GCPtr;
324 }
325 else if ( !strncmp(pszSymbol, "TM", 2)
326 || !strcmp(pszSymbol, "g_pSUPGlobalInfoPage"))
327 {
328 RTGCPTR GCPtr = 0;
329 rc = TMR3GetImportGC(pVM, pszSymbol, &GCPtr);
330 if (VBOX_SUCCESS(rc))
331 *pValue = GCPtr;
332 }
333 else
334 {
335 AssertMsg(!pszModule, ("Unknown builtin symbol '%s' for module '%s'!\n", pszSymbol, pModule->szName)); NOREF(pModule);
336 rc = VERR_SYMBOL_NOT_FOUND;
337 }
338 if (VBOX_SUCCESS(rc) || pszModule)
339 return rc;
340 }
341
342 /*
343 * Search for module.
344 */
345 PPDMMOD pCur = pVM->pdm.s.pModules;
346 while (pCur)
347 {
348 if ( pCur->eType == PDMMOD_TYPE_GC
349 && ( !pszModule
350 || !strcmp(pCur->szName, pszModule))
351 )
352 {
353 /* Search for the symbol. */
354 int rc = RTLdrGetSymbolEx(pCur->hLdrMod, pCur->pvBits, pCur->ImageBase, pszSymbol, pValue);
355 if (VBOX_SUCCESS(rc))
356 {
357 AssertMsg(*pValue - pCur->ImageBase < RTLdrSize(pCur->hLdrMod),
358 ("%VGv-%VGv %s %VGv\n", (RTGCPTR)pCur->ImageBase,
359 (RTGCPTR)(pCur->ImageBase + RTLdrSize(pCur->hLdrMod) - 1),
360 pszSymbol, (RTGCPTR)*pValue));
361 return rc;
362 }
363 if (pszModule)
364 {
365 AssertMsgFailed(("Couldn't find symbol '%s' in module '%s'!\n", pszSymbol, pszModule));
366 LogRel(("PDMLdr: Couldn't find symbol '%s' in module '%s'!\n", pszSymbol, pszModule));
367 return VERR_SYMBOL_NOT_FOUND;
368 }
369 }
370
371 /* next */
372 pCur = pCur->pNext;
373 }
374
375 AssertMsgFailed(("Couldn't find module '%s' for resolving symbol '%s'!\n", pszModule, pszSymbol));
376 return VERR_SYMBOL_NOT_FOUND;
377}
378
379
380/**
381 * Loads a module into the guest context (i.e. into the Hypervisor memory region).
382 *
383 * The external (to PDM) use of this interface is to load VMMGC.gc.
384 *
385 * @returns VBox status code.
386 * @param pVM The VM to load it into.
387 * @param pszFilename Filename of the module binary.
388 * @param pszName Module name. Case sensitive and the length is limited!
389 */
390PDMR3DECL(int) PDMR3LoadGC(PVM pVM, const char *pszFilename, const char *pszName)
391{
392 /*
393 * Validate input.
394 */
395 AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
396 PPDMMOD pCur = pVM->pdm.s.pModules;
397 while (pCur)
398 {
399 if (!strcmp(pCur->szName, pszName))
400 {
401 AssertMsgFailed(("We've already got a module '%s' loaded!\n", pszName));
402 return VERR_PDM_MODULE_NAME_CLASH;
403 }
404 /* next */
405 pCur = pCur->pNext;
406 }
407
408 /*
409 * Find the file if not specified.
410 */
411 char *pszFile = NULL;
412 if (!pszFilename)
413 pszFilename = pszFile = pdmR3FileGC(pszName);
414
415 /*
416 * Allocate the module list node.
417 */
418 PPDMMOD pModule = (PPDMMOD)RTMemAllocZ(sizeof(*pModule) + strlen(pszFilename));
419 if (!pModule)
420 {
421 RTMemTmpFree(pszFile);
422 return VERR_NO_MEMORY;
423 }
424 AssertMsg(strlen(pszName) + 1 < sizeof(pModule->szName),
425 ("pazName is too long (%d chars) max is %d chars.\n", strlen(pszName), sizeof(pModule->szName) - 1));
426 strcpy(pModule->szName, pszName);
427 pModule->eType = PDMMOD_TYPE_GC;
428 strcpy(pModule->szFilename, pszFilename);
429
430
431 /*
432 * Open the loader item.
433 */
434 int rc = RTLdrOpen(pszFilename, &pModule->hLdrMod);
435 if (VBOX_SUCCESS(rc))
436 {
437 /*
438 * Allocate space in the hypervisor.
439 */
440 size_t cb = RTLdrSize(pModule->hLdrMod);
441 cb = RT_ALIGN_Z(cb, PAGE_SIZE);
442 rc = SUPPageAlloc(cb >> PAGE_SHIFT, &pModule->pvBits);
443 if (VBOX_SUCCESS(rc))
444 {
445 RTGCPTR GCPtr;
446 rc = MMR3HyperMapHCRam(pVM, pModule->pvBits, cb, true, pModule->szName, &GCPtr);
447 if (VBOX_SUCCESS(rc))
448 {
449 MMR3HyperReserve(pVM, PAGE_SIZE, "fence", NULL);
450
451 /*
452 * Get relocated image bits.
453 */
454 Assert(MMHyperHC2GC(pVM, pModule->pvBits) == GCPtr);
455 pModule->ImageBase = GCPtr;
456 PDMGETIMPORTARGS Args;
457 Args.pVM = pVM;
458 Args.pModule = pModule;
459 rc = RTLdrGetBits(pModule->hLdrMod, pModule->pvBits, pModule->ImageBase, pdmr3GetImportGC, &Args);
460 if (VBOX_SUCCESS(rc))
461 {
462 /*
463 * Insert the module.
464 */
465 if (pVM->pdm.s.pModules)
466 {
467 /* we don't expect this list to be very long, so rather save the tail pointer. */
468 PPDMMOD pCur = pVM->pdm.s.pModules;
469 while (pCur->pNext)
470 pCur = pCur->pNext;
471 pCur->pNext = pModule;
472 }
473 else
474 pVM->pdm.s.pModules = pModule; /* (pNext is zeroed by alloc) */
475 Log(("PDM: GC Module at %VGvx %s (%s)\n", (RTGCPTR)pModule->ImageBase, pszName, pszFilename));
476 RTMemTmpFree(pszFile);
477 return VINF_SUCCESS;
478 }
479 }
480 else
481 {
482 AssertRC(rc);
483 SUPPageFree(pModule->pvBits);
484 }
485 }
486 else
487 AssertMsgFailed(("SUPPageAlloc(%d,) -> %Vrc\n", cb >> PAGE_SHIFT, rc));
488 int rc2 = RTLdrClose(pModule->hLdrMod);
489 AssertRC(rc2);
490 }
491 RTMemFree(pModule);
492 RTMemTmpFree(pszFile);
493
494 return rc;
495}
496
497
498/**
499 * Loads a module into the ring-0 context.
500 *
501 * @returns VBox status code.
502 * @param pVM The VM to load it into.
503 * @param pszFilename Filename of the module binary.
504 * @param pszName Module name. Case sensitive and the length is limited!
505 */
506static int pdmR3LoadR0(PVM pVM, const char *pszFilename, const char *pszName)
507{
508 /*
509 * Validate input.
510 */
511 AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
512 PPDMMOD pCur = pVM->pdm.s.pModules;
513 while (pCur)
514 {
515 if (!strcmp(pCur->szName, pszName))
516 {
517 AssertMsgFailed(("We've already got a module '%s' loaded!\n", pszName));
518 return VERR_PDM_MODULE_NAME_CLASH;
519 }
520 /* next */
521 pCur = pCur->pNext;
522 }
523
524 /*
525 * Find the file if not specified.
526 */
527 char *pszFile = NULL;
528 if (!pszFilename)
529 pszFilename = pszFile = pdmR3FileR0(pszName);
530
531 /*
532 * Allocate the module list node.
533 */
534 PPDMMOD pModule = (PPDMMOD)RTMemAllocZ(sizeof(*pModule) + strlen(pszFilename));
535 if (!pModule)
536 {
537 RTMemTmpFree(pszFile);
538 return VERR_NO_MEMORY;
539 }
540 AssertMsg(strlen(pszName) + 1 < sizeof(pModule->szName),
541 ("pazName is too long (%d chars) max is %d chars.\n", strlen(pszName), sizeof(pModule->szName) - 1));
542 strcpy(pModule->szName, pszName);
543 pModule->eType = PDMMOD_TYPE_R0;
544 strcpy(pModule->szFilename, pszFilename);
545
546 /*
547 * Ask the support library to load it.
548 */
549 void *pvImageBase;
550 int rc = SUPLoadModule(pszFilename, pszName, &pvImageBase);
551 if (VBOX_SUCCESS(rc))
552 {
553 pModule->hLdrMod = NIL_RTLDRMOD;
554 pModule->ImageBase = (uintptr_t)pvImageBase;
555
556 /*
557 * Insert the module.
558 */
559 if (pVM->pdm.s.pModules)
560 {
561 /* we don't expect this list to be very long, so rather save the tail pointer. */
562 PPDMMOD pCur = pVM->pdm.s.pModules;
563 while (pCur->pNext)
564 pCur = pCur->pNext;
565 pCur->pNext = pModule;
566 }
567 else
568 pVM->pdm.s.pModules = pModule; /* (pNext is zeroed by alloc) */
569 Log(("PDM: GC Module at %VGvx %s (%s)\n", (RTGCPTR)pModule->ImageBase, pszName, pszFilename));
570 RTMemTmpFree(pszFile);
571 return VINF_SUCCESS;
572 }
573
574 RTMemFree(pModule);
575 RTMemTmpFree(pszFile);
576 LogRel(("pdmR3LoadR0: pszName=\"%s\" rc=%Vrc\n", pszName, rc));
577 return rc;
578}
579
580
581
582/**
583 * Get the address of a symbol in a given HC ring 3 module.
584 *
585 * @returns VBox status code.
586 * @param pVM VM handle.
587 * @param pszModule Module name.
588 * @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
589 * ordinal value rather than a string pointer.
590 * @param ppvValue Where to store the symbol value.
591 */
592PDMR3DECL(int) PDMR3GetSymbolR3(PVM pVM, const char *pszModule, const char *pszSymbol, void **ppvValue)
593{
594 /*
595 * Validate input.
596 */
597 AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
598
599 /*
600 * Find the module.
601 */
602 for (PPDMMOD pModule = pVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
603 {
604 if ( pModule->eType == PDMMOD_TYPE_R3
605 && !strcmp(pModule->szName, pszModule))
606 {
607 RTUINTPTR Value = 0;
608 int rc = RTLdrGetSymbolEx(pModule->hLdrMod, pModule->pvBits, pModule->ImageBase, pszSymbol, &Value);
609 if (VBOX_SUCCESS(rc))
610 {
611 *ppvValue = (void *)(uintptr_t)Value;
612 Assert((uintptr_t)*ppvValue == Value);
613 }
614 else
615 {
616 if (pszSymbol < (const char*)(void*)0x10000)
617 AssertMsg(rc, ("Couldn't symbol '%u' in module '%s'\n", (unsigned)(uintptr_t)pszSymbol, pszModule));
618 else
619 AssertMsg(rc, ("Couldn't symbol '%s' in module '%s'\n", pszSymbol, pszModule));
620 }
621 return rc;
622 }
623 }
624
625 AssertMsgFailed(("Couldn't locate module '%s'\n", pszModule));
626 return VERR_SYMBOL_NOT_FOUND;
627}
628
629
630/**
631 * Get the address of a symbol in a given HC ring 0 module.
632 *
633 * @returns VBox status code.
634 * @param pVM VM handle.
635 * @param pszModule Module name. If NULL the main R0 module (VMMR0.r0) is assumes.
636 * @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
637 * ordinal value rather than a string pointer.
638 * @param ppvValue Where to store the symbol value.
639 */
640PDMR3DECL(int) PDMR3GetSymbolR0(PVM pVM, const char *pszModule, const char *pszSymbol, void **ppvValue)
641{
642#ifdef PDMLDR_FAKE_MODE
643 *ppvValue = (void *)0xdeadbeef;
644 return VINF_SUCCESS;
645
646#else
647 /*
648 * Validate input.
649 */
650 AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
651 if (!pszModule)
652 pszModule = "VMMR0.r0";
653
654 /*
655 * Find the module.
656 */
657 for (PPDMMOD pModule = pVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
658 {
659 if ( pModule->eType == PDMMOD_TYPE_R0
660 && !strcmp(pModule->szName, pszModule))
661 {
662 int rc = SUPGetSymbolR0((void *)(uintptr_t)pModule->ImageBase, pszSymbol, ppvValue);
663 if (VBOX_FAILURE(rc))
664 {
665 AssertMsgRC(rc, ("Couldn't find symbol '%s' in module '%s'\n", pszSymbol, pszModule));
666 LogRel(("PDMGetSymbol: Couldn't find symbol '%s' in module '%s'\n", pszSymbol, pszModule));
667 }
668 return rc;
669 }
670 }
671
672 AssertMsgFailed(("Couldn't locate module '%s'\n", pszModule));
673 return VERR_SYMBOL_NOT_FOUND;
674#endif
675}
676
677
678/**
679 * Same as PDMR3GetSymbolR0 except that the module will be attempted loaded if not found.
680 *
681 * @returns VBox status code.
682 * @param pVM VM handle.
683 * @param pszModule Module name. If NULL the main R0 module (VMMR0.r0) is assumed.
684 * @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
685 * ordinal value rather than a string pointer.
686 * @param ppvValue Where to store the symbol value.
687 */
688PDMR3DECL(int) PDMR3GetSymbolR0Lazy(PVM pVM, const char *pszModule, const char *pszSymbol, void **ppvValue)
689{
690#ifdef PDMLDR_FAKE_MODE
691 *ppvValue = (void *)0xdeadbeef;
692 return VINF_SUCCESS;
693
694#else
695 /*
696 * Since we're lazy, we'll only check if the module is present
697 * and hand it over to PDMR3GetSymbolR0 when that's done.
698 */
699 AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
700 if (pszModule)
701 {
702 AssertMsgReturn(!strpbrk(pszModule, "/\\:\n\r\t"), ("pszModule=%s\n", pszModule), VERR_INVALID_PARAMETER);
703 PPDMMOD pModule;
704 for (pModule = pVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
705 if ( pModule->eType == PDMMOD_TYPE_R0
706 && !strcmp(pModule->szName, pszModule))
707 break;
708 if (!pModule)
709 {
710 int rc = pdmR3LoadR0(pVM, NULL, pszModule);
711 AssertMsgRCReturn(rc, ("pszModule=%s rc=%Vrc\n", pszModule, rc), VERR_MODULE_NOT_FOUND);
712 }
713 }
714 return PDMR3GetSymbolR0(pVM, pszModule, pszSymbol, ppvValue);
715#endif
716}
717
718
719/**
720 * Get the address of a symbol in a given GC module.
721 *
722 * @returns VBox status code.
723 * @param pVM VM handle.
724 * @param pszModule Module name. If NULL the main R0 module (VMMGC.gc) is assumes.
725 * @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
726 * ordinal value rather than a string pointer.
727 * @param pGCPtrValue Where to store the symbol value.
728 */
729PDMR3DECL(int) PDMR3GetSymbolGC(PVM pVM, const char *pszModule, const char *pszSymbol, PRTGCPTR pGCPtrValue)
730{
731#ifdef PDMLDR_FAKE_MODE
732 *pGCPtrValue = 0xfeedf00d;
733 return VINF_SUCCESS;
734
735#else
736 /*
737 * Validate input.
738 */
739 AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
740 if (!pszModule)
741 pszModule = "VMMGC.gc";
742
743 /*
744 * Find the module.
745 */
746 for (PPDMMOD pModule = pVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
747 {
748 if ( pModule->eType == PDMMOD_TYPE_GC
749 && !strcmp(pModule->szName, pszModule))
750 {
751 RTUINTPTR Value;
752 int rc = RTLdrGetSymbolEx(pModule->hLdrMod, pModule->pvBits, pModule->ImageBase, pszSymbol, &Value);
753 if (VBOX_SUCCESS(rc))
754 {
755 *pGCPtrValue = (RTGCPTR)Value;
756 Assert(*pGCPtrValue == Value);
757 }
758 else
759 {
760 if (pszSymbol < (const char*)(void*)0x10000)
761 AssertMsg(rc, ("Couldn't symbol '%u' in module '%s'\n", (unsigned)(uintptr_t)pszSymbol, pszModule));
762 else
763 AssertMsg(rc, ("Couldn't symbol '%s' in module '%s'\n", pszSymbol, pszModule));
764 }
765 return rc;
766 }
767 }
768
769 AssertMsgFailed(("Couldn't locate module '%s'\n", pszModule));
770 return VERR_SYMBOL_NOT_FOUND;
771#endif
772}
773
774
775/**
776 * Same as PDMR3GetSymbolGC except that the module will be attempted loaded if not found.
777 *
778 * @returns VBox status code.
779 * @param pVM VM handle.
780 * @param pszModule Module name. If NULL the main R0 module (VMMGC.gc) is assumes.
781 * @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
782 * ordinal value rather than a string pointer.
783 * @param pGCPtrValue Where to store the symbol value.
784 */
785PDMR3DECL(int) PDMR3GetSymbolGCLazy(PVM pVM, const char *pszModule, const char *pszSymbol, PRTGCPTR pGCPtrValue)
786{
787#ifdef PDMLDR_FAKE_MODE
788 *pGCPtrValue = 0xfeedf00d;
789 return VINF_SUCCESS;
790
791#else
792 /*
793 * Since we're lazy, we'll only check if the module is present
794 * and hand it over to PDMR3GetSymbolGC when that's done.
795 */
796 AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
797 if (pszModule)
798 {
799 AssertMsgReturn(!strpbrk(pszModule, "/\\:\n\r\t"), ("pszModule=%s\n", pszModule), VERR_INVALID_PARAMETER);
800 PPDMMOD pModule;
801 for (pModule = pVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
802 if ( pModule->eType == PDMMOD_TYPE_GC
803 && !strcmp(pModule->szName, pszModule))
804 break;
805 if (!pModule)
806 {
807 char *pszFilename = pdmR3FileGC(pszModule);
808 AssertMsgReturn(pszFilename, ("pszModule=%s\n", pszModule), VERR_MODULE_NOT_FOUND);
809 int rc = PDMR3LoadGC(pVM, pszFilename, pszModule);
810 RTMemTmpFree(pszFilename);
811 AssertMsgRCReturn(rc, ("pszModule=%s rc=%Vrc\n", pszModule, rc), VERR_MODULE_NOT_FOUND);
812 }
813 }
814 return PDMR3GetSymbolGC(pVM, pszModule, pszSymbol, pGCPtrValue);
815#endif
816}
817
818
819/**
820 * Constructs the full filename for a R3 image file.
821 *
822 * @returns Pointer to temporary memory containing the filename.
823 * Caller must free this using RTMemTmpFree().
824 * @returns NULL on failure.
825 * @param pszFile File name (no path).
826 * @todo We'll have this elsewhere than in the root later!
827 */
828char *pdmR3FileR3(const char *pszFile)
829{
830 return pdmR3File(pszFile, NULL);
831}
832
833
834/**
835 * Constructs the full filename for a R0 image file.
836 *
837 * @returns Pointer to temporary memory containing the filename.
838 * Caller must free this using RTMemTmpFree().
839 * @returns NULL on failure.
840 * @param pszFile File name (no path).
841 * @todo We'll have this elsewhere than in the root later!
842 */
843char * pdmR3FileR0(const char *pszFile)
844{
845 return pdmR3File(pszFile, NULL);
846}
847
848
849/**
850 * Constructs the full filename for a GC image file.
851 *
852 * @returns Pointer to temporary memory containing the filename.
853 * Caller must free this using RTMemTmpFree().
854 * @returns NULL on failure.
855 * @param pszFile File name (no path).
856 * @todo We'll have this elsewhere than in the root later!
857 */
858char * pdmR3FileGC(const char *pszFile)
859{
860 return pdmR3File(pszFile, NULL);
861}
862
863
864/**
865 * Worker for pdmR3FileGC() and pdmR3FileHC().
866 *
867 * @returns Pointer to temporary memory containing the filename.
868 * Caller must free this using RTMemTmpFree().
869 * @returns NULL on failure.
870 * @param pszFile File name (no path).
871 * @param pszDefaultExt The default extention, NULL if none.
872 * @todo We'll have this elsewhere than in the root later!
873 */
874static char * pdmR3File(const char *pszFile, const char *pszDefaultExt)
875{
876 /*
877 * Default extention?
878 */
879 unsigned cchDefaultExt;
880 if (!pszDefaultExt || strchr(pszFile, '.'))
881 cchDefaultExt = 0;
882 else
883 cchDefaultExt = strlen(pszDefaultExt);
884
885 /*
886 * Query program path.
887 */
888 unsigned cchFile = strlen(pszFile);
889 char szPath[RTPATH_MAX];
890 int rc = RTPathProgram(szPath, sizeof(szPath) - cchFile - cchDefaultExt - 1);
891 if (!VBOX_SUCCESS(rc))
892 {
893 AssertMsgFailed(("RTPathProgram(,%d) failed rc=%d!\n", sizeof(szPath), rc));
894 return NULL;
895 }
896
897 /*
898 * Allocate temp memory for return buffer.
899 */
900 unsigned cch = strlen(szPath);
901 char *pszRet = (char *)RTMemTmpAlloc(cch + 1 + cchFile + cchDefaultExt + 1);
902 if (!pszRet)
903 {
904 AssertMsgFailed(("Out of temporary memory!\n"));
905 return NULL;
906 }
907
908 /*
909 * Construct the filename.
910 */
911 memcpy(pszRet, szPath, cch);
912 pszRet[cch++] = '/'; /* this works everywhere */
913 memcpy(pszRet + cch, pszFile, cchFile + 1);
914 if (cchDefaultExt)
915 memcpy(pszRet + cch + cchFile, pszDefaultExt, cchDefaultExt + 1);
916 return pszRet;
917}
918
919
920/** @internal */
921typedef struct QMFEIPARG
922{
923 uint32_t uEIP;
924
925 char *pszNearSym1;
926 unsigned cchNearSym1;
927 RTINTPTR offNearSym1;
928
929 char *pszNearSym2;
930 unsigned cchNearSym2;
931 RTINTPTR offNearSym2;
932} QMFEIPARG, *PQMFEIPARG;
933
934/**
935 * Queries module information from an EIP.
936 *
937 * This is typically used to locate a crash address.
938 *
939 * @returns VBox status code.
940 * @param pVM VM handle
941 * @param uEIP EIP to locate.
942 * @param pszModName Where to store the module name.
943 * @param cchModName Size of the module name buffer.
944 * @param pMod Base address of the module.
945 * @param pszNearSym1 Name of the closes symbol from below.
946 * @param cchNearSym1 Size of the buffer pointed to by pszNearSym1.
947 * @param pNearSym1 The address of pszNearSym1.
948 * @param pszNearSym2 Name of the closes symbol from below.
949 * @param cchNearSym2 Size of the buffer pointed to by pszNearSym2.
950 * @param pNearSym2 The address of pszNearSym2.
951 */
952PDMR3DECL(int) PDMR3QueryModFromEIP(PVM pVM, uint32_t uEIP,
953 char *pszModName, unsigned cchModName, RTGCPTR *pMod,
954 char *pszNearSym1, unsigned cchNearSym1, RTGCPTR *pNearSym1,
955 char *pszNearSym2, unsigned cchNearSym2, RTGCPTR *pNearSym2)
956{
957 int rc = VERR_MODULE_NOT_FOUND;
958 PPDMMOD pCur;
959 for (pCur = pVM->pdm.s.pModules; pCur; pCur = pCur->pNext)
960 {
961 /* Skip anything which isn't in GC. */
962 if (pCur->eType != PDMMOD_TYPE_GC)
963 continue;
964 if ((RTUINTPTR)uEIP - pCur->ImageBase < RTLdrSize(pCur->hLdrMod))
965 {
966 if (pMod)
967 *pMod = pCur->ImageBase;
968 if (pszModName && cchModName)
969 {
970 *pszModName = '\0';
971 strncat(pszModName, pCur->szName, cchModName);
972 }
973 if (pNearSym1) *pNearSym1 = 0;
974 if (pNearSym2) *pNearSym2 = 0;
975 if (pszNearSym1) *pszNearSym1 = '\0';
976 if (pszNearSym2) *pszNearSym2 = '\0';
977
978 /*
979 * Locate the nearest symbols.
980 */
981 QMFEIPARG Args;
982 Args.uEIP = uEIP;
983 Args.pszNearSym1 = pszNearSym1;
984 Args.cchNearSym1 = cchNearSym1;
985 Args.offNearSym1 = INT_MIN; /** @todo fix INT_MIN/MAX! */
986 Args.pszNearSym2 = pszNearSym2;
987 Args.cchNearSym2 = cchNearSym2;
988 Args.offNearSym2 = INT_MAX;
989
990 rc = RTLdrEnumSymbols(pCur->hLdrMod, RTLDR_ENUM_SYMBOL_FLAGS_ALL, pCur->pvBits, pCur->ImageBase,
991 pdmR3QueryModFromEIPEnumSymbols, &Args);
992 if (pNearSym1 && Args.offNearSym1 != INT_MIN)
993 *pNearSym1 = Args.offNearSym1 + uEIP;
994 if (pNearSym2 && Args.offNearSym2 != INT_MAX)
995 *pNearSym2 = Args.offNearSym2 + uEIP;
996
997 rc = VINF_SUCCESS;
998 if (pCur->eType == PDMMOD_TYPE_GC)
999 break;
1000 }
1001
1002 }
1003 return rc;
1004}
1005
1006
1007/**
1008 * Enumeration callback function used by RTLdrEnumSymbols().
1009 *
1010 * @returns VBox status code. Failure will stop the enumeration.
1011 * @param hLdrMod The loader module handle.
1012 * @param pszSymbol Symbol name. NULL if ordinal only.
1013 * @param uSymbol Symbol ordinal, ~0 if not used.
1014 * @param Value Symbol value.
1015 * @param pvUser The user argument specified to RTLdrEnumSymbols().
1016 */
1017static DECLCALLBACK(int) pdmR3QueryModFromEIPEnumSymbols(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser)
1018{
1019 PQMFEIPARG pArgs = (PQMFEIPARG)pvUser;
1020
1021 RTINTPTR off = Value - pArgs->uEIP;
1022 if (off <= 0) /* near1 is before or at same location. */
1023 {
1024 if (off > pArgs->offNearSym1)
1025 {
1026 pArgs->offNearSym1 = off;
1027 if (pArgs->pszNearSym1 && pArgs->cchNearSym1)
1028 {
1029 *pArgs->pszNearSym1 = '\0';
1030 if (pszSymbol)
1031 strncat(pArgs->pszNearSym1, pszSymbol, pArgs->cchNearSym1);
1032 else
1033 {
1034 char szOrd[32];
1035 RTStrPrintf(szOrd, sizeof(szOrd), "#%#x", uSymbol);
1036 strncat(pArgs->pszNearSym1, szOrd, pArgs->cchNearSym1);
1037 }
1038 }
1039 }
1040 }
1041 else /* near2 is after */
1042 {
1043 if (off < pArgs->offNearSym2)
1044 {
1045 pArgs->offNearSym2 = off;
1046 if (pArgs->pszNearSym2 && pArgs->cchNearSym2)
1047 {
1048 *pArgs->pszNearSym2 = '\0';
1049 if (pszSymbol)
1050 strncat(pArgs->pszNearSym2, pszSymbol, pArgs->cchNearSym2);
1051 else
1052 {
1053 char szOrd[32];
1054 RTStrPrintf(szOrd, sizeof(szOrd), "#%#x", uSymbol);
1055 strncat(pArgs->pszNearSym2, szOrd, pArgs->cchNearSym2);
1056 }
1057 }
1058 }
1059 }
1060
1061 return VINF_SUCCESS;
1062}
1063
1064
1065/**
1066 * Enumerate all PDM modules.
1067 *
1068 * @returns VBox status.
1069 * @param pVM VM Handle.
1070 * @param pfnCallback Function to call back for each of the modules.
1071 * @param pvArg User argument.
1072 */
1073PDMR3DECL(int) PDMR3EnumModules(PVM pVM, PFNPDMR3ENUM pfnCallback, void *pvArg)
1074{
1075 PPDMMOD pCur;
1076 for (pCur = pVM->pdm.s.pModules; pCur; pCur = pCur->pNext)
1077 {
1078 int rc = pfnCallback(pVM,
1079 pCur->szFilename,
1080 pCur->szName,
1081 pCur->ImageBase,
1082 pCur->eType == PDMMOD_TYPE_GC ? RTLdrSize(pCur->hLdrMod) : 0,
1083 pCur->eType == PDMMOD_TYPE_GC);
1084 if (VBOX_FAILURE(rc))
1085 return rc;
1086 }
1087 return VINF_SUCCESS;
1088}
1089
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