VirtualBox

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

Last change on this file since 30160 was 30072, checked in by vboxsync, 14 years ago

VMM: Ring-0 stack on guru meditations originating with an assertion for all 32-bit targets. The symbol resolving is ugly. Dump register context as well.

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