VirtualBox

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

Last change on this file since 61570 was 61570, checked in by vboxsync, 8 years ago

DBGFR3Info*: Added DBGFINFO_FLAGS_ALL_EMTS flag for cpum, apic and others dealing with per-vcpu state. Also got rid of some redundant VMR3ReqCallWaitU calls when we're already on the rigth EMT, and replacing them with priority calls when we actually need them. Didn't make sense to only do priority calls from DBGFR3InfoEx.

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