VirtualBox

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

Last change on this file since 80191 was 80191, checked in by vboxsync, 5 years ago

VMM/r3: Refactored VMCPU enumeration in preparation that aCpus will be replaced with a pointer array. Removed two raw-mode offset members from the CPUM and CPUMCPU sub-structures. bugref:9217 bugref:9517

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

© 2023 Oracle
ContactPrivacy policyTerms of Use