VirtualBox

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

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

PDM: Moving more stuff to PDMUSERPERVM. Protect the loader list using ListCritSect.

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