VirtualBox

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

Last change on this file since 62644 was 62643, checked in by vboxsync, 8 years ago

VMMR3: warnings

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