VirtualBox

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

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

VMM: -Wunused-parameter

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