VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/DBGFR3PlugIn.cpp@ 106952

Last change on this file since 106952 was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.6 KB
Line 
1/* $Id: DBGFR3PlugIn.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * DBGF - Debugger Facility, Plug-In Support.
4 */
5
6/*
7 * Copyright (C) 2008-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_DBGF
33#include <VBox/vmm/dbgf.h>
34#include <VBox/vmm/mm.h>
35#include <VBox/vmm/vmm.h>
36#include "DBGFInternal.h"
37#include <VBox/vmm/uvm.h>
38#include <VBox/vmm/vm.h>
39#include <VBox/err.h>
40#include <VBox/log.h>
41#include <VBox/version.h>
42
43#include <iprt/alloca.h>
44#include <iprt/assert.h>
45#include <iprt/ctype.h>
46#include <iprt/env.h>
47#include <iprt/dir.h>
48#include <iprt/ldr.h>
49#include <iprt/param.h>
50#include <iprt/path.h>
51
52
53/*********************************************************************************************************************************
54* Defined Constants And Macros *
55*********************************************************************************************************************************/
56
57#define DBGF_PLUG_IN_READ_LOCK(pUVM) \
58 do { int rcLock = RTCritSectRwEnterShared(&pUVM->dbgf.s.CritSect); AssertRC(rcLock); } while (0)
59#define DBGF_PLUG_IN_READ_UNLOCK(pUVM) \
60 do { int rcLock = RTCritSectRwLeaveShared(&pUVM->dbgf.s.CritSect); AssertRC(rcLock); } while (0)
61
62#define DBGF_PLUG_IN_WRITE_LOCK(pUVM) \
63 do { int rcLock = RTCritSectRwEnterExcl(&pUVM->dbgf.s.CritSect); AssertRC(rcLock); } while (0)
64#define DBGF_PLUG_IN_WRITE_UNLOCK(pUVM) \
65 do { int rcLock = RTCritSectRwLeaveExcl(&pUVM->dbgf.s.CritSect); AssertRC(rcLock); } while (0)
66
67/** Max allowed length of a plug-in name (excludes the path and suffix). */
68#define DBGFPLUGIN_MAX_NAME 64
69
70
71/*********************************************************************************************************************************
72* Structures and Typedefs *
73*********************************************************************************************************************************/
74/**
75 * Plug-in tracking record.
76 */
77typedef struct DBGFPLUGIN
78{
79 /** Pointer to the next plug-in. */
80 struct DBGFPLUGIN *pNext;
81 /** The loader handle. */
82 RTLDRMOD hLdrMod;
83 /** The plug-in entry point. */
84 PFNDBGFPLUGIN pfnEntry;
85 /** The name length. */
86 uint8_t cchName;
87 /** The plug-in name (variable length). */
88 char szName[1];
89} DBGFPLUGIN;
90/** Pointer to plug-in tracking record. */
91typedef DBGFPLUGIN *PDBGFPLUGIN;
92
93
94/*********************************************************************************************************************************
95* Internal Functions *
96*********************************************************************************************************************************/
97static DECLCALLBACK(void) dbgfPlugInUnloadAll(PUVM pUVM);
98static FNDBGFHANDLERINT dbgfR3PlugInInfoList;
99
100
101/**
102 * Internal init routine called by DBGFR3Init().
103 *
104 * @returns VBox status code.
105 * @param pUVM The user mode VM handle.
106 */
107int dbgfR3PlugInInit(PUVM pUVM)
108{
109 return DBGFR3InfoRegisterInternal(pUVM->pVM, "plugins", "Lists the debugger plug-ins.", dbgfR3PlugInInfoList);
110}
111
112
113/**
114 * Internal cleanup routine called by DBGFR3Term().
115 *
116 * @param pUVM The user mode VM handle.
117 */
118void dbgfR3PlugInTerm(PUVM pUVM)
119{
120 dbgfPlugInUnloadAll(pUVM);
121}
122
123
124/**
125 * Extracts the plug-in name from a plug-in specifier that may or may not
126 * include path and/or suffix.
127 *
128 * @returns VBox status code.
129 *
130 * @param pszDst Where to return the name. At least DBGFPLUGIN_MAX_NAME
131 * worth of buffer space.
132 * @param pszPlugIn The plug-in module specifier to parse.
133 * @param pErrInfo Optional error information structure.
134 */
135static int dbgfPlugInExtractName(char *pszDst, const char *pszPlugIn, PRTERRINFO pErrInfo)
136{
137 /*
138 * Parse out the name stopping at the extension.
139 */
140 const char *pszName = RTPathFilename(pszPlugIn);
141 if (!pszName || !*pszName)
142 return VERR_INVALID_NAME;
143 if (!RTStrNICmp(pszName, RT_STR_TUPLE(DBGF_PLUG_IN_PREFIX)))
144 {
145 pszName += sizeof(DBGF_PLUG_IN_PREFIX) - 1;
146 if (!*pszName)
147 return RTErrInfoSetF(pErrInfo, VERR_INVALID_NAME, "Invalid plug-in name: nothing after the prefix");
148 }
149
150 int ch;
151 size_t cchName = 0;
152 while ( (ch = pszName[cchName]) != '\0'
153 && ch != '.')
154 {
155 if ( RT_C_IS_ALPHA(ch)
156 || (RT_C_IS_DIGIT(ch) && cchName != 0))
157 cchName++;
158 else
159 {
160 if (!RT_C_IS_DIGIT(ch))
161 return RTErrInfoSetF(pErrInfo, VERR_INVALID_NAME, "Invalid plug-in name: '%c' is not alphanumeric", ch);
162 return RTErrInfoSetF(pErrInfo, VERR_INVALID_NAME,
163 "Invalid plug-in name: Cannot start with a digit (after the prefix)");
164 }
165 }
166
167 if (cchName >= DBGFPLUGIN_MAX_NAME)
168 return RTErrInfoSetF(pErrInfo, VERR_INVALID_NAME, "Invalid plug-in name: too long (max %u)", DBGFPLUGIN_MAX_NAME);
169
170 /*
171 * We're very picky about the extension when present.
172 */
173 if ( ch == '.'
174 && RTStrICmp(&pszName[cchName], RTLdrGetSuff()))
175 return RTErrInfoSetF(pErrInfo, VERR_INVALID_NAME,
176 "Invalid plug-in name: Suffix isn't the default dll/so/dylib one (%s): '%s'",
177 RTLdrGetSuff(), &pszName[cchName]);
178
179 /*
180 * Copy it.
181 */
182 memcpy(pszDst, pszName, cchName);
183 pszDst[cchName] = '\0';
184 return VINF_SUCCESS;
185}
186
187
188/**
189 * Locate a loaded plug-in.
190 *
191 * @returns Pointer to the plug-in tracking structure.
192 * @param pUVM Pointer to the user-mode VM structure.
193 * @param pszName The name of the plug-in we're looking for.
194 * @param ppPrev Where to optionally return the pointer to the
195 * previous list member.
196 */
197static PDBGFPLUGIN dbgfR3PlugInLocate(PUVM pUVM, const char *pszName, PDBGFPLUGIN *ppPrev)
198{
199 PDBGFPLUGIN pPrev = NULL;
200 PDBGFPLUGIN pCur = pUVM->dbgf.s.pPlugInHead;
201 while (pCur)
202 {
203 if (!RTStrICmp(pCur->szName, pszName))
204 {
205 if (ppPrev)
206 *ppPrev = pPrev;
207 return pCur;
208 }
209
210 /* advance */
211 pPrev = pCur;
212 pCur = pCur->pNext;
213 }
214 return NULL;
215}
216
217
218/**
219 * Try load the specified plug-in module.
220 *
221 * @returns VINF_SUCCESS on success, path error or loader error on failure.
222 *
223 * @param pPlugIn The plug-in tracing record.
224 * @param pszModule Module name.
225 * @param pErrInfo Optional error information structure.
226 */
227static int dbgfR3PlugInTryLoad(PDBGFPLUGIN pPlugIn, const char *pszModule, PRTERRINFO pErrInfo)
228{
229 /*
230 * Load it and try resolve the entry point.
231 */
232 int rc = SUPR3HardenedVerifyPlugIn(pszModule, pErrInfo);
233 if (RT_SUCCESS(rc))
234 rc = RTLdrLoadEx(pszModule, &pPlugIn->hLdrMod, RTLDRLOAD_FLAGS_LOCAL, pErrInfo);
235 if (RT_SUCCESS(rc))
236 {
237 rc = RTLdrGetSymbol(pPlugIn->hLdrMod, DBGF_PLUG_IN_ENTRYPOINT, (void **)&pPlugIn->pfnEntry);
238 if (RT_SUCCESS(rc))
239 {
240 LogRel(("DBGF: Loaded Plug-In '%s' (%s)\n", pPlugIn->szName, pszModule));
241 return VINF_SUCCESS;
242 }
243
244 RTErrInfoSet(pErrInfo, rc, "Failed to locate plug-in entrypoint (" DBGF_PLUG_IN_ENTRYPOINT ")" );
245 LogRel(("DBGF: RTLdrGetSymbol('%s', '%s',) -> %Rrc\n", pszModule, DBGF_PLUG_IN_ENTRYPOINT, rc));
246
247 RTLdrClose(pPlugIn->hLdrMod);
248 pPlugIn->hLdrMod = NIL_RTLDRMOD;
249 }
250 return rc;
251}
252
253
254/**
255 * RTPathTraverseList callback.
256 *
257 * @returns See FNRTPATHTRAVERSER.
258 *
259 * @param pchPath See FNRTPATHTRAVERSER.
260 * @param cchPath See FNRTPATHTRAVERSER.
261 * @param pvUser1 The plug-in specifier.
262 * @param pvUser2 The plug-in tracking record.
263 */
264static DECLCALLBACK(int) dbgfR3PlugInLoadCallback(const char *pchPath, size_t cchPath, void *pvUser1, void *pvUser2)
265{
266 PDBGFPLUGIN pPlugIn = (PDBGFPLUGIN)pvUser1;
267 PRTERRINFO pErrInfo = (PRTERRINFO)pvUser2;
268
269 /*
270 * Join the path and the specified plug-in name, adding prefix and suffix.
271 */
272 const char *pszSuff = RTLdrGetSuff();
273 size_t const cchSuff = strlen(pszSuff);
274 size_t const cchModule = cchPath + sizeof(RTPATH_SLASH_STR) + sizeof(DBGF_PLUG_IN_PREFIX) + pPlugIn->cchName + cchSuff + 4;
275 char *pszModule = (char *)alloca(cchModule);
276 AssertReturn(pszModule, VERR_TRY_AGAIN);
277
278 memcpy(pszModule, pchPath, cchPath);
279 pszModule[cchPath] = '\0';
280
281 int rc = RTPathAppend(pszModule, cchModule, DBGF_PLUG_IN_PREFIX);
282 AssertRCReturn(rc, VERR_TRY_AGAIN); /* (This cannot possibly fail, just usual paranoia convention.) */
283 size_t const cchWithPrefix = cchPath + strlen(&pszModule[cchPath]); /* (May have added a slash.) */
284
285 Assert(cchWithPrefix + pPlugIn->cchName + cchSuff < cchModule - 4);
286 memcpy(mempcpy(&pszModule[cchWithPrefix], pPlugIn->szName, pPlugIn->cchName), pszSuff, cchSuff + 1);
287
288 if (RTPathExists(pszModule))
289 {
290 rc = dbgfR3PlugInTryLoad(pPlugIn, pszModule, pErrInfo);
291 if (RT_SUCCESS(rc))
292 return VINF_SUCCESS;
293 }
294
295 return VERR_TRY_AGAIN;
296}
297
298
299/**
300 * Loads a plug-in.
301 *
302 * @returns VBox status code.
303 * @param pUVM Pointer to the user-mode VM structure.
304 * @param pszName The plug-in name.
305 * @param pszMaybeModule Path to the plug-in, or just the
306 * plug-in name as specified by the user. Ignored
307 * if no path.
308 * @param pErrInfo Optional error information structure.
309 */
310static DECLCALLBACK(int) dbgfR3PlugInLoad(PUVM pUVM, const char *pszName, const char *pszMaybeModule, PRTERRINFO pErrInfo)
311{
312 DBGF_PLUG_IN_WRITE_LOCK(pUVM);
313
314 /*
315 * Check if a plug-in by the given name already exists.
316 */
317 PDBGFPLUGIN pPlugIn = dbgfR3PlugInLocate(pUVM, pszName, NULL);
318 if (pPlugIn)
319 {
320 DBGF_PLUG_IN_WRITE_UNLOCK(pUVM);
321 return RTErrInfoSetF(pErrInfo, VERR_ALREADY_EXISTS, "A plug-in by the name '%s' already exists", pszName);
322 }
323
324 /*
325 * Create a module structure and we can pass around via RTPathTraverseList if needed.
326 */
327 size_t cbName = strlen(pszName) + 1;
328 pPlugIn = (PDBGFPLUGIN)MMR3HeapAllocZU(pUVM, MM_TAG_DBGF, RT_UOFFSETOF_DYN(DBGFPLUGIN, szName[cbName]));
329 if (RT_UNLIKELY(!pPlugIn))
330 {
331 DBGF_PLUG_IN_WRITE_UNLOCK(pUVM);
332 return VERR_NO_MEMORY;
333 }
334 memcpy(pPlugIn->szName, pszName, cbName);
335 pPlugIn->cchName = (uint8_t)cbName - 1;
336 Assert(pPlugIn->cchName == cbName - 1);
337
338 /*
339 * If the caller specified a path, try load exactly what was specified.
340 */
341 int rc;
342 if (RTPathHavePath(pszMaybeModule))
343 rc = dbgfR3PlugInTryLoad(pPlugIn, pszMaybeModule, pErrInfo);
344 else
345 {
346 /*
347 * No path specified, search for the plug-in using the canonical
348 * module name for it.
349 */
350 RTErrInfoClear(pErrInfo);
351
352 /* 1. The private architecture directory. */
353 char szPath[_4K];
354 rc = RTPathAppPrivateArch(szPath, sizeof(szPath));
355 if (RT_SUCCESS(rc))
356 rc = RTPathTraverseList(szPath, '\0', dbgfR3PlugInLoadCallback, pPlugIn, pErrInfo);
357 if (RT_FAILURE_NP(rc))
358 {
359 /* 2. The config value 'PlugInPath' */
360 int rc2 = CFGMR3QueryString(CFGMR3GetChild(CFGMR3GetRootU(pUVM), "/DBGF"), "PlugInPath", szPath, sizeof(szPath));
361 if (RT_SUCCESS(rc2))
362 rc = RTPathTraverseList(szPath, ';', dbgfR3PlugInLoadCallback, pPlugIn, pErrInfo);
363 if (RT_FAILURE_NP(rc))
364 {
365 /* 3. The VBOXDBG_PLUG_IN_PATH environment variable. */
366 rc2 = RTEnvGetEx(RTENV_DEFAULT, "VBOXDBG_PLUG_IN_PATH", szPath, sizeof(szPath), NULL);
367 if (RT_SUCCESS(rc2))
368 rc = RTPathTraverseList(szPath, ';', dbgfR3PlugInLoadCallback, pPlugIn, pErrInfo);
369 }
370 }
371
372 if (rc == VERR_END_OF_STRING)
373 rc = VERR_FILE_NOT_FOUND;
374 if (pErrInfo && !RTErrInfoIsSet(pErrInfo))
375 RTErrInfoSetF(pErrInfo, rc, "Failed to locate '%s'", pPlugIn->szName);
376 }
377 if (RT_SUCCESS(rc))
378 {
379 /*
380 * Try initialize it.
381 */
382 rc = pPlugIn->pfnEntry(DBGFPLUGINOP_INIT, pUVM, VMMR3GetVTable(), VBOX_VERSION);
383 if (RT_SUCCESS(rc))
384 {
385 /*
386 * Link it and we're good.
387 */
388 pPlugIn->pNext = pUVM->dbgf.s.pPlugInHead;
389 pUVM->dbgf.s.pPlugInHead = pPlugIn;
390
391 DBGF_PLUG_IN_WRITE_UNLOCK(pUVM);
392 return VINF_SUCCESS;
393 }
394
395 RTErrInfoSet(pErrInfo, rc, "Plug-in init failed");
396 LogRel(("DBGF: Plug-in '%s' failed during init: %Rrc\n", pPlugIn->szName, rc));
397 RTLdrClose(pPlugIn->hLdrMod);
398 }
399 MMR3HeapFree(pPlugIn);
400
401 DBGF_PLUG_IN_WRITE_UNLOCK(pUVM);
402 return rc;
403}
404
405
406/**
407 * Load a debugging plug-in.
408 *
409 * @returns VBox status code.
410 * @retval VERR_ALREADY_EXISTS if the module was already loaded.
411 * @retval VINF_BUFFER_OVERFLOW if the actual plug-in name buffer was too small
412 * (the plug-in was still successfully loaded).
413 * @param pUVM Pointer to the user-mode VM structure.
414 * @param pszPlugIn The plug-in name. This may specify the exact path to
415 * the plug-in module, or it may just specify the core name
416 * of the plug-in without prefix, suffix and path.
417 * @param pszActual Buffer to return the actual plug-in name in. Optional.
418 * This will be returned on VERR_ALREADY_EXSIST too.
419 * @param cbActual The size of @a pszActual.
420 * @param pErrInfo Optional error information structure.
421 */
422VMMR3DECL(int) DBGFR3PlugInLoad(PUVM pUVM, const char *pszPlugIn, char *pszActual, size_t cbActual, PRTERRINFO pErrInfo)
423{
424 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
425 AssertPtrReturn(pszPlugIn, VERR_INVALID_PARAMETER);
426
427 /*
428 * Extract the plug-in name. Copy it to the return buffer as we'll want to
429 * return it in the VERR_ALREADY_EXISTS case too.
430 */
431 char szName[DBGFPLUGIN_MAX_NAME];
432 int rc = dbgfPlugInExtractName(szName, pszPlugIn, pErrInfo);
433 if (RT_SUCCESS(rc))
434 {
435 int rc2 = VINF_SUCCESS;
436 if (pszActual)
437 rc2 = RTStrCopy(pszActual, cbActual, szName);
438
439 /*
440 * Write lock releated DBGF bits and try load it.
441 */
442 rc = VMR3ReqPriorityCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3PlugInLoad, 4, pUVM, szName, pszPlugIn, pErrInfo);
443 if (rc2 != VINF_SUCCESS && RT_SUCCESS(rc))
444 rc = VINF_BUFFER_OVERFLOW;
445 }
446
447 return rc;
448}
449
450
451/**
452 * Load all plug-ins from the architechture private directory of VBox.
453 *
454 * @param pUVM Pointer to the user-mode VM structure.
455 */
456VMMR3DECL(void) DBGFR3PlugInLoadAll(PUVM pUVM)
457{
458 UVM_ASSERT_VALID_EXT_RETURN_VOID(pUVM);
459
460 /*
461 * Pass it on to EMT(0) if necessary (thanks to DBGFR3Os*).
462 */
463 if (VMR3GetVMCPUId(pUVM->pVM) != 0)
464 {
465 VMR3ReqPriorityCallVoidWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)DBGFR3PlugInLoadAll, 1, pUVM);
466 return;
467 }
468
469
470 /*
471 * Open the architecture specific directory with a filter on our prefix
472 * and names including a dot.
473 */
474 const char *pszSuff = RTLdrGetSuff();
475 size_t cchSuff = strlen(pszSuff);
476
477 char szPath[RTPATH_MAX];
478 int rc = RTPathAppPrivateArch(szPath, sizeof(szPath) - cchSuff);
479 AssertRCReturnVoid(rc);
480 size_t offDir = strlen(szPath);
481
482 rc = RTPathAppend(szPath, sizeof(szPath) - cchSuff, DBGF_PLUG_IN_PREFIX "*");
483 AssertRCReturnVoid(rc);
484 rc = RTStrCat(szPath, sizeof(szPath), pszSuff);
485 AssertRCReturnVoid(rc);
486
487 RTDIR hDir;
488 rc = RTDirOpenFiltered(&hDir, szPath, RTDIRFILTER_WINNT, 0 /*fFlags*/);
489 if (RT_SUCCESS(rc))
490 {
491 /*
492 * Now read it and try load each of the plug-in modules.
493 */
494 RTDIRENTRY DirEntry;
495 while (RT_SUCCESS(RTDirRead(hDir, &DirEntry, NULL)))
496 {
497 szPath[offDir] = '\0';
498 rc = RTPathAppend(szPath, sizeof(szPath), DirEntry.szName);
499 if (RT_SUCCESS(rc))
500 {
501 char szName[DBGFPLUGIN_MAX_NAME];
502 rc = dbgfPlugInExtractName(szName, DirEntry.szName, NULL);
503 if (RT_SUCCESS(rc))
504 {
505 DBGF_PLUG_IN_WRITE_LOCK(pUVM);
506 dbgfR3PlugInLoad(pUVM, szName, szPath, NULL);
507 DBGF_PLUG_IN_WRITE_UNLOCK(pUVM);
508 }
509 }
510 }
511
512 RTDirClose(hDir);
513 }
514}
515
516
517/**
518 * Unloads a plug-in by name (no path, prefix or suffix).
519 *
520 * @returns VBox status code.
521 * @retval VERR_NOT_FOUND if the specified plug-in wasn't found.
522 * @param pUVM Pointer to the user-mode VM structure.
523 * @param pszName The name of the plug-in to unload.
524 */
525VMMR3DECL(int) DBGFR3PlugInUnload(PUVM pUVM, const char *pszName)
526{
527 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
528
529 /*
530 * Pass it on to EMT(0) if necessary (thanks to DBGFR3Os*).
531 */
532 if (VMR3GetVMCPUId(pUVM->pVM) != 0)
533 return VMR3ReqPriorityCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)DBGFR3PlugInUnload, 2, pUVM, pszName);
534
535
536 /*
537 * Find the plug-in.
538 */
539 DBGF_PLUG_IN_WRITE_LOCK(pUVM);
540
541 int rc;
542 PDBGFPLUGIN pPrevPlugIn;
543 PDBGFPLUGIN pPlugIn = dbgfR3PlugInLocate(pUVM, pszName, &pPrevPlugIn);
544 if (pPlugIn)
545 {
546 /*
547 * Unlink, terminate, unload and free the plug-in.
548 */
549 if (pPrevPlugIn)
550 pPrevPlugIn->pNext = pPlugIn->pNext;
551 else
552 pUVM->dbgf.s.pPlugInHead = pPlugIn->pNext;
553
554 pPlugIn->pfnEntry(DBGFPLUGINOP_TERM, pUVM, VMMR3GetVTable(), 0);
555 RTLdrClose(pPlugIn->hLdrMod);
556
557 pPlugIn->pfnEntry = NULL;
558 pPlugIn->hLdrMod = NIL_RTLDRMOD;
559 MMR3HeapFree(pPlugIn->pNext);
560 rc = VINF_SUCCESS;
561 }
562 else
563 rc = VERR_NOT_FOUND;
564
565 DBGF_PLUG_IN_WRITE_UNLOCK(pUVM);
566 return rc;
567}
568
569
570/**
571 * Unload all plug-ins.
572 *
573 * @param pUVM Pointer to the user-mode VM structure.
574 */
575static DECLCALLBACK(void) dbgfPlugInUnloadAll(PUVM pUVM)
576{
577 DBGF_PLUG_IN_WRITE_LOCK(pUVM);
578
579 while (pUVM->dbgf.s.pPlugInHead)
580 {
581 PDBGFPLUGIN pPlugin = pUVM->dbgf.s.pPlugInHead;
582 pUVM->dbgf.s.pPlugInHead = pPlugin->pNext;
583
584 pPlugin->pfnEntry(DBGFPLUGINOP_TERM, pUVM, VMMR3GetVTable(), 0);
585
586 int rc2 = RTLdrClose(pPlugin->hLdrMod);
587 AssertRC(rc2);
588
589 pPlugin->pfnEntry = NULL;
590 pPlugin->hLdrMod = NIL_RTLDRMOD;
591 MMR3HeapFree(pPlugin);
592 }
593
594 DBGF_PLUG_IN_WRITE_UNLOCK(pUVM);
595}
596
597
598/**
599 * Unloads all plug-ins.
600 *
601 * @param pUVM Pointer to the user-mode VM structure.
602 */
603VMMR3DECL(void) DBGFR3PlugInUnloadAll(PUVM pUVM)
604{
605 UVM_ASSERT_VALID_EXT_RETURN_VOID(pUVM);
606 /* Thanks to DBGFR3Os, this must be done on EMT(0). */
607 VMR3ReqPriorityCallVoidWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfPlugInUnloadAll, 1, pUVM);
608}
609
610
611
612/**
613 * @callback_method_impl{FNDBGFHANDLERINT, The 'plugins' info item.}
614 */
615static DECLCALLBACK(void) dbgfR3PlugInInfoList(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
616{
617 PDBGFPLUGIN pPlugIn = pVM->pUVM->dbgf.s.pPlugInHead;
618 RT_NOREF_PV(pszArgs);
619 if (pPlugIn)
620 {
621 pHlp->pfnPrintf(pHlp, "Debugging plug-in%s: %s", pPlugIn->pNext ? "s" : "", pPlugIn->szName);
622 while ((pPlugIn = pPlugIn->pNext) != NULL)
623 pHlp->pfnPrintf(pHlp, ", %s", pPlugIn->szName);
624 pHlp->pfnPrintf(pHlp, "\n");
625
626 }
627 else
628 pHlp->pfnPrintf(pHlp, "No plug-ins loaded\n");
629}
630
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