VirtualBox

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

Last change on this file since 24912 was 24580, checked in by vboxsync, 15 years ago

PDMLdr.cpp: Call VMSetError before freeing the filename used in the message formatting.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use