VirtualBox

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

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

VMM/r3: Refactored VMCPU enumeration in preparation that aCpus will be replaced with a pointer array. Removed two raw-mode offset members from the CPUM and CPUMCPU sub-structures. bugref:9217 bugref:9517

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