VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/DBGFInfo.cpp

Last change on this file was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 50.5 KB
Line 
1/* $Id: DBGFInfo.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * DBGF - Debugger Facility, Info.
4 */
5
6/*
7 * Copyright (C) 2006-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_INFO
33#include <VBox/vmm/dbgf.h>
34
35#include <VBox/vmm/mm.h>
36#include "DBGFInternal.h"
37#include <VBox/vmm/vm.h>
38#include <VBox/vmm/uvm.h>
39#include <VBox/err.h>
40#include <VBox/log.h>
41
42#include <iprt/assert.h>
43#include <iprt/ctype.h>
44#include <iprt/getopt.h>
45#include <iprt/param.h>
46#include <iprt/semaphore.h>
47#include <iprt/stream.h>
48#include <iprt/string.h>
49#include <iprt/thread.h>
50
51
52/*********************************************************************************************************************************
53* Internal Functions *
54*********************************************************************************************************************************/
55static DECLCALLBACK(void) dbgfR3InfoLog_Printf(PCDBGFINFOHLP pHlp, const char *pszFormat, ...);
56static DECLCALLBACK(void) dbgfR3InfoLog_PrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args);
57static DECLCALLBACK(void) dbgfR3InfoLogRel_Printf(PCDBGFINFOHLP pHlp, const char *pszFormat, ...);
58static DECLCALLBACK(void) dbgfR3InfoLogRel_PrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args);
59static DECLCALLBACK(void) dbgfR3InfoStdErr_Printf(PCDBGFINFOHLP pHlp, const char *pszFormat, ...);
60static DECLCALLBACK(void) dbgfR3InfoStdErr_PrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args);
61static DECLCALLBACK(void) dbgfR3InfoHelp(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
62
63
64/*********************************************************************************************************************************
65* Global Variables *
66*********************************************************************************************************************************/
67/** Logger output. */
68static const DBGFINFOHLP g_dbgfR3InfoLogHlp =
69{
70 dbgfR3InfoLog_Printf,
71 dbgfR3InfoLog_PrintfV,
72 DBGFR3InfoGenericGetOptError,
73};
74
75/** Release logger output. */
76static const DBGFINFOHLP g_dbgfR3InfoLogRelHlp =
77{
78 dbgfR3InfoLogRel_Printf,
79 dbgfR3InfoLogRel_PrintfV,
80 DBGFR3InfoGenericGetOptError
81};
82
83/** Standard error output. */
84static const DBGFINFOHLP g_dbgfR3InfoStdErrHlp =
85{
86 dbgfR3InfoStdErr_Printf,
87 dbgfR3InfoStdErr_PrintfV,
88 DBGFR3InfoGenericGetOptError
89};
90
91
92/**
93 * Initialize the info handlers.
94 *
95 * This is called first during the DBGF init process and thus does the shared
96 * critsect init.
97 *
98 * @returns VBox status code.
99 * @param pUVM The user mode VM handle.
100 */
101int dbgfR3InfoInit(PUVM pUVM)
102{
103 /*
104 * Make sure we already didn't initialized in the lazy manner.
105 */
106 if (RTCritSectRwIsInitialized(&pUVM->dbgf.s.CritSect))
107 return VINF_SUCCESS;
108
109 /*
110 * Initialize the crit sect.
111 */
112 int rc = RTCritSectRwInitNamed(&pUVM->dbgf.s.CritSect, "DBGF-CritSect-RW");
113 AssertRCReturn(rc, rc);
114
115 /*
116 * Register the 'info help' item.
117 */
118 rc = DBGFR3InfoRegisterInternal(pUVM->pVM, "help", "List of info items.", dbgfR3InfoHelp);
119 AssertRCReturn(rc, rc);
120
121 return VINF_SUCCESS;
122}
123
124
125/**
126 * Terminate the info handlers.
127 *
128 * @returns VBox status code.
129 * @param pUVM The user mode VM handle.
130 */
131int dbgfR3InfoTerm(PUVM pUVM)
132{
133 /*
134 * Delete the crit sect.
135 */
136 int rc = RTCritSectRwDelete(&pUVM->dbgf.s.CritSect);
137 AssertRC(rc);
138 return rc;
139}
140
141
142/**
143 * @interface_method_impl{DBGFINFOHLP,pfnGetOptError}
144 */
145VMMR3DECL(void) DBGFR3InfoGenericGetOptError(PCDBGFINFOHLP pHlp, int rc, PRTGETOPTUNION pValueUnion, PRTGETOPTSTATE pState)
146{
147 RT_NOREF(pState);
148 char szMsg[1024];
149 RTGetOptFormatError(szMsg, sizeof(szMsg), rc, pValueUnion);
150 pHlp->pfnPrintf(pHlp, "syntax error: %s\n", szMsg);
151}
152
153
154/**
155 * @interface_method_impl{DBGFINFOHLP,pfnPrintf, Logger output.}
156 */
157static DECLCALLBACK(void) dbgfR3InfoLog_Printf(PCDBGFINFOHLP pHlp, const char *pszFormat, ...)
158{
159 NOREF(pHlp);
160 va_list args;
161 va_start(args, pszFormat);
162 RTLogPrintfV(pszFormat, args);
163 va_end(args);
164}
165
166
167/**
168 * @interface_method_impl{DBGFINFOHLP,pfnPrintfV, Logger output.}
169 */
170static DECLCALLBACK(void) dbgfR3InfoLog_PrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args)
171{
172 NOREF(pHlp);
173 RTLogPrintfV(pszFormat, args);
174}
175
176
177/**
178 * Gets the logger info helper.
179 * The returned info helper will unconditionally write all output to the log.
180 *
181 * @returns Pointer to the logger info helper.
182 */
183VMMR3DECL(PCDBGFINFOHLP) DBGFR3InfoLogHlp(void)
184{
185 return &g_dbgfR3InfoLogHlp;
186}
187
188
189/**
190 * @interface_method_impl{DBGFINFOHLP,pfnPrintf, Release logger output.}
191 */
192static DECLCALLBACK(void) dbgfR3InfoLogRel_Printf(PCDBGFINFOHLP pHlp, const char *pszFormat, ...)
193{
194 NOREF(pHlp);
195 va_list args;
196 va_start(args, pszFormat);
197 RTLogRelPrintfV(pszFormat, args);
198 va_end(args);
199}
200
201
202/**
203 * @interface_method_impl{DBGFINFOHLP,pfnPrintfV, Release logger output.}
204 */
205static DECLCALLBACK(void) dbgfR3InfoLogRel_PrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args)
206{
207 NOREF(pHlp);
208 RTLogRelPrintfV(pszFormat, args);
209}
210
211
212/**
213 * @interface_method_impl{DBGFINFOHLP,pfnPrintf, Stdandard error output.}
214 */
215static DECLCALLBACK(void) dbgfR3InfoStdErr_Printf(PCDBGFINFOHLP pHlp, const char *pszFormat, ...)
216{
217 NOREF(pHlp);
218 va_list args;
219 va_start(args, pszFormat);
220 RTStrmPrintfV(g_pStdErr, pszFormat, args);
221 va_end(args);
222}
223
224
225/**
226 * @interface_method_impl{DBGFINFOHLP,pfnPrintfV, Stdandard error output.}
227 */
228static DECLCALLBACK(void) dbgfR3InfoStdErr_PrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args)
229{
230 NOREF(pHlp);
231 RTStrmPrintfV(g_pStdErr, pszFormat, args);
232}
233
234
235/**
236 * Gets the release logger info helper.
237 * The returned info helper will unconditionally write all output to the release log.
238 *
239 * @returns Pointer to the release logger info helper.
240 */
241VMMR3DECL(PCDBGFINFOHLP) DBGFR3InfoLogRelHlp(void)
242{
243 return &g_dbgfR3InfoLogRelHlp;
244}
245
246
247/**
248 * Handle registration worker.
249 *
250 * This allocates the structure, initializes the common fields and inserts into the list.
251 * Upon successful return the we're inside the crit sect and the caller must leave it.
252 *
253 * @returns VBox status code.
254 * @param pUVM The user mode VM handle.
255 * @param pszName The identifier of the info.
256 * @param pszDesc The description of the info and any arguments the handler may take.
257 * @param fFlags The flags.
258 * @param ppInfo Where to store the created
259 */
260static int dbgfR3InfoRegister(PUVM pUVM, const char *pszName, const char *pszDesc, uint32_t fFlags, PDBGFINFO *ppInfo)
261{
262 /*
263 * Validate.
264 */
265 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
266 AssertReturn(*pszName, VERR_INVALID_PARAMETER);
267 AssertPtrReturn(pszDesc, VERR_INVALID_POINTER);
268 AssertMsgReturn(!(fFlags & ~(DBGFINFO_FLAGS_RUN_ON_EMT | DBGFINFO_FLAGS_ALL_EMTS)),
269 ("fFlags=%#x\n", fFlags), VERR_INVALID_FLAGS);
270
271 /*
272 * Allocate and initialize.
273 */
274 int rc;
275 size_t cchName = strlen(pszName) + 1;
276 PDBGFINFO pInfo = (PDBGFINFO)MMR3HeapAllocU(pUVM, MM_TAG_DBGF_INFO, RT_UOFFSETOF_DYN(DBGFINFO, szName[cchName]));
277 if (pInfo)
278 {
279 pInfo->enmType = DBGFINFOTYPE_INVALID;
280 pInfo->fFlags = fFlags;
281 pInfo->pszDesc = pszDesc;
282 pInfo->cchName = cchName - 1;
283 memcpy(pInfo->szName, pszName, cchName);
284
285 /* lazy init */
286 rc = VINF_SUCCESS;
287 if (!RTCritSectRwIsInitialized(&pUVM->dbgf.s.CritSect))
288 rc = dbgfR3InfoInit(pUVM);
289 if (RT_SUCCESS(rc))
290 {
291 /*
292 * Insert in alphabetical order.
293 */
294 rc = RTCritSectRwEnterExcl(&pUVM->dbgf.s.CritSect);
295 AssertRC(rc);
296 PDBGFINFO pPrev = NULL;
297 PDBGFINFO pCur;
298 for (pCur = pUVM->dbgf.s.pInfoFirst; pCur; pPrev = pCur, pCur = pCur->pNext)
299 if (strcmp(pszName, pCur->szName) < 0)
300 break;
301 pInfo->pNext = pCur;
302 if (pPrev)
303 pPrev->pNext = pInfo;
304 else
305 pUVM->dbgf.s.pInfoFirst = pInfo;
306
307 *ppInfo = pInfo;
308 return VINF_SUCCESS;
309 }
310 MMR3HeapFree(pInfo);
311 }
312 else
313 rc = VERR_NO_MEMORY;
314 return rc;
315}
316
317
318/**
319 * Register a info handler owned by a device.
320 *
321 * @returns VBox status code.
322 * @param pVM The cross context VM structure.
323 * @param pszName The identifier of the info.
324 * @param pszDesc The description of the info and any arguments the handler may take.
325 * @param pfnHandler The handler function to be called to display the info.
326 * @param pDevIns The device instance owning the info.
327 */
328VMMR3_INT_DECL(int) DBGFR3InfoRegisterDevice(PVM pVM, const char *pszName, const char *pszDesc,
329 PFNDBGFHANDLERDEV pfnHandler, PPDMDEVINS pDevIns)
330{
331 LogFlow(("DBGFR3InfoRegisterDevice: pszName=%p:{%s} pszDesc=%p:{%s} pfnHandler=%p pDevIns=%p\n",
332 pszName, pszName, pszDesc, pszDesc, pfnHandler, pDevIns));
333
334 /*
335 * Validate the specific stuff.
336 */
337 AssertPtrReturn(pfnHandler, VERR_INVALID_POINTER);
338 AssertPtrReturn(pDevIns, VERR_INVALID_POINTER);
339
340 /*
341 * Register
342 */
343 PDBGFINFO pInfo;
344 int rc = dbgfR3InfoRegister(pVM->pUVM, pszName, pszDesc, 0, &pInfo);
345 if (RT_SUCCESS(rc))
346 {
347 pInfo->enmType = DBGFINFOTYPE_DEV;
348 pInfo->u.Dev.pfnHandler = pfnHandler;
349 pInfo->u.Dev.pDevIns = pDevIns;
350 RTCritSectRwLeaveExcl(&pVM->pUVM->dbgf.s.CritSect);
351 }
352
353 return rc;
354}
355
356
357/**
358 * Register a info handler owned by a driver.
359 *
360 * @returns VBox status code.
361 * @param pVM The cross context VM structure.
362 * @param pszName The identifier of the info.
363 * @param pszDesc The description of the info and any arguments the handler may take.
364 * @param pfnHandler The handler function to be called to display the info.
365 * @param pDrvIns The driver instance owning the info.
366 */
367VMMR3_INT_DECL(int) DBGFR3InfoRegisterDriver(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFHANDLERDRV pfnHandler, PPDMDRVINS pDrvIns)
368{
369 LogFlow(("DBGFR3InfoRegisterDriver: pszName=%p:{%s} pszDesc=%p:{%s} pfnHandler=%p pDrvIns=%p\n",
370 pszName, pszName, pszDesc, pszDesc, pfnHandler, pDrvIns));
371
372 /*
373 * Validate the specific stuff.
374 */
375 AssertPtrReturn(pfnHandler, VERR_INVALID_POINTER);
376 AssertPtrReturn(pDrvIns, VERR_INVALID_POINTER);
377
378 /*
379 * Register
380 */
381 PDBGFINFO pInfo;
382 int rc = dbgfR3InfoRegister(pVM->pUVM, pszName, pszDesc, 0, &pInfo);
383 if (RT_SUCCESS(rc))
384 {
385 pInfo->enmType = DBGFINFOTYPE_DRV;
386 pInfo->u.Drv.pfnHandler = pfnHandler;
387 pInfo->u.Drv.pDrvIns = pDrvIns;
388 RTCritSectRwLeaveExcl(&pVM->pUVM->dbgf.s.CritSect);
389 }
390
391 return rc;
392}
393
394
395/**
396 * Register a info handler owned by an internal component.
397 *
398 * @returns VBox status code.
399 * @param pVM The cross context VM structure.
400 * @param pszName The identifier of the info.
401 * @param pszDesc The description of the info and any arguments the handler may take.
402 * @param pfnHandler The handler function to be called to display the info.
403 */
404VMMR3_INT_DECL(int) DBGFR3InfoRegisterInternal(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFHANDLERINT pfnHandler)
405{
406 return DBGFR3InfoRegisterInternalEx(pVM, pszName, pszDesc, pfnHandler, 0);
407}
408
409
410/**
411 * Register a info handler owned by an internal component.
412 *
413 * @returns VBox status code.
414 * @param pVM The cross context VM structure.
415 * @param pszName The identifier of the info.
416 * @param pszDesc The description of the info and any arguments the handler may take.
417 * @param pfnHandler The handler function to be called to display the info.
418 * @param fFlags Flags, see the DBGFINFO_FLAGS_*.
419 */
420VMMR3_INT_DECL(int) DBGFR3InfoRegisterInternalEx(PVM pVM, const char *pszName, const char *pszDesc,
421 PFNDBGFHANDLERINT pfnHandler, uint32_t fFlags)
422{
423 LogFlow(("DBGFR3InfoRegisterInternalEx: pszName=%p:{%s} pszDesc=%p:{%s} pfnHandler=%p fFlags=%x\n",
424 pszName, pszName, pszDesc, pszDesc, pfnHandler, fFlags));
425
426 /*
427 * Validate the specific stuff.
428 */
429 AssertPtrReturn(pfnHandler, VERR_INVALID_POINTER);
430
431 /*
432 * Register
433 */
434 PDBGFINFO pInfo;
435 int rc = dbgfR3InfoRegister(pVM->pUVM, pszName, pszDesc, fFlags, &pInfo);
436 if (RT_SUCCESS(rc))
437 {
438 pInfo->enmType = DBGFINFOTYPE_INT;
439 pInfo->u.Int.pfnHandler = pfnHandler;
440 RTCritSectRwLeaveExcl(&pVM->pUVM->dbgf.s.CritSect);
441 }
442
443 return rc;
444}
445
446
447/**
448 * Register a info handler owned by an external component.
449 *
450 * @returns VBox status code.
451 * @param pUVM The user mode VM handle.
452 * @param pszName The identifier of the info.
453 * @param pszDesc The description of the info and any arguments the handler may take.
454 * @param pfnHandler The handler function to be called to display the info.
455 * @param pvUser User argument to be passed to the handler.
456 */
457VMMR3DECL(int) DBGFR3InfoRegisterExternal(PUVM pUVM, const char *pszName, const char *pszDesc,
458 PFNDBGFHANDLEREXT pfnHandler, void *pvUser)
459{
460 LogFlow(("DBGFR3InfoRegisterExternal: pszName=%p:{%s} pszDesc=%p:{%s} pfnHandler=%p pvUser=%p\n",
461 pszName, pszName, pszDesc, pszDesc, pfnHandler, pvUser));
462
463 /*
464 * Validate the specific stuff.
465 */
466 AssertPtrReturn(pfnHandler, VERR_INVALID_POINTER);
467 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
468
469 /*
470 * Register
471 */
472 PDBGFINFO pInfo;
473 int rc = dbgfR3InfoRegister(pUVM, pszName, pszDesc, 0, &pInfo);
474 if (RT_SUCCESS(rc))
475 {
476 pInfo->enmType = DBGFINFOTYPE_EXT;
477 pInfo->u.Ext.pfnHandler = pfnHandler;
478 pInfo->u.Ext.pvUser = pvUser;
479 RTCritSectRwLeaveExcl(&pUVM->dbgf.s.CritSect);
480 }
481
482 return rc;
483}
484
485
486/**
487 * Register a info handler owned by a device, argv style.
488 *
489 * @returns VBox status code.
490 * @param pVM The cross context VM structure.
491 * @param pszName The identifier of the info.
492 * @param pszDesc The description of the info and any arguments the handler may take.
493 * @param pfnHandler The handler function to be called to display the info.
494 * @param pDevIns The device instance owning the info.
495 */
496VMMR3_INT_DECL(int) DBGFR3InfoRegisterDeviceArgv(PVM pVM, const char *pszName, const char *pszDesc,
497 PFNDBGFINFOARGVDEV pfnHandler, PPDMDEVINS pDevIns)
498{
499 LogFlow(("DBGFR3InfoRegisterDeviceArgv: pszName=%p:{%s} pszDesc=%p:{%s} pfnHandler=%p pDevIns=%p\n",
500 pszName, pszName, pszDesc, pszDesc, pfnHandler, pDevIns));
501
502 /*
503 * Validate the specific stuff.
504 */
505 AssertPtrReturn(pfnHandler, VERR_INVALID_POINTER);
506 AssertPtrReturn(pDevIns, VERR_INVALID_POINTER);
507
508 /*
509 * Register
510 */
511 PDBGFINFO pInfo;
512 int rc = dbgfR3InfoRegister(pVM->pUVM, pszName, pszDesc, 0, &pInfo);
513 if (RT_SUCCESS(rc))
514 {
515 pInfo->enmType = DBGFINFOTYPE_DEV_ARGV;
516 pInfo->u.DevArgv.pfnHandler = pfnHandler;
517 pInfo->u.DevArgv.pDevIns = pDevIns;
518 RTCritSectRwLeaveExcl(&pVM->pUVM->dbgf.s.CritSect);
519 }
520
521 return rc;
522}
523
524
525/**
526 * Register a info handler owned by a driver, argv style.
527 *
528 * @returns VBox status code.
529 * @param pVM The cross context VM structure.
530 * @param pszName The identifier of the info.
531 * @param pszDesc The description of the info and any arguments the handler may take.
532 * @param pfnHandler The handler function to be called to display the info.
533 * @param pDrvIns The driver instance owning the info.
534 */
535VMMR3_INT_DECL(int) DBGFR3InfoRegisterDriverArgv(PVM pVM, const char *pszName, const char *pszDesc,
536 PFNDBGFINFOARGVDRV pfnHandler, PPDMDRVINS pDrvIns)
537{
538 LogFlow(("DBGFR3InfoRegisterDriverArgv: pszName=%p:{%s} pszDesc=%p:{%s} pfnHandler=%p pDrvIns=%p\n",
539 pszName, pszName, pszDesc, pszDesc, pfnHandler, pDrvIns));
540
541 /*
542 * Validate the specific stuff.
543 */
544 AssertPtrReturn(pfnHandler, VERR_INVALID_POINTER);
545 AssertPtrReturn(pDrvIns, VERR_INVALID_POINTER);
546
547 /*
548 * Register
549 */
550 PDBGFINFO pInfo;
551 int rc = dbgfR3InfoRegister(pVM->pUVM, pszName, pszDesc, 0, &pInfo);
552 if (RT_SUCCESS(rc))
553 {
554 pInfo->enmType = DBGFINFOTYPE_DRV_ARGV;
555 pInfo->u.DrvArgv.pfnHandler = pfnHandler;
556 pInfo->u.DrvArgv.pDrvIns = pDrvIns;
557 RTCritSectRwLeaveExcl(&pVM->pUVM->dbgf.s.CritSect);
558 }
559
560 return rc;
561}
562
563
564/**
565 * Register a info handler owned by a USB device, argv style.
566 *
567 * @returns VBox status code.
568 * @param pVM The cross context VM structure.
569 * @param pszName The identifier of the info.
570 * @param pszDesc The description of the info and any arguments the handler may take.
571 * @param pfnHandler The handler function to be called to display the info.
572 * @param pUsbIns The USB device instance owning the info.
573 */
574VMMR3_INT_DECL(int) DBGFR3InfoRegisterUsbArgv(PVM pVM, const char *pszName, const char *pszDesc,
575 PFNDBGFINFOARGVUSB pfnHandler, PPDMUSBINS pUsbIns)
576{
577 LogFlow(("DBGFR3InfoRegisterDriverArgv: pszName=%p:{%s} pszDesc=%p:{%s} pfnHandler=%p pUsbIns=%p\n",
578 pszName, pszName, pszDesc, pszDesc, pfnHandler, pUsbIns));
579
580 /*
581 * Validate the specific stuff.
582 */
583 AssertPtrReturn(pfnHandler, VERR_INVALID_POINTER);
584 AssertPtrReturn(pUsbIns, VERR_INVALID_POINTER);
585
586 /*
587 * Register
588 */
589 PDBGFINFO pInfo;
590 int rc = dbgfR3InfoRegister(pVM->pUVM, pszName, pszDesc, 0, &pInfo);
591 if (RT_SUCCESS(rc))
592 {
593 pInfo->enmType = DBGFINFOTYPE_USB_ARGV;
594 pInfo->u.UsbArgv.pfnHandler = pfnHandler;
595 pInfo->u.UsbArgv.pUsbIns = pUsbIns;
596 RTCritSectRwLeaveExcl(&pVM->pUVM->dbgf.s.CritSect);
597 }
598
599 return rc;
600}
601
602
603/**
604 * Register a info handler owned by an internal component, argv style.
605 *
606 * @returns VBox status code.
607 * @param pVM The cross context VM structure.
608 * @param pszName The identifier of the info.
609 * @param pszDesc The description of the info and any arguments the handler may take.
610 * @param pfnHandler The handler function to be called to display the info.
611 * @param fFlags Flags, see the DBGFINFO_FLAGS_*.
612 */
613VMMR3_INT_DECL(int) DBGFR3InfoRegisterInternalArgv(PVM pVM, const char *pszName, const char *pszDesc,
614 PFNDBGFINFOARGVINT pfnHandler, uint32_t fFlags)
615{
616 LogFlow(("DBGFR3InfoRegisterInternalArgv: pszName=%p:{%s} pszDesc=%p:{%s} pfnHandler=%p fFlags=%x\n",
617 pszName, pszName, pszDesc, pszDesc, pfnHandler, fFlags));
618
619 /*
620 * Validate the specific stuff.
621 */
622 AssertPtrReturn(pfnHandler, VERR_INVALID_POINTER);
623
624 /*
625 * Register
626 */
627 PDBGFINFO pInfo;
628 int rc = dbgfR3InfoRegister(pVM->pUVM, pszName, pszDesc, fFlags, &pInfo);
629 if (RT_SUCCESS(rc))
630 {
631 pInfo->enmType = DBGFINFOTYPE_INT_ARGV;
632 pInfo->u.IntArgv.pfnHandler = pfnHandler;
633 RTCritSectRwLeaveExcl(&pVM->pUVM->dbgf.s.CritSect);
634 }
635
636 return rc;
637}
638
639
640/**
641 * Register a info handler owned by an external component.
642 *
643 * @returns VBox status code.
644 * @param pUVM The user mode VM handle.
645 * @param pszName The identifier of the info.
646 * @param pszDesc The description of the info and any arguments the handler may take.
647 * @param pfnHandler The handler function to be called to display the info.
648 * @param pvUser User argument to be passed to the handler.
649 */
650VMMR3DECL(int) DBGFR3InfoRegisterExternalArgv(PUVM pUVM, const char *pszName, const char *pszDesc,
651 PFNDBGFINFOARGVEXT pfnHandler, void *pvUser)
652{
653 LogFlow(("DBGFR3InfoRegisterExternalArgv: pszName=%p:{%s} pszDesc=%p:{%s} pfnHandler=%p pvUser=%p\n",
654 pszName, pszName, pszDesc, pszDesc, pfnHandler, pvUser));
655
656 /*
657 * Validate the specific stuff.
658 */
659 AssertPtrReturn(pfnHandler, VERR_INVALID_POINTER);
660 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
661
662 /*
663 * Register
664 */
665 PDBGFINFO pInfo;
666 int rc = dbgfR3InfoRegister(pUVM, pszName, pszDesc, 0, &pInfo);
667 if (RT_SUCCESS(rc))
668 {
669 pInfo->enmType = DBGFINFOTYPE_EXT_ARGV;
670 pInfo->u.ExtArgv.pfnHandler = pfnHandler;
671 pInfo->u.ExtArgv.pvUser = pvUser;
672 RTCritSectRwLeaveExcl(&pUVM->dbgf.s.CritSect);
673 }
674
675 return rc;
676}
677
678
679/**
680 * Deregister one(/all) info handler(s) owned by a device.
681 *
682 * @returns VBox status code.
683 * @param pVM The cross context VM structure.
684 * @param pDevIns Device instance.
685 * @param pszName The identifier of the info. If NULL all owned by the device.
686 */
687VMMR3_INT_DECL(int) DBGFR3InfoDeregisterDevice(PVM pVM, PPDMDEVINS pDevIns, const char *pszName)
688{
689 LogFlow(("DBGFR3InfoDeregisterDevice: pDevIns=%p pszName=%p:{%s}\n", pDevIns, pszName, pszName));
690
691 /*
692 * Validate input.
693 */
694 AssertPtrReturn(pDevIns, VERR_INVALID_POINTER);
695 AssertPtrNullReturn(pszName, VERR_INVALID_POINTER);
696 size_t cchName = pszName ? strlen(pszName) : 0;
697 PUVM pUVM = pVM->pUVM;
698
699 /*
700 * Enumerate the info handlers and free the requested entries.
701 */
702 int rc = RTCritSectRwEnterExcl(&pUVM->dbgf.s.CritSect); AssertRC(rc);
703 rc = VERR_FILE_NOT_FOUND;
704 PDBGFINFO pPrev = NULL;
705 PDBGFINFO pInfo = pUVM->dbgf.s.pInfoFirst;
706 if (pszName)
707 {
708 /*
709 * Free a specific one.
710 */
711 for (; pInfo; pPrev = pInfo, pInfo = pInfo->pNext)
712 if ( ( (pInfo->enmType == DBGFINFOTYPE_DEV && pInfo->u.Dev.pDevIns == pDevIns)
713 || (pInfo->enmType == DBGFINFOTYPE_DEV_ARGV && pInfo->u.DevArgv.pDevIns == pDevIns))
714 && pInfo->cchName == cchName
715 && memcmp(pInfo->szName, pszName, cchName) == 0)
716 {
717 if (pPrev)
718 pPrev->pNext = pInfo->pNext;
719 else
720 pUVM->dbgf.s.pInfoFirst = pInfo->pNext;
721 MMR3HeapFree(pInfo);
722 rc = VINF_SUCCESS;
723 break;
724 }
725 }
726 else
727 {
728 /*
729 * Free all owned by the device.
730 */
731 while (pInfo != NULL)
732 if ( (pInfo->enmType == DBGFINFOTYPE_DEV && pInfo->u.Dev.pDevIns == pDevIns)
733 || (pInfo->enmType == DBGFINFOTYPE_DEV_ARGV && pInfo->u.DevArgv.pDevIns == pDevIns))
734 {
735 PDBGFINFO volatile pFree = pInfo;
736 pInfo = pInfo->pNext;
737 if (pPrev)
738 pPrev->pNext = pInfo;
739 else
740 pUVM->dbgf.s.pInfoFirst = pInfo;
741 MMR3HeapFree(pFree);
742 }
743 else
744 {
745 pPrev = pInfo;
746 pInfo = pInfo->pNext;
747 }
748 rc = VINF_SUCCESS;
749 }
750 int rc2 = RTCritSectRwLeaveExcl(&pUVM->dbgf.s.CritSect);
751 AssertRC(rc2);
752 AssertRC(rc);
753 LogFlow(("DBGFR3InfoDeregisterDevice: returns %Rrc\n", rc));
754 return rc;
755}
756
757
758/**
759 * Deregister one(/all) info handler(s) owned by a driver.
760 *
761 * @returns VBox status code.
762 * @param pVM The cross context VM structure.
763 * @param pDrvIns Driver instance.
764 * @param pszName The identifier of the info. If NULL all owned by the driver.
765 */
766VMMR3_INT_DECL(int) DBGFR3InfoDeregisterDriver(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName)
767{
768 LogFlow(("DBGFR3InfoDeregisterDriver: pDrvIns=%p pszName=%p:{%s}\n", pDrvIns, pszName, pszName));
769
770 /*
771 * Validate input.
772 */
773 AssertPtrReturn(pDrvIns, VERR_INVALID_POINTER);
774 AssertPtrNullReturn(pszName, VERR_INVALID_POINTER);
775 size_t cchName = pszName ? strlen(pszName) : 0;
776 PUVM pUVM = pVM->pUVM;
777
778 /*
779 * Enumerate the info handlers and free the requested entries.
780 */
781 int rc = RTCritSectRwEnterExcl(&pUVM->dbgf.s.CritSect); AssertRC(rc);
782 rc = VERR_FILE_NOT_FOUND;
783 PDBGFINFO pPrev = NULL;
784 PDBGFINFO pInfo = pUVM->dbgf.s.pInfoFirst;
785 if (pszName)
786 {
787 /*
788 * Free a specific one.
789 */
790 for (; pInfo; pPrev = pInfo, pInfo = pInfo->pNext)
791 if ( ( (pInfo->enmType == DBGFINFOTYPE_DRV && pInfo->u.Drv.pDrvIns == pDrvIns)
792 || (pInfo->enmType == DBGFINFOTYPE_DRV_ARGV && pInfo->u.DrvArgv.pDrvIns == pDrvIns))
793 && pInfo->cchName == cchName
794 && memcmp(pInfo->szName, pszName, cchName) == 0)
795 {
796 if (pPrev)
797 pPrev->pNext = pInfo->pNext;
798 else
799 pUVM->dbgf.s.pInfoFirst = pInfo->pNext;
800 MMR3HeapFree(pInfo);
801 rc = VINF_SUCCESS;
802 break;
803 }
804 }
805 else
806 {
807 /*
808 * Free all owned by the driver.
809 */
810 while (pInfo != NULL)
811 if ( (pInfo->enmType == DBGFINFOTYPE_DRV && pInfo->u.Drv.pDrvIns == pDrvIns)
812 || (pInfo->enmType == DBGFINFOTYPE_DRV_ARGV && pInfo->u.DrvArgv.pDrvIns == pDrvIns))
813 {
814 PDBGFINFO volatile pFree = pInfo;
815 pInfo = pInfo->pNext;
816 if (pPrev)
817 pPrev->pNext = pInfo;
818 else
819 pUVM->dbgf.s.pInfoFirst = pInfo;
820 MMR3HeapFree(pFree);
821 }
822 else
823 {
824 pPrev = pInfo;
825 pInfo = pInfo->pNext;
826 }
827 rc = VINF_SUCCESS;
828 }
829 int rc2 = RTCritSectRwLeaveExcl(&pUVM->dbgf.s.CritSect);
830 AssertRC(rc2);
831 AssertRC(rc);
832 LogFlow(("DBGFR3InfoDeregisterDriver: returns %Rrc\n", rc));
833 return rc;
834}
835
836
837/**
838 * Deregister one(/all) info handler(s) owned by a USB device.
839 *
840 * @returns VBox status code.
841 * @param pVM The cross context VM structure.
842 * @param pUsbIns USB device instance.
843 * @param pszName The identifier of the info. If NULL all owned by the driver.
844 */
845VMMR3_INT_DECL(int) DBGFR3InfoDeregisterUsb(PVM pVM, PPDMUSBINS pUsbIns, const char *pszName)
846{
847 LogFlow(("DBGFR3InfoDeregisterUsb: pUsbIns=%p pszName=%p:{%s}\n", pUsbIns, pszName, pszName));
848
849 /*
850 * Validate input.
851 */
852 AssertPtrReturn(pUsbIns, VERR_INVALID_POINTER);
853 AssertPtrNullReturn(pszName, VERR_INVALID_POINTER);
854 size_t cchName = pszName ? strlen(pszName) : 0;
855 PUVM pUVM = pVM->pUVM;
856
857 /*
858 * Enumerate the info handlers and free the requested entries.
859 */
860 int rc = RTCritSectRwEnterExcl(&pUVM->dbgf.s.CritSect); AssertRC(rc);
861 rc = VERR_FILE_NOT_FOUND;
862 PDBGFINFO pPrev = NULL;
863 PDBGFINFO pInfo = pUVM->dbgf.s.pInfoFirst;
864 if (pszName)
865 {
866 /*
867 * Free a specific one.
868 */
869 for (; pInfo; pPrev = pInfo, pInfo = pInfo->pNext)
870 if ( pInfo->enmType == DBGFINFOTYPE_USB_ARGV
871 && pInfo->u.UsbArgv.pUsbIns == pUsbIns
872 && pInfo->cchName == cchName
873 && memcmp(pInfo->szName, pszName, cchName) == 0)
874 {
875 if (pPrev)
876 pPrev->pNext = pInfo->pNext;
877 else
878 pUVM->dbgf.s.pInfoFirst = pInfo->pNext;
879 MMR3HeapFree(pInfo);
880 rc = VINF_SUCCESS;
881 break;
882 }
883 }
884 else
885 {
886 /*
887 * Free all owned by the driver.
888 */
889 while (pInfo != NULL)
890 if ( pInfo->enmType == DBGFINFOTYPE_USB_ARGV
891 && pInfo->u.UsbArgv.pUsbIns == pUsbIns)
892 {
893 PDBGFINFO volatile pFree = pInfo;
894 pInfo = pInfo->pNext;
895 if (pPrev)
896 pPrev->pNext = pInfo;
897 else
898 pUVM->dbgf.s.pInfoFirst = pInfo;
899 MMR3HeapFree(pFree);
900 }
901 else
902 {
903 pPrev = pInfo;
904 pInfo = pInfo->pNext;
905 }
906 rc = VINF_SUCCESS;
907 }
908 int rc2 = RTCritSectRwLeaveExcl(&pUVM->dbgf.s.CritSect);
909 AssertRC(rc2);
910 AssertRC(rc);
911 LogFlow(("DBGFR3InfoDeregisterDriver: returns %Rrc\n", rc));
912 return rc;
913}
914
915
916/**
917 * Internal deregistration helper.
918 *
919 * @returns VBox status code.
920 * @param pUVM Pointer to the VM.
921 * @param pszName The identifier of the info.
922 * @param enmType1 The first info owner type (old style).
923 * @param enmType2 The second info owner type (argv).
924 */
925static int dbgfR3InfoDeregister(PUVM pUVM, const char *pszName, DBGFINFOTYPE enmType1, DBGFINFOTYPE enmType2)
926{
927 /*
928 * Validate input.
929 */
930 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
931
932 /*
933 * Find the info handler.
934 */
935 size_t cchName = strlen(pszName);
936 int rc = RTCritSectRwEnterExcl(&pUVM->dbgf.s.CritSect);
937 AssertRC(rc);
938 rc = VERR_FILE_NOT_FOUND;
939 PDBGFINFO pPrev = NULL;
940 PDBGFINFO pInfo = pUVM->dbgf.s.pInfoFirst;
941 for (; pInfo; pPrev = pInfo, pInfo = pInfo->pNext)
942 if ( pInfo->cchName == cchName
943 && memcmp(pInfo->szName, pszName, cchName) == 0
944 && (pInfo->enmType == enmType1 || pInfo->enmType == enmType2))
945 {
946 if (pPrev)
947 pPrev->pNext = pInfo->pNext;
948 else
949 pUVM->dbgf.s.pInfoFirst = pInfo->pNext;
950 MMR3HeapFree(pInfo);
951 rc = VINF_SUCCESS;
952 break;
953 }
954 int rc2 = RTCritSectRwLeaveExcl(&pUVM->dbgf.s.CritSect);
955 AssertRC(rc2);
956 AssertRC(rc);
957 LogFlow(("dbgfR3InfoDeregister: returns %Rrc\n", rc));
958 return rc;
959}
960
961
962/**
963 * Deregister a info handler owned by an internal component.
964 *
965 * @returns VBox status code.
966 * @param pVM The cross context VM structure.
967 * @param pszName The identifier of the info. If NULL all owned by the device.
968 */
969VMMR3_INT_DECL(int) DBGFR3InfoDeregisterInternal(PVM pVM, const char *pszName)
970{
971 LogFlow(("DBGFR3InfoDeregisterInternal: pszName=%p:{%s}\n", pszName, pszName));
972 return dbgfR3InfoDeregister(pVM->pUVM, pszName, DBGFINFOTYPE_INT, DBGFINFOTYPE_INT_ARGV);
973}
974
975
976/**
977 * Deregister a info handler owned by an external component.
978 *
979 * @returns VBox status code.
980 * @param pUVM The user mode VM handle.
981 * @param pszName The identifier of the info. If NULL all owned by the device.
982 */
983VMMR3DECL(int) DBGFR3InfoDeregisterExternal(PUVM pUVM, const char *pszName)
984{
985 LogFlow(("DBGFR3InfoDeregisterExternal: pszName=%p:{%s}\n", pszName, pszName));
986 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
987 return dbgfR3InfoDeregister(pUVM, pszName, DBGFINFOTYPE_EXT, DBGFINFOTYPE_EXT_ARGV);
988}
989
990
991/**
992 * Worker for DBGFR3InfoEx.
993 *
994 * @returns VBox status code.
995 * @param pUVM The user mode VM handle.
996 * @param idCpu Which CPU to run EMT bound handlers on. VMCPUID_ANY or
997 * a valid CPU ID.
998 * @param pszName What to dump.
999 * @param pszArgs Arguments, optional.
1000 * @param pHlp Output helper, optional.
1001 */
1002static DECLCALLBACK(int) dbgfR3Info(PUVM pUVM, VMCPUID idCpu, const char *pszName, const char *pszArgs, PCDBGFINFOHLP pHlp)
1003{
1004 /*
1005 * Validate input.
1006 */
1007 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
1008 AssertPtrNullReturn(pszArgs, VERR_INVALID_POINTER);
1009 if (pHlp)
1010 {
1011 AssertPtrReturn(pHlp, VERR_INVALID_PARAMETER);
1012 AssertPtrReturn(pHlp->pfnPrintf, VERR_INVALID_PARAMETER);
1013 AssertPtrReturn(pHlp->pfnPrintfV, VERR_INVALID_PARAMETER);
1014 }
1015 else
1016 pHlp = &g_dbgfR3InfoLogHlp;
1017 Assert(idCpu == NIL_VMCPUID || idCpu < pUVM->cCpus); /* if not nil, we're on that EMT already. */
1018
1019 /*
1020 * Find the info handler.
1021 */
1022 size_t cchName = strlen(pszName);
1023 int rc = RTCritSectRwEnterShared(&pUVM->dbgf.s.CritSect);
1024 AssertRC(rc);
1025 PDBGFINFO pInfo = pUVM->dbgf.s.pInfoFirst;
1026 for (; pInfo; pInfo = pInfo->pNext)
1027 if ( pInfo->cchName == cchName
1028 && !memcmp(pInfo->szName, pszName, cchName))
1029 break;
1030 if (pInfo)
1031 {
1032 /*
1033 * Found it.
1034 */
1035 VMCPUID idDstCpu = NIL_VMCPUID;
1036 if ((pInfo->fFlags & (DBGFINFO_FLAGS_RUN_ON_EMT | DBGFINFO_FLAGS_ALL_EMTS)) && idCpu == NIL_VMCPUID)
1037 idDstCpu = pInfo->fFlags & DBGFINFO_FLAGS_ALL_EMTS ? VMCPUID_ALL : VMCPUID_ANY;
1038
1039 rc = VINF_SUCCESS;
1040 switch (pInfo->enmType)
1041 {
1042 case DBGFINFOTYPE_DEV:
1043 if (idDstCpu != NIL_VMCPUID)
1044 rc = VMR3ReqPriorityCallWaitU(pUVM, idDstCpu, (PFNRT)pInfo->u.Dev.pfnHandler, 3,
1045 pInfo->u.Dev.pDevIns, pHlp, pszArgs);
1046 else
1047 pInfo->u.Dev.pfnHandler(pInfo->u.Dev.pDevIns, pHlp, pszArgs);
1048 break;
1049
1050 case DBGFINFOTYPE_DRV:
1051 if (idDstCpu != NIL_VMCPUID)
1052 rc = VMR3ReqPriorityCallWaitU(pUVM, idDstCpu, (PFNRT)pInfo->u.Drv.pfnHandler, 3,
1053 pInfo->u.Drv.pDrvIns, pHlp, pszArgs);
1054 else
1055 pInfo->u.Drv.pfnHandler(pInfo->u.Drv.pDrvIns, pHlp, pszArgs);
1056 break;
1057
1058 case DBGFINFOTYPE_INT:
1059 if (RT_VALID_PTR(pUVM->pVM))
1060 {
1061 if (idDstCpu != NIL_VMCPUID)
1062 rc = VMR3ReqPriorityCallWaitU(pUVM, idDstCpu, (PFNRT)pInfo->u.Int.pfnHandler, 3,
1063 pUVM->pVM, pHlp, pszArgs);
1064 else
1065 pInfo->u.Int.pfnHandler(pUVM->pVM, pHlp, pszArgs);
1066 }
1067 else
1068 rc = VERR_INVALID_VM_HANDLE;
1069 break;
1070
1071 case DBGFINFOTYPE_EXT:
1072 if (idDstCpu != NIL_VMCPUID)
1073 rc = VMR3ReqPriorityCallWaitU(pUVM, idDstCpu, (PFNRT)pInfo->u.Ext.pfnHandler, 3,
1074 pInfo->u.Ext.pvUser, pHlp, pszArgs);
1075 else
1076 pInfo->u.Ext.pfnHandler(pInfo->u.Ext.pvUser, pHlp, pszArgs);
1077 break;
1078
1079 case DBGFINFOTYPE_DEV_ARGV:
1080 case DBGFINFOTYPE_DRV_ARGV:
1081 case DBGFINFOTYPE_USB_ARGV:
1082 case DBGFINFOTYPE_INT_ARGV:
1083 case DBGFINFOTYPE_EXT_ARGV:
1084 {
1085 char **papszArgv;
1086 int cArgs;
1087 rc = RTGetOptArgvFromString(&papszArgv, &cArgs, pszArgs ? pszArgs : "", RTGETOPTARGV_CNV_QUOTE_BOURNE_SH, NULL);
1088 if (RT_SUCCESS(rc))
1089 {
1090 switch (pInfo->enmType)
1091 {
1092 case DBGFINFOTYPE_DEV_ARGV:
1093 if (idDstCpu != NIL_VMCPUID)
1094 rc = VMR3ReqPriorityCallWaitU(pUVM, idDstCpu, (PFNRT)pInfo->u.DevArgv.pfnHandler, 4,
1095 pInfo->u.DevArgv.pDevIns, pHlp, cArgs, papszArgv);
1096 else
1097 pInfo->u.DevArgv.pfnHandler(pInfo->u.DevArgv.pDevIns, pHlp, cArgs, papszArgv);
1098 break;
1099
1100 case DBGFINFOTYPE_DRV_ARGV:
1101 if (idDstCpu != NIL_VMCPUID)
1102 rc = VMR3ReqPriorityCallWaitU(pUVM, idDstCpu, (PFNRT)pInfo->u.DrvArgv.pfnHandler, 4,
1103 pInfo->u.DrvArgv.pDrvIns, pHlp, cArgs, papszArgv);
1104 else
1105 pInfo->u.DrvArgv.pfnHandler(pInfo->u.DrvArgv.pDrvIns, pHlp, cArgs, papszArgv);
1106 break;
1107
1108 case DBGFINFOTYPE_USB_ARGV:
1109 if (idDstCpu != NIL_VMCPUID)
1110 rc = VMR3ReqPriorityCallWaitU(pUVM, idDstCpu, (PFNRT)pInfo->u.UsbArgv.pfnHandler, 4,
1111 pInfo->u.UsbArgv.pUsbIns, pHlp, cArgs, papszArgv);
1112 else
1113 pInfo->u.UsbArgv.pfnHandler(pInfo->u.UsbArgv.pUsbIns, pHlp, cArgs, papszArgv);
1114 break;
1115
1116 case DBGFINFOTYPE_INT_ARGV:
1117 if (RT_VALID_PTR(pUVM->pVM))
1118 {
1119 if (idDstCpu != NIL_VMCPUID)
1120 rc = VMR3ReqPriorityCallWaitU(pUVM, idDstCpu, (PFNRT)pInfo->u.IntArgv.pfnHandler, 4,
1121 pUVM->pVM, pHlp, cArgs, papszArgv);
1122 else
1123 pInfo->u.IntArgv.pfnHandler(pUVM->pVM, pHlp, cArgs, papszArgv);
1124 }
1125 else
1126 rc = VERR_INVALID_VM_HANDLE;
1127 break;
1128
1129 case DBGFINFOTYPE_EXT_ARGV:
1130 if (idDstCpu != NIL_VMCPUID)
1131 rc = VMR3ReqPriorityCallWaitU(pUVM, idDstCpu, (PFNRT)pInfo->u.ExtArgv.pfnHandler, 4,
1132 pInfo->u.ExtArgv.pvUser, pHlp, cArgs, papszArgv);
1133 else
1134 pInfo->u.ExtArgv.pfnHandler(pInfo->u.ExtArgv.pvUser, pHlp, cArgs, papszArgv);
1135 break;
1136
1137 default:
1138 AssertFailedBreakStmt(rc = VERR_INTERNAL_ERROR);
1139 }
1140
1141 RTGetOptArgvFree(papszArgv);
1142 }
1143 break;
1144 }
1145
1146 default:
1147 AssertMsgFailedReturn(("Invalid info type enmType=%d\n", pInfo->enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE);
1148 }
1149
1150 int rc2 = RTCritSectRwLeaveShared(&pUVM->dbgf.s.CritSect);
1151 AssertRC(rc2);
1152 }
1153 else
1154 {
1155 rc = RTCritSectRwLeaveShared(&pUVM->dbgf.s.CritSect);
1156 AssertRC(rc);
1157 rc = VERR_FILE_NOT_FOUND;
1158 }
1159 return rc;
1160}
1161
1162
1163/**
1164 * Display a piece of info writing to the supplied handler.
1165 *
1166 * @returns VBox status code.
1167 * @param pUVM The user mode VM handle.
1168 * @param pszName The identifier of the info to display.
1169 * @param pszArgs Arguments to the info handler.
1170 * @param pHlp The output helper functions. If NULL the logger will be used.
1171 */
1172VMMR3DECL(int) DBGFR3Info(PUVM pUVM, const char *pszName, const char *pszArgs, PCDBGFINFOHLP pHlp)
1173{
1174 return DBGFR3InfoEx(pUVM, NIL_VMCPUID, pszName, pszArgs, pHlp);
1175}
1176
1177
1178/**
1179 * Display a piece of info writing to the supplied handler.
1180 *
1181 * @returns VBox status code.
1182 * @param pUVM The user mode VM handle.
1183 * @param idCpu The CPU to exectue the request on. Pass NIL_VMCPUID
1184 * to not involve any EMT unless necessary.
1185 * @param pszName The identifier of the info to display.
1186 * @param pszArgs Arguments to the info handler.
1187 * @param pHlp The output helper functions. If NULL the logger will be used.
1188 */
1189VMMR3DECL(int) DBGFR3InfoEx(PUVM pUVM, VMCPUID idCpu, const char *pszName, const char *pszArgs, PCDBGFINFOHLP pHlp)
1190{
1191 /*
1192 * Some input validation.
1193 */
1194 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1195 AssertReturn( idCpu != VMCPUID_ANY_QUEUE
1196 && idCpu != VMCPUID_ALL
1197 && idCpu != VMCPUID_ALL_REVERSE, VERR_INVALID_PARAMETER);
1198
1199 /*
1200 * Run on any specific EMT?
1201 */
1202 if (idCpu == NIL_VMCPUID)
1203 return dbgfR3Info(pUVM, NIL_VMCPUID, pszName, pszArgs, pHlp);
1204 return VMR3ReqPriorityCallWaitU(pUVM, idCpu, (PFNRT)dbgfR3Info, 5, pUVM, idCpu, pszName, pszArgs, pHlp);
1205}
1206
1207
1208/**
1209 * Wrapper for DBGFR3Info that outputs to the release log.
1210 *
1211 * @returns See DBGFR3Info.
1212 * @param pUVM The user mode VM handle.
1213 * @param pszName See DBGFR3Info.
1214 * @param pszArgs See DBGFR3Info.
1215 */
1216VMMR3DECL(int) DBGFR3InfoLogRel(PUVM pUVM, const char *pszName, const char *pszArgs)
1217{
1218 return DBGFR3InfoEx(pUVM, NIL_VMCPUID, pszName, pszArgs, &g_dbgfR3InfoLogRelHlp);
1219}
1220
1221
1222/**
1223 * Wrapper for DBGFR3Info that outputs to standard error.
1224 *
1225 * @returns See DBGFR3Info.
1226 * @param pUVM The user mode VM handle.
1227 * @param pszName See DBGFR3Info.
1228 * @param pszArgs See DBGFR3Info.
1229 */
1230VMMR3DECL(int) DBGFR3InfoStdErr(PUVM pUVM, const char *pszName, const char *pszArgs)
1231{
1232 return DBGFR3InfoEx(pUVM, NIL_VMCPUID, pszName, pszArgs, &g_dbgfR3InfoStdErrHlp);
1233}
1234
1235
1236/**
1237 * Display several info items.
1238 *
1239 * This is intended used by the fatal error dump only.
1240 *
1241 * @returns VBox status code.
1242 * @param pVM The cross context VM structure.
1243 * @param pszIncludePat Simple string pattern of info items to include.
1244 * @param pszExcludePat Simple string pattern of info items to exclude.
1245 * @param pszSepFmt Item separator format string. The item name will be
1246 * given as parameter.
1247 * @param pHlp The output helper functions. If NULL the logger
1248 * will be used.
1249 *
1250 * @thread EMT
1251 */
1252VMMR3_INT_DECL(int) DBGFR3InfoMulti(PVM pVM, const char *pszIncludePat, const char *pszExcludePat, const char *pszSepFmt,
1253 PCDBGFINFOHLP pHlp)
1254{
1255 /*
1256 * Validate input.
1257 */
1258 PUVM pUVM = pVM->pUVM;
1259 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
1260 AssertPtrReturn(pszIncludePat, VERR_INVALID_POINTER);
1261 AssertPtrReturn(pszExcludePat, VERR_INVALID_POINTER);
1262 if (pHlp)
1263 {
1264 AssertPtrReturn(pHlp->pfnPrintf, VERR_INVALID_POINTER);
1265 AssertPtrReturn(pHlp->pfnPrintfV, VERR_INVALID_POINTER);
1266 }
1267 else
1268 pHlp = &g_dbgfR3InfoLogHlp;
1269
1270 size_t const cchIncludePat = strlen(pszIncludePat);
1271 size_t const cchExcludePat = strlen(pszExcludePat);
1272 const char *pszArgs = "";
1273
1274 /*
1275 * Enumerate the info handlers and call the ones matching.
1276 * Note! We won't leave the critical section here...
1277 */
1278 char *apszArgs[2] = { NULL, NULL };
1279 int rc = RTCritSectRwEnterShared(&pUVM->dbgf.s.CritSect);
1280 AssertRC(rc);
1281 rc = VWRN_NOT_FOUND;
1282 for (PDBGFINFO pInfo = pUVM->dbgf.s.pInfoFirst; pInfo; pInfo = pInfo->pNext)
1283 {
1284 if ( RTStrSimplePatternMultiMatch(pszIncludePat, cchIncludePat, pInfo->szName, pInfo->cchName, NULL)
1285 && !RTStrSimplePatternMultiMatch(pszExcludePat, cchExcludePat, pInfo->szName, pInfo->cchName, NULL))
1286 {
1287 pHlp->pfnPrintf(pHlp, pszSepFmt, pInfo->szName);
1288
1289 VMCPUID idDstCpu = NIL_VMCPUID;
1290 if (pInfo->fFlags & (DBGFINFO_FLAGS_RUN_ON_EMT | DBGFINFO_FLAGS_ALL_EMTS))
1291 idDstCpu = pInfo->fFlags & DBGFINFO_FLAGS_ALL_EMTS ? VMCPUID_ALL : VMCPUID_ANY;
1292
1293 rc = VINF_SUCCESS;
1294 switch (pInfo->enmType)
1295 {
1296 case DBGFINFOTYPE_DEV:
1297 if (idDstCpu != NIL_VMCPUID)
1298 rc = VMR3ReqPriorityCallVoidWaitU(pUVM, idDstCpu, (PFNRT)pInfo->u.Dev.pfnHandler, 3,
1299 pInfo->u.Dev.pDevIns, pHlp, pszArgs);
1300 else
1301 pInfo->u.Dev.pfnHandler(pInfo->u.Dev.pDevIns, pHlp, pszArgs);
1302 break;
1303
1304 case DBGFINFOTYPE_DRV:
1305 if (idDstCpu != NIL_VMCPUID)
1306 rc = VMR3ReqPriorityCallVoidWaitU(pUVM, idDstCpu, (PFNRT)pInfo->u.Drv.pfnHandler, 3,
1307 pInfo->u.Drv.pDrvIns, pHlp, pszArgs);
1308 else
1309 pInfo->u.Drv.pfnHandler(pInfo->u.Drv.pDrvIns, pHlp, pszArgs);
1310 break;
1311
1312 case DBGFINFOTYPE_INT:
1313 if (idDstCpu != NIL_VMCPUID)
1314 rc = VMR3ReqPriorityCallVoidWaitU(pUVM, idDstCpu, (PFNRT)pInfo->u.Int.pfnHandler, 3,
1315 pVM, pHlp, pszArgs);
1316 else
1317 pInfo->u.Int.pfnHandler(pVM, pHlp, pszArgs);
1318 break;
1319
1320 case DBGFINFOTYPE_EXT:
1321 if (idDstCpu != NIL_VMCPUID)
1322 rc = VMR3ReqPriorityCallVoidWaitU(pUVM, idDstCpu, (PFNRT)pInfo->u.Ext.pfnHandler, 3,
1323 pInfo->u.Ext.pvUser, pHlp, pszArgs);
1324 else
1325 pInfo->u.Ext.pfnHandler(pInfo->u.Ext.pvUser, pHlp, pszArgs);
1326 break;
1327
1328 case DBGFINFOTYPE_DEV_ARGV:
1329 if (idDstCpu != NIL_VMCPUID)
1330 rc = VMR3ReqPriorityCallWaitU(pUVM, idDstCpu, (PFNRT)pInfo->u.DevArgv.pfnHandler, 4,
1331 pInfo->u.DevArgv.pDevIns, pHlp, 0, &apszArgs[0]);
1332 else
1333 pInfo->u.DevArgv.pfnHandler(pInfo->u.DevArgv.pDevIns, pHlp, 0, &apszArgs[0]);
1334 break;
1335
1336 case DBGFINFOTYPE_DRV_ARGV:
1337 if (idDstCpu != NIL_VMCPUID)
1338 rc = VMR3ReqPriorityCallWaitU(pUVM, idDstCpu, (PFNRT)pInfo->u.DrvArgv.pfnHandler, 4,
1339 pInfo->u.DrvArgv.pDrvIns, pHlp, 0, &apszArgs[0]);
1340 else
1341 pInfo->u.DrvArgv.pfnHandler(pInfo->u.DrvArgv.pDrvIns, pHlp, 0, &apszArgs[0]);
1342 break;
1343
1344 case DBGFINFOTYPE_USB_ARGV:
1345 if (idDstCpu != NIL_VMCPUID)
1346 rc = VMR3ReqPriorityCallWaitU(pUVM, idDstCpu, (PFNRT)pInfo->u.UsbArgv.pfnHandler, 4,
1347 pInfo->u.UsbArgv.pUsbIns, pHlp, 0, &apszArgs[0]);
1348 else
1349 pInfo->u.UsbArgv.pfnHandler(pInfo->u.UsbArgv.pUsbIns, pHlp, 0, &apszArgs[0]);
1350 break;
1351
1352 case DBGFINFOTYPE_INT_ARGV:
1353 if (RT_VALID_PTR(pUVM->pVM))
1354 {
1355 if (idDstCpu != NIL_VMCPUID)
1356 rc = VMR3ReqPriorityCallWaitU(pUVM, idDstCpu, (PFNRT)pInfo->u.IntArgv.pfnHandler, 4,
1357 pUVM->pVM, pHlp, 0, &apszArgs[0]);
1358 else
1359 pInfo->u.IntArgv.pfnHandler(pUVM->pVM, pHlp, 0, &apszArgs[0]);
1360 }
1361 else
1362 rc = VERR_INVALID_VM_HANDLE;
1363 break;
1364
1365 case DBGFINFOTYPE_EXT_ARGV:
1366 if (idDstCpu != NIL_VMCPUID)
1367 rc = VMR3ReqPriorityCallWaitU(pUVM, idDstCpu, (PFNRT)pInfo->u.ExtArgv.pfnHandler, 4,
1368 pInfo->u.ExtArgv.pvUser, pHlp, 0, &apszArgs[0]);
1369 else
1370 pInfo->u.ExtArgv.pfnHandler(pInfo->u.ExtArgv.pvUser, pHlp, 0, &apszArgs[0]);
1371 break;
1372
1373 default:
1374 AssertMsgFailedReturn(("Invalid info type enmType=%d\n", pInfo->enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE);
1375 }
1376 }
1377 }
1378 int rc2 = RTCritSectRwLeaveShared(&pUVM->dbgf.s.CritSect);
1379 AssertRC(rc2);
1380
1381 return rc;
1382}
1383
1384
1385/**
1386 * Enumerate all the register info handlers.
1387 *
1388 * @returns VBox status code.
1389 * @param pUVM The user mode VM handle.
1390 * @param pfnCallback Pointer to callback function.
1391 * @param pvUser User argument to pass to the callback.
1392 */
1393VMMR3DECL(int) DBGFR3InfoEnum(PUVM pUVM, PFNDBGFINFOENUM pfnCallback, void *pvUser)
1394{
1395 LogFlow(("DBGFR3InfoLog: pfnCallback=%p pvUser=%p\n", pfnCallback, pvUser));
1396
1397 /*
1398 * Validate input.
1399 */
1400 if (!pfnCallback)
1401 {
1402 AssertMsgFailed(("!pfnCallback\n"));
1403 return VERR_INVALID_PARAMETER;
1404 }
1405 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1406
1407 /*
1408 * Enter and enumerate.
1409 */
1410 int rc = RTCritSectRwEnterShared(&pUVM->dbgf.s.CritSect);
1411 AssertRC(rc);
1412
1413 rc = VINF_SUCCESS;
1414 for (PDBGFINFO pInfo = pUVM->dbgf.s.pInfoFirst; RT_SUCCESS(rc) && pInfo; pInfo = pInfo->pNext)
1415 rc = pfnCallback(pUVM, pInfo->szName, pInfo->pszDesc, pvUser);
1416
1417 /*
1418 * Leave and exit.
1419 */
1420 int rc2 = RTCritSectRwLeaveShared(&pUVM->dbgf.s.CritSect);
1421 AssertRC(rc2);
1422
1423 LogFlow(("DBGFR3InfoLog: returns %Rrc\n", rc));
1424 return rc;
1425}
1426
1427
1428/**
1429 * Info handler, internal version.
1430 *
1431 * @param pVM The cross context VM structure.
1432 * @param pHlp Callback functions for doing output.
1433 * @param pszArgs Argument string. Optional and specific to the handler.
1434 */
1435static DECLCALLBACK(void) dbgfR3InfoHelp(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
1436{
1437 LogFlow(("dbgfR3InfoHelp: pszArgs=%s\n", pszArgs));
1438
1439 /*
1440 * Enter and enumerate.
1441 */
1442 PUVM pUVM = pVM->pUVM;
1443 int rc = RTCritSectRwEnterShared(&pUVM->dbgf.s.CritSect);
1444 AssertRC(rc);
1445
1446 if (pszArgs && *pszArgs)
1447 {
1448 for (PDBGFINFO pInfo = pUVM->dbgf.s.pInfoFirst; pInfo; pInfo = pInfo->pNext)
1449 {
1450 const char *psz = strstr(pszArgs, pInfo->szName);
1451 if ( psz
1452 && ( psz == pszArgs
1453 || RT_C_IS_SPACE(psz[-1]))
1454 && ( !psz[pInfo->cchName]
1455 || RT_C_IS_SPACE(psz[pInfo->cchName])))
1456 pHlp->pfnPrintf(pHlp, "%-16s %s\n",
1457 pInfo->szName, pInfo->pszDesc);
1458 }
1459 }
1460 else
1461 {
1462 for (PDBGFINFO pInfo = pUVM->dbgf.s.pInfoFirst; pInfo; pInfo = pInfo->pNext)
1463 pHlp->pfnPrintf(pHlp, "%-16s %s\n",
1464 pInfo->szName, pInfo->pszDesc);
1465 }
1466
1467 /*
1468 * Leave and exit.
1469 */
1470 rc = RTCritSectRwLeaveShared(&pUVM->dbgf.s.CritSect);
1471 AssertRC(rc);
1472}
1473
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