VirtualBox

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

Last change on this file since 93609 was 93554, checked in by vboxsync, 3 years ago

VMM: Changed PAGE_SIZE -> GUEST_PAGE_SIZE / HOST_PAGE_SIZE, PAGE_SHIFT -> GUEST_PAGE_SHIFT / HOST_PAGE_SHIFT, and PAGE_OFFSET_MASK -> GUEST_PAGE_OFFSET_MASK / HOST_PAGE_OFFSET_MASK. Also removed most usage of ASMMemIsZeroPage and ASMMemZeroPage since the host and guest page size doesn't need to be the same any more. Some work left to do in the page pool code. bugref:9898

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