VirtualBox

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

Last change on this file since 38791 was 37443, checked in by vboxsync, 13 years ago

PDM: Implemented the NOP critical section.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 58.5 KB
Line 
1/* $Id: PDMLdr.cpp 37443 2011-06-14 14:34:11Z vboxsync $ */
2/** @file
3 * PDM - Pluggable Device Manager, module loader.
4 */
5
6/*
7 * Copyright (C) 2006-2011 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/vmm/pdm.h>
26#include <VBox/vmm/mm.h>
27#include <VBox/vmm/vmm.h>
28#include <VBox/vmm/vm.h>
29#include <VBox/vmm/uvm.h>
30#include <VBox/sup.h>
31#include <VBox/param.h>
32#include <VBox/err.h>
33#include <VBox/vmm/hwaccm.h>
34
35#include <VBox/log.h>
36#include <iprt/assert.h>
37#include <iprt/ctype.h>
38#include <iprt/file.h>
39#include <iprt/ldr.h>
40#include <iprt/mem.h>
41#include <iprt/path.h>
42#include <iprt/string.h>
43
44#include <limits.h>
45
46
47/*******************************************************************************
48* Structures and Typedefs *
49*******************************************************************************/
50/**
51 * Structure which the user argument of the RTLdrGetBits() callback points to.
52 * @internal
53 */
54typedef struct PDMGETIMPORTARGS
55{
56 PVM pVM;
57 PPDMMOD pModule;
58} PDMGETIMPORTARGS, *PPDMGETIMPORTARGS;
59
60
61/*******************************************************************************
62* Internal Functions *
63*******************************************************************************/
64static DECLCALLBACK(int) pdmR3GetImportRC(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol, unsigned uSymbol, RTUINTPTR *pValue, void *pvUser);
65static int pdmR3LoadR0U(PUVM pUVM, const char *pszFilename, const char *pszName, const char *pszSearchPath);
66static char *pdmR3FileRC(const char *pszFile, const char *pszSearchPath);
67static char *pdmR3FileR0(const char *pszFile, const char *pszSearchPath);
68static char *pdmR3File(const char *pszFile, const char *pszDefaultExt, const char *pszSearchPath, bool fShared);
69
70
71
72/**
73 * Loads the VMMR0.r0 module early in the init process.
74 *
75 * @returns VBox status code.
76 * @param pUVM Pointer to the user mode VM structure.
77 */
78VMMR3DECL(int) PDMR3LdrLoadVMMR0U(PUVM pUVM)
79{
80 return pdmR3LoadR0U(pUVM, NULL, VMMR0_MAIN_MODULE_NAME, NULL);
81}
82
83
84/**
85 * Init the module loader part of PDM.
86 *
87 * This routine will load the Host Context Ring-0 and Guest
88 * Context VMM modules.
89 *
90 * @returns VBox status code.
91 * @param pUVM Pointer to the user mode VM structure.
92 * @param pvVMMR0Mod The opaque returned by PDMR3LdrLoadVMMR0.
93 */
94int pdmR3LdrInitU(PUVM pUVM)
95{
96#if defined(PDMLDR_FAKE_MODE) || !defined(VBOX_WITH_RAW_MODE)
97 return VINF_SUCCESS;
98
99#else
100
101 /*
102 * Load the mandatory GC module, the VMMR0.r0 is loaded before VM creation.
103 */
104 return PDMR3LdrLoadRC(pUVM->pVM, NULL, VMMGC_MAIN_MODULE_NAME);
105#endif
106}
107
108
109/**
110 * Terminate the module loader part of PDM.
111 *
112 * This will unload and free all modules.
113 *
114 * @param pVM The VM handle.
115 *
116 * @remarks This is normally called twice during termination.
117 */
118void pdmR3LdrTermU(PUVM pUVM)
119{
120 /*
121 * Free the modules.
122 */
123 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
124 PPDMMOD pModule = pUVM->pdm.s.pModules;
125 pUVM->pdm.s.pModules = NULL;
126 while (pModule)
127 {
128 /* free loader item. */
129 if (pModule->hLdrMod != NIL_RTLDRMOD)
130 {
131 int rc2 = RTLdrClose(pModule->hLdrMod);
132 AssertRC(rc2);
133 pModule->hLdrMod = NIL_RTLDRMOD;
134 }
135
136 /* free bits. */
137 switch (pModule->eType)
138 {
139 case PDMMOD_TYPE_R0:
140 {
141 Assert(pModule->ImageBase);
142 int rc2 = SUPR3FreeModule((void *)(uintptr_t)pModule->ImageBase);
143 AssertRC(rc2);
144 pModule->ImageBase = 0;
145 break;
146 }
147
148#ifdef VBOX_WITH_RAW_MODE
149 case PDMMOD_TYPE_RC:
150#endif
151 case PDMMOD_TYPE_R3:
152 /* MM will free this memory for us - it's alloc only memory. :-) */
153 break;
154
155 default:
156 AssertMsgFailed(("eType=%d\n", pModule->eType));
157 break;
158 }
159 pModule->pvBits = NULL;
160
161 void *pvFree = pModule;
162 pModule = pModule->pNext;
163 RTMemFree(pvFree);
164 }
165 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
166}
167
168
169/**
170 * Applies relocations to GC modules.
171 *
172 * This must be done very early in the relocation
173 * process so that components can resolve GC symbols during relocation.
174 *
175 * @param pUVM Pointer to the user mode VM structure.
176 * @param offDelta Relocation delta relative to old location.
177 */
178VMMR3DECL(void) PDMR3LdrRelocateU(PUVM pUVM, RTGCINTPTR offDelta)
179{
180#ifdef VBOX_WITH_RAW_MODE
181 LogFlow(("PDMR3LdrRelocate: offDelta=%RGv\n", offDelta));
182
183 /*
184 * GC Modules.
185 */
186 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
187 if (pUVM->pdm.s.pModules)
188 {
189 /*
190 * The relocation have to be done in two passes so imports
191 * can be correctly 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 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
223#endif
224}
225
226
227/**
228 * Loads a module into the host context ring-3.
229 *
230 * This is used by the driver and device init functions to load modules
231 * containing the drivers and devices. The function can be extended to
232 * load modules which are not native to the environment we're running in,
233 * but at the moment this is not required.
234 *
235 * No reference counting is kept, since we don't implement any facilities
236 * for unloading the module. But the module will naturally be released
237 * when the VM terminates.
238 *
239 * @returns VBox status code.
240 * @param pUVM Pointer to the user mode VM structure.
241 * @param pszFilename Filename of the module binary.
242 * @param pszName Module name. Case sensitive and the length is limited!
243 */
244int pdmR3LoadR3U(PUVM pUVM, const char *pszFilename, const char *pszName)
245{
246 /*
247 * Validate input.
248 */
249 AssertMsg(PDMCritSectIsInitialized(&pUVM->pVM->pdm.s.CritSect), ("bad init order!\n"));
250 Assert(pszFilename);
251 size_t cchFilename = strlen(pszFilename);
252 Assert(pszName);
253 size_t cchName = strlen(pszName);
254 PPDMMOD pCur;
255 if (cchName >= sizeof(pCur->szName))
256 {
257 AssertMsgFailed(("Name is too long, cchName=%d pszName='%s'\n", cchName, pszName));
258 return VERR_INVALID_PARAMETER;
259 }
260
261 /*
262 * Try lookup the name and see if the module exists.
263 */
264 int rc;
265 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
266 for (pCur = pUVM->pdm.s.pModules; pCur; pCur = pCur->pNext)
267 {
268 if (!strcmp(pCur->szName, pszName))
269 {
270 if (pCur->eType == PDMMOD_TYPE_R3)
271 rc = VINF_PDM_ALREADY_LOADED;
272 else
273 rc = VERR_PDM_MODULE_NAME_CLASH;
274 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
275
276 AssertMsgRC(rc, ("We've already got a module '%s' loaded!\n", pszName));
277 return rc;
278 }
279 }
280
281 /*
282 * Allocate the module list node and initialize it.
283 */
284 const char *pszSuff = RTLdrGetSuff();
285 size_t cchSuff = RTPathHaveExt(pszFilename) ? 0 : strlen(pszSuff);
286 PPDMMOD pModule = (PPDMMOD)RTMemAllocZ(RT_OFFSETOF(PDMMOD, szFilename[cchFilename + cchSuff + 1]));
287 if (pModule)
288 {
289 pModule->eType = PDMMOD_TYPE_R3;
290 memcpy(pModule->szName, pszName, cchName); /* memory is zero'd, no need to copy terminator :-) */
291 memcpy(pModule->szFilename, pszFilename, cchFilename);
292 memcpy(&pModule->szFilename[cchFilename], pszSuff, cchSuff);
293
294 /*
295 * Load the loader item.
296 */
297 RTERRINFOSTATIC ErrInfo;
298 RTErrInfoInitStatic(&ErrInfo);
299 rc = SUPR3HardenedLdrLoadPlugIn(pModule->szFilename, &pModule->hLdrMod, &ErrInfo.Core);
300 if (RT_SUCCESS(rc))
301 {
302 pModule->pNext = pUVM->pdm.s.pModules;
303 pUVM->pdm.s.pModules = pModule;
304 }
305 else
306 {
307 /* Something went wrong, most likely module not found. Don't consider other unlikely errors */
308 rc = VMSetError(pUVM->pVM, rc, RT_SRC_POS,
309 N_("Unable to load R3 module %s (%s): %s"), pModule->szFilename, pszName, ErrInfo.Core.pszMsg);
310 RTMemFree(pModule);
311 }
312 }
313 else
314 rc = VERR_NO_MEMORY;
315
316 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
317 return rc;
318}
319
320
321#ifdef VBOX_WITH_RAW_MODE
322/**
323 * Resolve an external symbol during RTLdrGetBits() of a RC module.
324 *
325 * @returns VBox status code.
326 * @param hLdrMod The loader module handle.
327 * @param pszModule Module name.
328 * @param pszSymbol Symbol name, NULL if uSymbol should be used.
329 * @param uSymbol Symbol ordinal, ~0 if pszSymbol should be used.
330 * @param pValue Where to store the symbol value (address).
331 * @param pvUser User argument.
332 */
333static DECLCALLBACK(int) pdmR3GetImportRC(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol, unsigned uSymbol, RTUINTPTR *pValue, void *pvUser)
334{
335 PVM pVM = ((PPDMGETIMPORTARGS)pvUser)->pVM;
336 PPDMMOD pModule = ((PPDMGETIMPORTARGS)pvUser)->pModule;
337
338 /*
339 * Adjust input.
340 */
341 if (pszModule && !*pszModule)
342 pszModule = NULL;
343
344 /*
345 * Builtin module.
346 */
347 if (!pszModule || !strcmp(pszModule, "VMMRCBuiltin.rc"))
348 {
349 int rc = VINF_SUCCESS;
350 if (!strcmp(pszSymbol, "g_VM"))
351 *pValue = pVM->pVMRC;
352 else if (!strcmp(pszSymbol, "g_CPUM"))
353 *pValue = VM_RC_ADDR(pVM, &pVM->cpum);
354 else if (!strcmp(pszSymbol, "g_TRPM"))
355 *pValue = VM_RC_ADDR(pVM, &pVM->trpm);
356 else if (!strcmp(pszSymbol, "g_TRPMCPU"))
357 *pValue = VM_RC_ADDR(pVM, &pVM->aCpus[0].trpm);
358 else if ( !strncmp(pszSymbol, "VMM", 3)
359 || !strcmp(pszSymbol, "g_Logger")
360 || !strcmp(pszSymbol, "g_RelLogger"))
361 {
362 RTRCPTR RCPtr = 0;
363 rc = VMMR3GetImportRC(pVM, pszSymbol, &RCPtr);
364 if (RT_SUCCESS(rc))
365 *pValue = RCPtr;
366 }
367 else if ( !strncmp(pszSymbol, "TM", 2)
368 || !strcmp(pszSymbol, "g_pSUPGlobalInfoPage"))
369 {
370 RTRCPTR RCPtr = 0;
371 rc = TMR3GetImportRC(pVM, pszSymbol, &RCPtr);
372 if (RT_SUCCESS(rc))
373 *pValue = RCPtr;
374 }
375 else
376 {
377 AssertMsg(!pszModule, ("Unknown builtin symbol '%s' for module '%s'!\n", pszSymbol, pModule->szName)); NOREF(pModule);
378 rc = VERR_SYMBOL_NOT_FOUND;
379 }
380 if (RT_SUCCESS(rc) || pszModule)
381 {
382 if (RT_FAILURE(rc))
383 LogRel(("PDMLdr: Couldn't find symbol '%s' in module '%s'!\n", pszSymbol, pszModule));
384 return rc;
385 }
386 }
387
388 /*
389 * Search for module.
390 */
391 PUVM pUVM = pVM->pUVM;
392 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
393 PPDMMOD pCur = pUVM->pdm.s.pModules;
394 while (pCur)
395 {
396 if ( pCur->eType == PDMMOD_TYPE_RC
397 && ( !pszModule
398 || !strcmp(pCur->szName, pszModule))
399 )
400 {
401 /* Search for the symbol. */
402 int rc = RTLdrGetSymbolEx(pCur->hLdrMod, pCur->pvBits, pCur->ImageBase, pszSymbol, pValue);
403 if (RT_SUCCESS(rc))
404 {
405 AssertMsg(*pValue - pCur->ImageBase < RTLdrSize(pCur->hLdrMod),
406 ("%RRv-%RRv %s %RRv\n", (RTRCPTR)pCur->ImageBase,
407 (RTRCPTR)(pCur->ImageBase + RTLdrSize(pCur->hLdrMod) - 1),
408 pszSymbol, (RTRCPTR)*pValue));
409 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
410 return rc;
411 }
412 if (pszModule)
413 {
414 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
415 AssertLogRelMsgFailed(("PDMLdr: Couldn't find symbol '%s' in module '%s'!\n", pszSymbol, pszModule));
416 return VERR_SYMBOL_NOT_FOUND;
417 }
418 }
419
420 /* next */
421 pCur = pCur->pNext;
422 }
423
424 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
425 AssertLogRelMsgFailed(("Couldn't find module '%s' for resolving symbol '%s'!\n", pszModule, pszSymbol));
426 return VERR_SYMBOL_NOT_FOUND;
427}
428
429
430/**
431 * Loads a module into the guest context (i.e. into the Hypervisor memory region).
432 *
433 * @returns VBox status code.
434 * @param pVM The VM to load it into.
435 * @param pszFilename Filename of the module binary.
436 * @param pszName Module name. Case sensitive and the length is limited!
437 */
438VMMR3DECL(int) PDMR3LdrLoadRC(PVM pVM, const char *pszFilename, const char *pszName)
439{
440 /*
441 * Validate input.
442 */
443 AssertMsg(PDMCritSectIsInitialized(&pVM->pdm.s.CritSect), ("bad init order!\n"));
444 PUVM pUVM = pVM->pUVM;
445 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
446 PPDMMOD pCur = pUVM->pdm.s.pModules;
447 while (pCur)
448 {
449 if (!strcmp(pCur->szName, pszName))
450 {
451 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
452 AssertMsgFailed(("We've already got a module '%s' loaded!\n", pszName));
453 return VERR_PDM_MODULE_NAME_CLASH;
454 }
455 /* next */
456 pCur = pCur->pNext;
457 }
458
459 /*
460 * Find the file if not specified.
461 */
462 char *pszFile = NULL;
463 if (!pszFilename)
464 pszFilename = pszFile = pdmR3FileRC(pszName, NULL);
465
466 /*
467 * Allocate the module list node.
468 */
469 PPDMMOD pModule = (PPDMMOD)RTMemAllocZ(sizeof(*pModule) + strlen(pszFilename));
470 if (!pModule)
471 {
472 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
473 RTMemTmpFree(pszFile);
474 return VERR_NO_MEMORY;
475 }
476 AssertMsg(strlen(pszName) + 1 < sizeof(pModule->szName),
477 ("pazName is too long (%d chars) max is %d chars.\n", strlen(pszName), sizeof(pModule->szName) - 1));
478 strcpy(pModule->szName, pszName);
479 pModule->eType = PDMMOD_TYPE_RC;
480 strcpy(pModule->szFilename, pszFilename);
481
482
483 /*
484 * Open the loader item.
485 */
486 RTERRINFOSTATIC ErrInfo;
487 RTErrInfoInitStatic(&ErrInfo);
488 int rc = SUPR3HardenedVerifyPlugIn(pszFilename, &ErrInfo.Core);
489 if (RT_SUCCESS(rc))
490 {
491 RTErrInfoClear(&ErrInfo.Core);
492 rc = RTLdrOpen(pszFilename, 0, RTLDRARCH_X86_32, &pModule->hLdrMod);
493 }
494 if (RT_SUCCESS(rc))
495 {
496 /*
497 * Allocate space in the hypervisor.
498 */
499 size_t cb = RTLdrSize(pModule->hLdrMod);
500 cb = RT_ALIGN_Z(cb, PAGE_SIZE);
501 uint32_t cPages = (uint32_t)(cb >> PAGE_SHIFT);
502 if (((size_t)cPages << PAGE_SHIFT) == cb)
503 {
504 PSUPPAGE paPages = (PSUPPAGE)RTMemTmpAlloc(cPages * sizeof(paPages[0]));
505 if (paPages)
506 {
507 rc = SUPR3PageAllocEx(cPages, 0 /*fFlags*/, &pModule->pvBits, NULL /*pR0Ptr*/, paPages);
508 if (RT_SUCCESS(rc))
509 {
510 RTGCPTR GCPtr;
511 rc = MMR3HyperMapPages(pVM, pModule->pvBits, NIL_RTR0PTR,
512 cPages, paPages, pModule->szName, &GCPtr);
513 if (RT_SUCCESS(rc))
514 {
515 MMR3HyperReserve(pVM, PAGE_SIZE, "fence", NULL);
516
517 /*
518 * Get relocated image bits.
519 */
520 Assert(MMHyperR3ToRC(pVM, pModule->pvBits) == GCPtr);
521 pModule->ImageBase = GCPtr;
522 PDMGETIMPORTARGS Args;
523 Args.pVM = pVM;
524 Args.pModule = pModule;
525 rc = RTLdrGetBits(pModule->hLdrMod, pModule->pvBits, pModule->ImageBase, pdmR3GetImportRC, &Args);
526 if (RT_SUCCESS(rc))
527 {
528 /*
529 * Insert the module.
530 */
531 if (pUVM->pdm.s.pModules)
532 {
533 /* we don't expect this list to be very long, so rather save the tail pointer. */
534 pCur = pUVM->pdm.s.pModules;
535 while (pCur->pNext)
536 pCur = pCur->pNext;
537 pCur->pNext = pModule;
538 }
539 else
540 pUVM->pdm.s.pModules = pModule; /* (pNext is zeroed by alloc) */
541 Log(("PDM: RC Module at %RRv %s (%s)\n", (RTRCPTR)pModule->ImageBase, pszName, pszFilename));
542 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
543 RTMemTmpFree(pszFile);
544 RTMemTmpFree(paPages);
545 return VINF_SUCCESS;
546 }
547 }
548 else
549 {
550 AssertRC(rc);
551 SUPR3PageFreeEx(pModule->pvBits, cPages);
552 }
553 }
554 else
555 AssertMsgFailed(("SUPR3PageAlloc(%d,) -> %Rrc\n", cPages, rc));
556 RTMemTmpFree(paPages);
557 }
558 else
559 rc = VERR_NO_TMP_MEMORY;
560 }
561 else
562 rc = VERR_OUT_OF_RANGE;
563 int rc2 = RTLdrClose(pModule->hLdrMod);
564 AssertRC(rc2);
565 }
566 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
567
568 /* Don't consider VERR_PDM_MODULE_NAME_CLASH and VERR_NO_MEMORY above as these are very unlikely. */
569 if (RT_FAILURE(rc) && RTErrInfoIsSet(&ErrInfo.Core))
570 rc = VMSetError(pVM, rc, RT_SRC_POS, N_("Cannot load RC module %s: %s"), pszFilename, ErrInfo.Core.pszMsg);
571 else if (RT_FAILURE(rc))
572 rc = VMSetError(pVM, rc, RT_SRC_POS, N_("Cannot load RC module %s"), pszFilename);
573
574 RTMemFree(pModule);
575 RTMemTmpFree(pszFile);
576 return rc;
577}
578#endif /* VBOX_WITH_RAW_MODE */
579
580
581/**
582 * Loads a module into the ring-0 context.
583 *
584 * @returns VBox status code.
585 * @param pUVM Pointer to the user mode VM structure.
586 * @param pszFilename Filename of the module binary.
587 * @param pszName Module name. Case sensitive and the length is limited!
588 * @param pszSearchPath List of directories to search if @a pszFilename is
589 * not specified. Can be NULL, in which case the arch
590 * dependent install dir is searched.
591 */
592static int pdmR3LoadR0U(PUVM pUVM, const char *pszFilename, const char *pszName, const char *pszSearchPath)
593{
594 /*
595 * Validate input.
596 */
597 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
598 PPDMMOD pCur = pUVM->pdm.s.pModules;
599 while (pCur)
600 {
601 if (!strcmp(pCur->szName, pszName))
602 {
603 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
604 AssertMsgFailed(("We've already got a module '%s' loaded!\n", pszName));
605 return VERR_PDM_MODULE_NAME_CLASH;
606 }
607 /* next */
608 pCur = pCur->pNext;
609 }
610
611 /*
612 * Find the file if not specified.
613 */
614 char *pszFile = NULL;
615 if (!pszFilename)
616 pszFilename = pszFile = pdmR3FileR0(pszName, pszSearchPath);
617
618 /*
619 * Allocate the module list node.
620 */
621 PPDMMOD pModule = (PPDMMOD)RTMemAllocZ(sizeof(*pModule) + strlen(pszFilename));
622 if (!pModule)
623 {
624 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
625 RTMemTmpFree(pszFile);
626 return VERR_NO_MEMORY;
627 }
628 AssertMsg(strlen(pszName) + 1 < sizeof(pModule->szName),
629 ("pazName is too long (%d chars) max is %d chars.\n", strlen(pszName), sizeof(pModule->szName) - 1));
630 strcpy(pModule->szName, pszName);
631 pModule->eType = PDMMOD_TYPE_R0;
632 strcpy(pModule->szFilename, pszFilename);
633
634 /*
635 * Ask the support library to load it.
636 */
637 void *pvImageBase;
638 RTERRINFOSTATIC ErrInfo;
639 RTErrInfoInitStatic(&ErrInfo);
640 int rc = SUPR3LoadModule(pszFilename, pszName, &pvImageBase, &ErrInfo.Core);
641 if (RT_SUCCESS(rc))
642 {
643 pModule->hLdrMod = NIL_RTLDRMOD;
644 pModule->ImageBase = (uintptr_t)pvImageBase;
645
646 /*
647 * Insert the module.
648 */
649 if (pUVM->pdm.s.pModules)
650 {
651 /* we don't expect this list to be very long, so rather save the tail pointer. */
652 pCur = pUVM->pdm.s.pModules;
653 while (pCur->pNext)
654 pCur = pCur->pNext;
655 pCur->pNext = pModule;
656 }
657 else
658 pUVM->pdm.s.pModules = pModule; /* (pNext is zeroed by alloc) */
659 Log(("PDM: R0 Module at %RHv %s (%s)\n", (RTR0PTR)pModule->ImageBase, pszName, pszFilename));
660 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
661 RTMemTmpFree(pszFile);
662 return VINF_SUCCESS;
663 }
664
665 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
666 RTMemFree(pModule);
667 LogRel(("pdmR3LoadR0U: pszName=\"%s\" rc=%Rrc szErr=\"%s\"\n", pszName, rc, ErrInfo.Core.pszMsg));
668
669 /* Don't consider VERR_PDM_MODULE_NAME_CLASH and VERR_NO_MEMORY above as these are very unlikely. */
670 if (RT_FAILURE(rc) && pUVM->pVM) /** @todo VMR3SetErrorU. */
671 rc = VMSetError(pUVM->pVM, rc, RT_SRC_POS, N_("Cannot load R0 module %s: %s"), pszFilename, ErrInfo.Core.pszMsg);
672
673 RTMemTmpFree(pszFile); /* might be reference thru pszFilename in the above VMSetError call. */
674 return rc;
675}
676
677
678
679/**
680 * Get the address of a symbol in a given HC ring 3 module.
681 *
682 * @returns VBox status code.
683 * @param pVM VM handle.
684 * @param pszModule Module name.
685 * @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
686 * ordinal value rather than a string pointer.
687 * @param ppvValue Where to store the symbol value.
688 */
689VMMR3DECL(int) PDMR3LdrGetSymbolR3(PVM pVM, const char *pszModule, const char *pszSymbol, void **ppvValue)
690{
691 /*
692 * Validate input.
693 */
694 AssertPtr(pVM);
695 AssertPtr(pszModule);
696 AssertPtr(ppvValue);
697 AssertMsg(PDMCritSectIsInitialized(&pVM->pdm.s.CritSect), ("bad init order!\n"));
698
699 /*
700 * Find the module.
701 */
702 PUVM pUVM = pVM->pUVM;
703 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
704 for (PPDMMOD pModule = pUVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
705 {
706 if ( pModule->eType == PDMMOD_TYPE_R3
707 && !strcmp(pModule->szName, pszModule))
708 {
709 RTUINTPTR Value = 0;
710 int rc = RTLdrGetSymbolEx(pModule->hLdrMod, pModule->pvBits, pModule->ImageBase, pszSymbol, &Value);
711 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
712 if (RT_SUCCESS(rc))
713 {
714 *ppvValue = (void *)(uintptr_t)Value;
715 Assert((uintptr_t)*ppvValue == Value);
716 }
717 else
718 {
719 if ((uintptr_t)pszSymbol < 0x10000)
720 AssertMsg(rc, ("Couldn't symbol '%u' in module '%s'\n", (unsigned)(uintptr_t)pszSymbol, pszModule));
721 else
722 AssertMsg(rc, ("Couldn't symbol '%s' in module '%s'\n", pszSymbol, pszModule));
723 }
724 return rc;
725 }
726 }
727 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
728 AssertMsgFailed(("Couldn't locate module '%s'\n", pszModule));
729 return VERR_SYMBOL_NOT_FOUND;
730}
731
732
733/**
734 * Get the address of a symbol in a given HC ring 0 module.
735 *
736 * @returns VBox status code.
737 * @param pVM VM handle.
738 * @param pszModule Module name. If NULL the main R0 module (VMMR0.r0) is assumes.
739 * @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
740 * ordinal value rather than a string pointer.
741 * @param ppvValue Where to store the symbol value.
742 */
743VMMR3DECL(int) PDMR3LdrGetSymbolR0(PVM pVM, const char *pszModule, const char *pszSymbol, PRTR0PTR ppvValue)
744{
745#ifdef PDMLDR_FAKE_MODE
746 *ppvValue = 0xdeadbeef;
747 return VINF_SUCCESS;
748
749#else
750 /*
751 * Validate input.
752 */
753 AssertPtr(pVM);
754 AssertPtrNull(pszModule);
755 AssertPtr(ppvValue);
756 AssertMsg(PDMCritSectIsInitialized(&pVM->pdm.s.CritSect), ("bad init order!\n"));
757
758 if (!pszModule)
759 pszModule = "VMMR0.r0";
760
761 /*
762 * Find the module.
763 */
764 PUVM pUVM = pVM->pUVM;
765 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
766 for (PPDMMOD pModule = pUVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
767 {
768 if ( pModule->eType == PDMMOD_TYPE_R0
769 && !strcmp(pModule->szName, pszModule))
770 {
771 int rc = SUPR3GetSymbolR0((void *)(uintptr_t)pModule->ImageBase, pszSymbol, (void **)ppvValue);
772 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
773 if (RT_FAILURE(rc))
774 {
775 AssertMsgRC(rc, ("Couldn't find symbol '%s' in module '%s'\n", pszSymbol, pszModule));
776 LogRel(("PDMGetSymbol: Couldn't find symbol '%s' in module '%s'\n", pszSymbol, pszModule));
777 }
778 return rc;
779 }
780 }
781 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
782 AssertMsgFailed(("Couldn't locate module '%s'\n", pszModule));
783 return VERR_SYMBOL_NOT_FOUND;
784#endif
785}
786
787
788/**
789 * Same as PDMR3LdrGetSymbolR0 except that the module will be attempted loaded if not found.
790 *
791 * @returns VBox status code.
792 * @param pVM VM handle.
793 * @param pszModule Module name. If NULL the main R0 module (VMMR0.r0) is assumed.
794 * @param pszSearchPath List of directories to search if @a pszFile is
795 * not qualified with a path. Can be NULL, in which
796 * case the arch dependent install dir is searched.
797 * @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
798 * ordinal value rather than a string pointer.
799 * @param ppvValue Where to store the symbol value.
800 */
801VMMR3DECL(int) PDMR3LdrGetSymbolR0Lazy(PVM pVM, const char *pszModule, const char *pszSearchPath, const char *pszSymbol,
802 PRTR0PTR ppvValue)
803{
804#ifdef PDMLDR_FAKE_MODE
805 *ppvValue = 0xdeadbeef;
806 return VINF_SUCCESS;
807
808#else
809 AssertPtr(pVM);
810 AssertPtrNull(pszModule);
811 AssertPtr(ppvValue);
812 AssertMsg(PDMCritSectIsInitialized(&pVM->pdm.s.CritSect), ("bad init order!\n"));
813
814 /*
815 * Since we're lazy, we'll only check if the module is present
816 * and hand it over to PDMR3LdrGetSymbolR0 when that's done.
817 */
818 if (pszModule)
819 {
820 AssertMsgReturn(!strpbrk(pszModule, "/\\:\n\r\t"), ("pszModule=%s\n", pszModule), VERR_INVALID_PARAMETER);
821 PUVM pUVM = pVM->pUVM;
822 PPDMMOD pModule;
823 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
824 for (pModule = pUVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
825 if ( pModule->eType == PDMMOD_TYPE_R0
826 && !strcmp(pModule->szName, pszModule))
827 break;
828 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
829 if (!pModule)
830 {
831 int rc = pdmR3LoadR0U(pUVM, NULL, pszModule, pszSearchPath);
832 AssertMsgRCReturn(rc, ("pszModule=%s rc=%Rrc\n", pszModule, rc), VERR_MODULE_NOT_FOUND);
833 }
834 }
835 return PDMR3LdrGetSymbolR0(pVM, pszModule, pszSymbol, ppvValue);
836#endif
837}
838
839
840/**
841 * Get the address of a symbol in a given RC module.
842 *
843 * @returns VBox status code.
844 * @param pVM VM handle.
845 * @param pszModule Module name. If NULL the main R0 module (VMMGC.gc) is assumes.
846 * @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
847 * ordinal value rather than a string pointer.
848 * @param pRCPtrValue Where to store the symbol value.
849 */
850VMMR3DECL(int) PDMR3LdrGetSymbolRC(PVM pVM, const char *pszModule, const char *pszSymbol, PRTRCPTR pRCPtrValue)
851{
852#if defined(PDMLDR_FAKE_MODE) || !defined(VBOX_WITH_RAW_MODE)
853 *pRCPtrValue = 0xfeedf00d;
854 return VINF_SUCCESS;
855
856#else
857 /*
858 * Validate input.
859 */
860 AssertPtr(pVM);
861 AssertPtrNull(pszModule);
862 AssertPtr(pRCPtrValue);
863 AssertMsg(PDMCritSectIsInitialized(&pVM->pdm.s.CritSect), ("bad init order!\n"));
864
865 if (!pszModule)
866 pszModule = "VMMGC.gc";
867
868 /*
869 * Find the module.
870 */
871 PUVM pUVM = pVM->pUVM;
872 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
873 for (PPDMMOD pModule = pUVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
874 {
875 if ( pModule->eType == PDMMOD_TYPE_RC
876 && !strcmp(pModule->szName, pszModule))
877 {
878 RTUINTPTR Value;
879 int rc = RTLdrGetSymbolEx(pModule->hLdrMod, pModule->pvBits, pModule->ImageBase, pszSymbol, &Value);
880 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
881 if (RT_SUCCESS(rc))
882 {
883 *pRCPtrValue = (RTGCPTR)Value;
884 Assert(*pRCPtrValue == Value);
885 }
886 else
887 {
888 if ((uintptr_t)pszSymbol < 0x10000)
889 AssertMsg(rc, ("Couldn't symbol '%u' in module '%s'\n", (unsigned)(uintptr_t)pszSymbol, pszModule));
890 else
891 AssertMsg(rc, ("Couldn't symbol '%s' in module '%s'\n", pszSymbol, pszModule));
892 }
893 return rc;
894 }
895 }
896 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
897 AssertMsgFailed(("Couldn't locate module '%s'\n", pszModule));
898 return VERR_SYMBOL_NOT_FOUND;
899#endif
900}
901
902
903/**
904 * Same as PDMR3LdrGetSymbolRC except that the module will be attempted loaded if not found.
905 *
906 * @returns VBox status code.
907 * @param pVM VM handle.
908 * @param pszModule Module name. If NULL the main R0 module (VMMGC.gc) is assumes.
909 * @param pszSearchPath List of directories to search if @a pszFile is
910 * not qualified with a path. Can be NULL, in which
911 * case the arch dependent install dir is searched.
912 * @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a
913 * ordinal value rather than a string pointer.
914 * @param pRCPtrValue Where to store the symbol value.
915 */
916VMMR3DECL(int) PDMR3LdrGetSymbolRCLazy(PVM pVM, const char *pszModule, const char *pszSearchPath, const char *pszSymbol,
917 PRTRCPTR pRCPtrValue)
918{
919#if defined(PDMLDR_FAKE_MODE) || !defined(VBOX_WITH_RAW_MODE)
920 *pRCPtrValue = 0xfeedf00d;
921 return VINF_SUCCESS;
922
923#else
924 AssertPtr(pVM);
925 AssertPtrNull(pszModule);
926 AssertPtr(pRCPtrValue);
927 AssertMsg(PDMCritSectIsInitialized(&pVM->pdm.s.CritSect), ("bad init order!\n"));
928
929 /*
930 * Since we're lazy, we'll only check if the module is present
931 * and hand it over to PDMR3LdrGetSymbolRC when that's done.
932 */
933 if (pszModule)
934 {
935 AssertMsgReturn(!strpbrk(pszModule, "/\\:\n\r\t"), ("pszModule=%s\n", pszModule), VERR_INVALID_PARAMETER);
936 PUVM pUVM = pVM->pUVM;
937 PPDMMOD pModule;
938 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
939 for (pModule = pUVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
940 if ( pModule->eType == PDMMOD_TYPE_RC
941 && !strcmp(pModule->szName, pszModule))
942 break;
943 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
944 if (!pModule)
945 {
946 char *pszFilename = pdmR3FileRC(pszModule, pszSearchPath);
947 AssertMsgReturn(pszFilename, ("pszModule=%s\n", pszModule), VERR_MODULE_NOT_FOUND);
948 int rc = PDMR3LdrLoadRC(pVM, pszFilename, pszModule);
949 RTMemTmpFree(pszFilename);
950 AssertMsgRCReturn(rc, ("pszModule=%s rc=%Rrc\n", pszModule, rc), VERR_MODULE_NOT_FOUND);
951 }
952 }
953 return PDMR3LdrGetSymbolRC(pVM, pszModule, pszSymbol, pRCPtrValue);
954#endif
955}
956
957
958/**
959 * Constructs the full filename for a R3 image file.
960 *
961 * @returns Pointer to temporary memory containing the filename.
962 * Caller must free this using RTMemTmpFree().
963 * @returns NULL on failure.
964 *
965 * @param pszFile File name (no path).
966 */
967char *pdmR3FileR3(const char *pszFile, bool fShared)
968{
969 return pdmR3File(pszFile, NULL, NULL, fShared);
970}
971
972
973/**
974 * Constructs the full filename for a R0 image file.
975 *
976 * @returns Pointer to temporary memory containing the filename.
977 * Caller must free this using RTMemTmpFree().
978 * @returns NULL on failure.
979 *
980 * @param pszFile File name (no path).
981 * @param pszSearchPath List of directories to search if @a pszFile is
982 * not qualified with a path. Can be NULL, in which
983 * case the arch dependent install dir is searched.
984 */
985char *pdmR3FileR0(const char *pszFile, const char *pszSearchPath)
986{
987 return pdmR3File(pszFile, NULL, pszSearchPath, /*fShared=*/false);
988}
989
990
991/**
992 * Constructs the full filename for a RC image file.
993 *
994 * @returns Pointer to temporary memory containing the filename.
995 * Caller must free this using RTMemTmpFree().
996 * @returns NULL on failure.
997 *
998 * @param pszFile File name (no path).
999 * @param pszSearchPath List of directories to search if @a pszFile is
1000 * not qualified with a path. Can be NULL, in which
1001 * case the arch dependent install dir is searched.
1002 */
1003char *pdmR3FileRC(const char *pszFile, const char *pszSearchPath)
1004{
1005 return pdmR3File(pszFile, NULL, pszSearchPath, /*fShared=*/false);
1006}
1007
1008
1009/**
1010 * Worker for pdmR3File().
1011 *
1012 * @returns Pointer to temporary memory containing the filename.
1013 * Caller must free this using RTMemTmpFree().
1014 * @returns NULL on failure.
1015 *
1016 * @param pszDir Directory part
1017 * @param pszFile File name part
1018 * @param pszDefaultExt Extension part
1019 */
1020static char *pdmR3FileConstruct(const char *pszDir, const char *pszFile, const char *pszDefaultExt)
1021{
1022 /*
1023 * Allocate temp memory for return buffer.
1024 */
1025 size_t cchDir = strlen(pszDir);
1026 size_t cchFile = strlen(pszFile);
1027 size_t cchDefaultExt;
1028
1029 /*
1030 * Default extention?
1031 */
1032 if (!pszDefaultExt || strchr(pszFile, '.'))
1033 cchDefaultExt = 0;
1034 else
1035 cchDefaultExt = strlen(pszDefaultExt);
1036
1037 size_t cchPath = cchDir + 1 + cchFile + cchDefaultExt + 1;
1038 AssertMsgReturn(cchPath <= RTPATH_MAX, ("Path too long!\n"), NULL);
1039
1040 char *pszRet = (char *)RTMemTmpAlloc(cchDir + 1 + cchFile + cchDefaultExt + 1);
1041 AssertMsgReturn(pszRet, ("Out of temporary memory!\n"), NULL);
1042
1043 /*
1044 * Construct the filename.
1045 */
1046 memcpy(pszRet, pszDir, cchDir);
1047 pszRet[cchDir++] = '/'; /* this works everywhere */
1048 memcpy(pszRet + cchDir, pszFile, cchFile + 1);
1049 if (cchDefaultExt)
1050 memcpy(pszRet + cchDir + cchFile, pszDefaultExt, cchDefaultExt + 1);
1051
1052 return pszRet;
1053}
1054
1055
1056/**
1057 * Worker for pdmR3FileRC(), pdmR3FileR0() and pdmR3FileR3().
1058 *
1059 * @returns Pointer to temporary memory containing the filename.
1060 * Caller must free this using RTMemTmpFree().
1061 * @returns NULL on failure.
1062 * @param pszFile File name (no path).
1063 * @param pszDefaultExt The default extention, NULL if none.
1064 * @param pszSearchPath List of directories to search if @a pszFile is
1065 * not qualified with a path. Can be NULL, in which
1066 * case the arch dependent install dir is searched.
1067 * @param fShared If true, search in the shared directory (/usr/lib on Unix), else
1068 * search in the private directory (/usr/lib/virtualbox on Unix).
1069 * Ignored if VBOX_PATH_SHARED_LIBS is not defined.
1070 * @todo We'll have this elsewhere than in the root later!
1071 * @todo Remove the fShared hack again once we don't need to link against VBoxDD anymore!
1072 */
1073static char *pdmR3File(const char *pszFile, const char *pszDefaultExt, const char *pszSearchPath, bool fShared)
1074{
1075 char szPath[RTPATH_MAX];
1076 int rc;
1077
1078 AssertLogRelReturn(!fShared || !pszSearchPath, NULL);
1079 Assert(!RTPathHavePath(pszFile));
1080
1081 /*
1082 * If there is a path, search it.
1083 */
1084 if ( pszSearchPath
1085 && *pszSearchPath)
1086 {
1087 /* Check the filename length. */
1088 size_t const cchFile = strlen(pszFile);
1089 if (cchFile >= sizeof(szPath))
1090 return NULL;
1091
1092 /*
1093 * Walk the search path.
1094 */
1095 const char *psz = pszSearchPath;
1096 while (*psz)
1097 {
1098 /* Skip leading blanks - no directories with leading spaces, thank you. */
1099 while (RT_C_IS_BLANK(*psz))
1100 psz++;
1101
1102 /* Find the end of this element. */
1103 const char *pszNext;
1104 const char *pszEnd = strchr(psz, ';');
1105 if (!pszEnd)
1106 pszEnd = pszNext = strchr(psz, '\0');
1107 else
1108 pszNext = pszEnd + 1;
1109 if (pszEnd != psz)
1110 {
1111 rc = RTPathJoinEx(szPath, sizeof(szPath), psz, pszEnd - psz, pszFile, cchFile);
1112 if (RT_SUCCESS(rc))
1113 {
1114 if (RTFileExists(szPath))
1115 {
1116 size_t cchPath = strlen(szPath) + 1;
1117 char *pszRet = (char *)RTMemTmpAlloc(cchPath);
1118 if (pszRet)
1119 memcpy(pszRet, szPath, cchPath);
1120 return pszRet;
1121 }
1122 }
1123 }
1124
1125 /* advance */
1126 psz = pszNext;
1127 }
1128 }
1129
1130 /*
1131 * Use the default location.
1132 */
1133 rc = fShared
1134 ? RTPathSharedLibs( szPath, sizeof(szPath))
1135 : RTPathAppPrivateArch(szPath, sizeof(szPath));
1136 if (!RT_SUCCESS(rc))
1137 {
1138 AssertMsgFailed(("RTPath[SharedLibs|AppPrivateArch](,%d) failed rc=%d!\n", sizeof(szPath), rc));
1139 return NULL;
1140 }
1141
1142 return pdmR3FileConstruct(szPath, pszFile, pszDefaultExt);
1143}
1144
1145
1146/** @internal */
1147typedef struct QMFEIPARG
1148{
1149 RTINTPTR uPC;
1150
1151 char *pszNearSym1;
1152 size_t cchNearSym1;
1153 RTINTPTR offNearSym1;
1154
1155 char *pszNearSym2;
1156 size_t cchNearSym2;
1157 RTINTPTR offNearSym2;
1158} QMFEIPARG, *PQMFEIPARG;
1159
1160
1161/**
1162 * Enumeration callback function used by RTLdrEnumSymbols().
1163 *
1164 * @returns VBox status code. Failure will stop the enumeration.
1165 * @param hLdrMod The loader module handle.
1166 * @param pszSymbol Symbol name. NULL if ordinal only.
1167 * @param uSymbol Symbol ordinal, ~0 if not used.
1168 * @param Value Symbol value.
1169 * @param pvUser The user argument specified to RTLdrEnumSymbols().
1170 */
1171static DECLCALLBACK(int) pdmR3QueryModFromEIPEnumSymbols(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser)
1172{
1173 PQMFEIPARG pArgs = (PQMFEIPARG)pvUser;
1174
1175 RTINTPTR off = Value - pArgs->uPC;
1176 if (off <= 0) /* near1 is before or at same location. */
1177 {
1178 if (off > pArgs->offNearSym1)
1179 {
1180 pArgs->offNearSym1 = off;
1181 if (pArgs->pszNearSym1 && pArgs->cchNearSym1)
1182 {
1183 *pArgs->pszNearSym1 = '\0';
1184 if (pszSymbol)
1185 strncat(pArgs->pszNearSym1, pszSymbol, pArgs->cchNearSym1);
1186 else
1187 {
1188 char szOrd[32];
1189 RTStrPrintf(szOrd, sizeof(szOrd), "#%#x", uSymbol);
1190 strncat(pArgs->pszNearSym1, szOrd, pArgs->cchNearSym1);
1191 }
1192 }
1193 }
1194 }
1195 else /* near2 is after */
1196 {
1197 if (off < pArgs->offNearSym2)
1198 {
1199 pArgs->offNearSym2 = off;
1200 if (pArgs->pszNearSym2 && pArgs->cchNearSym2)
1201 {
1202 *pArgs->pszNearSym2 = '\0';
1203 if (pszSymbol)
1204 strncat(pArgs->pszNearSym2, pszSymbol, pArgs->cchNearSym2);
1205 else
1206 {
1207 char szOrd[32];
1208 RTStrPrintf(szOrd, sizeof(szOrd), "#%#x", uSymbol);
1209 strncat(pArgs->pszNearSym2, szOrd, pArgs->cchNearSym2);
1210 }
1211 }
1212 }
1213 }
1214
1215 return VINF_SUCCESS;
1216}
1217
1218
1219/**
1220 * Internal worker for PDMR3LdrQueryRCModFromPC and PDMR3LdrQueryR0ModFromPC.
1221 *
1222 * @returns VBox status code.
1223 *
1224 * @param pVM VM handle
1225 * @param uPC The program counter (eip/rip) to locate the module for.
1226 * @param enmType The module type.
1227 * @param pszModName Where to store the module name.
1228 * @param cchModName Size of the module name buffer.
1229 * @param pMod Base address of the module.
1230 * @param pszNearSym1 Name of the closes symbol from below.
1231 * @param cchNearSym1 Size of the buffer pointed to by pszNearSym1.
1232 * @param pNearSym1 The address of pszNearSym1.
1233 * @param pszNearSym2 Name of the closes symbol from below.
1234 * @param cchNearSym2 Size of the buffer pointed to by pszNearSym2.
1235 * @param pNearSym2 The address of pszNearSym2.
1236 */
1237static int pdmR3LdrQueryModFromPC(PVM pVM, RTUINTPTR uPC, PDMMODTYPE enmType,
1238 char *pszModName, size_t cchModName, PRTUINTPTR pMod,
1239 char *pszNearSym1, size_t cchNearSym1, PRTUINTPTR pNearSym1,
1240 char *pszNearSym2, size_t cchNearSym2, PRTUINTPTR pNearSym2)
1241{
1242 PUVM pUVM = pVM->pUVM;
1243 int rc = VERR_MODULE_NOT_FOUND;
1244 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
1245 for (PPDMMOD pCur= pUVM->pdm.s.pModules; pCur; pCur = pCur->pNext)
1246 {
1247 if (pCur->eType != enmType)
1248 continue;
1249
1250 /* The following RTLdrOpen call is a dirty hack to get ring-0 module information. */
1251 RTLDRMOD hLdrMod = pCur->hLdrMod;
1252 if (hLdrMod == NIL_RTLDRMOD && uPC >= pCur->ImageBase)
1253 {
1254 int rc2 = RTLdrOpen(pCur->szFilename, 0 /*fFlags*/, RTLDRARCH_HOST, &hLdrMod);
1255 if (RT_FAILURE(rc2))
1256 hLdrMod = NIL_RTLDRMOD;
1257 }
1258
1259 if ( hLdrMod != NIL_RTLDRMOD
1260 && uPC - pCur->ImageBase < RTLdrSize(hLdrMod))
1261 {
1262 if (pMod)
1263 *pMod = pCur->ImageBase;
1264 if (pszModName && cchModName)
1265 {
1266 *pszModName = '\0';
1267 strncat(pszModName, pCur->szName, cchModName);
1268 }
1269 if (pNearSym1) *pNearSym1 = 0;
1270 if (pNearSym2) *pNearSym2 = 0;
1271 if (pszNearSym1) *pszNearSym1 = '\0';
1272 if (pszNearSym2) *pszNearSym2 = '\0';
1273
1274 /*
1275 * Locate the nearest symbols.
1276 */
1277 QMFEIPARG Args;
1278 Args.uPC = uPC;
1279 Args.pszNearSym1 = pszNearSym1;
1280 Args.cchNearSym1 = cchNearSym1;
1281 Args.offNearSym1 = RTINTPTR_MIN;
1282 Args.pszNearSym2 = pszNearSym2;
1283 Args.cchNearSym2 = cchNearSym2;
1284 Args.offNearSym2 = RTINTPTR_MAX;
1285
1286 rc = RTLdrEnumSymbols(hLdrMod, RTLDR_ENUM_SYMBOL_FLAGS_ALL, pCur->pvBits, pCur->ImageBase,
1287 pdmR3QueryModFromEIPEnumSymbols, &Args);
1288 if (pNearSym1 && Args.offNearSym1 != RTINTPTR_MIN)
1289 *pNearSym1 = Args.offNearSym1 + uPC;
1290 if (pNearSym2 && Args.offNearSym2 != RTINTPTR_MAX)
1291 *pNearSym2 = Args.offNearSym2 + uPC;
1292
1293 rc = VINF_SUCCESS;
1294 }
1295
1296 if (hLdrMod != pCur->hLdrMod && hLdrMod != NIL_RTLDRMOD)
1297 RTLdrClose(hLdrMod);
1298
1299 if (RT_SUCCESS(rc))
1300 break;
1301 }
1302 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
1303 return rc;
1304}
1305
1306
1307/**
1308 * Queries raw-mode context module information from an PC (eip/rip).
1309 *
1310 * This is typically used to locate a crash address.
1311 *
1312 * @returns VBox status code.
1313 *
1314 * @param pVM VM handle
1315 * @param uPC The program counter (eip/rip) to locate the module for.
1316 * @param pszModName Where to store the module name.
1317 * @param cchModName Size of the module name buffer.
1318 * @param pMod Base address of the module.
1319 * @param pszNearSym1 Name of the closes symbol from below.
1320 * @param cchNearSym1 Size of the buffer pointed to by pszNearSym1.
1321 * @param pNearSym1 The address of pszNearSym1.
1322 * @param pszNearSym2 Name of the closes symbol from below.
1323 * @param cchNearSym2 Size of the buffer pointed to by pszNearSym2.
1324 * @param pNearSym2 The address of pszNearSym2.
1325 */
1326VMMR3DECL(int) PDMR3LdrQueryRCModFromPC(PVM pVM, RTRCPTR uPC,
1327 char *pszModName, size_t cchModName, PRTRCPTR pMod,
1328 char *pszNearSym1, size_t cchNearSym1, PRTRCPTR pNearSym1,
1329 char *pszNearSym2, size_t cchNearSym2, PRTRCPTR pNearSym2)
1330{
1331 RTUINTPTR AddrMod = 0;
1332 RTUINTPTR AddrNear1 = 0;
1333 RTUINTPTR AddrNear2 = 0;
1334 int rc = pdmR3LdrQueryModFromPC(pVM, uPC, PDMMOD_TYPE_RC,
1335 pszModName, cchModName, &AddrMod,
1336 pszNearSym1, cchNearSym1, &AddrNear1,
1337 pszNearSym2, cchNearSym2, &AddrNear2);
1338 if (RT_SUCCESS(rc))
1339 {
1340 if (pMod)
1341 *pMod = (RTRCPTR)AddrMod;
1342 if (pNearSym1)
1343 *pNearSym1 = (RTRCPTR)AddrNear1;
1344 if (pNearSym2)
1345 *pNearSym2 = (RTRCPTR)AddrNear2;
1346 }
1347 return rc;
1348}
1349
1350
1351/**
1352 * Queries ring-0 context module information from an PC (eip/rip).
1353 *
1354 * This is typically used to locate a crash address.
1355 *
1356 * @returns VBox status code.
1357 *
1358 * @param pVM VM handle
1359 * @param uPC The program counter (eip/rip) to locate the module for.
1360 * @param pszModName Where to store the module name.
1361 * @param cchModName Size of the module name buffer.
1362 * @param pMod Base address of the module.
1363 * @param pszNearSym1 Name of the closes symbol from below.
1364 * @param cchNearSym1 Size of the buffer pointed to by pszNearSym1.
1365 * @param pNearSym1 The address of pszNearSym1.
1366 * @param pszNearSym2 Name of the closes symbol from below.
1367 * @param cchNearSym2 Size of the buffer pointed to by pszNearSym2. Optional.
1368 * @param pNearSym2 The address of pszNearSym2. Optional.
1369 */
1370VMMR3DECL(int) PDMR3LdrQueryR0ModFromPC(PVM pVM, RTR0PTR uPC,
1371 char *pszModName, size_t cchModName, PRTR0PTR pMod,
1372 char *pszNearSym1, size_t cchNearSym1, PRTR0PTR pNearSym1,
1373 char *pszNearSym2, size_t cchNearSym2, PRTR0PTR pNearSym2)
1374{
1375 RTUINTPTR AddrMod = 0;
1376 RTUINTPTR AddrNear1 = 0;
1377 RTUINTPTR AddrNear2 = 0;
1378 int rc = pdmR3LdrQueryModFromPC(pVM, uPC, PDMMOD_TYPE_R0,
1379 pszModName, cchModName, &AddrMod,
1380 pszNearSym1, cchNearSym1, &AddrNear1,
1381 pszNearSym2, cchNearSym2, &AddrNear2);
1382 if (RT_SUCCESS(rc))
1383 {
1384 if (pMod)
1385 *pMod = (RTR0PTR)AddrMod;
1386 if (pNearSym1)
1387 *pNearSym1 = (RTR0PTR)AddrNear1;
1388 if (pNearSym2)
1389 *pNearSym2 = (RTR0PTR)AddrNear2;
1390 }
1391 return rc;
1392}
1393
1394
1395/**
1396 * Enumerate all PDM modules.
1397 *
1398 * @returns VBox status.
1399 * @param pVM VM Handle.
1400 * @param pfnCallback Function to call back for each of the modules.
1401 * @param pvArg User argument.
1402 */
1403VMMR3DECL(int) PDMR3LdrEnumModules(PVM pVM, PFNPDMR3ENUM pfnCallback, void *pvArg)
1404{
1405 PUVM pUVM = pVM->pUVM;
1406 int rc = VINF_SUCCESS;
1407 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
1408 for (PPDMMOD pCur = pUVM->pdm.s.pModules; pCur; pCur = pCur->pNext)
1409 {
1410 rc = pfnCallback(pVM,
1411 pCur->szFilename,
1412 pCur->szName,
1413 pCur->ImageBase,
1414 pCur->eType == PDMMOD_TYPE_RC ? RTLdrSize(pCur->hLdrMod) : 0,
1415 pCur->eType == PDMMOD_TYPE_RC,
1416 pvArg);
1417 if (RT_FAILURE(rc))
1418 break;
1419 }
1420 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
1421 return rc;
1422}
1423
1424
1425/**
1426 * Locates a module.
1427 *
1428 * @returns Pointer to the module if found.
1429 * @param pUVM Pointer to the user mode VM structure.
1430 * @param pszModule The module name.
1431 * @param enmType The module type.
1432 * @param fLazy Lazy loading the module if set.
1433 * @param pszSearchPath Search path for use when lazy loading.
1434 */
1435static PPDMMOD pdmR3LdrFindModule(PUVM pUVM, const char *pszModule, PDMMODTYPE enmType,
1436 bool fLazy, const char *pszSearchPath)
1437{
1438 RTCritSectEnter(&pUVM->pdm.s.ListCritSect);
1439 for (PPDMMOD pModule = pUVM->pdm.s.pModules; pModule; pModule = pModule->pNext)
1440 if ( pModule->eType == enmType
1441 && !strcmp(pModule->szName, pszModule))
1442 {
1443 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
1444 return pModule;
1445 }
1446 RTCritSectLeave(&pUVM->pdm.s.ListCritSect);
1447 if (fLazy)
1448 {
1449 switch (enmType)
1450 {
1451#ifdef VBOX_WITH_RAW_MODE
1452 case PDMMOD_TYPE_RC:
1453 {
1454 char *pszFilename = pdmR3FileRC(pszModule, pszSearchPath);
1455 if (pszFilename)
1456 {
1457 int rc = PDMR3LdrLoadRC(pUVM->pVM, pszFilename, pszModule);
1458 RTMemTmpFree(pszFilename);
1459 if (RT_SUCCESS(rc))
1460 return pdmR3LdrFindModule(pUVM, pszModule, enmType, false, NULL);
1461 }
1462 break;
1463 }
1464#endif
1465
1466 case PDMMOD_TYPE_R0:
1467 {
1468 int rc = pdmR3LoadR0U(pUVM, NULL, pszModule, pszSearchPath);
1469 if (RT_SUCCESS(rc))
1470 return pdmR3LdrFindModule(pUVM, pszModule, enmType, false, NULL);
1471 break;
1472 }
1473
1474 default:
1475 AssertFailed();
1476 }
1477 }
1478 return NULL;
1479}
1480
1481
1482/**
1483 * Resolves a ring-0 or raw-mode context interface.
1484 *
1485 * @returns VBox status code.
1486 * @param pVM The VM handle.
1487 * @param pvInterface Pointer to the interface structure. The symbol list
1488 * describes the layout.
1489 * @param cbInterface The size of the structure pvInterface is pointing
1490 * to. For bounds checking.
1491 * @param pszModule The module name. If NULL we assume it's the default
1492 * R0 or RC module (@a fRing0OrRC). We'll attempt to
1493 * load the module if it isn't found in the module
1494 * list.
1495 * @param pszSearchPath The module search path. If NULL, search the
1496 * architecture dependent install directory.
1497 * @param pszSymPrefix What to prefix the symbols in the list with. The
1498 * idea is that you define a list that goes with an
1499 * interface (INTERFACE_SYM_LIST) and reuse it with
1500 * each implementation.
1501 * @param pszSymList The symbol list for the interface. This is a
1502 * semi-colon separated list of symbol base names. As
1503 * mentioned above, each is prefixed with @a
1504 * pszSymPrefix before resolving. There are a couple
1505 * of special symbol names that will cause us to skip
1506 * ahead a little bit:
1507 * - U8:whatever,
1508 * - U16:whatever,
1509 * - U32:whatever,
1510 * - U64:whatever,
1511 * - RCPTR:whatever,
1512 * - R3PTR:whatever,
1513 * - R0PTR:whatever,
1514 * - GCPHYS:whatever,
1515 * - HCPHYS:whatever.
1516 * @param fRing0 Set if it's a ring-0 context interface, clear if
1517 * it's raw-mode context interface.
1518 */
1519VMMR3DECL(int) PDMR3LdrGetInterfaceSymbols(PVM pVM, void *pvInterface, size_t cbInterface,
1520 const char *pszModule, const char *pszSearchPath,
1521 const char *pszSymPrefix, const char *pszSymList,
1522 bool fRing0)
1523{
1524 /*
1525 * Find the module.
1526 */
1527 int rc = VINF_SUCCESS;
1528 PPDMMOD pModule = pdmR3LdrFindModule(pVM->pUVM,
1529 pszModule ? pszModule : fRing0 ? "VMMR0.r0" : "VMMGC.gc",
1530 fRing0 ? PDMMOD_TYPE_R0 : PDMMOD_TYPE_RC,
1531 true /*fLazy*/, pszSearchPath);
1532 if (pModule)
1533 {
1534 /* Prep the symbol name. */
1535 char szSymbol[256];
1536 size_t const cchSymPrefix = strlen(pszSymPrefix);
1537 AssertReturn(cchSymPrefix + 5 < sizeof(szSymbol), VERR_SYMBOL_NOT_FOUND);
1538 memcpy(szSymbol, pszSymPrefix, cchSymPrefix);
1539
1540 /*
1541 * Iterate the symbol list.
1542 */
1543 uint32_t offInterface = 0;
1544 const char *pszCur = pszSymList;
1545 while (pszCur)
1546 {
1547 /*
1548 * Find the end of the current symbol name.
1549 */
1550 size_t cchSym;
1551 const char *pszNext = strchr(pszCur, ';');
1552 if (pszNext)
1553 {
1554 cchSym = pszNext - pszCur;
1555 pszNext++;
1556 }
1557 else
1558 cchSym = strlen(pszCur);
1559 AssertBreakStmt(cchSym > 0, rc = VERR_INVALID_PARAMETER);
1560
1561 /* Is it a skip instruction? */
1562 const char *pszColon = (const char *)memchr(pszCur, ':', cchSym);
1563 if (pszColon)
1564 {
1565 /*
1566 * String switch on the instruction and execute it, checking
1567 * that we didn't overshoot the interface structure.
1568 */
1569#define IS_SKIP_INSTR(szInstr) \
1570 ( cchSkip == sizeof(szInstr) - 1 \
1571 && !memcmp(pszCur, szInstr, sizeof(szInstr) - 1) )
1572
1573 size_t const cchSkip = pszColon - pszCur;
1574 if (IS_SKIP_INSTR("U8"))
1575 offInterface += sizeof(uint8_t);
1576 else if (IS_SKIP_INSTR("U16"))
1577 offInterface += sizeof(uint16_t);
1578 else if (IS_SKIP_INSTR("U32"))
1579 offInterface += sizeof(uint32_t);
1580 else if (IS_SKIP_INSTR("U64"))
1581 offInterface += sizeof(uint64_t);
1582 else if (IS_SKIP_INSTR("RCPTR"))
1583 offInterface += sizeof(RTRCPTR);
1584 else if (IS_SKIP_INSTR("R3PTR"))
1585 offInterface += sizeof(RTR3PTR);
1586 else if (IS_SKIP_INSTR("R0PTR"))
1587 offInterface += sizeof(RTR0PTR);
1588 else if (IS_SKIP_INSTR("HCPHYS"))
1589 offInterface += sizeof(RTHCPHYS);
1590 else if (IS_SKIP_INSTR("GCPHYS"))
1591 offInterface += sizeof(RTGCPHYS);
1592 else
1593 AssertMsgFailedBreakStmt(("Invalid skip instruction %.*s (prefix=%s)\n", cchSym, pszCur, pszSymPrefix),
1594 rc = VERR_INVALID_PARAMETER);
1595 AssertMsgBreakStmt(offInterface <= cbInterface,
1596 ("off=%#x cb=%#x (sym=%.*s prefix=%s)\n", offInterface, cbInterface, cchSym, pszCur, pszSymPrefix),
1597 rc = VERR_BUFFER_OVERFLOW);
1598#undef IS_SKIP_INSTR
1599 }
1600 else
1601 {
1602 /*
1603 * Construct the symbol name, get its value, store it and
1604 * advance the interface cursor.
1605 */
1606 AssertReturn(cchSymPrefix + cchSym < sizeof(szSymbol), VERR_SYMBOL_NOT_FOUND);
1607 memcpy(&szSymbol[cchSymPrefix], pszCur, cchSym);
1608 szSymbol[cchSymPrefix + cchSym] = '\0';
1609
1610 if (fRing0)
1611 {
1612 void *pvValue;
1613 rc = SUPR3GetSymbolR0((void *)(RTR0PTR)pModule->ImageBase, szSymbol, &pvValue);
1614 AssertMsgRCBreak(rc, ("Couldn't find symbol '%s' in module '%s'\n", szSymbol, pModule->szName));
1615
1616 PRTR0PTR pValue = (PRTR0PTR)((uintptr_t)pvInterface + offInterface);
1617 AssertMsgBreakStmt(offInterface + sizeof(*pValue) <= cbInterface,
1618 ("off=%#x cb=%#x sym=%s\n", offInterface, cbInterface, szSymbol),
1619 rc = VERR_BUFFER_OVERFLOW);
1620 *pValue = (RTR0PTR)pvValue;
1621 Assert((void *)*pValue == pvValue);
1622 offInterface += sizeof(*pValue);
1623 }
1624 else
1625 {
1626 RTUINTPTR Value;
1627 rc = RTLdrGetSymbolEx(pModule->hLdrMod, pModule->pvBits, pModule->ImageBase, szSymbol, &Value);
1628 AssertMsgRCBreak(rc, ("Couldn't find symbol '%s' in module '%s'\n", szSymbol, pModule->szName));
1629
1630 PRTRCPTR pValue = (PRTRCPTR)((uintptr_t)pvInterface + offInterface);
1631 AssertMsgBreakStmt(offInterface + sizeof(*pValue) <= cbInterface,
1632 ("off=%#x cb=%#x sym=%s\n", offInterface, cbInterface, szSymbol),
1633 rc = VERR_BUFFER_OVERFLOW);
1634 *pValue = (RTRCPTR)Value;
1635 Assert(*pValue == Value);
1636 offInterface += sizeof(*pValue);
1637 }
1638 }
1639
1640 /* advance */
1641 pszCur = pszNext;
1642 }
1643
1644 }
1645 else
1646 rc = VERR_MODULE_NOT_FOUND;
1647 return rc;
1648}
1649
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