VirtualBox

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

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

doxygen: fixes.

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