VirtualBox

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

Last change on this file since 34185 was 33877, checked in by vboxsync, 14 years ago

PDMLdr.cpp: log RC load failure better in release builds.

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