VirtualBox

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

Last change on this file since 30037 was 28800, checked in by vboxsync, 14 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 26.4 KB
Line 
1/* $Id: DBGFInfo.cpp 28800 2010-04-27 08:22:32Z 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/dbgf.h>
24
25#include <VBox/mm.h>
26#include "DBGFInternal.h"
27#include <VBox/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 VM handle.
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 VM handle.
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 va_list args;
128 va_start(args, pszFormat);
129 RTLogPrintfV(pszFormat, args);
130 va_end(args);
131}
132
133/** Logger output.
134 * @copydoc DBGFINFOHLP::pfnPrintfV */
135static DECLCALLBACK(void) dbgfR3InfoLog_PrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args)
136{
137 RTLogPrintfV(pszFormat, args);
138}
139
140
141/**
142 * Gets the logger info helper.
143 * The returned info helper will unconditionally write all output to the log.
144 *
145 * @returns Pointer to the logger info helper.
146 */
147VMMR3DECL(PCDBGFINFOHLP) DBGFR3InfoLogHlp(void)
148{
149 return &g_dbgfR3InfoLogHlp;
150}
151
152
153/** Release logger output.
154 * @copydoc DBGFINFOHLP::pfnPrintf */
155static DECLCALLBACK(void) dbgfR3InfoLogRel_Printf(PCDBGFINFOHLP pHlp, const char *pszFormat, ...)
156{
157 va_list args;
158 va_start(args, pszFormat);
159 RTLogRelPrintfV(pszFormat, args);
160 va_end(args);
161}
162
163/** Release logger output.
164 * @copydoc DBGFINFOHLP::pfnPrintfV */
165static DECLCALLBACK(void) dbgfR3InfoLogRel_PrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args)
166{
167 RTLogRelPrintfV(pszFormat, args);
168}
169
170
171/** Standard error output.
172 * @copydoc DBGFINFOHLP::pfnPrintf */
173static DECLCALLBACK(void) dbgfR3InfoStdErr_Printf(PCDBGFINFOHLP pHlp, const char *pszFormat, ...)
174{
175 va_list args;
176 va_start(args, pszFormat);
177 RTStrmPrintfV(g_pStdErr, pszFormat, args);
178 va_end(args);
179}
180
181/** Standard error output.
182 * @copydoc DBGFINFOHLP::pfnPrintfV */
183static DECLCALLBACK(void) dbgfR3InfoStdErr_PrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args)
184{
185 RTStrmPrintfV(g_pStdErr, pszFormat, args);
186}
187
188
189/**
190 * Gets the release logger info helper.
191 * The returned info helper will unconditionally write all output to the release log.
192 *
193 * @returns Pointer to the release logger info helper.
194 */
195VMMR3DECL(PCDBGFINFOHLP) DBGFR3InfoLogRelHlp(void)
196{
197 return &g_dbgfR3InfoLogRelHlp;
198}
199
200
201/**
202 * Handle registration worker.
203 * This allocates the structure, initalizes the common fields and inserts into the list.
204 * Upon successful return the we're inside the crit sect and the caller must leave it.
205 *
206 * @returns VBox status code.
207 * @param pVM VM handle.
208 * @param pszName The identifier of the info.
209 * @param pszDesc The description of the info and any arguments the handler may take.
210 * @param fFlags The flags.
211 * @param ppInfo Where to store the created
212 */
213static int dbgfR3InfoRegister(PVM pVM, const char *pszName, const char *pszDesc, uint32_t fFlags, PDBGFINFO *ppInfo)
214{
215 /*
216 * Validate.
217 */
218 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
219 AssertReturn(*pszName, VERR_INVALID_PARAMETER);
220 AssertPtrReturn(pszDesc, VERR_INVALID_POINTER);
221 AssertMsgReturn(!(fFlags & ~(DBGFINFO_FLAGS_RUN_ON_EMT)), ("fFlags=%#x\n", fFlags), VERR_INVALID_PARAMETER);
222
223 /*
224 * Allocate and initialize.
225 */
226 int rc;
227 size_t cchName = strlen(pszName) + 1;
228 PDBGFINFO pInfo = (PDBGFINFO)MMR3HeapAlloc(pVM, MM_TAG_DBGF_INFO, RT_OFFSETOF(DBGFINFO, szName[cchName]));
229 if (pInfo)
230 {
231 pInfo->enmType = DBGFINFOTYPE_INVALID;
232 pInfo->fFlags = fFlags;
233 pInfo->pszDesc = pszDesc;
234 pInfo->cchName = cchName - 1;
235 memcpy(pInfo->szName, pszName, cchName);
236
237 /* lazy init */
238 rc = VINF_SUCCESS;
239 if (!RTCritSectIsInitialized(&pVM->dbgf.s.InfoCritSect))
240 rc = dbgfR3InfoInit(pVM);
241 if (RT_SUCCESS(rc))
242 {
243 /*
244 * Insert in alphabetical order.
245 */
246 rc = RTCritSectEnter(&pVM->dbgf.s.InfoCritSect);
247 AssertRC(rc);
248 PDBGFINFO pPrev = NULL;
249 PDBGFINFO pCur;
250 for (pCur = pVM->dbgf.s.pInfoFirst; pCur; pPrev = pCur, pCur = pCur->pNext)
251 if (strcmp(pszName, pCur->szName) < 0)
252 break;
253 pInfo->pNext = pCur;
254 if (pPrev)
255 pPrev->pNext = pInfo;
256 else
257 pVM->dbgf.s.pInfoFirst = pInfo;
258
259 *ppInfo = pInfo;
260 return VINF_SUCCESS;
261 }
262 MMR3HeapFree(pInfo);
263 }
264 else
265 rc = VERR_NO_MEMORY;
266 return rc;
267}
268
269
270/**
271 * Register a info handler owned by a device.
272 *
273 * @returns VBox status code.
274 * @param pVM VM handle.
275 * @param pszName The identifier of the info.
276 * @param pszDesc The description of the info and any arguments the handler may take.
277 * @param pfnHandler The handler function to be called to display the info.
278 * @param pDevIns The device instance owning the info.
279 */
280VMMR3DECL(int) DBGFR3InfoRegisterDevice(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFHANDLERDEV pfnHandler, PPDMDEVINS pDevIns)
281{
282 LogFlow(("DBGFR3InfoRegisterDevice: pszName=%p:{%s} pszDesc=%p:{%s} pfnHandler=%p pDevIns=%p\n",
283 pszName, pszName, pszDesc, pszDesc, pfnHandler, pDevIns));
284
285 /*
286 * Validate the specific stuff.
287 */
288 if (!pfnHandler)
289 {
290 AssertMsgFailed(("No handler\n"));
291 return VERR_INVALID_PARAMETER;
292 }
293 if (!pDevIns)
294 {
295 AssertMsgFailed(("No pDevIns\n"));
296 return VERR_INVALID_PARAMETER;
297 }
298
299 /*
300 * Register
301 */
302 PDBGFINFO pInfo;
303 int rc = dbgfR3InfoRegister(pVM, pszName, pszDesc, 0, &pInfo);
304 if (RT_SUCCESS(rc))
305 {
306 pInfo->enmType = DBGFINFOTYPE_DEV;
307 pInfo->u.Dev.pfnHandler = pfnHandler;
308 pInfo->u.Dev.pDevIns = pDevIns;
309 RTCritSectLeave(&pVM->dbgf.s.InfoCritSect);
310 }
311
312 return rc;
313}
314
315
316/**
317 * Register a info handler owned by a driver.
318 *
319 * @returns VBox status code.
320 * @param pVM VM handle.
321 * @param pszName The identifier of the info.
322 * @param pszDesc The description of the info and any arguments the handler may take.
323 * @param pfnHandler The handler function to be called to display the info.
324 * @param pDrvIns The driver instance owning the info.
325 */
326VMMR3DECL(int) DBGFR3InfoRegisterDriver(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFHANDLERDRV pfnHandler, PPDMDRVINS pDrvIns)
327{
328 LogFlow(("DBGFR3InfoRegisterDriver: pszName=%p:{%s} pszDesc=%p:{%s} pfnHandler=%p pDrvIns=%p\n",
329 pszName, pszName, pszDesc, pszDesc, pfnHandler, pDrvIns));
330
331 /*
332 * Validate the specific stuff.
333 */
334 if (!pfnHandler)
335 {
336 AssertMsgFailed(("No handler\n"));
337 return VERR_INVALID_PARAMETER;
338 }
339 if (!pDrvIns)
340 {
341 AssertMsgFailed(("No pDrvIns\n"));
342 return VERR_INVALID_PARAMETER;
343 }
344
345 /*
346 * Register
347 */
348 PDBGFINFO pInfo;
349 int rc = dbgfR3InfoRegister(pVM, pszName, pszDesc, 0, &pInfo);
350 if (RT_SUCCESS(rc))
351 {
352 pInfo->enmType = DBGFINFOTYPE_DRV;
353 pInfo->u.Drv.pfnHandler = pfnHandler;
354 pInfo->u.Drv.pDrvIns = pDrvIns;
355 RTCritSectLeave(&pVM->dbgf.s.InfoCritSect);
356 }
357
358 return rc;
359}
360
361
362/**
363 * Register a info handler owned by an internal component.
364 *
365 * @returns VBox status code.
366 * @param pVM VM handle.
367 * @param pszName The identifier of the info.
368 * @param pszDesc The description of the info and any arguments the handler may take.
369 * @param pfnHandler The handler function to be called to display the info.
370 */
371VMMR3DECL(int) DBGFR3InfoRegisterInternal(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFHANDLERINT pfnHandler)
372{
373 return DBGFR3InfoRegisterInternalEx(pVM, pszName, pszDesc, pfnHandler, 0);
374}
375
376
377/**
378 * Register a info handler owned by an internal component.
379 *
380 * @returns VBox status code.
381 * @param pVM VM handle.
382 * @param pszName The identifier of the info.
383 * @param pszDesc The description of the info and any arguments the handler may take.
384 * @param pfnHandler The handler function to be called to display the info.
385 * @param fFlags Flags, see the DBGFINFO_FLAGS_*.
386 */
387VMMR3DECL(int) DBGFR3InfoRegisterInternalEx(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFHANDLERINT pfnHandler, uint32_t fFlags)
388{
389 LogFlow(("DBGFR3InfoRegisterInternal: 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 if (!pfnHandler)
396 {
397 AssertMsgFailed(("No handler\n"));
398 return VERR_INVALID_PARAMETER;
399 }
400
401 /*
402 * Register
403 */
404 PDBGFINFO pInfo;
405 int rc = dbgfR3InfoRegister(pVM, pszName, pszDesc, fFlags, &pInfo);
406 if (RT_SUCCESS(rc))
407 {
408 pInfo->enmType = DBGFINFOTYPE_INT;
409 pInfo->u.Int.pfnHandler = pfnHandler;
410 RTCritSectLeave(&pVM->dbgf.s.InfoCritSect);
411 }
412
413 return rc;
414}
415
416
417/**
418 * Register a info handler owned by an external component.
419 *
420 * @returns VBox status code.
421 * @param pVM VM handle.
422 * @param pszName The identifier of the info.
423 * @param pszDesc The description of the info and any arguments the handler may take.
424 * @param pfnHandler The handler function to be called to display the info.
425 * @param pvUser User argument to be passed to the handler.
426 */
427VMMR3DECL(int) DBGFR3InfoRegisterExternal(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFHANDLEREXT pfnHandler, void *pvUser)
428{
429 LogFlow(("DBGFR3InfoRegisterExternal: pszName=%p:{%s} pszDesc=%p:{%s} pfnHandler=%p pvUser=%p\n",
430 pszName, pszName, pszDesc, pszDesc, pfnHandler, pvUser));
431
432 /*
433 * Validate the specific stuff.
434 */
435 if (!pfnHandler)
436 {
437 AssertMsgFailed(("No handler\n"));
438 return VERR_INVALID_PARAMETER;
439 }
440
441 /*
442 * Register
443 */
444 PDBGFINFO pInfo;
445 int rc = dbgfR3InfoRegister(pVM, pszName, pszDesc, 0, &pInfo);
446 if (RT_SUCCESS(rc))
447 {
448 pInfo->enmType = DBGFINFOTYPE_EXT;
449 pInfo->u.Ext.pfnHandler = pfnHandler;
450 pInfo->u.Ext.pvUser = pvUser;
451 RTCritSectLeave(&pVM->dbgf.s.InfoCritSect);
452 }
453
454 return rc;
455}
456
457
458/**
459 * Deregister one(/all) info handler(s) owned by a device.
460 *
461 * @returns VBox status code.
462 * @param pVM VM Handle.
463 * @param pDevIns Device instance.
464 * @param pszName The identifier of the info. If NULL all owned by the device.
465 */
466VMMR3DECL(int) DBGFR3InfoDeregisterDevice(PVM pVM, PPDMDEVINS pDevIns, const char *pszName)
467{
468 LogFlow(("DBGFR3InfoDeregisterDevice: pDevIns=%p pszName=%p:{%s}\n", pDevIns, pszName, pszName));
469
470 /*
471 * Validate input.
472 */
473 if (!pDevIns)
474 {
475 AssertMsgFailed(("!pDevIns\n"));
476 return VERR_INVALID_PARAMETER;
477 }
478 size_t cchName = pszName ? strlen(pszName) : 0;
479
480 /*
481 * Enumerate the info handlers and free the requested entries.
482 */
483 int rc = RTCritSectEnter(&pVM->dbgf.s.InfoCritSect);
484 AssertRC(rc);
485 rc = VERR_FILE_NOT_FOUND;
486 PDBGFINFO pPrev = NULL;
487 PDBGFINFO pInfo = pVM->dbgf.s.pInfoFirst;
488 if (pszName)
489 {
490 /*
491 * Free a specific one.
492 */
493 for (; pInfo; pPrev = pInfo, pInfo = pInfo->pNext)
494 if ( pInfo->enmType == DBGFINFOTYPE_DEV
495 && pInfo->u.Dev.pDevIns == pDevIns
496 && pInfo->cchName == cchName
497 && !strcmp(pInfo->szName, pszName))
498 {
499 if (pPrev)
500 pPrev->pNext = pInfo->pNext;
501 else
502 pVM->dbgf.s.pInfoFirst = pInfo->pNext;
503 MMR3HeapFree(pInfo);
504 rc = VINF_SUCCESS;
505 break;
506 }
507 }
508 else
509 {
510 /*
511 * Free all owned by the driver.
512 */
513 for (; pInfo; pPrev = pInfo, pInfo = pInfo->pNext)
514 if ( pInfo->enmType == DBGFINFOTYPE_DEV
515 && pInfo->u.Dev.pDevIns == pDevIns)
516 {
517 if (pPrev)
518 pPrev->pNext = pInfo->pNext;
519 else
520 pVM->dbgf.s.pInfoFirst = pInfo->pNext;
521 MMR3HeapFree(pInfo);
522 pInfo = pPrev;
523 }
524 rc = VINF_SUCCESS;
525 }
526 int rc2 = RTCritSectLeave(&pVM->dbgf.s.InfoCritSect);
527 AssertRC(rc2);
528 AssertRC(rc);
529 LogFlow(("DBGFR3InfoDeregisterDevice: returns %Rrc\n", rc));
530 return rc;
531}
532
533/**
534 * Deregister one(/all) info handler(s) owned by a driver.
535 *
536 * @returns VBox status code.
537 * @param pVM VM Handle.
538 * @param pDrvIns Driver instance.
539 * @param pszName The identifier of the info. If NULL all owned by the driver.
540 */
541VMMR3DECL(int) DBGFR3InfoDeregisterDriver(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName)
542{
543 LogFlow(("DBGFR3InfoDeregisterDriver: pDrvIns=%p pszName=%p:{%s}\n", pDrvIns, pszName, pszName));
544
545 /*
546 * Validate input.
547 */
548 if (!pDrvIns)
549 {
550 AssertMsgFailed(("!pDrvIns\n"));
551 return VERR_INVALID_PARAMETER;
552 }
553 size_t cchName = pszName ? strlen(pszName) : 0;
554
555 /*
556 * Enumerate the info handlers and free the requested entries.
557 */
558 int rc = RTCritSectEnter(&pVM->dbgf.s.InfoCritSect);
559 AssertRC(rc);
560 rc = VERR_FILE_NOT_FOUND;
561 PDBGFINFO pPrev = NULL;
562 PDBGFINFO pInfo = pVM->dbgf.s.pInfoFirst;
563 if (pszName)
564 {
565 /*
566 * Free a specific one.
567 */
568 for (; pInfo; pPrev = pInfo, pInfo = pInfo->pNext)
569 if ( pInfo->enmType == DBGFINFOTYPE_DRV
570 && pInfo->u.Drv.pDrvIns == pDrvIns
571 && pInfo->cchName == cchName
572 && !strcmp(pInfo->szName, pszName))
573 {
574 if (pPrev)
575 pPrev->pNext = pInfo->pNext;
576 else
577 pVM->dbgf.s.pInfoFirst = pInfo->pNext;
578 MMR3HeapFree(pInfo);
579 rc = VINF_SUCCESS;
580 break;
581 }
582 }
583 else
584 {
585 /*
586 * Free all owned by the driver.
587 */
588 for (; pInfo; pPrev = pInfo, pInfo = pInfo->pNext)
589 if ( pInfo->enmType == DBGFINFOTYPE_DRV
590 && pInfo->u.Drv.pDrvIns == pDrvIns)
591 {
592 if (pPrev)
593 pPrev->pNext = pInfo->pNext;
594 else
595 pVM->dbgf.s.pInfoFirst = pInfo->pNext;
596 MMR3HeapFree(pInfo);
597 pInfo = pPrev;
598 }
599 rc = VINF_SUCCESS;
600 }
601 int rc2 = RTCritSectLeave(&pVM->dbgf.s.InfoCritSect);
602 AssertRC(rc2);
603 AssertRC(rc);
604 LogFlow(("DBGFR3InfoDeregisterDriver: returns %Rrc\n", rc));
605 return rc;
606}
607
608
609/**
610 * Internal deregistration helper.
611 *
612 * @returns VBox status code.
613 * @param pVM VM Handle.
614 * @param pszName The identifier of the info.
615 * @param enmType The info owner type.
616 */
617static int dbgfR3InfoDeregister(PVM pVM, const char *pszName, DBGFINFOTYPE enmType)
618{
619 /*
620 * Validate input.
621 */
622 if (!pszName)
623 {
624 AssertMsgFailed(("!pszName\n"));
625 return VERR_INVALID_PARAMETER;
626 }
627
628 /*
629 * Find the info handler.
630 */
631 size_t cchName = strlen(pszName);
632 int rc = RTCritSectEnter(&pVM->dbgf.s.InfoCritSect);
633 AssertRC(rc);
634 rc = VERR_FILE_NOT_FOUND;
635 PDBGFINFO pPrev = NULL;
636 PDBGFINFO pInfo = pVM->dbgf.s.pInfoFirst;
637 for (; pInfo; pPrev = pInfo, pInfo = pInfo->pNext)
638 if ( pInfo->cchName == cchName
639 && !strcmp(pInfo->szName, pszName)
640 && pInfo->enmType == enmType)
641 {
642 if (pPrev)
643 pPrev->pNext = pInfo->pNext;
644 else
645 pVM->dbgf.s.pInfoFirst = pInfo->pNext;
646 MMR3HeapFree(pInfo);
647 rc = VINF_SUCCESS;
648 break;
649 }
650 int rc2 = RTCritSectLeave(&pVM->dbgf.s.InfoCritSect);
651 AssertRC(rc2);
652 AssertRC(rc);
653 LogFlow(("dbgfR3InfoDeregister: returns %Rrc\n", rc));
654 return rc;
655}
656
657
658/**
659 * Deregister a info handler owned by an internal component.
660 *
661 * @returns VBox status code.
662 * @param pVM VM Handle.
663 * @param pszName The identifier of the info. If NULL all owned by the device.
664 */
665VMMR3DECL(int) DBGFR3InfoDeregisterInternal(PVM pVM, const char *pszName)
666{
667 LogFlow(("DBGFR3InfoDeregisterInternal: pszName=%p:{%s}\n", pszName, pszName));
668 return dbgfR3InfoDeregister(pVM, pszName, DBGFINFOTYPE_INT);
669}
670
671
672/**
673 * Deregister a info handler owned by an external component.
674 *
675 * @returns VBox status code.
676 * @param pVM VM Handle.
677 * @param pszName The identifier of the info. If NULL all owned by the device.
678 */
679VMMR3DECL(int) DBGFR3InfoDeregisterExternal(PVM pVM, const char *pszName)
680{
681 LogFlow(("DBGFR3InfoDeregisterExternal: pszName=%p:{%s}\n", pszName, pszName));
682 return dbgfR3InfoDeregister(pVM, pszName, DBGFINFOTYPE_EXT);
683}
684
685
686/**
687 * Display a piece of info writing to the supplied handler.
688 *
689 * @returns VBox status code.
690 * @param pVM VM handle.
691 * @param pszName The identifier of the info to display.
692 * @param pszArgs Arguments to the info handler.
693 * @param pHlp The output helper functions. If NULL the logger will be used.
694 */
695VMMR3DECL(int) DBGFR3Info(PVM pVM, const char *pszName, const char *pszArgs, PCDBGFINFOHLP pHlp)
696{
697 /*
698 * Validate input.
699 */
700 if (!pszName)
701 {
702 AssertMsgFailed(("!pszName\n"));
703 return VERR_INVALID_PARAMETER;
704 }
705 if (pHlp)
706 {
707 if ( !pHlp->pfnPrintf
708 || !pHlp->pfnPrintfV)
709 {
710 AssertMsgFailed(("A pHlp member is missing!\n"));
711 return VERR_INVALID_PARAMETER;
712 }
713 }
714 else
715 pHlp = &g_dbgfR3InfoLogHlp;
716
717 /*
718 * Find the info handler.
719 */
720 size_t cchName = strlen(pszName);
721 int rc = RTCritSectEnter(&pVM->dbgf.s.InfoCritSect);
722 AssertRC(rc);
723 PDBGFINFO pInfo = pVM->dbgf.s.pInfoFirst;
724 for (; pInfo; pInfo = pInfo->pNext)
725 if ( pInfo->cchName == cchName
726 && !memcmp(pInfo->szName, pszName, cchName))
727 break;
728 if (pInfo)
729 {
730 /*
731 * Found it.
732 * Make a copy of it on the stack so we can leave the crit sect.
733 * Switch on the type and invoke the handler.
734 */
735 DBGFINFO Info = *pInfo;
736 rc = RTCritSectLeave(&pVM->dbgf.s.InfoCritSect);
737 AssertRC(rc);
738 rc = VINF_SUCCESS;
739 switch (Info.enmType)
740 {
741 case DBGFINFOTYPE_DEV:
742 if (Info.fFlags & DBGFINFO_FLAGS_RUN_ON_EMT)
743 rc = VMR3ReqCallVoidWait(pVM, VMCPUID_ANY, (PFNRT)Info.u.Dev.pfnHandler, 3, Info.u.Dev.pDevIns, pHlp, pszArgs);
744 else
745 Info.u.Dev.pfnHandler(Info.u.Dev.pDevIns, pHlp, pszArgs);
746 break;
747
748 case DBGFINFOTYPE_DRV:
749 if (Info.fFlags & DBGFINFO_FLAGS_RUN_ON_EMT)
750 rc = VMR3ReqCallVoidWait(pVM, VMCPUID_ANY, (PFNRT)Info.u.Drv.pfnHandler, 3, Info.u.Drv.pDrvIns, pHlp, pszArgs);
751 else
752 Info.u.Drv.pfnHandler(Info.u.Drv.pDrvIns, pHlp, pszArgs);
753 break;
754
755 case DBGFINFOTYPE_INT:
756 if (Info.fFlags & DBGFINFO_FLAGS_RUN_ON_EMT)
757 rc = VMR3ReqCallVoidWait(pVM, VMCPUID_ANY, (PFNRT)Info.u.Int.pfnHandler, 3, pVM, pHlp, pszArgs);
758 else
759 Info.u.Int.pfnHandler(pVM, pHlp, pszArgs);
760 break;
761
762 case DBGFINFOTYPE_EXT:
763 if (Info.fFlags & DBGFINFO_FLAGS_RUN_ON_EMT)
764 rc = VMR3ReqCallVoidWait(pVM, VMCPUID_ANY, (PFNRT)Info.u.Ext.pfnHandler, 3, Info.u.Ext.pvUser, pHlp, pszArgs);
765 else
766 Info.u.Ext.pfnHandler(Info.u.Ext.pvUser, pHlp, pszArgs);
767 break;
768
769 default:
770 AssertMsgFailed(("Invalid info type enmType=%d\n", Info.enmType));
771 rc = VERR_INTERNAL_ERROR;
772 break;
773 }
774 }
775 else
776 {
777 rc = RTCritSectLeave(&pVM->dbgf.s.InfoCritSect);
778 AssertRC(rc);
779 rc = VERR_FILE_NOT_FOUND;
780 }
781 return rc;
782}
783
784
785/**
786 * Wrapper for DBGFR3Info that outputs to the release log.
787 *
788 * @returns See DBGFR3Info.
789 * @param pVM The VM handle.
790 * @param pszName See DBGFR3Info.
791 * @param pszArgs See DBGFR3Info.
792 */
793VMMR3DECL(int) DBGFR3InfoLogRel(PVM pVM, const char *pszName, const char *pszArgs)
794{
795 return DBGFR3Info(pVM, pszName, pszArgs, &g_dbgfR3InfoLogRelHlp);
796}
797
798
799/**
800 * Wrapper for DBGFR3Info that outputs to standard error.
801 *
802 * @returns See DBGFR3Info.
803 * @param pVM The VM handle.
804 * @param pszName See DBGFR3Info.
805 * @param pszArgs See DBGFR3Info.
806 */
807VMMR3DECL(int) DBGFR3InfoStdErr(PVM pVM, const char *pszName, const char *pszArgs)
808{
809 return DBGFR3Info(pVM, pszName, pszArgs, &g_dbgfR3InfoStdErrHlp);
810}
811
812
813/**
814 * Enumerate all the register info handlers.
815 *
816 * @returns VBox status code.
817 * @param pVM VM handle.
818 * @param pfnCallback Pointer to callback function.
819 * @param pvUser User argument to pass to the callback.
820 */
821VMMR3DECL(int) DBGFR3InfoEnum(PVM pVM, PFNDBGFINFOENUM pfnCallback, void *pvUser)
822{
823 LogFlow(("DBGFR3InfoLog: pfnCallback=%p pvUser=%p\n", pfnCallback, pvUser));
824
825 /*
826 * Validate input.
827 */
828 if (!pfnCallback)
829 {
830 AssertMsgFailed(("!pfnCallback\n"));
831 return VERR_INVALID_PARAMETER;
832 }
833
834 /*
835 * Enter and enumerate.
836 */
837 int rc = RTCritSectEnter(&pVM->dbgf.s.InfoCritSect);
838 AssertRC(rc);
839
840 rc = VINF_SUCCESS;
841 for (PDBGFINFO pInfo = pVM->dbgf.s.pInfoFirst; RT_SUCCESS(rc) && pInfo; pInfo = pInfo->pNext)
842 rc = pfnCallback(pVM, pInfo->szName, pInfo->pszDesc, pvUser);
843
844 /*
845 * Leave and exit.
846 */
847 int rc2 = RTCritSectLeave(&pVM->dbgf.s.InfoCritSect);
848 AssertRC(rc2);
849
850 LogFlow(("DBGFR3InfoLog: returns %Rrc\n", rc));
851 return rc;
852}
853
854
855/**
856 * Info handler, internal version.
857 *
858 * @param pVM The VM handle.
859 * @param pHlp Callback functions for doing output.
860 * @param pszArgs Argument string. Optional and specific to the handler.
861 */
862static DECLCALLBACK(void) dbgfR3InfoHelp(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
863{
864 LogFlow(("dbgfR3InfoHelp: pszArgs=%s\n", pszArgs));
865
866 /*
867 * Enter and enumerate.
868 */
869 int rc = RTCritSectEnter(&pVM->dbgf.s.InfoCritSect);
870 AssertRC(rc);
871
872 if (pszArgs && *pszArgs)
873 {
874 for (PDBGFINFO pInfo = pVM->dbgf.s.pInfoFirst; pInfo; pInfo = pInfo->pNext)
875 {
876 const char *psz = strstr(pszArgs, pInfo->szName);
877 if ( psz
878 && ( psz == pszArgs
879 || RT_C_IS_SPACE(psz[-1]))
880 && ( !psz[pInfo->cchName]
881 || RT_C_IS_SPACE(psz[pInfo->cchName])))
882 pHlp->pfnPrintf(pHlp, "%-16s %s\n",
883 pInfo->szName, pInfo->pszDesc);
884 }
885 }
886 else
887 {
888 for (PDBGFINFO pInfo = pVM->dbgf.s.pInfoFirst; pInfo; pInfo = pInfo->pNext)
889 pHlp->pfnPrintf(pHlp, "%-16s %s\n",
890 pInfo->szName, pInfo->pszDesc);
891 }
892
893 /*
894 * Leave and exit.
895 */
896 rc = RTCritSectLeave(&pVM->dbgf.s.InfoCritSect);
897 AssertRC(rc);
898}
899
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use