VirtualBox

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

Last change on this file since 76570 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

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