VirtualBox

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

Last change on this file since 80153 was 80153, checked in by vboxsync, 5 years ago

VMM/DBGF: Added argv style info handlers. USB devices only have argv-style info handlers.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use