VirtualBox

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

Last change on this file since 109008 was 108672, checked in by vboxsync, 5 weeks ago

VMM/VMMR3/DBGFR3Trace.cpp: Make it work for hosts where we don't know the host page size when building, bugref:10391

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette