VirtualBox

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

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

Fixed init problems wrt. VM ownership by implementing the UVM structure (U = user mode) and moving problematic ring-3 stuff over there (emt+reqs, r3heap, stam, loader[VMMR0.r0]). Big change, but it works fine here... :-)

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