VirtualBox

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

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

Biggest check-in ever. New source code headers for all (C) innotek files.

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