VirtualBox

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

Last change on this file since 29676 was 28800, checked in by vboxsync, 15 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 49.8 KB
Line 
1/* $Id: PDMLdr.cpp 28800 2010-04-27 08:22:32Z vboxsync $ */
2/** @file
3 * PDM - Pluggable Device Manager, module loader.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Oracle Corporation
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) pdmR3GetImportRC(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 * pdmR3FileRC(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 */
77VMMR3DECL(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#if defined(PDMLDR_FAKE_MODE) || !defined(VBOX_WITH_RAW_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 PDMR3LdrLoadRC(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 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
123 PPDMMOD pModule = pUVM->pdm.s.pModules;
124 pUVM->pdm.s.pModules = NULL;
125 while (pModule)
126 {
127 /* free loader item. */
128 if (pModule->hLdrMod != NIL_RTLDRMOD)
129 {
130 int rc2 = RTLdrClose(pModule->hLdrMod);
131 AssertRC(rc2);
132 pModule->hLdrMod = NIL_RTLDRMOD;
133 }
134
135 /* free bits. */
136 switch (pModule->eType)
137 {
138 case PDMMOD_TYPE_R0:
139 {
140 Assert(pModule->ImageBase);
141 int rc2 = SUPR3FreeModule((void *)(uintptr_t)pModule->ImageBase);
142 AssertRC(rc2);
143 pModule->ImageBase = 0;
144 break;
145 }
146
147#ifdef VBOX_WITH_RAW_MODE
148 case PDMMOD_TYPE_RC:
149#endif
150 case PDMMOD_TYPE_R3:
151 /* MM will free this memory for us - it's alloc only memory. :-) */
152 break;
153
154 default:
155 AssertMsgFailed(("eType=%d\n", pModule->eType));
156 break;
157 }
158 pModule->pvBits = NULL;
159
160 void *pvFree = pModule;
161 pModule = pModule->pNext;
162 RTMemFree(pvFree);
163 }
164 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
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#ifdef VBOX_WITH_RAW_MODE
180 LogFlow(("PDMR3LdrRelocate: offDelta=%RGv\n", offDelta));
181
182 /*
183 * GC Modules.
184 */
185 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
186 if (pUVM->pdm.s.pModules)
187 {
188 /*
189 * The relocation have to be done in two passes so imports
190 * can be correctely resolved. The first pass will update
191 * the ImageBase saving the current value in OldImageBase.
192 * The second pass will do the actual relocation.
193 */
194 /* pass 1 */
195 PPDMMOD pCur;
196 for (pCur = pUVM->pdm.s.pModules; pCur; pCur = pCur->pNext)
197 {
198 if (pCur->eType == PDMMOD_TYPE_RC)
199 {
200 pCur->OldImageBase = pCur->ImageBase;
201 pCur->ImageBase = MMHyperR3ToRC(pUVM->pVM, pCur->pvBits);
202 }
203 }
204
205 /* pass 2 */
206 for (pCur = pUVM->pdm.s.pModules; pCur; pCur = pCur->pNext)
207 {
208 if (pCur->eType == PDMMOD_TYPE_RC)
209 {
210 PDMGETIMPORTARGS Args;
211 Args.pVM = pUVM->pVM;
212 Args.pModule = pCur;
213 int rc = RTLdrRelocate(pCur->hLdrMod, pCur->pvBits, pCur->ImageBase, pCur->OldImageBase,
214 pdmR3GetImportRC, &Args);
215 AssertFatalMsgRC(rc, ("RTLdrRelocate failed, rc=%d\n", rc));
216 DBGFR3ModuleRelocate(pUVM->pVM, pCur->OldImageBase, pCur->ImageBase, RTLdrSize(pCur->hLdrMod),
217 pCur->szFilename, pCur->szName);
218 }
219 }
220 }
221 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
222#endif
223}
224
225
226/**
227 * Loads a module into the host context ring-3.
228 *
229 * This is used by the driver and device init functions to load modules
230 * containing the drivers and devices. The function can be extended to
231 * load modules which are not native to the environment we're running in,
232 * but at the moment this is not required.
233 *
234 * No reference counting is kept, since we don't implement any facilities
235 * for unloading the module. But the module will naturally be released
236 * when the VM terminates.
237 *
238 * @returns VBox status code.
239 * @param pUVM Pointer to the user mode VM structure.
240 * @param pszFilename Filename of the module binary.
241 * @param pszName Module name. Case sensitive and the length is limited!
242 */
243int pdmR3LoadR3U(PUVM pUVM, const char *pszFilename, const char *pszName)
244{
245 /*
246 * Validate input.
247 */
248 AssertMsg(pUVM->pVM->pdm.s.offVM, ("bad init order!\n"));
249 Assert(pszFilename);
250 size_t cchFilename = strlen(pszFilename);
251 Assert(pszName);
252 size_t cchName = strlen(pszName);
253 PPDMMOD pCur;
254 if (cchName >= sizeof(pCur->szName))
255 {
256 AssertMsgFailed(("Name is too long, cchName=%d pszName='%s'\n", cchName, pszName));
257 return VERR_INVALID_PARAMETER;
258 }
259
260 /*
261 * Try lookup the name and see if the module exists.
262 */
263 int rc;
264 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
265 for (pCur = pUVM->pdm.s.pModules; pCur; pCur = pCur->pNext)
266 {
267 if (!strcmp(pCur->szName, pszName))
268 {
269 if (pCur->eType == PDMMOD_TYPE_R3)
270 rc = VINF_PDM_ALREADY_LOADED;
271 else
272 rc = VERR_PDM_MODULE_NAME_CLASH;
273 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
274
275 AssertMsgRC(rc, ("We've already got a module '%s' loaded!\n", pszName));
276 return rc;
277 }
278 }
279
280 /*
281 * Allocate the module list node and initialize it.
282 */
283 const char *pszSuff = RTLdrGetSuff();
284 size_t cchSuff = RTPathHaveExt(pszFilename) ? 0 : strlen(pszSuff);
285 PPDMMOD pModule = (PPDMMOD)RTMemAllocZ(RT_OFFSETOF(PDMMOD, szFilename[cchFilename + cchSuff + 1]));
286 if (pModule)
287 {
288 pModule->eType = PDMMOD_TYPE_R3;
289 memcpy(pModule->szName, pszName, cchName); /* memory is zero'ed, no need to copy terminator :-) */
290 memcpy(pModule->szFilename, pszFilename, cchFilename);
291 memcpy(&pModule->szFilename[cchFilename], pszSuff, cchSuff);
292
293 /*
294 * Load the loader item.
295 */
296 rc = SUPR3HardenedVerifyFile(pModule->szFilename, "pdmR3LoadR3U", NULL);
297 if (RT_SUCCESS(rc))
298 rc = RTLdrLoad(pModule->szFilename, &pModule->hLdrMod);
299 if (RT_SUCCESS(rc))
300 {
301 pModule->pNext = pUVM->pdm.s.pModules;
302 pUVM->pdm.s.pModules = pModule;
303 }
304 else
305 {
306 /* Something went wrong, most likely module not found. Don't consider other unlikely errors */
307 rc = VMSetError(pUVM->pVM, rc, RT_SRC_POS, N_("Unable to load R3 module %s (%s)"), pModule->szFilename, pszName);
308 RTMemFree(pModule);
309 }
310 }
311 else
312 rc = VERR_NO_MEMORY;
313
314 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
315 return rc;
316}
317
318
319#ifdef VBOX_WITH_RAW_MODE
320/**
321 * Resolve an external symbol during RTLdrGetBits() of a RC module.
322 *
323 * @returns VBox status code.
324 * @param hLdrMod The loader module handle.
325 * @param pszModule Module name.
326 * @param pszSymbol Symbol name, NULL if uSymbol should be used.
327 * @param uSymbol Symbol ordinal, ~0 if pszSymbol should be used.
328 * @param pValue Where to store the symbol value (address).
329 * @param pvUser User argument.
330 */
331static DECLCALLBACK(int) pdmR3GetImportRC(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol, unsigned uSymbol, RTUINTPTR *pValue, void *pvUser)
332{
333 PVM pVM = ((PPDMGETIMPORTARGS)pvUser)->pVM;
334 PPDMMOD pModule = ((PPDMGETIMPORTARGS)pvUser)->pModule;
335
336 /*
337 * Adjust input.
338 */
339 if (pszModule && !*pszModule)
340 pszModule = NULL;
341
342 /*
343 * Builtin module.
344 */
345 if (!pszModule || !strcmp(pszModule, "VMMGCBuiltin.gc"))
346 {
347 int rc = VINF_SUCCESS;
348 if (!strcmp(pszSymbol, "g_VM"))
349 *pValue = pVM->pVMRC;
350 else if (!strcmp(pszSymbol, "g_CPUM"))
351 *pValue = VM_RC_ADDR(pVM, &pVM->cpum);
352 else if (!strcmp(pszSymbol, "g_TRPM"))
353 *pValue = VM_RC_ADDR(pVM, &pVM->trpm);
354 else if (!strcmp(pszSymbol, "g_TRPMCPU"))
355 *pValue = VM_RC_ADDR(pVM, &pVM->aCpus[0].trpm);
356 else if ( !strncmp(pszSymbol, "VMM", 3)
357 || !strcmp(pszSymbol, "g_Logger")
358 || !strcmp(pszSymbol, "g_RelLogger"))
359 {
360 RTRCPTR RCPtr = 0;
361 rc = VMMR3GetImportRC(pVM, pszSymbol, &RCPtr);
362 if (RT_SUCCESS(rc))
363 *pValue = RCPtr;
364 }
365 else if ( !strncmp(pszSymbol, "TM", 2)
366 || !strcmp(pszSymbol, "g_pSUPGlobalInfoPage"))
367 {
368 RTRCPTR RCPtr = 0;
369 rc = TMR3GetImportRC(pVM, pszSymbol, &RCPtr);
370 if (RT_SUCCESS(rc))
371 *pValue = RCPtr;
372 }
373 else
374 {
375 AssertMsg(!pszModule, ("Unknown builtin symbol '%s' for module '%s'!\n", pszSymbol, pModule->szName)); NOREF(pModule);
376 rc = VERR_SYMBOL_NOT_FOUND;
377 }
378 if (RT_SUCCESS(rc) || pszModule)
379 return rc;
380 }
381
382 /*
383 * Search for module.
384 */
385 PUVM pUVM = pVM->pUVM;
386 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
387 PPDMMOD pCur = pUVM->pdm.s.pModules;
388 while (pCur)
389 {
390 if ( pCur->eType == PDMMOD_TYPE_RC
391 && ( !pszModule
392 || !strcmp(pCur->szName, pszModule))
393 )
394 {
395 /* Search for the symbol. */
396 int rc = RTLdrGetSymbolEx(pCur->hLdrMod, pCur->pvBits, pCur->ImageBase, pszSymbol, pValue);
397 if (RT_SUCCESS(rc))
398 {
399 AssertMsg(*pValue - pCur->ImageBase < RTLdrSize(pCur->hLdrMod),
400 ("%RRv-%RRv %s %RRv\n", (RTRCPTR)pCur->ImageBase,
401 (RTRCPTR)(pCur->ImageBase + RTLdrSize(pCur->hLdrMod) - 1),
402 pszSymbol, (RTRCPTR)*pValue));
403 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
404 return rc;
405 }
406 if (pszModule)
407 {
408 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
409 AssertMsgFailed(("Couldn't find symbol '%s' in module '%s'!\n", pszSymbol, pszModule));
410 LogRel(("PDMLdr: Couldn't find symbol '%s' in module '%s'!\n", pszSymbol, pszModule));
411 return VERR_SYMBOL_NOT_FOUND;
412 }
413 }
414
415 /* next */
416 pCur = pCur->pNext;
417 }
418
419 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
420 AssertMsgFailed(("Couldn't find module '%s' for resolving symbol '%s'!\n", pszModule, pszSymbol));
421 return VERR_SYMBOL_NOT_FOUND;
422}
423
424
425/**
426 * Loads a module into the guest context (i.e. into the Hypervisor memory region).
427 *
428 * @returns VBox status code.
429 * @param pVM The VM to load it into.
430 * @param pszFilename Filename of the module binary.
431 * @param pszName Module name. Case sensitive and the length is limited!
432 */
433VMMR3DECL(int) PDMR3LdrLoadRC(PVM pVM, const char *pszFilename, const char *pszName)
434{
435 /*
436 * Validate input.
437 */
438 AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
439 PUVM pUVM = pVM->pUVM;
440 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
441 PPDMMOD pCur = pUVM->pdm.s.pModules;
442 while (pCur)
443 {
444 if (!strcmp(pCur->szName, pszName))
445 {
446 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
447 AssertMsgFailed(("We've already got a module '%s' loaded!\n", pszName));
448 return VERR_PDM_MODULE_NAME_CLASH;
449 }
450 /* next */
451 pCur = pCur->pNext;
452 }
453
454 /*
455 * Find the file if not specified.
456 */
457 char *pszFile = NULL;
458 if (!pszFilename)
459 pszFilename = pszFile = pdmR3FileRC(pszName);
460
461 /*
462 * Allocate the module list node.
463 */
464 PPDMMOD pModule = (PPDMMOD)RTMemAllocZ(sizeof(*pModule) + strlen(pszFilename));
465 if (!pModule)
466 {
467 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
468 RTMemTmpFree(pszFile);
469 return VERR_NO_MEMORY;
470 }
471 AssertMsg(strlen(pszName) + 1 < sizeof(pModule->szName),
472 ("pazName is too long (%d chars) max is %d chars.\n", strlen(pszName), sizeof(pModule->szName) - 1));
473 strcpy(pModule->szName, pszName);
474 pModule->eType = PDMMOD_TYPE_RC;
475 strcpy(pModule->szFilename, pszFilename);
476
477
478 /*
479 * Open the loader item.
480 */
481 int rc = SUPR3HardenedVerifyFile(pszFilename, "PDMR3LdrLoadRC", NULL);
482 if (RT_SUCCESS(rc))
483 rc = RTLdrOpen(pszFilename, 0, RTLDRARCH_X86_32, &pModule->hLdrMod);
484 if (RT_SUCCESS(rc))
485 {
486 /*
487 * Allocate space in the hypervisor.
488 */
489 size_t cb = RTLdrSize(pModule->hLdrMod);
490 cb = RT_ALIGN_Z(cb, PAGE_SIZE);
491 uint32_t cPages = (uint32_t)(cb >> PAGE_SHIFT);
492 if (((size_t)cPages << PAGE_SHIFT) == cb)
493 {
494 PSUPPAGE paPages = (PSUPPAGE)RTMemTmpAlloc(cPages * sizeof(paPages[0]));
495 if (paPages)
496 {
497 rc = SUPR3PageAllocEx(cPages, 0 /*fFlags*/, &pModule->pvBits, NULL /*pR0Ptr*/, paPages);
498 if (RT_SUCCESS(rc))
499 {
500 RTGCPTR GCPtr;
501 rc = MMR3HyperMapPages(pVM, pModule->pvBits, NIL_RTR0PTR,
502 cPages, paPages, pModule->szName, &GCPtr);
503 if (RT_SUCCESS(rc))
504 {
505 MMR3HyperReserve(pVM, PAGE_SIZE, "fence", NULL);
506
507 /*
508 * Get relocated image bits.
509 */
510 Assert(MMHyperR3ToRC(pVM, pModule->pvBits) == GCPtr);
511 pModule->ImageBase = GCPtr;
512 PDMGETIMPORTARGS Args;
513 Args.pVM = pVM;
514 Args.pModule = pModule;
515 rc = RTLdrGetBits(pModule->hLdrMod, pModule->pvBits, pModule->ImageBase, pdmR3GetImportRC, &Args);
516 if (RT_SUCCESS(rc))
517 {
518 /*
519 * Insert the module.
520 */
521 if (pUVM->pdm.s.pModules)
522 {
523 /* we don't expect this list to be very long, so rather save the tail pointer. */
524 pCur = pUVM->pdm.s.pModules;
525 while (pCur->pNext)
526 pCur = pCur->pNext;
527 pCur->pNext = pModule;
528 }
529 else
530 pUVM->pdm.s.pModules = pModule; /* (pNext is zeroed by alloc) */
531 Log(("PDM: RC Module at %RRv %s (%s)\n", (RTRCPTR)pModule->ImageBase, pszName, pszFilename));
532 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
533 RTMemTmpFree(pszFile);
534 RTMemTmpFree(paPages);
535 return VINF_SUCCESS;
536 }
537 }
538 else
539 {
540 AssertRC(rc);
541 SUPR3PageFreeEx(pModule->pvBits, cPages);
542 }
543 }
544 else
545 AssertMsgFailed(("SUPR3PageAlloc(%d,) -> %Rrc\n", cPages, rc));
546 RTMemTmpFree(paPages);
547 }
548 else
549 rc = VERR_NO_TMP_MEMORY;
550 }
551 else
552 rc = VERR_OUT_OF_RANGE;
553 int rc2 = RTLdrClose(pModule->hLdrMod);
554 AssertRC(rc2);
555 }
556 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
557
558 /* Don't consider VERR_PDM_MODULE_NAME_CLASH and VERR_NO_MEMORY above as these are very unlikely. */
559 if (RT_FAILURE(rc))
560 rc = VMSetError(pVM, rc, RT_SRC_POS, N_("Cannot load GC module %s"), pszFilename);
561
562 RTMemFree(pModule);
563 RTMemTmpFree(pszFile);
564 return rc;
565}
566#endif /* VBOX_WITH_RAW_MODE */
567
568
569/**
570 * Loads a module into the ring-0 context.
571 *
572 * @returns VBox status code.
573 * @param pUVM Pointer to the user mode VM structure.
574 * @param pszFilename Filename of the module binary.
575 * @param pszName Module name. Case sensitive and the length is limited!
576 */
577static int pdmR3LoadR0U(PUVM pUVM, const char *pszFilename, const char *pszName)
578{
579 /*
580 * Validate input.
581 */
582 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
583 PPDMMOD pCur = pUVM->pdm.s.pModules;
584 while (pCur)
585 {
586 if (!strcmp(pCur->szName, pszName))
587 {
588 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
589 AssertMsgFailed(("We've already got a module '%s' loaded!\n", pszName));
590 return VERR_PDM_MODULE_NAME_CLASH;
591 }
592 /* next */
593 pCur = pCur->pNext;
594 }
595
596 /*
597 * Find the file if not specified.
598 */
599 char *pszFile = NULL;
600 if (!pszFilename)
601 pszFilename = pszFile = pdmR3FileR0(pszName);
602
603 /*
604 * Allocate the module list node.
605 */
606 PPDMMOD pModule = (PPDMMOD)RTMemAllocZ(sizeof(*pModule) + strlen(pszFilename));
607 if (!pModule)
608 {
609 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
610 RTMemTmpFree(pszFile);
611 return VERR_NO_MEMORY;
612 }
613 AssertMsg(strlen(pszName) + 1 < sizeof(pModule->szName),
614 ("pazName is too long (%d chars) max is %d chars.\n", strlen(pszName), sizeof(pModule->szName) - 1));
615 strcpy(pModule->szName, pszName);
616 pModule->eType = PDMMOD_TYPE_R0;
617 strcpy(pModule->szFilename, pszFilename);
618
619 /*
620 * Ask the support library to load it.
621 */
622 void *pvImageBase;
623 int rc = SUPR3LoadModule(pszFilename, pszName, &pvImageBase);
624 if (RT_SUCCESS(rc))
625 {
626 pModule->hLdrMod = NIL_RTLDRMOD;
627 pModule->ImageBase = (uintptr_t)pvImageBase;
628
629 /*
630 * Insert the module.
631 */
632 if (pUVM->pdm.s.pModules)
633 {
634 /* we don't expect this list to be very long, so rather save the tail pointer. */
635 pCur = pUVM->pdm.s.pModules;
636 while (pCur->pNext)
637 pCur = pCur->pNext;
638 pCur->pNext = pModule;
639 }
640 else
641 pUVM->pdm.s.pModules = pModule; /* (pNext is zeroed by alloc) */
642 Log(("PDM: R0 Module at %RHv %s (%s)\n", (RTR0PTR)pModule->ImageBase, pszName, pszFilename));
643 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
644 RTMemTmpFree(pszFile);
645 return VINF_SUCCESS;
646 }
647
648 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
649 RTMemFree(pModule);
650 LogRel(("pdmR3LoadR0U: pszName=\"%s\" rc=%Rrc\n", pszName, rc));
651
652 /* Don't consider VERR_PDM_MODULE_NAME_CLASH and VERR_NO_MEMORY above as these are very unlikely. */
653 if (RT_FAILURE(rc) && pUVM->pVM) /** @todo VMR3SetErrorU. */
654 rc = VMSetError(pUVM->pVM, rc, RT_SRC_POS, N_("Cannot load R0 module %s"), pszFilename);
655
656 RTMemTmpFree(pszFile); /* might be reference thru pszFilename in the above VMSetError call. */
657 return rc;
658}
659
660
661
662/**
663 * Get the address of a symbol in a given HC ring 3 module.
664 *
665 * @returns VBox status code.
666 * @param pVM VM handle.
667 * @param pszModule Module name.
668 * @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
669 * ordinal value rather than a string pointer.
670 * @param ppvValue Where to store the symbol value.
671 */
672VMMR3DECL(int) PDMR3LdrGetSymbolR3(PVM pVM, const char *pszModule, const char *pszSymbol, void **ppvValue)
673{
674 /*
675 * Validate input.
676 */
677 AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
678
679 /*
680 * Find the module.
681 */
682 PUVM pUVM = pVM->pUVM;
683 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
684 for (PPDMMOD pModule = pUVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
685 {
686 if ( pModule->eType == PDMMOD_TYPE_R3
687 && !strcmp(pModule->szName, pszModule))
688 {
689 RTUINTPTR Value = 0;
690 int rc = RTLdrGetSymbolEx(pModule->hLdrMod, pModule->pvBits, pModule->ImageBase, pszSymbol, &Value);
691 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
692 if (RT_SUCCESS(rc))
693 {
694 *ppvValue = (void *)(uintptr_t)Value;
695 Assert((uintptr_t)*ppvValue == Value);
696 }
697 else
698 {
699 if ((uintptr_t)pszSymbol < 0x10000)
700 AssertMsg(rc, ("Couldn't symbol '%u' in module '%s'\n", (unsigned)(uintptr_t)pszSymbol, pszModule));
701 else
702 AssertMsg(rc, ("Couldn't symbol '%s' in module '%s'\n", pszSymbol, pszModule));
703 }
704 return rc;
705 }
706 }
707 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
708 AssertMsgFailed(("Couldn't locate module '%s'\n", pszModule));
709 return VERR_SYMBOL_NOT_FOUND;
710}
711
712
713/**
714 * Get the address of a symbol in a given HC ring 0 module.
715 *
716 * @returns VBox status code.
717 * @param pVM VM handle.
718 * @param pszModule Module name. If NULL the main R0 module (VMMR0.r0) is assumes.
719 * @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
720 * ordinal value rather than a string pointer.
721 * @param ppvValue Where to store the symbol value.
722 */
723VMMR3DECL(int) PDMR3LdrGetSymbolR0(PVM pVM, const char *pszModule, const char *pszSymbol, PRTR0PTR ppvValue)
724{
725#ifdef PDMLDR_FAKE_MODE
726 *ppvValue = 0xdeadbeef;
727 return VINF_SUCCESS;
728
729#else
730 /*
731 * Validate input.
732 */
733 AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
734 if (!pszModule)
735 pszModule = "VMMR0.r0";
736
737 /*
738 * Find the module.
739 */
740 PUVM pUVM = pVM->pUVM;
741 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
742 for (PPDMMOD pModule = pUVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
743 {
744 if ( pModule->eType == PDMMOD_TYPE_R0
745 && !strcmp(pModule->szName, pszModule))
746 {
747 int rc = SUPR3GetSymbolR0((void *)(uintptr_t)pModule->ImageBase, pszSymbol, (void **)ppvValue);
748 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
749 if (RT_FAILURE(rc))
750 {
751 AssertMsgRC(rc, ("Couldn't find symbol '%s' in module '%s'\n", pszSymbol, pszModule));
752 LogRel(("PDMGetSymbol: Couldn't find symbol '%s' in module '%s'\n", pszSymbol, pszModule));
753 }
754 return rc;
755 }
756 }
757 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
758 AssertMsgFailed(("Couldn't locate module '%s'\n", pszModule));
759 return VERR_SYMBOL_NOT_FOUND;
760#endif
761}
762
763
764/**
765 * Same as PDMR3LdrGetSymbolR0 except that the module will be attempted loaded if not found.
766 *
767 * @returns VBox status code.
768 * @param pVM VM handle.
769 * @param pszModule Module name. If NULL the main R0 module (VMMR0.r0) is assumed.
770 * @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
771 * ordinal value rather than a string pointer.
772 * @param ppvValue Where to store the symbol value.
773 */
774VMMR3DECL(int) PDMR3LdrGetSymbolR0Lazy(PVM pVM, const char *pszModule, const char *pszSymbol, PRTR0PTR ppvValue)
775{
776#ifdef PDMLDR_FAKE_MODE
777 *ppvValue = 0xdeadbeef;
778 return VINF_SUCCESS;
779
780#else
781 /*
782 * Since we're lazy, we'll only check if the module is present
783 * and hand it over to PDMR3LdrGetSymbolR0 when that's done.
784 */
785 AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
786 if (pszModule)
787 {
788 AssertMsgReturn(!strpbrk(pszModule, "/\\:\n\r\t"), ("pszModule=%s\n", pszModule), VERR_INVALID_PARAMETER);
789 PUVM pUVM = pVM->pUVM;
790 PPDMMOD pModule;
791 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
792 for (pModule = pUVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
793 if ( pModule->eType == PDMMOD_TYPE_R0
794 && !strcmp(pModule->szName, pszModule))
795 break;
796 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
797 if (!pModule)
798 {
799 int rc = pdmR3LoadR0U(pUVM, NULL, pszModule);
800 AssertMsgRCReturn(rc, ("pszModule=%s rc=%Rrc\n", pszModule, rc), VERR_MODULE_NOT_FOUND);
801 }
802 }
803 return PDMR3LdrGetSymbolR0(pVM, pszModule, pszSymbol, ppvValue);
804#endif
805}
806
807
808/**
809 * Get the address of a symbol in a given RC module.
810 *
811 * @returns VBox status code.
812 * @param pVM VM handle.
813 * @param pszModule Module name. If NULL the main R0 module (VMMGC.gc) is assumes.
814 * @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
815 * ordinal value rather than a string pointer.
816 * @param pRCPtrValue Where to store the symbol value.
817 */
818VMMR3DECL(int) PDMR3LdrGetSymbolRC(PVM pVM, const char *pszModule, const char *pszSymbol, PRTRCPTR pRCPtrValue)
819{
820#if defined(PDMLDR_FAKE_MODE) || !defined(VBOX_WITH_RAW_MODE)
821 *pRCPtrValue = 0xfeedf00d;
822 return VINF_SUCCESS;
823
824#else
825 /*
826 * Validate input.
827 */
828 AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
829 if (!pszModule)
830 pszModule = "VMMGC.gc";
831
832 /*
833 * Find the module.
834 */
835 PUVM pUVM = pVM->pUVM;
836 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
837 for (PPDMMOD pModule = pUVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
838 {
839 if ( pModule->eType == PDMMOD_TYPE_RC
840 && !strcmp(pModule->szName, pszModule))
841 {
842 RTUINTPTR Value;
843 int rc = RTLdrGetSymbolEx(pModule->hLdrMod, pModule->pvBits, pModule->ImageBase, pszSymbol, &Value);
844 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
845 if (RT_SUCCESS(rc))
846 {
847 *pRCPtrValue = (RTGCPTR)Value;
848 Assert(*pRCPtrValue == Value);
849 }
850 else
851 {
852 if ((uintptr_t)pszSymbol < 0x10000)
853 AssertMsg(rc, ("Couldn't symbol '%u' in module '%s'\n", (unsigned)(uintptr_t)pszSymbol, pszModule));
854 else
855 AssertMsg(rc, ("Couldn't symbol '%s' in module '%s'\n", pszSymbol, pszModule));
856 }
857 return rc;
858 }
859 }
860 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
861 AssertMsgFailed(("Couldn't locate module '%s'\n", pszModule));
862 return VERR_SYMBOL_NOT_FOUND;
863#endif
864}
865
866
867/**
868 * Same as PDMR3LdrGetSymbolRC except that the module will be attempted loaded if not found.
869 *
870 * @returns VBox status code.
871 * @param pVM VM handle.
872 * @param pszModule Module name. If NULL the main R0 module (VMMGC.gc) is assumes.
873 * @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
874 * ordinal value rather than a string pointer.
875 * @param pRCPtrValue Where to store the symbol value.
876 */
877VMMR3DECL(int) PDMR3LdrGetSymbolRCLazy(PVM pVM, const char *pszModule, const char *pszSymbol, PRTRCPTR pRCPtrValue)
878{
879#if defined(PDMLDR_FAKE_MODE) || !defined(VBOX_WITH_RAW_MODE)
880 *pRCPtrValue = 0xfeedf00d;
881 return VINF_SUCCESS;
882
883#else
884 /*
885 * Since we're lazy, we'll only check if the module is present
886 * and hand it over to PDMR3LdrGetSymbolRC when that's done.
887 */
888 AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
889 if (pszModule)
890 {
891 AssertMsgReturn(!strpbrk(pszModule, "/\\:\n\r\t"), ("pszModule=%s\n", pszModule), VERR_INVALID_PARAMETER);
892 PUVM pUVM = pVM->pUVM;
893 PPDMMOD pModule;
894 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
895 for (pModule = pUVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
896 if ( pModule->eType == PDMMOD_TYPE_RC
897 && !strcmp(pModule->szName, pszModule))
898 break;
899 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
900 if (!pModule)
901 {
902 char *pszFilename = pdmR3FileRC(pszModule);
903 AssertMsgReturn(pszFilename, ("pszModule=%s\n", pszModule), VERR_MODULE_NOT_FOUND);
904 int rc = PDMR3LdrLoadRC(pVM, pszFilename, pszModule);
905 RTMemTmpFree(pszFilename);
906 AssertMsgRCReturn(rc, ("pszModule=%s rc=%Rrc\n", pszModule, rc), VERR_MODULE_NOT_FOUND);
907 }
908 }
909 return PDMR3LdrGetSymbolRC(pVM, pszModule, pszSymbol, pRCPtrValue);
910#endif
911}
912
913
914/**
915 * Constructs the full filename for a R3 image file.
916 *
917 * @returns Pointer to temporary memory containing the filename.
918 * Caller must free this using RTMemTmpFree().
919 * @returns NULL on failure.
920 *
921 * @param pszFile File name (no path).
922 */
923char *pdmR3FileR3(const char *pszFile, bool fShared)
924{
925 return pdmR3File(pszFile, NULL, fShared);
926}
927
928
929/**
930 * Constructs the full filename for a R0 image file.
931 *
932 * @returns Pointer to temporary memory containing the filename.
933 * Caller must free this using RTMemTmpFree().
934 * @returns NULL on failure.
935 *
936 * @param pszFile File name (no path).
937 */
938char *pdmR3FileR0(const char *pszFile)
939{
940 return pdmR3File(pszFile, NULL, /*fShared=*/false);
941}
942
943
944/**
945 * Constructs the full filename for a RC image file.
946 *
947 * @returns Pointer to temporary memory containing the filename.
948 * Caller must free this using RTMemTmpFree().
949 * @returns NULL on failure.
950 *
951 * @param pszFile File name (no path).
952 */
953char *pdmR3FileRC(const char *pszFile)
954{
955 return pdmR3File(pszFile, NULL, /*fShared=*/false);
956}
957
958
959/**
960 * Worker for pdmR3File().
961 *
962 * @returns Pointer to temporary memory containing the filename.
963 * Caller must free this using RTMemTmpFree().
964 * @returns NULL on failure.
965 *
966 * @param pszDir Directory part
967 * @param pszFile File name part
968 * @param pszDefaultExt Extension part
969 */
970static char *pdmR3FileConstruct(const char *pszDir, const char *pszFile, const char *pszDefaultExt)
971{
972 /*
973 * Allocate temp memory for return buffer.
974 */
975 size_t cchDir = strlen(pszDir);
976 size_t cchFile = strlen(pszFile);
977 size_t cchDefaultExt;
978
979 /*
980 * Default extention?
981 */
982 if (!pszDefaultExt || strchr(pszFile, '.'))
983 cchDefaultExt = 0;
984 else
985 cchDefaultExt = strlen(pszDefaultExt);
986
987 size_t cchPath = cchDir + 1 + cchFile + cchDefaultExt + 1;
988 AssertMsgReturn(cchPath <= RTPATH_MAX, ("Path too long!\n"), NULL);
989
990 char *pszRet = (char *)RTMemTmpAlloc(cchDir + 1 + cchFile + cchDefaultExt + 1);
991 AssertMsgReturn(pszRet, ("Out of temporary memory!\n"), NULL);
992
993 /*
994 * Construct the filename.
995 */
996 memcpy(pszRet, pszDir, cchDir);
997 pszRet[cchDir++] = '/'; /* this works everywhere */
998 memcpy(pszRet + cchDir, pszFile, cchFile + 1);
999 if (cchDefaultExt)
1000 memcpy(pszRet + cchDir + cchFile, pszDefaultExt, cchDefaultExt + 1);
1001
1002 return pszRet;
1003}
1004
1005
1006/**
1007 * Worker for pdmR3FileRC(), pdmR3FileR0() and pdmR3FileR3().
1008 *
1009 * @returns Pointer to temporary memory containing the filename.
1010 * Caller must free this using RTMemTmpFree().
1011 * @returns NULL on failure.
1012 * @param pszFile File name (no path).
1013 * @param pszDefaultExt The default extention, NULL if none.
1014 * @param fShared If true, search in the shared directory (/usr/lib on Unix), else
1015 * search in the private directory (/usr/lib/virtualbox on Unix).
1016 * Ignored if VBOX_PATH_SHARED_LIBS is not defined.
1017 * @todo We'll have this elsewhere than in the root later!
1018 * @todo Remove the fShared hack again once we don't need to link against VBoxDD anymore!
1019 */
1020static char *pdmR3File(const char *pszFile, const char *pszDefaultExt, bool fShared)
1021{
1022 char szPath[RTPATH_MAX];
1023 int rc;
1024
1025 rc = fShared ? RTPathSharedLibs(szPath, sizeof(szPath))
1026 : RTPathAppPrivateArch(szPath, sizeof(szPath));
1027 if (!RT_SUCCESS(rc))
1028 {
1029 AssertMsgFailed(("RTPath[SharedLibs|AppPrivateArch](,%d) failed rc=%d!\n", sizeof(szPath), rc));
1030 return NULL;
1031 }
1032
1033 return pdmR3FileConstruct(szPath, pszFile, pszDefaultExt);
1034}
1035
1036
1037/** @internal */
1038typedef struct QMFEIPARG
1039{
1040 RTRCUINTPTR uPC;
1041
1042 char *pszNearSym1;
1043 size_t cchNearSym1;
1044 RTRCINTPTR offNearSym1;
1045
1046 char *pszNearSym2;
1047 size_t cchNearSym2;
1048 RTRCINTPTR offNearSym2;
1049} QMFEIPARG, *PQMFEIPARG;
1050
1051/**
1052 * Queries module information from an PC (eip/rip).
1053 *
1054 * This is typically used to locate a crash address.
1055 *
1056 * @returns VBox status code.
1057 *
1058 * @param pVM VM handle
1059 * @param uPC The program counter (eip/rip) to locate the module for.
1060 * @param pszModName Where to store the module name.
1061 * @param cchModName Size of the module name buffer.
1062 * @param pMod Base address of the module.
1063 * @param pszNearSym1 Name of the closes symbol from below.
1064 * @param cchNearSym1 Size of the buffer pointed to by pszNearSym1.
1065 * @param pNearSym1 The address of pszNearSym1.
1066 * @param pszNearSym2 Name of the closes symbol from below.
1067 * @param cchNearSym2 Size of the buffer pointed to by pszNearSym2.
1068 * @param pNearSym2 The address of pszNearSym2.
1069 */
1070VMMR3DECL(int) PDMR3LdrQueryRCModFromPC(PVM pVM, RTRCPTR uPC,
1071 char *pszModName, size_t cchModName, PRTRCPTR pMod,
1072 char *pszNearSym1, size_t cchNearSym1, PRTRCPTR pNearSym1,
1073 char *pszNearSym2, size_t cchNearSym2, PRTRCPTR pNearSym2)
1074{
1075 PUVM pUVM = pVM->pUVM;
1076 int rc = VERR_MODULE_NOT_FOUND;
1077 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
1078 for (PPDMMOD pCur= pUVM->pdm.s.pModules; pCur; pCur = pCur->pNext)
1079 {
1080 /* Skip anything which isn't in GC. */
1081 if (pCur->eType != PDMMOD_TYPE_RC)
1082 continue;
1083 if (uPC - pCur->ImageBase < RTLdrSize(pCur->hLdrMod))
1084 {
1085 if (pMod)
1086 *pMod = pCur->ImageBase;
1087 if (pszModName && cchModName)
1088 {
1089 *pszModName = '\0';
1090 strncat(pszModName, pCur->szName, cchModName);
1091 }
1092 if (pNearSym1) *pNearSym1 = 0;
1093 if (pNearSym2) *pNearSym2 = 0;
1094 if (pszNearSym1) *pszNearSym1 = '\0';
1095 if (pszNearSym2) *pszNearSym2 = '\0';
1096
1097 /*
1098 * Locate the nearest symbols.
1099 */
1100 QMFEIPARG Args;
1101 Args.uPC = uPC;
1102 Args.pszNearSym1 = pszNearSym1;
1103 Args.cchNearSym1 = cchNearSym1;
1104 Args.offNearSym1 = RTRCINTPTR_MIN;
1105 Args.pszNearSym2 = pszNearSym2;
1106 Args.cchNearSym2 = cchNearSym2;
1107 Args.offNearSym2 = RTRCINTPTR_MAX;
1108
1109 rc = RTLdrEnumSymbols(pCur->hLdrMod, RTLDR_ENUM_SYMBOL_FLAGS_ALL, pCur->pvBits, pCur->ImageBase,
1110 pdmR3QueryModFromEIPEnumSymbols, &Args);
1111 if (pNearSym1 && Args.offNearSym1 != INT_MIN)
1112 *pNearSym1 = Args.offNearSym1 + uPC;
1113 if (pNearSym2 && Args.offNearSym2 != INT_MAX)
1114 *pNearSym2 = Args.offNearSym2 + uPC;
1115
1116 rc = VINF_SUCCESS;
1117 if (pCur->eType == PDMMOD_TYPE_RC)
1118 break;
1119 }
1120
1121 }
1122 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
1123 return rc;
1124}
1125
1126
1127/**
1128 * Enumeration callback function used by RTLdrEnumSymbols().
1129 *
1130 * @returns VBox status code. Failure will stop the enumeration.
1131 * @param hLdrMod The loader module handle.
1132 * @param pszSymbol Symbol name. NULL if ordinal only.
1133 * @param uSymbol Symbol ordinal, ~0 if not used.
1134 * @param Value Symbol value.
1135 * @param pvUser The user argument specified to RTLdrEnumSymbols().
1136 */
1137static DECLCALLBACK(int) pdmR3QueryModFromEIPEnumSymbols(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser)
1138{
1139 PQMFEIPARG pArgs = (PQMFEIPARG)pvUser;
1140
1141 RTINTPTR off = Value - pArgs->uPC;
1142 if (off <= 0) /* near1 is before or at same location. */
1143 {
1144 if (off > pArgs->offNearSym1)
1145 {
1146 pArgs->offNearSym1 = off;
1147 if (pArgs->pszNearSym1 && pArgs->cchNearSym1)
1148 {
1149 *pArgs->pszNearSym1 = '\0';
1150 if (pszSymbol)
1151 strncat(pArgs->pszNearSym1, pszSymbol, pArgs->cchNearSym1);
1152 else
1153 {
1154 char szOrd[32];
1155 RTStrPrintf(szOrd, sizeof(szOrd), "#%#x", uSymbol);
1156 strncat(pArgs->pszNearSym1, szOrd, pArgs->cchNearSym1);
1157 }
1158 }
1159 }
1160 }
1161 else /* near2 is after */
1162 {
1163 if (off < pArgs->offNearSym2)
1164 {
1165 pArgs->offNearSym2 = off;
1166 if (pArgs->pszNearSym2 && pArgs->cchNearSym2)
1167 {
1168 *pArgs->pszNearSym2 = '\0';
1169 if (pszSymbol)
1170 strncat(pArgs->pszNearSym2, pszSymbol, pArgs->cchNearSym2);
1171 else
1172 {
1173 char szOrd[32];
1174 RTStrPrintf(szOrd, sizeof(szOrd), "#%#x", uSymbol);
1175 strncat(pArgs->pszNearSym2, szOrd, pArgs->cchNearSym2);
1176 }
1177 }
1178 }
1179 }
1180
1181 return VINF_SUCCESS;
1182}
1183
1184
1185/**
1186 * Enumerate all PDM modules.
1187 *
1188 * @returns VBox status.
1189 * @param pVM VM Handle.
1190 * @param pfnCallback Function to call back for each of the modules.
1191 * @param pvArg User argument.
1192 */
1193VMMR3DECL(int) PDMR3LdrEnumModules(PVM pVM, PFNPDMR3ENUM pfnCallback, void *pvArg)
1194{
1195 PUVM pUVM = pVM->pUVM;
1196 int rc = VINF_SUCCESS;
1197 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
1198 for (PPDMMOD pCur = pUVM->pdm.s.pModules; pCur; pCur = pCur->pNext)
1199 {
1200 rc = pfnCallback(pVM,
1201 pCur->szFilename,
1202 pCur->szName,
1203 pCur->ImageBase,
1204 pCur->eType == PDMMOD_TYPE_RC ? RTLdrSize(pCur->hLdrMod) : 0,
1205 pCur->eType == PDMMOD_TYPE_RC,
1206 pvArg);
1207 if (RT_FAILURE(rc))
1208 break;
1209 }
1210 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
1211 return rc;
1212}
1213
1214
1215/**
1216 * Locates a module.
1217 *
1218 * @returns Pointer to the module if found.
1219 * @param pUVM Pointer to the user mode VM structure.
1220 * @param pszModule The module name.
1221 * @param enmType The module type.
1222 * @param fLazy Lazy loading the module if set.
1223 */
1224static PPDMMOD pdmR3LdrFindModule(PUVM pUVM, const char *pszModule, PDMMODTYPE enmType, bool fLazy)
1225{
1226 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
1227 for (PPDMMOD pModule = pUVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
1228 if ( pModule->eType == enmType
1229 && !strcmp(pModule->szName, pszModule))
1230 {
1231 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
1232 return pModule;
1233 }
1234 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
1235 if (fLazy)
1236 {
1237 switch (enmType)
1238 {
1239#ifdef VBOX_WITH_RAW_MODE
1240 case PDMMOD_TYPE_RC:
1241 {
1242 char *pszFilename = pdmR3FileRC(pszModule);
1243 if (pszFilename)
1244 {
1245 int rc = PDMR3LdrLoadRC(pUVM->pVM, pszFilename, pszModule);
1246 RTMemTmpFree(pszFilename);
1247 if (RT_SUCCESS(rc))
1248 return pdmR3LdrFindModule(pUVM, pszModule, enmType, false);
1249 }
1250 break;
1251 }
1252#endif
1253
1254 case PDMMOD_TYPE_R0:
1255 {
1256 int rc = pdmR3LoadR0U(pUVM, NULL, pszModule);
1257 if (RT_SUCCESS(rc))
1258 return pdmR3LdrFindModule(pUVM, pszModule, enmType, false);
1259 break;
1260 }
1261
1262 default:
1263 AssertFailed();
1264 }
1265 }
1266 return NULL;
1267}
1268
1269
1270/**
1271 * Resolves a ring-0 or raw-mode context interface.
1272 *
1273 * @returns VBox status code.
1274 * @param pVM The VM handle.
1275 * @param pvInterface Pointer to the interface structure. The symbol list
1276 * describes the layout.
1277 * @param cbInterface The size of the structure pvInterface is pointing
1278 * to. For bounds checking.
1279 * @param pszModule The module name. If NULL we assume it's the default
1280 * R0 or RC module (@a fRing0OrRC). We'll attempt to
1281 * load the module if it isn't found in the module
1282 * list.
1283 * @param pszSymPrefix What to prefix the symbols in the list with. The
1284 * idea is that you define a list that goes with an
1285 * interface (INTERFACE_SYM_LIST) and reuse it with
1286 * each implementation.
1287 * @param pszSymList The symbol list for the interface. This is a
1288 * semi-colon separated list of symbol base names. As
1289 * mentioned above, each is prefixed with @a
1290 * pszSymPrefix before resolving. There are a couple
1291 * of special symbol names that will cause us to skip
1292 * ahead a little bit:
1293 * - U8:whatever,
1294 * - U16:whatever,
1295 * - U32:whatever,
1296 * - U64:whatever,
1297 * - RCPTR:whatever,
1298 * - R3PTR:whatever,
1299 * - R0PTR:whatever,
1300 * - GCPHYS:whatever,
1301 * - HCPHYS:whatever.
1302 * @param fRing0 Set if it's a ring-0 context interface, clear if
1303 * it's raw-mode context interface.
1304 */
1305VMMR3DECL(int) PDMR3LdrGetInterfaceSymbols(PVM pVM, void *pvInterface, size_t cbInterface,
1306 const char *pszModule, const char *pszSymPrefix,
1307 const char *pszSymList, bool fRing0)
1308{
1309 /*
1310 * Find the module.
1311 */
1312 int rc = VINF_SUCCESS;
1313 PPDMMOD pModule = pdmR3LdrFindModule(pVM->pUVM,
1314 pszModule ? pszModule : fRing0 ? "VMMR0.r0" : "VMMGC.gc",
1315 fRing0 ? PDMMOD_TYPE_R0 : PDMMOD_TYPE_RC,
1316 true /*fLazy*/);
1317 if (pModule)
1318 {
1319 /* Prep the symbol name. */
1320 char szSymbol[256];
1321 size_t const cchSymPrefix = strlen(pszSymPrefix);
1322 AssertReturn(cchSymPrefix + 5 < sizeof(szSymbol), VERR_SYMBOL_NOT_FOUND);
1323 memcpy(szSymbol, pszSymPrefix, cchSymPrefix);
1324
1325 /*
1326 * Iterate the symbol list.
1327 */
1328 uint32_t offInterface = 0;
1329 const char *pszCur = pszSymList;
1330 while (pszCur)
1331 {
1332 /*
1333 * Find the end of the current symbol name.
1334 */
1335 size_t cchSym;
1336 const char *pszNext = strchr(pszCur, ';');
1337 if (pszNext)
1338 {
1339 cchSym = pszNext - pszCur;
1340 pszNext++;
1341 }
1342 else
1343 cchSym = strlen(pszCur);
1344 AssertBreakStmt(cchSym > 0, rc = VERR_INVALID_PARAMETER);
1345
1346 /* Is it a skip instruction? */
1347 const char *pszColon = (const char *)memchr(pszCur, ':', cchSym);
1348 if (pszColon)
1349 {
1350 /*
1351 * String switch on the instruction and execute it, checking
1352 * that we didn't overshoot the interface structure.
1353 */
1354#define IS_SKIP_INSTR(szInstr) \
1355 ( cchSkip == sizeof(szInstr) - 1 \
1356 && !memcmp(pszCur, szInstr, sizeof(szInstr) - 1) )
1357
1358 size_t const cchSkip = pszColon - pszCur;
1359 if (IS_SKIP_INSTR("U8"))
1360 offInterface += sizeof(uint8_t);
1361 else if (IS_SKIP_INSTR("U16"))
1362 offInterface += sizeof(uint16_t);
1363 else if (IS_SKIP_INSTR("U32"))
1364 offInterface += sizeof(uint32_t);
1365 else if (IS_SKIP_INSTR("U64"))
1366 offInterface += sizeof(uint64_t);
1367 else if (IS_SKIP_INSTR("RCPTR"))
1368 offInterface += sizeof(RTRCPTR);
1369 else if (IS_SKIP_INSTR("R3PTR"))
1370 offInterface += sizeof(RTR3PTR);
1371 else if (IS_SKIP_INSTR("R0PTR"))
1372 offInterface += sizeof(RTR0PTR);
1373 else if (IS_SKIP_INSTR("HCPHYS"))
1374 offInterface += sizeof(RTHCPHYS);
1375 else if (IS_SKIP_INSTR("GCPHYS"))
1376 offInterface += sizeof(RTGCPHYS);
1377 else
1378 AssertMsgFailedBreakStmt(("Invalid skip instruction %.*s (prefix=%s)\n", cchSym, pszCur, pszSymPrefix),
1379 rc = VERR_INVALID_PARAMETER);
1380 AssertMsgBreakStmt(offInterface <= cbInterface,
1381 ("off=%#x cb=%#x (sym=%.*s prefix=%s)\n", offInterface, cbInterface, cchSym, pszCur, pszSymPrefix),
1382 rc = VERR_BUFFER_OVERFLOW);
1383#undef IS_SKIP_INSTR
1384 }
1385 else
1386 {
1387 /*
1388 * Construct the symbol name, get its value, store it and
1389 * advance the interface cursor.
1390 */
1391 AssertReturn(cchSymPrefix + cchSym < sizeof(szSymbol), VERR_SYMBOL_NOT_FOUND);
1392 memcpy(&szSymbol[cchSymPrefix], pszCur, cchSym);
1393 szSymbol[cchSymPrefix + cchSym] = '\0';
1394
1395 if (fRing0)
1396 {
1397 void *pvValue;
1398 rc = SUPR3GetSymbolR0((void *)(RTR0PTR)pModule->ImageBase, szSymbol, &pvValue);
1399 AssertMsgRCBreak(rc, ("Couldn't find symbol '%s' in module '%s'\n", szSymbol, pModule->szName));
1400
1401 PRTR0PTR pValue = (PRTR0PTR)((uintptr_t)pvInterface + offInterface);
1402 AssertMsgBreakStmt(offInterface + sizeof(*pValue) <= cbInterface,
1403 ("off=%#x cb=%#x sym=%s\n", offInterface, cbInterface, szSymbol),
1404 rc = VERR_BUFFER_OVERFLOW);
1405 *pValue = (RTR0PTR)pvValue;
1406 Assert((void *)*pValue == pvValue);
1407 offInterface += sizeof(*pValue);
1408 }
1409 else
1410 {
1411 RTUINTPTR Value;
1412 rc = RTLdrGetSymbolEx(pModule->hLdrMod, pModule->pvBits, pModule->ImageBase, szSymbol, &Value);
1413 AssertMsgRCBreak(rc, ("Couldn't find symbol '%s' in module '%s'\n", szSymbol, pModule->szName));
1414
1415 PRTRCPTR pValue = (PRTRCPTR)((uintptr_t)pvInterface + offInterface);
1416 AssertMsgBreakStmt(offInterface + sizeof(*pValue) <= cbInterface,
1417 ("off=%#x cb=%#x sym=%s\n", offInterface, cbInterface, szSymbol),
1418 rc = VERR_BUFFER_OVERFLOW);
1419 *pValue = (RTRCPTR)Value;
1420 Assert(*pValue == Value);
1421 offInterface += sizeof(*pValue);
1422 }
1423 }
1424
1425 /* advance */
1426 pszCur = pszNext;
1427 }
1428
1429 }
1430 else
1431 rc = VERR_MODULE_NOT_FOUND;
1432 return rc;
1433}
1434
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