VirtualBox

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

Last change on this file since 34906 was 34286, checked in by vboxsync, 14 years ago

nit

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