VirtualBox

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

Last change on this file since 41800 was 41783, checked in by vboxsync, 13 years ago

Doxygen, comment typos.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.7 KB
Line 
1/* $Id: DBGFR3Trace.cpp 41783 2012-06-16 19:24:15Z 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 = true;
154 const char * const pszConfigDefault = "all";
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 char *pszTracingConfig;
168 rc = CFGMR3QueryStringAllocDef(pDbgfNode, "TracingConfig", &pszTracingConfig, pszConfigDefault);
169 if (RT_SUCCESS(rc))
170 {
171 rc = DBGFR3TraceConfig(pVM, pszTracingConfig);
172 if (RT_FAILURE(rc))
173 rc = VMSetError(pVM, rc, RT_SRC_POS, "TracingConfig=\"%s\" -> %Rrc", pszTracingConfig, rc);
174 MMR3HeapFree(pszTracingConfig);
175 }
176 }
177 }
178
179 /*
180 * Register a debug info item that will dump the trace buffer content.
181 */
182 if (RT_SUCCESS(rc))
183 rc = DBGFR3InfoRegisterInternal(pVM, "tracebuf", "Display the trace buffer content. No arguments.", dbgfR3TraceInfo);
184
185 return rc;
186}
187
188
189/**
190 * Terminates the tracing.
191 *
192 * @param pVM Pointer to the VM.
193 */
194void dbgfR3TraceTerm(PVM pVM)
195{
196 /* nothing to do */
197 NOREF(pVM);
198}
199
200
201/**
202 * Relocates the trace buffer handle in RC.
203 *
204 * @param pVM Pointer to the VM.
205 */
206void dbgfR3TraceRelocate(PVM pVM)
207{
208 if (pVM->hTraceBufR3 != NIL_RTTRACEBUF)
209 pVM->hTraceBufRC = MMHyperCCToRC(pVM, pVM->hTraceBufR3);
210}
211
212
213/**
214 * Change the traceing configuration of the VM.
215 *
216 * @returns VBox status code.
217 * @retval VINF_SUCCESS
218 * @retval VERR_NOT_FOUND if any of the trace point groups mentioned in the
219 * config string cannot be found. (Or if the string cannot be made
220 * sense of.) No change made.
221 * @retval VERR_INVALID_VM_HANDLE
222 * @retval VERR_INVALID_POINTER
223 *
224 * @param pVM Pointer to the VM.
225 * @param pszConfig The configuration change specification.
226 *
227 * Trace point group names, optionally prefixed by a '-' to
228 * indicate that the group is being disabled. A special
229 * group 'all' can be used to enable or disable all trace
230 * points.
231 *
232 * Drivers, devices and USB devices each have their own
233 * trace point group which can be accessed by prefixing
234 * their official PDM name by 'drv', 'dev' or 'usb'
235 * respectively.
236 */
237VMMDECL(int) DBGFR3TraceConfig(PVM pVM, const char *pszConfig)
238{
239 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
240 AssertPtrReturn(pszConfig, VERR_INVALID_POINTER);
241 if (pVM->hTraceBufR3 == NIL_RTTRACEBUF)
242 return VERR_DBGF_NO_TRACE_BUFFER;
243
244 /*
245 * We do this in two passes, the first pass just validates the input string
246 * and the second applies the changes.
247 */
248 for (uint32_t uPass = 0; uPass < 1; uPass++)
249 {
250 char ch;
251 while ((ch = *pszConfig) != '\0')
252 {
253 if (RT_C_IS_SPACE(ch))
254 continue;
255
256 /*
257 * Operation prefix.
258 */
259 bool fNo = false;
260 do
261 {
262 if (ch == 'n' && pszConfig[1] == 'o')
263 {
264 fNo = !fNo;
265 pszConfig++;
266 }
267 else if (ch == '+')
268 fNo = false;
269 else if (ch == '-' || ch == '!' || ch == '~')
270 fNo = !fNo;
271 else
272 break;
273 } while ((ch = *++pszConfig) != '\0');
274 if (ch == '\0')
275 break;
276
277 /*
278 * Extract the name.
279 */
280 const char *pszName = pszConfig;
281 while ( ch != '\0'
282 && !RT_C_IS_SPACE(ch)
283 && !RT_C_IS_PUNCT(ch))
284 ch = *++pszConfig;
285 size_t const cchName = pszConfig - pszName;
286
287 /*
288 * 'all' - special group that enables or disables all trace points.
289 */
290 if (cchName == 3 && !strncmp(pszName, "all", 3))
291 {
292 if (uPass != 0)
293 {
294 uint32_t iCpu = pVM->cCpus;
295 if (!fNo)
296 while (iCpu-- > 0)
297 pVM->aCpus[iCpu].fTraceGroups = UINT32_MAX;
298 else
299 while (iCpu-- > 0)
300 pVM->aCpus[iCpu].fTraceGroups = 0;
301 PDMR3TracingConfig(pVM, NULL, 0, !fNo, uPass > 0);
302 }
303 }
304 else
305 {
306 /*
307 * A specific group, try the VMM first then PDM.
308 */
309 uint32_t i = RT_ELEMENTS(g_aVmmTpGroups);
310 while (i-- > 0)
311 if ( g_aVmmTpGroups[i].cchName == cchName
312 && !strncmp(g_aVmmTpGroups[i].pszName, pszName, cchName))
313 {
314 if (uPass != 0)
315 {
316 uint32_t iCpu = pVM->cCpus;
317 if (!fNo)
318 while (iCpu-- > 0)
319 pVM->aCpus[iCpu].fTraceGroups |= g_aVmmTpGroups[i].fMask;
320 else
321 while (iCpu-- > 0)
322 pVM->aCpus[iCpu].fTraceGroups &= ~g_aVmmTpGroups[i].fMask;
323 }
324 break;
325 }
326
327 if (i == UINT32_MAX)
328 {
329 int rc = PDMR3TracingConfig(pVM, pszName, cchName, !fNo, uPass > 0);
330 if (RT_FAILURE(rc))
331 return rc;
332 }
333 }
334 }
335 }
336
337 return VINF_SUCCESS;
338}
339
340
341/**
342 * Query the trace configuration specification string.
343 *
344 * @returns VBox status code.
345 * @retval VINF_SUCCESS
346 * @retval VERR_INVALID_VM_HANDLE
347 * @retval VERR_INVALID_POINTER
348 * @retval VERR_BUFFER_OVERFLOW if the buffer is too small. Buffer will be
349 * empty.
350
351 * @param pVM Pointer to the VM.
352 * @param pszConfig Pointer to the output buffer.
353 * @param cbConfig The size of the output buffer.
354 */
355VMMDECL(int) DBGFR3TraceQueryConfig(PVM pVM, char *pszConfig, size_t cbConfig)
356{
357 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
358 AssertPtrReturn(pszConfig, VERR_INVALID_POINTER);
359 if (cbConfig < 1)
360 return VERR_BUFFER_OVERFLOW;
361 *pszConfig = '\0';
362
363 if (pVM->hTraceBufR3 == NIL_RTTRACEBUF)
364 return VERR_DBGF_NO_TRACE_BUFFER;
365
366 int rc = VINF_SUCCESS;
367 uint32_t const fTraceGroups = pVM->aCpus[0].fTraceGroups;
368 if ( fTraceGroups == UINT32_MAX
369 && PDMR3TracingAreAll(pVM, true /*fEnabled*/))
370 rc = RTStrCopy(pszConfig, cbConfig, "all");
371 else if ( fTraceGroups == 0
372 && PDMR3TracingAreAll(pVM, false /*fEnabled*/))
373 rc = RTStrCopy(pszConfig, cbConfig, "-all");
374 else
375 {
376 char *pszDst = pszConfig;
377 size_t cbDst = cbConfig;
378 uint32_t i = RT_ELEMENTS(g_aVmmTpGroups);
379 while (i-- > 0)
380 if (g_aVmmTpGroups[i].fMask & fTraceGroups)
381 {
382 size_t cchThis = g_aVmmTpGroups[i].cchName + (pszDst != pszConfig);
383 if (cchThis >= cbDst)
384 {
385 rc = VERR_BUFFER_OVERFLOW;
386 break;
387 }
388 if (pszDst != pszConfig)
389 {
390 *pszDst = ' ';
391 memcpy(pszDst + 1, g_aVmmTpGroups[i].pszName, g_aVmmTpGroups[i].cchName + 1);
392 }
393 else
394 memcpy(pszDst, g_aVmmTpGroups[i].pszName, g_aVmmTpGroups[i].cchName + 1);
395 pszDst += cchThis;
396 cbDst -= cchThis;
397 }
398
399 if (RT_SUCCESS(rc))
400 rc = PDMR3TracingQueryConfig(pVM, pszDst, cbDst);
401 }
402
403 if (RT_FAILURE(rc))
404 *pszConfig = '\0';
405 return rc;
406}
407
408
409/**
410 * @callback_method_impl{FNRTTRACEBUFCALLBACK}
411 */
412static DECLCALLBACK(int)
413dbgfR3TraceInfoDumpEntry(RTTRACEBUF hTraceBuf, uint32_t iEntry, uint64_t NanoTS, RTCPUID idCpu, const char *pszMsg, void *pvUser)
414{
415 PCDBGFINFOHLP pHlp = (PCDBGFINFOHLP)pvUser;
416 pHlp->pfnPrintf(pHlp, "#%04u/%'llu/%02x: %s\n", iEntry, NanoTS, idCpu, pszMsg);
417 NOREF(hTraceBuf);
418 return VINF_SUCCESS;
419}
420
421
422/**
423 * @callback_method_impl{FNDBGFHANDLERINT, Info handler for displaying the trace buffer content.}
424 */
425static DECLCALLBACK(void) dbgfR3TraceInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
426{
427 RTTRACEBUF hTraceBuf = pVM->hTraceBufR3;
428 if (hTraceBuf == NIL_RTTRACEBUF)
429 pHlp->pfnPrintf(pHlp, "Tracing is disable\n");
430 else
431 {
432 pHlp->pfnPrintf(pHlp, "Trace buffer %p - %u entries of %u bytes\n",
433 hTraceBuf, RTTraceBufGetEntryCount(hTraceBuf), RTTraceBufGetEntrySize(hTraceBuf));
434 RTTraceBufEnumEntries(hTraceBuf, dbgfR3TraceInfoDumpEntry, (void *)pHlp);
435 }
436 NOREF(pszArgs);
437}
438
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