VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/DBGFR3Trace.cpp@ 55705

Last change on this file since 55705 was 47238, checked in by vboxsync, 11 years ago

Disable tracing by default even in debug builds. It's only useful when debugging and can then be turned on explicitly.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.0 KB
Line 
1/* $Id: DBGFR3Trace.cpp 47238 2013-07-18 22:31:09Z vboxsync $ */
2/** @file
3 * DBGF - Debugger Facility, Tracing.
4 */
5
6/*
7 * Copyright (C) 2011-2012 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
23#include <VBox/vmm/dbgftrace.h>
24#include <VBox/vmm/cfgm.h>
25#include <VBox/vmm/mm.h>
26#include <VBox/vmm/pdmapi.h>
27#include "DBGFInternal.h"
28#include <VBox/vmm/vm.h>
29#include "VMMTracing.h"
30
31#include <VBox/err.h>
32#include <VBox/log.h>
33#include <VBox/param.h>
34
35#include <iprt/assert.h>
36#include <iprt/ctype.h>
37#include <iprt/trace.h>
38
39
40/*******************************************************************************
41* Internal Functions *
42*******************************************************************************/
43static DECLCALLBACK(void) dbgfR3TraceInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
44
45
46/*******************************************************************************
47* Global Variables *
48*******************************************************************************/
49/**
50 * VMM trace point group translation table.
51 */
52static const struct
53{
54 /** The group name. */
55 const char *pszName;
56 /** The name length. */
57 uint32_t cchName;
58 /** The mask. */
59 uint32_t fMask;
60} g_aVmmTpGroups[] =
61{
62 { RT_STR_TUPLE("em"), VMMTPGROUP_EM },
63 { RT_STR_TUPLE("hm"), VMMTPGROUP_HM },
64 { RT_STR_TUPLE("tm"), VMMTPGROUP_TM },
65};
66
67
68/**
69 * Initializes the tracing.
70 *
71 * @returns VBox status code
72 * @param pVM Pointer to the VM.
73 */
74static int dbgfR3TraceEnable(PVM pVM, uint32_t cbEntry, uint32_t cEntries)
75{
76 /*
77 * Don't enable it twice.
78 */
79 if (pVM->hTraceBufR3 != NIL_RTTRACEBUF)
80 return VERR_ALREADY_EXISTS;
81
82 /*
83 * Resolve default parameter values.
84 */
85 int rc;
86 if (!cbEntry)
87 {
88 rc = CFGMR3QueryU32Def(CFGMR3GetChild(CFGMR3GetRoot(pVM), "DBGF"), "TraceBufEntrySize", &cbEntry, 128);
89 AssertRCReturn(rc, rc);
90 }
91 if (!cEntries)
92 {
93 rc = CFGMR3QueryU32Def(CFGMR3GetChild(CFGMR3GetRoot(pVM), "DBGF"), "TraceBufEntries", &cEntries, 4096);
94 AssertRCReturn(rc, rc);
95 }
96
97 /*
98 * Figure the required size.
99 */
100 RTTRACEBUF hTraceBuf;
101 size_t cbBlock = 0;
102 rc = RTTraceBufCarve(&hTraceBuf, cEntries, cbEntry, 0 /*fFlags*/, NULL, &cbBlock);
103 if (rc != VERR_BUFFER_OVERFLOW)
104 {
105 AssertReturn(!RT_SUCCESS_NP(rc), VERR_IPE_UNEXPECTED_INFO_STATUS);
106 return rc;
107 }
108
109 /*
110 * Allocate a hyper heap block and carve a trace buffer out of it.
111 *
112 * Note! We ASSUME that the returned trace buffer handle has the same value
113 * as the heap block.
114 */
115 cbBlock = RT_ALIGN_Z(cbBlock, PAGE_SIZE);
116 void *pvBlock;
117 rc = MMR3HyperAllocOnceNoRel(pVM, cbBlock, PAGE_SIZE, MM_TAG_DBGF, &pvBlock);
118 if (RT_FAILURE(rc))
119 return rc;
120
121 rc = RTTraceBufCarve(&hTraceBuf, cEntries, cbEntry, 0 /*fFlags*/, pvBlock, &cbBlock);
122 AssertRCReturn(rc, rc);
123 AssertRelease(hTraceBuf == (RTTRACEBUF)pvBlock && (void *)hTraceBuf == pvBlock);
124
125 pVM->hTraceBufR3 = hTraceBuf;
126 pVM->hTraceBufR0 = MMHyperCCToR0(pVM, hTraceBuf);
127 pVM->hTraceBufRC = MMHyperCCToRC(pVM, hTraceBuf);
128 return VINF_SUCCESS;
129}
130
131
132/**
133 * Initializes the tracing.
134 *
135 * @returns VBox status code
136 * @param pVM Pointer to the VM.
137 */
138int dbgfR3TraceInit(PVM pVM)
139{
140 /*
141 * Initialize the trace buffer handles.
142 */
143 Assert(NIL_RTTRACEBUF == (RTTRACEBUF)NULL);
144 pVM->hTraceBufR3 = NIL_RTTRACEBUF;
145 pVM->hTraceBufRC = NIL_RTRCPTR;
146 pVM->hTraceBufR0 = NIL_RTR0PTR;
147
148 /*
149 * Check the config and enable tracing if requested.
150 */
151 PCFGMNODE pDbgfNode = CFGMR3GetChild(CFGMR3GetRoot(pVM), "DBGF");
152#if defined(DEBUG) || defined(RTTRACE_ENABLED)
153 bool const fDefault = false;
154 const char * const pszConfigDefault = "";
155#else
156 bool const fDefault = false;
157 const char * const pszConfigDefault = "";
158#endif
159 bool fTracingEnabled;
160 int rc = CFGMR3QueryBoolDef(pDbgfNode, "TracingEnabled", &fTracingEnabled, fDefault);
161 AssertRCReturn(rc, rc);
162 if (fTracingEnabled)
163 {
164 rc = dbgfR3TraceEnable(pVM, 0, 0);
165 if (RT_SUCCESS(rc))
166 {
167 if (pDbgfNode)
168 {
169 char *pszTracingConfig;
170 rc = CFGMR3QueryStringAllocDef(pDbgfNode, "TracingConfig", &pszTracingConfig, pszConfigDefault);
171 if (RT_SUCCESS(rc))
172 {
173 rc = DBGFR3TraceConfig(pVM, pszTracingConfig);
174 if (RT_FAILURE(rc))
175 rc = VMSetError(pVM, rc, RT_SRC_POS, "TracingConfig=\"%s\" -> %Rrc", pszTracingConfig, rc);
176 MMR3HeapFree(pszTracingConfig);
177 }
178 }
179 else
180 {
181 rc = DBGFR3TraceConfig(pVM, pszConfigDefault);
182 if (RT_FAILURE(rc))
183 rc = VMSetError(pVM, rc, RT_SRC_POS, "TracingConfig=\"%s\" (default) -> %Rrc", pszConfigDefault, rc);
184 }
185 }
186 }
187
188 /*
189 * Register a debug info item that will dump the trace buffer content.
190 */
191 if (RT_SUCCESS(rc))
192 rc = DBGFR3InfoRegisterInternal(pVM, "tracebuf", "Display the trace buffer content. No arguments.", dbgfR3TraceInfo);
193
194 return rc;
195}
196
197
198/**
199 * Terminates the tracing.
200 *
201 * @param pVM Pointer to the VM.
202 */
203void dbgfR3TraceTerm(PVM pVM)
204{
205 /* nothing to do */
206 NOREF(pVM);
207}
208
209
210/**
211 * Relocates the trace buffer handle in RC.
212 *
213 * @param pVM Pointer to the VM.
214 */
215void dbgfR3TraceRelocate(PVM pVM)
216{
217 if (pVM->hTraceBufR3 != NIL_RTTRACEBUF)
218 pVM->hTraceBufRC = MMHyperCCToRC(pVM, pVM->hTraceBufR3);
219}
220
221
222/**
223 * Change the traceing configuration of the VM.
224 *
225 * @returns VBox status code.
226 * @retval VINF_SUCCESS
227 * @retval VERR_NOT_FOUND if any of the trace point groups mentioned in the
228 * config string cannot be found. (Or if the string cannot be made
229 * sense of.) No change made.
230 * @retval VERR_INVALID_VM_HANDLE
231 * @retval VERR_INVALID_POINTER
232 *
233 * @param pVM Pointer to the VM.
234 * @param pszConfig The configuration change specification.
235 *
236 * Trace point group names, optionally prefixed by a '-' to
237 * indicate that the group is being disabled. A special
238 * group 'all' can be used to enable or disable all trace
239 * points.
240 *
241 * Drivers, devices and USB devices each have their own
242 * trace point group which can be accessed by prefixing
243 * their official PDM name by 'drv', 'dev' or 'usb'
244 * respectively.
245 */
246VMMDECL(int) DBGFR3TraceConfig(PVM pVM, const char *pszConfig)
247{
248 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
249 AssertPtrReturn(pszConfig, VERR_INVALID_POINTER);
250 if (pVM->hTraceBufR3 == NIL_RTTRACEBUF)
251 return VERR_DBGF_NO_TRACE_BUFFER;
252
253 /*
254 * We do this in two passes, the first pass just validates the input string
255 * and the second applies the changes.
256 */
257 for (uint32_t uPass = 0; uPass < 1; uPass++)
258 {
259 char ch;
260 while ((ch = *pszConfig) != '\0')
261 {
262 if (RT_C_IS_SPACE(ch))
263 continue;
264
265 /*
266 * Operation prefix.
267 */
268 bool fNo = false;
269 do
270 {
271 if (ch == 'n' && pszConfig[1] == 'o')
272 {
273 fNo = !fNo;
274 pszConfig++;
275 }
276 else if (ch == '+')
277 fNo = false;
278 else if (ch == '-' || ch == '!' || ch == '~')
279 fNo = !fNo;
280 else
281 break;
282 } while ((ch = *++pszConfig) != '\0');
283 if (ch == '\0')
284 break;
285
286 /*
287 * Extract the name.
288 */
289 const char *pszName = pszConfig;
290 while ( ch != '\0'
291 && !RT_C_IS_SPACE(ch)
292 && !RT_C_IS_PUNCT(ch))
293 ch = *++pszConfig;
294 size_t const cchName = pszConfig - pszName;
295
296 /*
297 * 'all' - special group that enables or disables all trace points.
298 */
299 if (cchName == 3 && !strncmp(pszName, "all", 3))
300 {
301 if (uPass != 0)
302 {
303 uint32_t iCpu = pVM->cCpus;
304 if (!fNo)
305 while (iCpu-- > 0)
306 pVM->aCpus[iCpu].fTraceGroups = UINT32_MAX;
307 else
308 while (iCpu-- > 0)
309 pVM->aCpus[iCpu].fTraceGroups = 0;
310 PDMR3TracingConfig(pVM, NULL, 0, !fNo, uPass > 0);
311 }
312 }
313 else
314 {
315 /*
316 * A specific group, try the VMM first then PDM.
317 */
318 uint32_t i = RT_ELEMENTS(g_aVmmTpGroups);
319 while (i-- > 0)
320 if ( g_aVmmTpGroups[i].cchName == cchName
321 && !strncmp(g_aVmmTpGroups[i].pszName, pszName, cchName))
322 {
323 if (uPass != 0)
324 {
325 uint32_t iCpu = pVM->cCpus;
326 if (!fNo)
327 while (iCpu-- > 0)
328 pVM->aCpus[iCpu].fTraceGroups |= g_aVmmTpGroups[i].fMask;
329 else
330 while (iCpu-- > 0)
331 pVM->aCpus[iCpu].fTraceGroups &= ~g_aVmmTpGroups[i].fMask;
332 }
333 break;
334 }
335
336 if (i == UINT32_MAX)
337 {
338 int rc = PDMR3TracingConfig(pVM, pszName, cchName, !fNo, uPass > 0);
339 if (RT_FAILURE(rc))
340 return rc;
341 }
342 }
343 }
344 }
345
346 return VINF_SUCCESS;
347}
348
349
350/**
351 * Query the trace configuration specification string.
352 *
353 * @returns VBox status code.
354 * @retval VINF_SUCCESS
355 * @retval VERR_INVALID_VM_HANDLE
356 * @retval VERR_INVALID_POINTER
357 * @retval VERR_BUFFER_OVERFLOW if the buffer is too small. Buffer will be
358 * empty.
359
360 * @param pVM Pointer to the VM.
361 * @param pszConfig Pointer to the output buffer.
362 * @param cbConfig The size of the output buffer.
363 */
364VMMDECL(int) DBGFR3TraceQueryConfig(PVM pVM, char *pszConfig, size_t cbConfig)
365{
366 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
367 AssertPtrReturn(pszConfig, VERR_INVALID_POINTER);
368 if (cbConfig < 1)
369 return VERR_BUFFER_OVERFLOW;
370 *pszConfig = '\0';
371
372 if (pVM->hTraceBufR3 == NIL_RTTRACEBUF)
373 return VERR_DBGF_NO_TRACE_BUFFER;
374
375 int rc = VINF_SUCCESS;
376 uint32_t const fTraceGroups = pVM->aCpus[0].fTraceGroups;
377 if ( fTraceGroups == UINT32_MAX
378 && PDMR3TracingAreAll(pVM, true /*fEnabled*/))
379 rc = RTStrCopy(pszConfig, cbConfig, "all");
380 else if ( fTraceGroups == 0
381 && PDMR3TracingAreAll(pVM, false /*fEnabled*/))
382 rc = RTStrCopy(pszConfig, cbConfig, "-all");
383 else
384 {
385 char *pszDst = pszConfig;
386 size_t cbDst = cbConfig;
387 uint32_t i = RT_ELEMENTS(g_aVmmTpGroups);
388 while (i-- > 0)
389 if (g_aVmmTpGroups[i].fMask & fTraceGroups)
390 {
391 size_t cchThis = g_aVmmTpGroups[i].cchName + (pszDst != pszConfig);
392 if (cchThis >= cbDst)
393 {
394 rc = VERR_BUFFER_OVERFLOW;
395 break;
396 }
397 if (pszDst != pszConfig)
398 {
399 *pszDst = ' ';
400 memcpy(pszDst + 1, g_aVmmTpGroups[i].pszName, g_aVmmTpGroups[i].cchName + 1);
401 }
402 else
403 memcpy(pszDst, g_aVmmTpGroups[i].pszName, g_aVmmTpGroups[i].cchName + 1);
404 pszDst += cchThis;
405 cbDst -= cchThis;
406 }
407
408 if (RT_SUCCESS(rc))
409 rc = PDMR3TracingQueryConfig(pVM, pszDst, cbDst);
410 }
411
412 if (RT_FAILURE(rc))
413 *pszConfig = '\0';
414 return rc;
415}
416
417
418/**
419 * @callback_method_impl{FNRTTRACEBUFCALLBACK}
420 */
421static DECLCALLBACK(int)
422dbgfR3TraceInfoDumpEntry(RTTRACEBUF hTraceBuf, uint32_t iEntry, uint64_t NanoTS, RTCPUID idCpu, const char *pszMsg, void *pvUser)
423{
424 PCDBGFINFOHLP pHlp = (PCDBGFINFOHLP)pvUser;
425 pHlp->pfnPrintf(pHlp, "#%04u/%'llu/%02x: %s\n", iEntry, NanoTS, idCpu, pszMsg);
426 NOREF(hTraceBuf);
427 return VINF_SUCCESS;
428}
429
430
431/**
432 * @callback_method_impl{FNDBGFHANDLERINT, Info handler for displaying the trace buffer content.}
433 */
434static DECLCALLBACK(void) dbgfR3TraceInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
435{
436 RTTRACEBUF hTraceBuf = pVM->hTraceBufR3;
437 if (hTraceBuf == NIL_RTTRACEBUF)
438 pHlp->pfnPrintf(pHlp, "Tracing is disable\n");
439 else
440 {
441 pHlp->pfnPrintf(pHlp, "Trace buffer %p - %u entries of %u bytes\n",
442 hTraceBuf, RTTraceBufGetEntryCount(hTraceBuf), RTTraceBufGetEntrySize(hTraceBuf));
443 RTTraceBufEnumEntries(hTraceBuf, dbgfR3TraceInfoDumpEntry, (void *)pHlp);
444 }
445 NOREF(pszArgs);
446}
447
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