VirtualBox

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

Last change on this file since 11997 was 11889, checked in by vboxsync, 16 years ago

VMM/SUP: Added SUPR3HardenedVerifyFile and use it to verify files we load.

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