VirtualBox

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

Last change on this file since 58116 was 58116, checked in by vboxsync, 9 years ago

VMM: Doxygen fixes.

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