VirtualBox

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

Last change on this file since 25414 was 24009, checked in by vboxsync, 15 years ago

don't use <ctype.h> on UTF-8.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use