VirtualBox

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

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

Fixed raw mode regression caused by r57572

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