VirtualBox

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

Last change on this file since 41965 was 41965, checked in by vboxsync, 12 years ago

VMM: ran scm. Mostly svn:keywords changes (adding Revision).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 31.6 KB
Line 
1/* $Id: DBGFInfo.cpp 41965 2012-06-29 02:52:49Z vboxsync $ */
2/** @file
3 * DBGF - Debugger Facility, Info.
4 */
5
6/*
7 * Copyright (C) 2006-2007 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/err.h>
29#include <VBox/log.h>
30
31#include <iprt/assert.h>
32#include <iprt/ctype.h>
33#include <iprt/semaphore.h>
34#include <iprt/stream.h>
35#include <iprt/string.h>
36#include <iprt/thread.h>
37
38
39/*******************************************************************************
40* Internal Functions *
41*******************************************************************************/
42static DECLCALLBACK(void) dbgfR3InfoLog_Printf(PCDBGFINFOHLP pHlp, const char *pszFormat, ...);
43static DECLCALLBACK(void) dbgfR3InfoLog_PrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args);
44static DECLCALLBACK(void) dbgfR3InfoLogRel_Printf(PCDBGFINFOHLP pHlp, const char *pszFormat, ...);
45static DECLCALLBACK(void) dbgfR3InfoLogRel_PrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args);
46static DECLCALLBACK(void) dbgfR3InfoStdErr_Printf(PCDBGFINFOHLP pHlp, const char *pszFormat, ...);
47static DECLCALLBACK(void) dbgfR3InfoStdErr_PrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args);
48static DECLCALLBACK(void) dbgfR3InfoHelp(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
49
50
51/*******************************************************************************
52* Global Variables *
53*******************************************************************************/
54/** Logger output. */
55static const DBGFINFOHLP g_dbgfR3InfoLogHlp =
56{
57 dbgfR3InfoLog_Printf,
58 dbgfR3InfoLog_PrintfV
59};
60
61/** Release logger output. */
62static const DBGFINFOHLP g_dbgfR3InfoLogRelHlp =
63{
64 dbgfR3InfoLogRel_Printf,
65 dbgfR3InfoLogRel_PrintfV
66};
67
68/** Standard error output. */
69static const DBGFINFOHLP g_dbgfR3InfoStdErrHlp =
70{
71 dbgfR3InfoStdErr_Printf,
72 dbgfR3InfoStdErr_PrintfV
73};
74
75
76/**
77 * Initialize the info handlers.
78 *
79 * @returns VBox status code.
80 * @param pVM Pointer to the VM.
81 */
82int dbgfR3InfoInit(PVM pVM)
83{
84 /*
85 * Make sure we already didn't initialized in the lazy manner.
86 */
87 if (RTCritSectIsInitialized(&pVM->dbgf.s.InfoCritSect))
88 return VINF_SUCCESS;
89
90 /*
91 * Initialize the crit sect.
92 */
93 int rc = RTCritSectInit(&pVM->dbgf.s.InfoCritSect);
94 AssertRCReturn(rc, rc);
95
96 /*
97 * Register the 'info help' item.
98 */
99 rc = DBGFR3InfoRegisterInternal(pVM, "help", "List of info items.", dbgfR3InfoHelp);
100 AssertRCReturn(rc, rc);
101
102 return VINF_SUCCESS;
103}
104
105
106/**
107 * Terminate the info handlers.
108 *
109 * @returns VBox status code.
110 * @param pVM Pointer to the VM.
111 */
112int dbgfR3InfoTerm(PVM pVM)
113{
114 /*
115 * Delete the crit sect.
116 */
117 int rc = RTCritSectDelete(&pVM->dbgf.s.InfoCritSect);
118 AssertRC(rc);
119 return rc;
120}
121
122
123/** Logger output.
124 * @copydoc DBGFINFOHLP::pfnPrintf */
125static DECLCALLBACK(void) dbgfR3InfoLog_Printf(PCDBGFINFOHLP pHlp, const char *pszFormat, ...)
126{
127 NOREF(pHlp);
128 va_list args;
129 va_start(args, pszFormat);
130 RTLogPrintfV(pszFormat, args);
131 va_end(args);
132}
133
134/** Logger output.
135 * @copydoc DBGFINFOHLP::pfnPrintfV */
136static DECLCALLBACK(void) dbgfR3InfoLog_PrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args)
137{
138 NOREF(pHlp);
139 RTLogPrintfV(pszFormat, args);
140}
141
142
143/**
144 * Gets the logger info helper.
145 * The returned info helper will unconditionally write all output to the log.
146 *
147 * @returns Pointer to the logger info helper.
148 */
149VMMR3DECL(PCDBGFINFOHLP) DBGFR3InfoLogHlp(void)
150{
151 return &g_dbgfR3InfoLogHlp;
152}
153
154
155/** Release logger output.
156 * @copydoc DBGFINFOHLP::pfnPrintf */
157static DECLCALLBACK(void) dbgfR3InfoLogRel_Printf(PCDBGFINFOHLP pHlp, const char *pszFormat, ...)
158{
159 NOREF(pHlp);
160 va_list args;
161 va_start(args, pszFormat);
162 RTLogRelPrintfV(pszFormat, args);
163 va_end(args);
164}
165
166/** Release logger output.
167 * @copydoc DBGFINFOHLP::pfnPrintfV */
168static DECLCALLBACK(void) dbgfR3InfoLogRel_PrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args)
169{
170 NOREF(pHlp);
171 RTLogRelPrintfV(pszFormat, args);
172}
173
174
175/** Standard error output.
176 * @copydoc DBGFINFOHLP::pfnPrintf */
177static DECLCALLBACK(void) dbgfR3InfoStdErr_Printf(PCDBGFINFOHLP pHlp, const char *pszFormat, ...)
178{
179 NOREF(pHlp);
180 va_list args;
181 va_start(args, pszFormat);
182 RTStrmPrintfV(g_pStdErr, pszFormat, args);
183 va_end(args);
184}
185
186/** Standard error output.
187 * @copydoc DBGFINFOHLP::pfnPrintfV */
188static DECLCALLBACK(void) dbgfR3InfoStdErr_PrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args)
189{
190 NOREF(pHlp);
191 RTStrmPrintfV(g_pStdErr, pszFormat, args);
192}
193
194
195/**
196 * Gets the release logger info helper.
197 * The returned info helper will unconditionally write all output to the release log.
198 *
199 * @returns Pointer to the release logger info helper.
200 */
201VMMR3DECL(PCDBGFINFOHLP) DBGFR3InfoLogRelHlp(void)
202{
203 return &g_dbgfR3InfoLogRelHlp;
204}
205
206
207/**
208 * Handle registration worker.
209 * This allocates the structure, initializes the common fields and inserts into the list.
210 * Upon successful return the we're inside the crit sect and the caller must leave it.
211 *
212 * @returns VBox status code.
213 * @param pVM Pointer to the VM.
214 * @param pszName The identifier of the info.
215 * @param pszDesc The description of the info and any arguments the handler may take.
216 * @param fFlags The flags.
217 * @param ppInfo Where to store the created
218 */
219static int dbgfR3InfoRegister(PVM pVM, const char *pszName, const char *pszDesc, uint32_t fFlags, PDBGFINFO *ppInfo)
220{
221 /*
222 * Validate.
223 */
224 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
225 AssertReturn(*pszName, VERR_INVALID_PARAMETER);
226 AssertPtrReturn(pszDesc, VERR_INVALID_POINTER);
227 AssertMsgReturn(!(fFlags & ~(DBGFINFO_FLAGS_RUN_ON_EMT)), ("fFlags=%#x\n", fFlags), VERR_INVALID_PARAMETER);
228
229 /*
230 * Allocate and initialize.
231 */
232 int rc;
233 size_t cchName = strlen(pszName) + 1;
234 PDBGFINFO pInfo = (PDBGFINFO)MMR3HeapAlloc(pVM, MM_TAG_DBGF_INFO, RT_OFFSETOF(DBGFINFO, szName[cchName]));
235 if (pInfo)
236 {
237 pInfo->enmType = DBGFINFOTYPE_INVALID;
238 pInfo->fFlags = fFlags;
239 pInfo->pszDesc = pszDesc;
240 pInfo->cchName = cchName - 1;
241 memcpy(pInfo->szName, pszName, cchName);
242
243 /* lazy init */
244 rc = VINF_SUCCESS;
245 if (!RTCritSectIsInitialized(&pVM->dbgf.s.InfoCritSect))
246 rc = dbgfR3InfoInit(pVM);
247 if (RT_SUCCESS(rc))
248 {
249 /*
250 * Insert in alphabetical order.
251 */
252 rc = RTCritSectEnter(&pVM->dbgf.s.InfoCritSect);
253 AssertRC(rc);
254 PDBGFINFO pPrev = NULL;
255 PDBGFINFO pCur;
256 for (pCur = pVM->dbgf.s.pInfoFirst; pCur; pPrev = pCur, pCur = pCur->pNext)
257 if (strcmp(pszName, pCur->szName) < 0)
258 break;
259 pInfo->pNext = pCur;
260 if (pPrev)
261 pPrev->pNext = pInfo;
262 else
263 pVM->dbgf.s.pInfoFirst = pInfo;
264
265 *ppInfo = pInfo;
266 return VINF_SUCCESS;
267 }
268 MMR3HeapFree(pInfo);
269 }
270 else
271 rc = VERR_NO_MEMORY;
272 return rc;
273}
274
275
276/**
277 * Register a info handler owned by a device.
278 *
279 * @returns VBox status code.
280 * @param pVM Pointer to the VM.
281 * @param pszName The identifier of the info.
282 * @param pszDesc The description of the info and any arguments the handler may take.
283 * @param pfnHandler The handler function to be called to display the info.
284 * @param pDevIns The device instance owning the info.
285 */
286VMMR3DECL(int) DBGFR3InfoRegisterDevice(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFHANDLERDEV pfnHandler, PPDMDEVINS pDevIns)
287{
288 LogFlow(("DBGFR3InfoRegisterDevice: pszName=%p:{%s} pszDesc=%p:{%s} pfnHandler=%p pDevIns=%p\n",
289 pszName, pszName, pszDesc, pszDesc, pfnHandler, pDevIns));
290
291 /*
292 * Validate the specific stuff.
293 */
294 if (!pfnHandler)
295 {
296 AssertMsgFailed(("No handler\n"));
297 return VERR_INVALID_PARAMETER;
298 }
299 if (!pDevIns)
300 {
301 AssertMsgFailed(("No pDevIns\n"));
302 return VERR_INVALID_PARAMETER;
303 }
304
305 /*
306 * Register
307 */
308 PDBGFINFO pInfo;
309 int rc = dbgfR3InfoRegister(pVM, pszName, pszDesc, 0, &pInfo);
310 if (RT_SUCCESS(rc))
311 {
312 pInfo->enmType = DBGFINFOTYPE_DEV;
313 pInfo->u.Dev.pfnHandler = pfnHandler;
314 pInfo->u.Dev.pDevIns = pDevIns;
315 RTCritSectLeave(&pVM->dbgf.s.InfoCritSect);
316 }
317
318 return rc;
319}
320
321
322/**
323 * Register a info handler owned by a driver.
324 *
325 * @returns VBox status code.
326 * @param pVM Pointer to the VM.
327 * @param pszName The identifier of the info.
328 * @param pszDesc The description of the info and any arguments the handler may take.
329 * @param pfnHandler The handler function to be called to display the info.
330 * @param pDrvIns The driver instance owning the info.
331 */
332VMMR3DECL(int) DBGFR3InfoRegisterDriver(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFHANDLERDRV pfnHandler, PPDMDRVINS pDrvIns)
333{
334 LogFlow(("DBGFR3InfoRegisterDriver: pszName=%p:{%s} pszDesc=%p:{%s} pfnHandler=%p pDrvIns=%p\n",
335 pszName, pszName, pszDesc, pszDesc, pfnHandler, pDrvIns));
336
337 /*
338 * Validate the specific stuff.
339 */
340 if (!pfnHandler)
341 {
342 AssertMsgFailed(("No handler\n"));
343 return VERR_INVALID_PARAMETER;
344 }
345 if (!pDrvIns)
346 {
347 AssertMsgFailed(("No pDrvIns\n"));
348 return VERR_INVALID_PARAMETER;
349 }
350
351 /*
352 * Register
353 */
354 PDBGFINFO pInfo;
355 int rc = dbgfR3InfoRegister(pVM, pszName, pszDesc, 0, &pInfo);
356 if (RT_SUCCESS(rc))
357 {
358 pInfo->enmType = DBGFINFOTYPE_DRV;
359 pInfo->u.Drv.pfnHandler = pfnHandler;
360 pInfo->u.Drv.pDrvIns = pDrvIns;
361 RTCritSectLeave(&pVM->dbgf.s.InfoCritSect);
362 }
363
364 return rc;
365}
366
367
368/**
369 * Register a info handler owned by an internal component.
370 *
371 * @returns VBox status code.
372 * @param pVM Pointer to the VM.
373 * @param pszName The identifier of the info.
374 * @param pszDesc The description of the info and any arguments the handler may take.
375 * @param pfnHandler The handler function to be called to display the info.
376 */
377VMMR3DECL(int) DBGFR3InfoRegisterInternal(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFHANDLERINT pfnHandler)
378{
379 return DBGFR3InfoRegisterInternalEx(pVM, pszName, pszDesc, pfnHandler, 0);
380}
381
382
383/**
384 * Register a info handler owned by an internal component.
385 *
386 * @returns VBox status code.
387 * @param pVM Pointer to the VM.
388 * @param pszName The identifier of the info.
389 * @param pszDesc The description of the info and any arguments the handler may take.
390 * @param pfnHandler The handler function to be called to display the info.
391 * @param fFlags Flags, see the DBGFINFO_FLAGS_*.
392 */
393VMMR3DECL(int) DBGFR3InfoRegisterInternalEx(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFHANDLERINT pfnHandler, uint32_t fFlags)
394{
395 LogFlow(("DBGFR3InfoRegisterInternal: pszName=%p:{%s} pszDesc=%p:{%s} pfnHandler=%p fFlags=%x\n",
396 pszName, pszName, pszDesc, pszDesc, pfnHandler, fFlags));
397
398 /*
399 * Validate the specific stuff.
400 */
401 if (!pfnHandler)
402 {
403 AssertMsgFailed(("No handler\n"));
404 return VERR_INVALID_PARAMETER;
405 }
406
407 /*
408 * Register
409 */
410 PDBGFINFO pInfo;
411 int rc = dbgfR3InfoRegister(pVM, pszName, pszDesc, fFlags, &pInfo);
412 if (RT_SUCCESS(rc))
413 {
414 pInfo->enmType = DBGFINFOTYPE_INT;
415 pInfo->u.Int.pfnHandler = pfnHandler;
416 RTCritSectLeave(&pVM->dbgf.s.InfoCritSect);
417 }
418
419 return rc;
420}
421
422
423/**
424 * Register a info handler owned by an external component.
425 *
426 * @returns VBox status code.
427 * @param pVM Pointer to the VM.
428 * @param pszName The identifier of the info.
429 * @param pszDesc The description of the info and any arguments the handler may take.
430 * @param pfnHandler The handler function to be called to display the info.
431 * @param pvUser User argument to be passed to the handler.
432 */
433VMMR3DECL(int) DBGFR3InfoRegisterExternal(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFHANDLEREXT pfnHandler, void *pvUser)
434{
435 LogFlow(("DBGFR3InfoRegisterExternal: pszName=%p:{%s} pszDesc=%p:{%s} pfnHandler=%p pvUser=%p\n",
436 pszName, pszName, pszDesc, pszDesc, pfnHandler, pvUser));
437
438 /*
439 * Validate the specific stuff.
440 */
441 if (!pfnHandler)
442 {
443 AssertMsgFailed(("No handler\n"));
444 return VERR_INVALID_PARAMETER;
445 }
446
447 /*
448 * Register
449 */
450 PDBGFINFO pInfo;
451 int rc = dbgfR3InfoRegister(pVM, pszName, pszDesc, 0, &pInfo);
452 if (RT_SUCCESS(rc))
453 {
454 pInfo->enmType = DBGFINFOTYPE_EXT;
455 pInfo->u.Ext.pfnHandler = pfnHandler;
456 pInfo->u.Ext.pvUser = pvUser;
457 RTCritSectLeave(&pVM->dbgf.s.InfoCritSect);
458 }
459
460 return rc;
461}
462
463
464/**
465 * Deregister one(/all) info handler(s) owned by a device.
466 *
467 * @returns VBox status code.
468 * @param pVM Pointer to the VM.
469 * @param pDevIns Device instance.
470 * @param pszName The identifier of the info. If NULL all owned by the device.
471 */
472VMMR3DECL(int) DBGFR3InfoDeregisterDevice(PVM pVM, PPDMDEVINS pDevIns, const char *pszName)
473{
474 LogFlow(("DBGFR3InfoDeregisterDevice: pDevIns=%p pszName=%p:{%s}\n", pDevIns, pszName, pszName));
475
476 /*
477 * Validate input.
478 */
479 if (!pDevIns)
480 {
481 AssertMsgFailed(("!pDevIns\n"));
482 return VERR_INVALID_PARAMETER;
483 }
484 size_t cchName = pszName ? strlen(pszName) : 0;
485
486 /*
487 * Enumerate the info handlers and free the requested entries.
488 */
489 int rc = RTCritSectEnter(&pVM->dbgf.s.InfoCritSect);
490 AssertRC(rc);
491 rc = VERR_FILE_NOT_FOUND;
492 PDBGFINFO pPrev = NULL;
493 PDBGFINFO pInfo = pVM->dbgf.s.pInfoFirst;
494 if (pszName)
495 {
496 /*
497 * Free a specific one.
498 */
499 for (; pInfo; pPrev = pInfo, pInfo = pInfo->pNext)
500 if ( pInfo->enmType == DBGFINFOTYPE_DEV
501 && pInfo->u.Dev.pDevIns == pDevIns
502 && pInfo->cchName == cchName
503 && !strcmp(pInfo->szName, pszName))
504 {
505 if (pPrev)
506 pPrev->pNext = pInfo->pNext;
507 else
508 pVM->dbgf.s.pInfoFirst = pInfo->pNext;
509 MMR3HeapFree(pInfo);
510 rc = VINF_SUCCESS;
511 break;
512 }
513 }
514 else
515 {
516 /*
517 * Free all owned by the driver.
518 */
519 for (; pInfo; pPrev = pInfo, pInfo = pInfo->pNext)
520 if ( pInfo->enmType == DBGFINFOTYPE_DEV
521 && pInfo->u.Dev.pDevIns == pDevIns)
522 {
523 if (pPrev)
524 pPrev->pNext = pInfo->pNext;
525 else
526 pVM->dbgf.s.pInfoFirst = pInfo->pNext;
527 MMR3HeapFree(pInfo);
528 pInfo = pPrev;
529 }
530 rc = VINF_SUCCESS;
531 }
532 int rc2 = RTCritSectLeave(&pVM->dbgf.s.InfoCritSect);
533 AssertRC(rc2);
534 AssertRC(rc);
535 LogFlow(("DBGFR3InfoDeregisterDevice: returns %Rrc\n", rc));
536 return rc;
537}
538
539/**
540 * Deregister one(/all) info handler(s) owned by a driver.
541 *
542 * @returns VBox status code.
543 * @param pVM Pointer to the VM.
544 * @param pDrvIns Driver instance.
545 * @param pszName The identifier of the info. If NULL all owned by the driver.
546 */
547VMMR3DECL(int) DBGFR3InfoDeregisterDriver(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName)
548{
549 LogFlow(("DBGFR3InfoDeregisterDriver: pDrvIns=%p pszName=%p:{%s}\n", pDrvIns, pszName, pszName));
550
551 /*
552 * Validate input.
553 */
554 if (!pDrvIns)
555 {
556 AssertMsgFailed(("!pDrvIns\n"));
557 return VERR_INVALID_PARAMETER;
558 }
559 size_t cchName = pszName ? strlen(pszName) : 0;
560
561 /*
562 * Enumerate the info handlers and free the requested entries.
563 */
564 int rc = RTCritSectEnter(&pVM->dbgf.s.InfoCritSect);
565 AssertRC(rc);
566 rc = VERR_FILE_NOT_FOUND;
567 PDBGFINFO pPrev = NULL;
568 PDBGFINFO pInfo = pVM->dbgf.s.pInfoFirst;
569 if (pszName)
570 {
571 /*
572 * Free a specific one.
573 */
574 for (; pInfo; pPrev = pInfo, pInfo = pInfo->pNext)
575 if ( pInfo->enmType == DBGFINFOTYPE_DRV
576 && pInfo->u.Drv.pDrvIns == pDrvIns
577 && pInfo->cchName == cchName
578 && !strcmp(pInfo->szName, pszName))
579 {
580 if (pPrev)
581 pPrev->pNext = pInfo->pNext;
582 else
583 pVM->dbgf.s.pInfoFirst = pInfo->pNext;
584 MMR3HeapFree(pInfo);
585 rc = VINF_SUCCESS;
586 break;
587 }
588 }
589 else
590 {
591 /*
592 * Free all owned by the driver.
593 */
594 for (; pInfo; pPrev = pInfo, pInfo = pInfo->pNext)
595 if ( pInfo->enmType == DBGFINFOTYPE_DRV
596 && pInfo->u.Drv.pDrvIns == pDrvIns)
597 {
598 if (pPrev)
599 pPrev->pNext = pInfo->pNext;
600 else
601 pVM->dbgf.s.pInfoFirst = pInfo->pNext;
602 MMR3HeapFree(pInfo);
603 pInfo = pPrev;
604 }
605 rc = VINF_SUCCESS;
606 }
607 int rc2 = RTCritSectLeave(&pVM->dbgf.s.InfoCritSect);
608 AssertRC(rc2);
609 AssertRC(rc);
610 LogFlow(("DBGFR3InfoDeregisterDriver: returns %Rrc\n", rc));
611 return rc;
612}
613
614
615/**
616 * Internal deregistration helper.
617 *
618 * @returns VBox status code.
619 * @param pVM Pointer to the VM.
620 * @param pszName The identifier of the info.
621 * @param enmType The info owner type.
622 */
623static int dbgfR3InfoDeregister(PVM pVM, const char *pszName, DBGFINFOTYPE enmType)
624{
625 /*
626 * Validate input.
627 */
628 if (!pszName)
629 {
630 AssertMsgFailed(("!pszName\n"));
631 return VERR_INVALID_PARAMETER;
632 }
633
634 /*
635 * Find the info handler.
636 */
637 size_t cchName = strlen(pszName);
638 int rc = RTCritSectEnter(&pVM->dbgf.s.InfoCritSect);
639 AssertRC(rc);
640 rc = VERR_FILE_NOT_FOUND;
641 PDBGFINFO pPrev = NULL;
642 PDBGFINFO pInfo = pVM->dbgf.s.pInfoFirst;
643 for (; pInfo; pPrev = pInfo, pInfo = pInfo->pNext)
644 if ( pInfo->cchName == cchName
645 && !strcmp(pInfo->szName, pszName)
646 && pInfo->enmType == enmType)
647 {
648 if (pPrev)
649 pPrev->pNext = pInfo->pNext;
650 else
651 pVM->dbgf.s.pInfoFirst = pInfo->pNext;
652 MMR3HeapFree(pInfo);
653 rc = VINF_SUCCESS;
654 break;
655 }
656 int rc2 = RTCritSectLeave(&pVM->dbgf.s.InfoCritSect);
657 AssertRC(rc2);
658 AssertRC(rc);
659 LogFlow(("dbgfR3InfoDeregister: returns %Rrc\n", rc));
660 return rc;
661}
662
663
664/**
665 * Deregister a info handler owned by an internal component.
666 *
667 * @returns VBox status code.
668 * @param pVM Pointer to the VM.
669 * @param pszName The identifier of the info. If NULL all owned by the device.
670 */
671VMMR3DECL(int) DBGFR3InfoDeregisterInternal(PVM pVM, const char *pszName)
672{
673 LogFlow(("DBGFR3InfoDeregisterInternal: pszName=%p:{%s}\n", pszName, pszName));
674 return dbgfR3InfoDeregister(pVM, pszName, DBGFINFOTYPE_INT);
675}
676
677
678/**
679 * Deregister a info handler owned by an external component.
680 *
681 * @returns VBox status code.
682 * @param pVM Pointer to the VM.
683 * @param pszName The identifier of the info. If NULL all owned by the device.
684 */
685VMMR3DECL(int) DBGFR3InfoDeregisterExternal(PVM pVM, const char *pszName)
686{
687 LogFlow(("DBGFR3InfoDeregisterExternal: pszName=%p:{%s}\n", pszName, pszName));
688 return dbgfR3InfoDeregister(pVM, pszName, DBGFINFOTYPE_EXT);
689}
690
691
692/**
693 * Worker for DBGFR3Info and DBGFR3InfoEx.
694 *
695 * @returns VBox status code.
696 * @param pVM Pointer to the VM.
697 * @param idCpu Which CPU to run EMT bound handlers on.
698 * VMCPUID_ANY or a valid CPU ID.
699 * @param pszName What to dump.
700 * @param pszArgs Arguments, optional.
701 * @param pHlp Output helper, optional.
702 */
703static DECLCALLBACK(int) dbgfR3Info(PVM pVM, VMCPUID idCpu, const char *pszName, const char *pszArgs, PCDBGFINFOHLP pHlp)
704{
705 /*
706 * Validate input.
707 */
708 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
709 if (pHlp)
710 {
711 if ( !pHlp->pfnPrintf
712 || !pHlp->pfnPrintfV)
713 {
714 AssertMsgFailed(("A pHlp member is missing!\n"));
715 return VERR_INVALID_PARAMETER;
716 }
717 }
718 else
719 pHlp = &g_dbgfR3InfoLogHlp;
720
721 /*
722 * Find the info handler.
723 */
724 size_t cchName = strlen(pszName);
725 int rc = RTCritSectEnter(&pVM->dbgf.s.InfoCritSect);
726 AssertRC(rc);
727 PDBGFINFO pInfo = pVM->dbgf.s.pInfoFirst;
728 for (; pInfo; pInfo = pInfo->pNext)
729 if ( pInfo->cchName == cchName
730 && !memcmp(pInfo->szName, pszName, cchName))
731 break;
732 if (pInfo)
733 {
734 /*
735 * Found it.
736 * Make a copy of it on the stack so we can leave the crit sect.
737 * Switch on the type and invoke the handler.
738 */
739 DBGFINFO Info = *pInfo;
740 rc = RTCritSectLeave(&pVM->dbgf.s.InfoCritSect);
741 AssertRC(rc);
742 rc = VINF_SUCCESS;
743 switch (Info.enmType)
744 {
745 case DBGFINFOTYPE_DEV:
746 if (Info.fFlags & DBGFINFO_FLAGS_RUN_ON_EMT)
747 rc = VMR3ReqCallVoidWait(pVM, idCpu, (PFNRT)Info.u.Dev.pfnHandler, 3, Info.u.Dev.pDevIns, pHlp, pszArgs);
748 else
749 Info.u.Dev.pfnHandler(Info.u.Dev.pDevIns, pHlp, pszArgs);
750 break;
751
752 case DBGFINFOTYPE_DRV:
753 if (Info.fFlags & DBGFINFO_FLAGS_RUN_ON_EMT)
754 rc = VMR3ReqCallVoidWait(pVM, idCpu, (PFNRT)Info.u.Drv.pfnHandler, 3, Info.u.Drv.pDrvIns, pHlp, pszArgs);
755 else
756 Info.u.Drv.pfnHandler(Info.u.Drv.pDrvIns, pHlp, pszArgs);
757 break;
758
759 case DBGFINFOTYPE_INT:
760 if (Info.fFlags & DBGFINFO_FLAGS_RUN_ON_EMT)
761 rc = VMR3ReqCallVoidWait(pVM, idCpu, (PFNRT)Info.u.Int.pfnHandler, 3, pVM, pHlp, pszArgs);
762 else
763 Info.u.Int.pfnHandler(pVM, pHlp, pszArgs);
764 break;
765
766 case DBGFINFOTYPE_EXT:
767 if (Info.fFlags & DBGFINFO_FLAGS_RUN_ON_EMT)
768 rc = VMR3ReqCallVoidWait(pVM, idCpu, (PFNRT)Info.u.Ext.pfnHandler, 3, Info.u.Ext.pvUser, pHlp, pszArgs);
769 else
770 Info.u.Ext.pfnHandler(Info.u.Ext.pvUser, pHlp, pszArgs);
771 break;
772
773 default:
774 AssertMsgFailedReturn(("Invalid info type enmType=%d\n", Info.enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE);
775 }
776 }
777 else
778 {
779 rc = RTCritSectLeave(&pVM->dbgf.s.InfoCritSect);
780 AssertRC(rc);
781 rc = VERR_FILE_NOT_FOUND;
782 }
783 return rc;
784}
785
786/**
787 * Display a piece of info writing to the supplied handler.
788 *
789 * @returns VBox status code.
790 * @param pVM Pointer to the VM.
791 * @param pszName The identifier of the info to display.
792 * @param pszArgs Arguments to the info handler.
793 * @param pHlp The output helper functions. If NULL the logger will be used.
794 */
795VMMR3DECL(int) DBGFR3Info(PVM pVM, const char *pszName, const char *pszArgs, PCDBGFINFOHLP pHlp)
796{
797 return dbgfR3Info(pVM, VMCPUID_ANY, pszName, pszArgs, pHlp);
798}
799
800
801/**
802 * Display a piece of info writing to the supplied handler.
803 *
804 * @returns VBox status code.
805 * @param pVM Pointer to the VM.
806 * @param idCpu The CPU to exectue the request on. Pass NIL_VMCPUID
807 * to not involve any EMT.
808 * @param pszName The identifier of the info to display.
809 * @param pszArgs Arguments to the info handler.
810 * @param pHlp The output helper functions. If NULL the logger will be used.
811 */
812VMMR3DECL(int) DBGFR3InfoEx(PVM pVM, VMCPUID idCpu, const char *pszName, const char *pszArgs, PCDBGFINFOHLP pHlp)
813{
814 if (idCpu == NIL_VMCPUID)
815 return dbgfR3Info(pVM, VMCPUID_ANY, pszName, pszArgs, pHlp);
816 return VMR3ReqPriorityCallWait(pVM, idCpu,
817 (PFNRT)dbgfR3Info, 5, pVM, idCpu, pszName, pszArgs, pHlp);
818}
819
820
821/**
822 * Wrapper for DBGFR3Info that outputs to the release log.
823 *
824 * @returns See DBGFR3Info.
825 * @param pVM Pointer to the VM.
826 * @param pszName See DBGFR3Info.
827 * @param pszArgs See DBGFR3Info.
828 */
829VMMR3DECL(int) DBGFR3InfoLogRel(PVM pVM, const char *pszName, const char *pszArgs)
830{
831 return DBGFR3Info(pVM, pszName, pszArgs, &g_dbgfR3InfoLogRelHlp);
832}
833
834
835/**
836 * Wrapper for DBGFR3Info that outputs to standard error.
837 *
838 * @returns See DBGFR3Info.
839 * @param pVM Pointer to the VM.
840 * @param pszName See DBGFR3Info.
841 * @param pszArgs See DBGFR3Info.
842 */
843VMMR3DECL(int) DBGFR3InfoStdErr(PVM pVM, const char *pszName, const char *pszArgs)
844{
845 return DBGFR3Info(pVM, pszName, pszArgs, &g_dbgfR3InfoStdErrHlp);
846}
847
848
849/**
850 * Display several info items.
851 *
852 * This is intended used by the fatal error dump only.
853 *
854 * @returns
855 * @param pVM Pointer to the VM.
856 * @param pszIncludePat Simple string pattern of info items to include.
857 * @param pszExcludePat Simple string pattern of info items to exclude.
858 * @param pszSepFmt Item separator format string. The item name will be
859 * given as parameter.
860 * @param pHlp The output helper functions. If NULL the logger
861 * will be used.
862 *
863 * @threads EMT
864 */
865VMMR3DECL(int) DBGFR3InfoMulti(PVM pVM, const char *pszIncludePat, const char *pszExcludePat, const char *pszSepFmt,
866 PCDBGFINFOHLP pHlp)
867{
868 /*
869 * Validate input.
870 */
871 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
872 AssertPtrReturn(pszIncludePat, VERR_INVALID_POINTER);
873 AssertPtrReturn(pszExcludePat, VERR_INVALID_POINTER);
874 if (pHlp)
875 {
876 AssertPtrReturn(pHlp->pfnPrintf, VERR_INVALID_POINTER);
877 AssertPtrReturn(pHlp->pfnPrintfV, VERR_INVALID_POINTER);
878 }
879 else
880 pHlp = &g_dbgfR3InfoLogHlp;
881
882 size_t const cchIncludePat = strlen(pszIncludePat);
883 size_t const cchExcludePat = strlen(pszExcludePat);
884 const char *pszArgs = "";
885
886 /*
887 * Enumerate the info handlers and call the ones matching.
888 * Note! We won't leave the critical section here...
889 */
890 int rc = RTCritSectEnter(&pVM->dbgf.s.InfoCritSect);
891 AssertRC(rc);
892 rc = VWRN_NOT_FOUND;
893 for (PDBGFINFO pInfo = pVM->dbgf.s.pInfoFirst; pInfo; pInfo = pInfo->pNext)
894 {
895 if ( RTStrSimplePatternMultiMatch(pszIncludePat, cchIncludePat, pInfo->szName, pInfo->cchName, NULL)
896 && !RTStrSimplePatternMultiMatch(pszExcludePat, cchExcludePat, pInfo->szName, pInfo->cchName, NULL))
897 {
898 pHlp->pfnPrintf(pHlp, pszSepFmt, pInfo->szName);
899 rc = VINF_SUCCESS;
900 switch (pInfo->enmType)
901 {
902 case DBGFINFOTYPE_DEV:
903 if (pInfo->fFlags & DBGFINFO_FLAGS_RUN_ON_EMT)
904 rc = VMR3ReqCallVoidWait(pVM, VMCPUID_ANY, (PFNRT)pInfo->u.Dev.pfnHandler, 3, pInfo->u.Dev.pDevIns, pHlp, pszArgs);
905 else
906 pInfo->u.Dev.pfnHandler(pInfo->u.Dev.pDevIns, pHlp, pszArgs);
907 break;
908
909 case DBGFINFOTYPE_DRV:
910 if (pInfo->fFlags & DBGFINFO_FLAGS_RUN_ON_EMT)
911 rc = VMR3ReqCallVoidWait(pVM, VMCPUID_ANY, (PFNRT)pInfo->u.Drv.pfnHandler, 3, pInfo->u.Drv.pDrvIns, pHlp, pszArgs);
912 else
913 pInfo->u.Drv.pfnHandler(pInfo->u.Drv.pDrvIns, pHlp, pszArgs);
914 break;
915
916 case DBGFINFOTYPE_INT:
917 if (pInfo->fFlags & DBGFINFO_FLAGS_RUN_ON_EMT)
918 rc = VMR3ReqCallVoidWait(pVM, VMCPUID_ANY, (PFNRT)pInfo->u.Int.pfnHandler, 3, pVM, pHlp, pszArgs);
919 else
920 pInfo->u.Int.pfnHandler(pVM, pHlp, pszArgs);
921 break;
922
923 case DBGFINFOTYPE_EXT:
924 if (pInfo->fFlags & DBGFINFO_FLAGS_RUN_ON_EMT)
925 rc = VMR3ReqCallVoidWait(pVM, VMCPUID_ANY, (PFNRT)pInfo->u.Ext.pfnHandler, 3, pInfo->u.Ext.pvUser, pHlp, pszArgs);
926 else
927 pInfo->u.Ext.pfnHandler(pInfo->u.Ext.pvUser, pHlp, pszArgs);
928 break;
929
930 default:
931 AssertMsgFailedReturn(("Invalid info type enmType=%d\n", pInfo->enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE);
932 }
933 }
934 }
935 int rc2 = RTCritSectLeave(&pVM->dbgf.s.InfoCritSect);
936 AssertRC(rc2);
937
938 return rc;
939}
940
941
942/**
943 * Enumerate all the register info handlers.
944 *
945 * @returns VBox status code.
946 * @param pVM Pointer to the VM.
947 * @param pfnCallback Pointer to callback function.
948 * @param pvUser User argument to pass to the callback.
949 */
950VMMR3DECL(int) DBGFR3InfoEnum(PVM pVM, PFNDBGFINFOENUM pfnCallback, void *pvUser)
951{
952 LogFlow(("DBGFR3InfoLog: pfnCallback=%p pvUser=%p\n", pfnCallback, pvUser));
953
954 /*
955 * Validate input.
956 */
957 if (!pfnCallback)
958 {
959 AssertMsgFailed(("!pfnCallback\n"));
960 return VERR_INVALID_PARAMETER;
961 }
962
963 /*
964 * Enter and enumerate.
965 */
966 int rc = RTCritSectEnter(&pVM->dbgf.s.InfoCritSect);
967 AssertRC(rc);
968
969 rc = VINF_SUCCESS;
970 for (PDBGFINFO pInfo = pVM->dbgf.s.pInfoFirst; RT_SUCCESS(rc) && pInfo; pInfo = pInfo->pNext)
971 rc = pfnCallback(pVM, pInfo->szName, pInfo->pszDesc, pvUser);
972
973 /*
974 * Leave and exit.
975 */
976 int rc2 = RTCritSectLeave(&pVM->dbgf.s.InfoCritSect);
977 AssertRC(rc2);
978
979 LogFlow(("DBGFR3InfoLog: returns %Rrc\n", rc));
980 return rc;
981}
982
983
984/**
985 * Info handler, internal version.
986 *
987 * @param pVM Pointer to the VM.
988 * @param pHlp Callback functions for doing output.
989 * @param pszArgs Argument string. Optional and specific to the handler.
990 */
991static DECLCALLBACK(void) dbgfR3InfoHelp(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
992{
993 LogFlow(("dbgfR3InfoHelp: pszArgs=%s\n", pszArgs));
994
995 /*
996 * Enter and enumerate.
997 */
998 int rc = RTCritSectEnter(&pVM->dbgf.s.InfoCritSect);
999 AssertRC(rc);
1000
1001 if (pszArgs && *pszArgs)
1002 {
1003 for (PDBGFINFO pInfo = pVM->dbgf.s.pInfoFirst; pInfo; pInfo = pInfo->pNext)
1004 {
1005 const char *psz = strstr(pszArgs, pInfo->szName);
1006 if ( psz
1007 && ( psz == pszArgs
1008 || RT_C_IS_SPACE(psz[-1]))
1009 && ( !psz[pInfo->cchName]
1010 || RT_C_IS_SPACE(psz[pInfo->cchName])))
1011 pHlp->pfnPrintf(pHlp, "%-16s %s\n",
1012 pInfo->szName, pInfo->pszDesc);
1013 }
1014 }
1015 else
1016 {
1017 for (PDBGFINFO pInfo = pVM->dbgf.s.pInfoFirst; pInfo; pInfo = pInfo->pNext)
1018 pHlp->pfnPrintf(pHlp, "%-16s %s\n",
1019 pInfo->szName, pInfo->pszDesc);
1020 }
1021
1022 /*
1023 * Leave and exit.
1024 */
1025 rc = RTCritSectLeave(&pVM->dbgf.s.InfoCritSect);
1026 AssertRC(rc);
1027}
1028
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use