VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/DBGFR3Tracer.cpp@ 100696

Last change on this file since 100696 was 99775, checked in by vboxsync, 19 months ago

*: Mark functions as static if not used outside of a given compilation unit. Enables the compiler to optimize inlining, reduces the symbol tables, exposes unused functions and in some rare cases exposes mismtaches between function declarations and definitions, but most importantly reduces the number of parfait reports for the extern-function-no-forward-declaration category. This should not result in any functional changes, bugref:3409

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 45.1 KB
Line 
1/* $Id: DBGFR3Tracer.cpp 99775 2023-05-12 12:21:58Z vboxsync $ */
2/** @file
3 * DBGF - Debugger Facility, tracing parts.
4 */
5
6/*
7 * Copyright (C) 2020-2023 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 "DBGFInternal.h"
34#include <VBox/vmm/pdm.h>
35#include <VBox/vmm/cfgm.h>
36#include <VBox/vmm/uvm.h>
37#include <VBox/vmm/vm.h>
38#include <VBox/vmm/vmm.h>
39#include <VBox/sup.h>
40
41#include <VBox/version.h>
42#include <VBox/log.h>
43#include <VBox/err.h>
44#include <iprt/buildconfig.h>
45#include <iprt/alloc.h>
46#include <iprt/alloca.h>
47#include <iprt/asm.h>
48#include <iprt/assert.h>
49#include <iprt/path.h>
50#include <iprt/semaphore.h>
51#include <iprt/string.h>
52#include <iprt/thread.h>
53#include <iprt/tracelog.h>
54
55
56/*********************************************************************************************************************************
57* Structures and Typedefs *
58*********************************************************************************************************************************/
59
60
61
62/*********************************************************************************************************************************
63* Global Variables *
64*********************************************************************************************************************************/
65/** The event descriptors written to the trace log. */
66
67static const RTTRACELOGEVTDESC g_EvtSrcRegisterEvtDesc =
68{
69 "EvtSrc.Register",
70 "An event source was registered",
71 RTTRACELOGEVTSEVERITY_DEBUG,
72 0,
73 NULL
74};
75
76
77static const RTTRACELOGEVTDESC g_EvtSrcDeregisterEvtDesc =
78{
79 "EvtSrc.Deregister",
80 "An event source was de-registered",
81 RTTRACELOGEVTSEVERITY_DEBUG,
82 0,
83 NULL
84};
85
86
87static const RTTRACELOGEVTITEMDESC g_DevMmioCreateEvtItems[] =
88{
89 {"hMmioRegion", "The MMIO region handle being returned by IOM", RTTRACELOGTYPE_UINT64, 0},
90 {"cbRegion", "Size of the MMIO region in bytes", RTTRACELOGTYPE_UINT64, 0},
91 {"fIomFlags", "Flags passed to IOM", RTTRACELOGTYPE_UINT32, 0},
92 {"iPciRegion", "PCI region used for a PCI device", RTTRACELOGTYPE_UINT32, 0},
93};
94
95static const RTTRACELOGEVTDESC g_DevMmioCreateEvtDesc =
96{
97 "Dev.MmioCreate",
98 "MMIO region of a device is being created",
99 RTTRACELOGEVTSEVERITY_DEBUG,
100 RT_ELEMENTS(g_DevMmioCreateEvtItems),
101 &g_DevMmioCreateEvtItems[0]
102};
103
104
105static const RTTRACELOGEVTITEMDESC g_DevMmioMapEvtItems[] =
106{
107 {"hMmioRegion", "The MMIO region handle being mapped", RTTRACELOGTYPE_UINT64, 0},
108 {"GCPhysMmioBase", "The guest physical address where the region is mapped", RTTRACELOGTYPE_UINT64, 0}
109};
110
111static const RTTRACELOGEVTDESC g_DevMmioMapEvtDesc =
112{
113 "Dev.MmioMap",
114 "MMIO region of a device is being mapped",
115 RTTRACELOGEVTSEVERITY_DEBUG,
116 RT_ELEMENTS(g_DevMmioMapEvtItems),
117 &g_DevMmioMapEvtItems[0]
118};
119
120
121static const RTTRACELOGEVTITEMDESC g_DevMmioUnmapEvtItems[] =
122{
123 {"hMmioRegion", "The MMIO region handle being unmapped", RTTRACELOGTYPE_UINT64, 0}
124};
125
126static const RTTRACELOGEVTDESC g_DevMmioUnmapEvtDesc =
127{
128 "Dev.MmioUnmap",
129 "MMIO region of a device is being unmapped",
130 RTTRACELOGEVTSEVERITY_DEBUG,
131 RT_ELEMENTS(g_DevMmioUnmapEvtItems),
132 &g_DevMmioUnmapEvtItems[0]
133};
134
135
136static const RTTRACELOGEVTITEMDESC g_DevMmioRwEvtItems[] =
137{
138 {"hMmioRegion", "The MMIO region handle being accessed", RTTRACELOGTYPE_UINT64, 0},
139 {"offMmio", "The offset in the MMIO region being accessed", RTTRACELOGTYPE_UINT64, 0},
140 {"cbXfer", "Number of bytes being transfered", RTTRACELOGTYPE_UINT64, 0},
141 {"u64Val", "The value read or written", RTTRACELOGTYPE_UINT64, 0},
142};
143
144static const RTTRACELOGEVTDESC g_DevMmioReadEvtDesc =
145{
146 "Dev.MmioRead",
147 "MMIO region of a device is being read",
148 RTTRACELOGEVTSEVERITY_DEBUG,
149 RT_ELEMENTS(g_DevMmioRwEvtItems),
150 &g_DevMmioRwEvtItems[0]
151};
152
153static const RTTRACELOGEVTDESC g_DevMmioWriteEvtDesc =
154{
155 "Dev.MmioWrite",
156 "MMIO region of a device is being written",
157 RTTRACELOGEVTSEVERITY_DEBUG,
158 RT_ELEMENTS(g_DevMmioRwEvtItems),
159 &g_DevMmioRwEvtItems[0]
160};
161
162
163static const RTTRACELOGEVTITEMDESC g_DevMmioFillEvtItems[] =
164{
165 {"hMmioRegion", "The MMIO region handle being unmapped", RTTRACELOGTYPE_UINT64, 0},
166 {"offMmio", "The offset in the MMIO region being accessed", RTTRACELOGTYPE_UINT64, 0},
167 {"cbItem", "Item size in bytes", RTTRACELOGTYPE_UINT32, 0},
168 {"cItems", "Number of items being written", RTTRACELOGTYPE_UINT32, 0},
169 {"u32Val", "The value used for filling", RTTRACELOGTYPE_UINT32, 0},
170};
171
172static const RTTRACELOGEVTDESC g_DevMmioFillEvtDesc =
173{
174 "Dev.MmioFill",
175 "MMIO region of a device is being filled",
176 RTTRACELOGEVTSEVERITY_DEBUG,
177 RT_ELEMENTS(g_DevMmioFillEvtItems),
178 &g_DevMmioFillEvtItems[0]
179};
180
181
182static const RTTRACELOGEVTITEMDESC g_DevIoPortCreateEvtItems[] =
183{
184 {"hIoPorts", "The I/O port region handle being returned by IOM", RTTRACELOGTYPE_UINT64, 0},
185 {"cPorts", "Size of the region in number of ports", RTTRACELOGTYPE_UINT16, 0},
186 {"fIomFlags", "Flags passed to IOM", RTTRACELOGTYPE_UINT32, 0},
187 {"iPciRegion", "PCI region used for a PCI device", RTTRACELOGTYPE_UINT32, 0},
188};
189
190static const RTTRACELOGEVTDESC g_DevIoPortCreateEvtDesc =
191{
192 "Dev.IoPortCreate",
193 "I/O port region of a device is being created",
194 RTTRACELOGEVTSEVERITY_DEBUG,
195 RT_ELEMENTS(g_DevIoPortCreateEvtItems),
196 &g_DevIoPortCreateEvtItems[0]
197};
198
199
200static const RTTRACELOGEVTITEMDESC g_DevIoPortMapEvtItems[] =
201{
202 {"hIoPorts", "The I/O port region handle being mapped", RTTRACELOGTYPE_UINT64, 0},
203 {"IoPortBase", "The I/O port base address where the region is mapped", RTTRACELOGTYPE_UINT16, 0}
204};
205
206static const RTTRACELOGEVTDESC g_DevIoPortMapEvtDesc =
207{
208 "Dev.IoPortMap",
209 "I/O port region of a device is being mapped",
210 RTTRACELOGEVTSEVERITY_DEBUG,
211 RT_ELEMENTS(g_DevIoPortMapEvtItems),
212 &g_DevIoPortMapEvtItems[0]
213};
214
215
216static const RTTRACELOGEVTITEMDESC g_DevIoPortUnmapEvtItems[] =
217{
218 {"hIoPorts", "The I/O port region handle being unmapped", RTTRACELOGTYPE_UINT64, 0}
219};
220
221static const RTTRACELOGEVTDESC g_DevIoPortUnmapEvtDesc =
222{
223 "Dev.IoPortUnmap",
224 "I/O port region of a device is being unmapped",
225 RTTRACELOGEVTSEVERITY_DEBUG,
226 RT_ELEMENTS(g_DevIoPortUnmapEvtItems),
227 &g_DevIoPortUnmapEvtItems[0]
228};
229
230
231static const RTTRACELOGEVTITEMDESC g_DevIoPortRwEvtItems[] =
232{
233 {"hIoPorts", "The I/O region handle being accessed", RTTRACELOGTYPE_UINT64, 0},
234 {"offPort", "The offset in the I/O port region being accessed", RTTRACELOGTYPE_UINT16, 0},
235 {"cbXfer", "Number of bytes being transfered", RTTRACELOGTYPE_UINT64, 0},
236 {"u32Val", "The value read or written", RTTRACELOGTYPE_UINT32, 0},
237};
238
239static const RTTRACELOGEVTDESC g_DevIoPortReadEvtDesc =
240{
241 "Dev.IoPortRead",
242 "I/O port region of a device is being read",
243 RTTRACELOGEVTSEVERITY_DEBUG,
244 RT_ELEMENTS(g_DevIoPortRwEvtItems),
245 &g_DevIoPortRwEvtItems[0]
246};
247
248static const RTTRACELOGEVTDESC g_DevIoPortWriteEvtDesc =
249{
250 "Dev.IoPortWrite",
251 "I/O port region of a device is being written",
252 RTTRACELOGEVTSEVERITY_DEBUG,
253 RT_ELEMENTS(g_DevIoPortRwEvtItems),
254 &g_DevIoPortRwEvtItems[0]
255};
256
257
258static const RTTRACELOGEVTITEMDESC g_DevIoPortRwStrEvtItems[] =
259{
260 {"hIoPorts", "The I/O region handle being accesses", RTTRACELOGTYPE_UINT64, 0},
261 {"offPort", "The offset in the I/O port region being accessed", RTTRACELOGTYPE_UINT16, 0},
262 {"cbItem", "Item size for the access", RTTRACELOGTYPE_UINT32, 0},
263 {"cTransfersReq", "Number of transfers requested by the guest", RTTRACELOGTYPE_UINT32, 0},
264 {"cTransfersRet", "Number of transfers executed by the device", RTTRACELOGTYPE_UINT32, 0}
265};
266
267static const RTTRACELOGEVTDESC g_DevIoPortReadStrEvtDesc =
268{
269 "Dev.IoPortReadStr",
270 "I/O port region of a device is being read using REP INS",
271 RTTRACELOGEVTSEVERITY_DEBUG,
272 RT_ELEMENTS(g_DevIoPortRwStrEvtItems),
273 &g_DevIoPortRwStrEvtItems[0]
274};
275
276static const RTTRACELOGEVTDESC g_DevIoPortWriteStrEvtDesc =
277{
278 "Dev.IoPortWriteStr",
279 "I/O port region of a device is being written using REP OUTS",
280 RTTRACELOGEVTSEVERITY_DEBUG,
281 RT_ELEMENTS(g_DevIoPortRwStrEvtItems),
282 &g_DevIoPortRwStrEvtItems[0]
283};
284
285
286static const RTTRACELOGEVTITEMDESC g_DevIrqEvtItems[] =
287{
288 {"iIrq", "The IRQ line", RTTRACELOGTYPE_INT32, 0},
289 {"fIrqLvl", "The IRQ level", RTTRACELOGTYPE_INT32, 0}
290};
291
292static const RTTRACELOGEVTDESC g_DevIrqEvtDesc =
293{
294 "Dev.Irq",
295 "Device raised or lowered an IRQ line",
296 RTTRACELOGEVTSEVERITY_DEBUG,
297 RT_ELEMENTS(g_DevIrqEvtItems),
298 &g_DevIrqEvtItems[0]
299};
300
301
302static const RTTRACELOGEVTITEMDESC g_DevIoApicMsiEvtItems[] =
303{
304 {"GCPhys", "Physical guest address being written", RTTRACELOGTYPE_UINT64, 0},
305 {"u32Val", "value being written", RTTRACELOGTYPE_UINT32, 0}
306};
307
308static const RTTRACELOGEVTDESC g_DevIoApicMsiEvtDesc =
309{
310 "Dev.IoApicMsi",
311 "Device sent a MSI event through the I/O APIC",
312 RTTRACELOGEVTSEVERITY_DEBUG,
313 RT_ELEMENTS(g_DevIoApicMsiEvtItems),
314 &g_DevIoApicMsiEvtItems[0]
315};
316
317
318static const RTTRACELOGEVTITEMDESC g_DevGCPhysRwStartEvtItems[] =
319{
320 {"GCPhys", "Physical guest address being accessed", RTTRACELOGTYPE_UINT64, 0},
321 {"cbXfer", "Number of bytes being transfered", RTTRACELOGTYPE_UINT64, 0},
322};
323
324
325static const RTTRACELOGEVTDESC g_DevGCPhysReadEvtDesc =
326{
327 "Dev.GCPhysRead",
328 "Device read data from guest physical memory",
329 RTTRACELOGEVTSEVERITY_DEBUG,
330 RT_ELEMENTS(g_DevGCPhysRwStartEvtItems),
331 &g_DevGCPhysRwStartEvtItems[0]
332};
333
334
335static const RTTRACELOGEVTDESC g_DevGCPhysWriteEvtDesc =
336{
337 "Dev.GCPhysWrite",
338 "Device wrote data to guest physical memory",
339 RTTRACELOGEVTSEVERITY_DEBUG,
340 RT_ELEMENTS(g_DevGCPhysRwStartEvtItems),
341 &g_DevGCPhysRwStartEvtItems[0]
342};
343
344
345static const RTTRACELOGEVTITEMDESC g_DevRwDataEvtItems[] =
346{
347 {"abData", "The data being read/written", RTTRACELOGTYPE_RAWDATA, 0}
348};
349
350static const RTTRACELOGEVTDESC g_DevRwDataEvtDesc =
351{
352 "Dev.RwData",
353 "The data being read or written",
354 RTTRACELOGEVTSEVERITY_DEBUG,
355 RT_ELEMENTS(g_DevRwDataEvtItems),
356 &g_DevRwDataEvtItems[0]
357};
358
359
360/*********************************************************************************************************************************
361* Internal Functions *
362*********************************************************************************************************************************/
363
364
365/**
366 * Returns an unused guest memory read/write data aggregation structure.
367 *
368 * @returns Pointer to a new aggregation structure or NULL if out of memory.
369 * @param pThis The DBGF tracer instance.
370 */
371static PDBGFTRACERGCPHYSRWAGG dbgfTracerR3EvtRwAggNew(PDBGFTRACERINSR3 pThis)
372{
373 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aGstMemRwData); i++)
374 {
375 if (pThis->aGstMemRwData[i].idEvtStart == DBGF_TRACER_EVT_HDR_ID_INVALID)
376 return &pThis->aGstMemRwData[i];
377 }
378
379 return NULL;
380}
381
382
383/**
384 * Find the guest memory read/write data aggregation structure for the given event ID.
385 *
386 * @returns Pointer to a new aggregation structure or NULL if not found.
387 * @param pThis The DBGF tracer instance.
388 * @param idEvtPrev The event ID to look for.
389 */
390static PDBGFTRACERGCPHYSRWAGG dbgfTracerR3EvtRwAggFind(PDBGFTRACERINSR3 pThis, uint64_t idEvtPrev)
391{
392 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aGstMemRwData); i++)
393 {
394 if ( pThis->aGstMemRwData[i].idEvtStart != DBGF_TRACER_EVT_HDR_ID_INVALID
395 && pThis->aGstMemRwData[i].idEvtPrev == idEvtPrev)
396 return &pThis->aGstMemRwData[i];
397 }
398
399 return NULL;
400}
401
402
403/**
404 * Common code for the guest memory and string I/O port read/write events.
405 *
406 * @returns VBox status code.
407 * @param pThis The DBGF tracer instance.
408 * @param pEvtHdr The event header.
409 * @param cbXfer Overall number of bytes of data for this event.
410 * @param pvData Initial data supplied in the event starting the aggregation.
411 * @param cbData Number of initial bytes of data.
412 */
413static int dbgfTracerR3EvtRwStartCommon(PDBGFTRACERINSR3 pThis, PCDBGFTRACEREVTHDR pEvtHdr, size_t cbXfer, const void *pvData, size_t cbData)
414{
415 /* Slow path, find an empty aggregation structure. */
416 int rc = VINF_SUCCESS;
417 PDBGFTRACERGCPHYSRWAGG pDataAgg = dbgfTracerR3EvtRwAggNew(pThis);
418 if (RT_LIKELY(pDataAgg))
419 {
420 /* Initialize it. */
421 pDataAgg->idEvtStart = pEvtHdr->idEvt;
422 pDataAgg->idEvtPrev = pEvtHdr->idEvt;
423 pDataAgg->cbXfer = cbXfer;
424 pDataAgg->cbLeft = pDataAgg->cbXfer;
425 pDataAgg->offBuf = 0;
426
427 /* Need to reallocate the buffer to hold the complete data? */
428 if (RT_UNLIKELY(pDataAgg->cbBufMax < pDataAgg->cbXfer))
429 {
430 uint8_t *pbBufNew = (uint8_t *)RTMemRealloc(pDataAgg->pbBuf, pDataAgg->cbXfer);
431 if (RT_LIKELY(pbBufNew))
432 {
433 pDataAgg->pbBuf = pbBufNew;
434 pDataAgg->cbBufMax = pDataAgg->cbXfer;
435 }
436 else
437 rc = VERR_NO_MEMORY;
438 }
439
440 if (RT_SUCCESS(rc))
441 {
442 memcpy(pDataAgg->pbBuf, pvData, cbData);
443 pDataAgg->offBuf += cbData;
444 pDataAgg->cbLeft -= cbData;
445 }
446 }
447 else
448 rc = VERR_NO_MEMORY;
449
450 if (RT_FAILURE(rc))
451 {
452 LogRelMax(10, ("DBGF: Creating new data aggregation structure for memory read/write failed with %Rrc, trace log will not contain data for this event!\n", rc));
453
454 /* Write out the finish event without any data. */
455 size_t cbEvtData = 0;
456 rc = RTTraceLogWrEvtAdd(pThis->hTraceLog, &g_DevRwDataEvtDesc, RTTRACELOG_WR_ADD_EVT_F_GRP_FINISH,
457 pEvtHdr->idEvt, pEvtHdr->hEvtSrc, NULL, &cbEvtData);
458 if (pDataAgg) /* Reset the aggregation event. */
459 pDataAgg->idEvtStart = DBGF_TRACER_EVT_HDR_ID_INVALID;
460 }
461
462 return rc;
463}
464
465
466/**
467 * Starts a new guest memory read/write event.
468 *
469 * @returns VBox status code.
470 * @param pThis The DBGF tracer instance.
471 * @param pEvtHdr The event header.
472 * @param pEvtGCPhysRw The guest memory read/write event descriptor.
473 * @param pEvtDesc The event descriptor written to the trace log.
474 */
475static int dbgfTracerR3EvtGCPhysRwStart(PDBGFTRACERINSR3 pThis, PCDBGFTRACEREVTHDR pEvtHdr,
476 PCDBGFTRACEREVTGCPHYS pEvtGCPhysRw, PCRTTRACELOGEVTDESC pEvtDesc)
477{
478 /* Write out the event header first in any case. */
479 int rc = RTTraceLogWrEvtAddL(pThis->hTraceLog, pEvtDesc, RTTRACELOG_WR_ADD_EVT_F_GRP_START,
480 pEvtHdr->idEvt, pEvtHdr->hEvtSrc, pEvtGCPhysRw->GCPhys, pEvtGCPhysRw->cbXfer);
481 if (RT_SUCCESS(rc))
482 {
483 /*
484 * If the amount of data is small enough to fit into the single event descriptor we can skip allocating
485 * an aggregation tracking structure and write the event containing the complete data out immediately.
486 */
487 if (pEvtGCPhysRw->cbXfer <= sizeof(pEvtGCPhysRw->abData))
488 {
489 size_t cbEvtData = pEvtGCPhysRw->cbXfer;
490
491 rc = RTTraceLogWrEvtAdd(pThis->hTraceLog, &g_DevRwDataEvtDesc, RTTRACELOG_WR_ADD_EVT_F_GRP_FINISH,
492 pEvtHdr->idEvt, pEvtHdr->hEvtSrc, &pEvtGCPhysRw->abData[0], &cbEvtData);
493 }
494 else
495 rc = dbgfTracerR3EvtRwStartCommon(pThis, pEvtHdr, pEvtGCPhysRw->cbXfer, &pEvtGCPhysRw->abData[0], sizeof(pEvtGCPhysRw->abData));
496 }
497
498 return rc;
499}
500
501
502/**
503 * Starts a new I/O port string read/write event.
504 *
505 * @returns VBox status code.
506 * @param pThis The DBGF tracer instance.
507 * @param pEvtHdr The event header.
508 * @param pEvtIoPortStrRw The I/O port string read/write event descriptor.
509 * @param cbXfer Number of bytes of valid data for this event.
510 * @param pEvtDesc The event descriptor written to the trace log.
511 */
512static int dbgfTracerR3EvtIoPortStrRwStart(PDBGFTRACERINSR3 pThis, PCDBGFTRACEREVTHDR pEvtHdr,
513 PCDBGFTRACEREVTIOPORTSTR pEvtIoPortStrRw, size_t cbXfer,
514 PCRTTRACELOGEVTDESC pEvtDesc)
515{
516 /* Write out the event header first in any case. */
517 int rc = RTTraceLogWrEvtAddL(pThis->hTraceLog, pEvtDesc, RTTRACELOG_WR_ADD_EVT_F_GRP_START,
518 pEvtHdr->idEvt, pEvtHdr->hEvtSrc, pEvtIoPortStrRw->hIoPorts, pEvtIoPortStrRw->offPort,
519 pEvtIoPortStrRw->cbItem, pEvtIoPortStrRw->cTransfersReq, pEvtIoPortStrRw->cTransfersRet);
520 if (RT_SUCCESS(rc))
521 {
522 /*
523 * If the amount of data is small enough to fit into the single event descriptor we can skip allocating
524 * an aggregation tracking structure and write the event containing the complete data out immediately.
525 */
526 if (cbXfer <= sizeof(pEvtIoPortStrRw->abData))
527 {
528 size_t cbEvtData = cbXfer;
529
530 rc = RTTraceLogWrEvtAdd(pThis->hTraceLog, &g_DevRwDataEvtDesc, RTTRACELOG_WR_ADD_EVT_F_GRP_FINISH,
531 pEvtHdr->idEvt, pEvtHdr->hEvtSrc, &pEvtIoPortStrRw->abData[0], &cbEvtData);
532 }
533 else
534 rc = dbgfTracerR3EvtRwStartCommon(pThis, pEvtHdr, cbXfer, &pEvtIoPortStrRw->abData[0], sizeof(pEvtIoPortStrRw->abData));
535 }
536
537 return rc;
538}
539
540
541/**
542 * Continues a previously started guest memory or string I/O port read/write event.
543 *
544 * @returns VBox status code.
545 * @param pThis The DBGF tracer instance.
546 * @param pEvtHdr The event header.
547 * @param pvData The data to log.
548 */
549static int dbgfTracerR3EvtRwContinue(PDBGFTRACERINSR3 pThis, PCDBGFTRACEREVTHDR pEvtHdr, void *pvData)
550{
551 int rc = VINF_SUCCESS;
552 PDBGFTRACERGCPHYSRWAGG pDataAgg = dbgfTracerR3EvtRwAggFind(pThis, pEvtHdr->idEvtPrev);
553
554 if (RT_LIKELY(pDataAgg))
555 {
556 size_t cbThisXfer = RT_MIN(pDataAgg->cbLeft, DBGF_TRACER_EVT_PAYLOAD_SZ);
557
558 memcpy(pDataAgg->pbBuf + pDataAgg->offBuf, pvData, cbThisXfer);
559 pDataAgg->offBuf += cbThisXfer;
560 pDataAgg->cbLeft -= cbThisXfer;
561
562 if (!pDataAgg->cbLeft)
563 {
564 /* All data aggregated, write it out and reset the structure. */
565 rc = RTTraceLogWrEvtAdd(pThis->hTraceLog, &g_DevRwDataEvtDesc, RTTRACELOG_WR_ADD_EVT_F_GRP_FINISH,
566 pDataAgg->idEvtStart, pEvtHdr->hEvtSrc, pDataAgg->pbBuf, &pDataAgg->cbXfer);
567 pDataAgg->offBuf = 0;
568 pDataAgg->idEvtStart = DBGF_TRACER_EVT_HDR_ID_INVALID;
569 }
570 else
571 pDataAgg->idEvtPrev = pEvtHdr->idEvt; /* So the next event containing more data can find the aggregation structure. */
572 }
573 else /* This can only happen if creating a new structure failed before. */
574 rc = VERR_DBGF_TRACER_IPE_1;
575
576 return rc;
577}
578
579
580/**
581 * Processes the given event.
582 *
583 * @returns VBox status code.
584 * @param pThis The DBGF tracer instance.
585 * @param pEvtHdr The event to process.
586 */
587static int dbgfR3TracerEvtProcess(PDBGFTRACERINSR3 pThis, PDBGFTRACEREVTHDR pEvtHdr)
588{
589 int rc = VINF_SUCCESS;
590
591 LogFlowFunc(("pThis=%p pEvtHdr=%p{idEvt=%llu,enmEvt=%u}\n",
592 pThis, pEvtHdr, pEvtHdr->idEvt, pEvtHdr->enmEvt));
593
594 switch (pEvtHdr->enmEvt)
595 {
596 case DBGFTRACEREVT_SRC_REGISTER:
597 {
598 rc = RTTraceLogWrEvtAddL(pThis->hTraceLog, &g_EvtSrcRegisterEvtDesc, RTTRACELOG_WR_ADD_EVT_F_GRP_START,
599 pEvtHdr->hEvtSrc, 0 /*uParentGrpId*/);
600 break;
601 }
602 case DBGFTRACEREVT_SRC_DEREGISTER:
603 {
604 rc = RTTraceLogWrEvtAddL(pThis->hTraceLog, &g_EvtSrcDeregisterEvtDesc, RTTRACELOG_WR_ADD_EVT_F_GRP_FINISH,
605 pEvtHdr->hEvtSrc, 0 /*uParentGrpId*/);
606 break;
607 }
608 case DBGFTRACEREVT_MMIO_REGION_CREATE:
609 {
610 PCDBGFTRACEREVTMMIOCREATE pEvtMmioCreate = (PCDBGFTRACEREVTMMIOCREATE)(pEvtHdr + 1);
611
612 rc = RTTraceLogWrEvtAddL(pThis->hTraceLog, &g_DevMmioCreateEvtDesc, 0 /*fFlags*/,
613 pEvtHdr->idEvt, pEvtHdr->hEvtSrc, pEvtMmioCreate->hMmioRegion, pEvtMmioCreate->cbRegion,
614 pEvtMmioCreate->fIomFlags, pEvtMmioCreate->iPciRegion);
615 break;
616 }
617 case DBGFTRACEREVT_MMIO_MAP:
618 {
619 PCDBGFTRACEREVTMMIOMAP pEvtMmioMap = (PCDBGFTRACEREVTMMIOMAP)(pEvtHdr + 1);
620
621 rc = RTTraceLogWrEvtAddL(pThis->hTraceLog, &g_DevMmioMapEvtDesc, 0 /*fFlags*/,
622 pEvtHdr->idEvt, pEvtHdr->hEvtSrc, pEvtMmioMap->hMmioRegion, pEvtMmioMap->GCPhysMmioBase);
623 break;
624 }
625 case DBGFTRACEREVT_MMIO_UNMAP:
626 {
627 PCDBGFTRACEREVTMMIOUNMAP pEvtMmioUnmap = (PCDBGFTRACEREVTMMIOUNMAP)(pEvtHdr + 1);
628
629 rc = RTTraceLogWrEvtAddL(pThis->hTraceLog, &g_DevMmioUnmapEvtDesc, 0 /*fFlags*/,
630 pEvtHdr->idEvt, pEvtHdr->hEvtSrc, pEvtMmioUnmap->hMmioRegion);
631 break;
632 }
633 case DBGFTRACEREVT_MMIO_READ:
634 case DBGFTRACEREVT_MMIO_WRITE:
635 {
636 PCDBGFTRACEREVTMMIO pEvtMmioRw = (PCDBGFTRACEREVTMMIO)(pEvtHdr + 1);
637
638 rc = RTTraceLogWrEvtAddL(pThis->hTraceLog,
639 pEvtHdr->enmEvt == DBGFTRACEREVT_MMIO_READ
640 ? &g_DevMmioReadEvtDesc
641 : &g_DevMmioWriteEvtDesc,
642 0 /*fFlags*/,
643 pEvtHdr->idEvt, pEvtHdr->hEvtSrc, pEvtMmioRw->hMmioRegion, pEvtMmioRw->offMmio,
644 pEvtMmioRw->cbXfer, pEvtMmioRw->u64Val);
645 break;
646 }
647 case DBGFTRACEREVT_MMIO_FILL:
648 {
649 PCDBGFTRACEREVTMMIOFILL pEvtMmioFill = (PCDBGFTRACEREVTMMIOFILL)(pEvtHdr + 1);
650
651 rc = RTTraceLogWrEvtAddL(pThis->hTraceLog, &g_DevMmioFillEvtDesc, 0 /*fFlags*/,
652 pEvtHdr->idEvt, pEvtHdr->hEvtSrc, pEvtMmioFill->hMmioRegion, pEvtMmioFill->offMmio,
653 pEvtMmioFill->cbItem, pEvtMmioFill->cItems, pEvtMmioFill->u32Item);
654 break;
655 }
656 case DBGFTRACEREVT_IOPORT_REGION_CREATE:
657 {
658 PCDBGFTRACEREVTIOPORTCREATE pEvtIoPortCreate = (PCDBGFTRACEREVTIOPORTCREATE)(pEvtHdr + 1);
659
660 rc = RTTraceLogWrEvtAddL(pThis->hTraceLog, &g_DevIoPortCreateEvtDesc, 0 /*fFlags*/,
661 pEvtHdr->idEvt, pEvtHdr->hEvtSrc, pEvtIoPortCreate->hIoPorts, pEvtIoPortCreate->cPorts,
662 pEvtIoPortCreate->fIomFlags, pEvtIoPortCreate->iPciRegion);
663 break;
664 }
665 case DBGFTRACEREVT_IOPORT_MAP:
666 {
667 PCDBGFTRACEREVTIOPORTMAP pEvtIoPortMap = (PCDBGFTRACEREVTIOPORTMAP)(pEvtHdr + 1);
668
669 rc = RTTraceLogWrEvtAddL(pThis->hTraceLog, &g_DevIoPortMapEvtDesc, 0 /*fFlags*/,
670 pEvtHdr->idEvt, pEvtHdr->hEvtSrc, pEvtIoPortMap->hIoPorts, pEvtIoPortMap->IoPortBase);
671 break;
672 }
673 case DBGFTRACEREVT_IOPORT_UNMAP:
674 {
675 PCDBGFTRACEREVTIOPORTUNMAP pEvtIoPortUnmap = (PCDBGFTRACEREVTIOPORTUNMAP)(pEvtHdr + 1);
676
677 rc = RTTraceLogWrEvtAddL(pThis->hTraceLog, &g_DevIoPortUnmapEvtDesc, 0 /*fFlags*/,
678 pEvtHdr->idEvt, pEvtHdr->hEvtSrc, pEvtIoPortUnmap->hIoPorts);
679 break;
680 }
681 case DBGFTRACEREVT_IOPORT_READ:
682 case DBGFTRACEREVT_IOPORT_WRITE:
683 {
684 PCDBGFTRACEREVTIOPORT pEvtIoPortRw = (PCDBGFTRACEREVTIOPORT)(pEvtHdr + 1);
685
686 rc = RTTraceLogWrEvtAddL(pThis->hTraceLog,
687 pEvtHdr->enmEvt == DBGFTRACEREVT_IOPORT_READ
688 ? &g_DevIoPortReadEvtDesc
689 : &g_DevIoPortWriteEvtDesc,
690 0 /*fFlags*/,
691 pEvtHdr->idEvt, pEvtHdr->hEvtSrc, pEvtIoPortRw->hIoPorts, pEvtIoPortRw->offPort,
692 pEvtIoPortRw->cbXfer, pEvtIoPortRw->u32Val);
693 break;
694 }
695 case DBGFTRACEREVT_IOPORT_READ_STR:
696 case DBGFTRACEREVT_IOPORT_WRITE_STR:
697 {
698 PCRTTRACELOGEVTDESC pEvtDesc = pEvtHdr->enmEvt == DBGFTRACEREVT_IOPORT_WRITE_STR
699 ? &g_DevIoPortWriteStrEvtDesc
700 : &g_DevIoPortReadStrEvtDesc;
701
702 /* If the previous event ID is invalid this starts a new read/write we have to aggregate all the data for. */
703 if (pEvtHdr->idEvtPrev == DBGF_TRACER_EVT_HDR_ID_INVALID)
704 {
705 PCDBGFTRACEREVTIOPORTSTR pEvtIoPortStrRw = (PCDBGFTRACEREVTIOPORTSTR)(pEvtHdr + 1);
706 size_t cbXfer = pEvtHdr->enmEvt == DBGFTRACEREVT_IOPORT_WRITE_STR
707 ? pEvtIoPortStrRw->cTransfersReq * pEvtIoPortStrRw->cbItem
708 : pEvtIoPortStrRw->cTransfersRet * pEvtIoPortStrRw->cbItem;
709
710 rc = dbgfTracerR3EvtIoPortStrRwStart(pThis, pEvtHdr, pEvtIoPortStrRw, cbXfer, pEvtDesc);
711 }
712 else
713 {
714 /* Continuation of a started read or write, look up the right tracking structure and process the new data. */
715 void *pvData = pEvtHdr + 1;
716 rc = dbgfTracerR3EvtRwContinue(pThis, pEvtHdr, pvData);
717 }
718 break;
719 }
720 case DBGFTRACEREVT_IRQ:
721 {
722 PCDBGFTRACEREVTIRQ pEvtIrq = (PCDBGFTRACEREVTIRQ)(pEvtHdr + 1);
723
724 rc = RTTraceLogWrEvtAddL(pThis->hTraceLog, &g_DevIrqEvtDesc, 0 /*fFlags*/,
725 pEvtHdr->idEvt, pEvtHdr->hEvtSrc, pEvtIrq->iIrq, pEvtIrq->fIrqLvl);
726 break;
727 }
728 case DBGFTRACEREVT_IOAPIC_MSI:
729 {
730 PCDBGFTRACEREVTIOAPICMSI pEvtIoApicMsi = (PCDBGFTRACEREVTIOAPICMSI)(pEvtHdr + 1);
731
732 rc = RTTraceLogWrEvtAddL(pThis->hTraceLog, &g_DevIrqEvtDesc, 0 /*fFlags*/,
733 pEvtHdr->idEvt, pEvtHdr->hEvtSrc, pEvtIoApicMsi->GCPhys, pEvtIoApicMsi->u32Val);
734 break;
735 }
736 case DBGFTRACEREVT_GCPHYS_READ:
737 case DBGFTRACEREVT_GCPHYS_WRITE:
738 {
739 PCRTTRACELOGEVTDESC pEvtDesc = pEvtHdr->enmEvt == DBGFTRACEREVT_GCPHYS_WRITE
740 ? &g_DevGCPhysWriteEvtDesc
741 : &g_DevGCPhysReadEvtDesc;
742
743 /* If the previous event ID is invalid this starts a new read/write we have to aggregate all the data for. */
744 if (pEvtHdr->idEvtPrev == DBGF_TRACER_EVT_HDR_ID_INVALID)
745 {
746 PCDBGFTRACEREVTGCPHYS pEvtGCPhysRw = (PCDBGFTRACEREVTGCPHYS)(pEvtHdr + 1);
747 rc = dbgfTracerR3EvtGCPhysRwStart(pThis, pEvtHdr, pEvtGCPhysRw, pEvtDesc);
748 }
749 else
750 {
751 /* Continuation of a started read or write, look up the right tracking structure and process the new data. */
752 void *pvData = pEvtHdr + 1;
753 rc = dbgfTracerR3EvtRwContinue(pThis, pEvtHdr, pvData);
754 }
755 break;
756 }
757 default:
758 AssertLogRelMsgFailed(("Invalid or unsupported event: %u!\n", pEvtHdr->enmEvt));
759 break;
760 }
761
762 return rc;
763}
764
765
766/**
767 * @callback_method_impl{FNRTTHREAD,
768 * DBGF Tracer flush thread}
769 */
770static DECLCALLBACK(int) dbgfR3TracerThreadFlush(RTTHREAD ThreadSelf, void *pvUser)
771{
772 PDBGFTRACERINSR3 pThis = (PDBGFTRACERINSR3)pvUser;
773 PDBGFTRACERSHARED pShared = pThis->pSharedR3;
774 PSUPDRVSESSION pSession = pThis->pVMR3->pSession;
775
776 /* Release the waiter. */
777 RTThreadUserSignal(ThreadSelf);
778
779 /*
780 * Process stuff until we're told to terminate.
781 */
782 for (;;)
783 {
784 ASMAtomicXchgBool(&pShared->fFlushThrdActive, false);
785 if (!ASMAtomicXchgBool(&pShared->fEvtsWaiting, false))
786 {
787 int rc = SUPSemEventWaitNoResume(pSession, pShared->hSupSemEvtFlush, RT_INDEFINITE_WAIT);
788 Assert(RT_SUCCESS(rc) || rc == VERR_INTERRUPTED); RT_NOREF(rc);
789
790 if (RT_UNLIKELY(ASMAtomicReadBool(&pThis->fShutdown)))
791 break;
792 }
793
794 ASMAtomicXchgBool(&pShared->fFlushThrdActive, true);
795
796 uint64_t idEvtNow = ASMAtomicReadU64(&pShared->idEvt);
797 uint64_t idEvt = pThis->idEvtLast;
798 size_t cRingBufEvts = pShared->cbRingBuf / DBGF_TRACER_EVT_SZ;
799 while (idEvt < idEvtNow)
800 {
801 uint64_t idxRingBuf = idEvt % cRingBufEvts; /* This gives the index in the ring buffer for the event. */
802 PDBGFTRACEREVTHDR pEvtHdr = (PDBGFTRACEREVTHDR)(pThis->CTX_SUFF(pbRingBuf) + idxRingBuf * DBGF_TRACER_EVT_SZ);
803
804 /*
805 * If the event header contains the invalid ID the producer was interrupted or didn't get that far yet, spin a bit
806 * and wait for the ID to become valid.
807 */
808 while (ASMAtomicReadU64(&pEvtHdr->idEvt) == DBGF_TRACER_EVT_HDR_ID_INVALID)
809 RTThreadYield();
810
811 int rc = dbgfR3TracerEvtProcess(pThis, pEvtHdr);
812 if (RT_FAILURE(rc))
813 LogRelMax(10, ("DBGF: Writing event failed with %Rrc, tracing log will be incomplete!\n", rc));
814
815 ASMAtomicWriteU64(&pEvtHdr->idEvt, DBGF_TRACER_EVT_HDR_ID_INVALID);
816 idEvt++;
817 }
818
819 pThis->idEvtLast = idEvt;
820 ASMAtomicXchgBool(&pShared->fEvtsWaiting, false);
821 }
822
823 return VINF_SUCCESS;
824}
825
826
827/**
828 * Registers a possible event descriptors with the created trace log for faster subsequent operations.
829 *
830 * @returns VBox status code.
831 * @param pThis The DBGF tracer instance.
832 */
833static int dbgfR3TracerTraceLogEvtDescRegister(PDBGFTRACERINSR3 pThis)
834{
835 int rc = RTTraceLogWrAddEvtDesc(pThis->hTraceLog, &g_DevMmioMapEvtDesc);
836 if (RT_SUCCESS(rc))
837 rc = RTTraceLogWrAddEvtDesc(pThis->hTraceLog, &g_DevMmioUnmapEvtDesc);
838 if (RT_SUCCESS(rc))
839 rc = RTTraceLogWrAddEvtDesc(pThis->hTraceLog, &g_DevMmioReadEvtDesc);
840 if (RT_SUCCESS(rc))
841 rc = RTTraceLogWrAddEvtDesc(pThis->hTraceLog, &g_DevMmioWriteEvtDesc);
842 if (RT_SUCCESS(rc))
843 rc = RTTraceLogWrAddEvtDesc(pThis->hTraceLog, &g_DevIoPortMapEvtDesc);
844 if (RT_SUCCESS(rc))
845 rc = RTTraceLogWrAddEvtDesc(pThis->hTraceLog, &g_DevIoPortUnmapEvtDesc);
846 if (RT_SUCCESS(rc))
847 rc = RTTraceLogWrAddEvtDesc(pThis->hTraceLog, &g_DevIoPortReadEvtDesc);
848 if (RT_SUCCESS(rc))
849 rc = RTTraceLogWrAddEvtDesc(pThis->hTraceLog, &g_DevIoPortWriteEvtDesc);
850 if (RT_SUCCESS(rc))
851 rc = RTTraceLogWrAddEvtDesc(pThis->hTraceLog, &g_DevIrqEvtDesc);
852 if (RT_SUCCESS(rc))
853 rc = RTTraceLogWrAddEvtDesc(pThis->hTraceLog, &g_DevIoApicMsiEvtDesc);
854
855 return rc;
856}
857
858
859/**
860 * Initializes the R3 and shared tarcer instance data and spins up the flush thread.
861 *
862 * @returns VBox status code.
863 * @param pThis The DBGF tracer instance.
864 * @param pszTraceFilePath The path of the trace file to create.
865 */
866static int dbgfR3TracerInitR3(PDBGFTRACERINSR3 pThis, const char *pszTraceFilePath)
867{
868 PVM pVM = pThis->pVMR3;
869 PDBGFTRACERSHARED pShared = pThis->pSharedR3;
870
871 pThis->fShutdown = false;
872
873 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aGstMemRwData); i++)
874 pThis->aGstMemRwData[i].idEvtStart = DBGF_TRACER_EVT_HDR_ID_INVALID;
875
876 /* Try to create a file based trace log. */
877 int rc = RTTraceLogWrCreateFile(&pThis->hTraceLog, RTBldCfgVersion(), pszTraceFilePath);
878 AssertLogRelRCReturn(rc, rc);
879
880 rc = dbgfR3TracerTraceLogEvtDescRegister(pThis);
881 AssertLogRelRCReturn(rc, rc);
882
883 /*
884 * Go through the whole ring buffer and initialize the event IDs of all entries
885 * to invalid values.
886 */
887 uint64_t cEvtEntries = pShared->cbRingBuf / DBGF_TRACER_EVT_SZ;
888 PDBGFTRACEREVTHDR pEvtHdr = (PDBGFTRACEREVTHDR)pThis->pbRingBufR3;
889 for (uint32_t i = 0; i < cEvtEntries; i++)
890 {
891 pEvtHdr->idEvt = DBGF_TRACER_EVT_HDR_ID_INVALID;
892 pEvtHdr++;
893 }
894
895 rc = SUPSemEventCreate(pVM->pSession, &pShared->hSupSemEvtFlush);
896 if (RT_SUCCESS(rc))
897 {
898 rc = RTThreadCreate(&pThis->hThrdFlush, dbgfR3TracerThreadFlush, pThis, 0 /*cbStack*/, RTTHREADTYPE_IO,
899 RTTHREADFLAGS_WAITABLE, "DBGFTracer");
900 if (RT_SUCCESS(rc))
901 {
902 rc = RTThreadUserWait(pThis->hThrdFlush, 10 * 1000);
903 if (RT_SUCCESS(rc))
904 {
905 return VINF_SUCCESS;
906 }
907 }
908
909 SUPSemEventClose(pVM->pSession, pShared->hSupSemEvtFlush);
910 }
911
912 return rc;
913}
914
915
916/**
917 * Creates a DBGF tracer based on the given config and returns it.
918 *
919 * @returns VBox status code.
920 * @param pVM The cross context VM structure.
921 * @param fR0Enabled Flag whether the tracer should have R0 support enabled.
922 * @param pszTraceFilePath The path of the trace file to create.
923 * @param cbRingBuf Size of the ring buffer in bytes.
924 * @param ppDbgfTracerR3 Where to store the pointer to the tracer on success.
925 */
926static int dbgfR3TracerCreate(PVM pVM, bool fR0Enabled, const char *pszTraceFilePath,
927 uint32_t cbRingBuf, PDBGFTRACERINSR3 *ppDbgfTracerR3)
928{
929 PDBGFTRACERINSR3 pThis = NULL;
930
931 /*
932 * Allocate the tracer instance.
933 */
934 if ((fR0Enabled /*|| fRCEnabled*/) && !SUPR3IsDriverless())
935 {
936 AssertLogRel(fR0Enabled /* not possible to just enabled raw-mode atm. */);
937
938 DBGFTRACERCREATEREQ Req;
939 Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
940 Req.Hdr.cbReq = sizeof(Req);
941 Req.pTracerInsR3 = NULL;
942 Req.cbRingBuf = cbRingBuf;
943 Req.fRCEnabled = false; /*fRCEnabled;*/
944 Req.afReserved[0] = false;
945 Req.afReserved[1] = false;
946 Req.afReserved[2] = false;
947 int rc = VMMR3CallR0Emt(pVM, pVM->apCpusR3[0], VMMR0_DO_DBGF_TRACER_CREATE, 0, &Req.Hdr);
948 AssertLogRelMsgRCReturn(rc, ("VMMR0_DO_DBGF_TRACER_CREATE failed: %Rrc\n", rc), rc);
949 pThis = Req.pTracerInsR3;
950 }
951 else
952 {
953 /* The code in this else branch works by the same rules as the DBGFR0Tracer.cpp
954 code, except there is only the ring-3 components of the tracer instance.
955 Changes here may need to be reflected in DBGFR0Tracer.cpp and vice versa! */
956 uint32_t cb = sizeof(DBGFTRACERINSR3);
957 cb = RT_ALIGN_32(cb, 64);
958 const uint32_t offShared = cb;
959 cb += sizeof(DBGFTRACERSHARED) + cbRingBuf;
960 AssertLogRelMsgReturn(cb <= DBGF_MAX_TRACER_INSTANCE_SIZE_R3,
961 ("Tracer total instance size is to big: %u, max %u\n",
962 cb, DBGF_MAX_TRACER_INSTANCE_SIZE_R3),
963 VERR_ALLOCATION_TOO_BIG);
964
965 int rc = MMR3HeapAllocZEx(pVM, MM_TAG_DBGF_TRACER, cb, (void **)&pThis);
966 AssertLogRelMsgRCReturn(rc, ("Failed to allocate %zu bytes of instance data for tracer. rc=%Rrc\n",
967 cb, rc), rc);
968
969 /* Initialize it: */
970 pThis->pNextR3 = NULL;
971 pThis->pVMR3 = pVM;
972 pThis->fR0Enabled = false;
973 pThis->pSharedR3 = (PDBGFTRACERSHARED)((uint8_t *)pThis + offShared);
974 pThis->pbRingBufR3 = (uint8_t *)(pThis->pSharedR3 + 1);
975
976 pThis->pSharedR3->idEvt = 0;
977 pThis->pSharedR3->cbRingBuf = cbRingBuf;
978 pThis->pSharedR3->fEvtsWaiting = false;
979 pThis->pSharedR3->fFlushThrdActive = false;
980 }
981
982 /* Initialize the rest of the R3 tracer instance and spin up the flush thread. */
983 int rc = dbgfR3TracerInitR3(pThis, pszTraceFilePath);
984 if (RT_SUCCESS(rc))
985 {
986 *ppDbgfTracerR3 = pThis;
987 return rc;
988 }
989
990 /** @todo Cleanup. */
991 LogFlow(("dbgfR3TracerCreate: returns %Rrc\n", rc));
992 return rc;
993}
994
995
996/**
997 * Initializes and configures the tracer if configured.
998 *
999 * @returns VBox status code.
1000 * @param pVM The cross context VM pointer.
1001 */
1002DECLHIDDEN(int) dbgfR3TracerInit(PVM pVM)
1003{
1004 PUVM pUVM = pVM->pUVM;
1005
1006 pUVM->dbgf.s.pTracerR3 = NULL;
1007
1008 /*
1009 * Check the config and enable tracing if requested.
1010 */
1011 PCFGMNODE pDbgfNode = CFGMR3GetChild(CFGMR3GetRoot(pVM), "DBGF");
1012 bool fTracerEnabled;
1013 int rc = CFGMR3QueryBoolDef(pDbgfNode, "TracerEnabled", &fTracerEnabled, false);
1014 AssertRCReturn(rc, rc);
1015 if (fTracerEnabled)
1016 {
1017 bool fR0Enabled;
1018 uint32_t cbRingBuf = 0;
1019 char *pszTraceFilePath = NULL;
1020 rc = CFGMR3QueryBoolDef(pDbgfNode, "TracerR0Enabled", &fR0Enabled, false);
1021 if (RT_SUCCESS(rc))
1022 rc = CFGMR3QueryU32Def(pDbgfNode, "TracerRingBufSz", &cbRingBuf, _4M);
1023 if (RT_SUCCESS(rc))
1024 rc = CFGMR3QueryStringAlloc(pDbgfNode, "TracerFilePath", &pszTraceFilePath);
1025 if (RT_SUCCESS(rc))
1026 {
1027 AssertLogRelMsgReturn(cbRingBuf && cbRingBuf == (size_t)cbRingBuf,
1028 ("Tracing ringbuffer size %#RX64 is invalid\n", cbRingBuf),
1029 VERR_INVALID_PARAMETER);
1030
1031 rc = dbgfR3TracerCreate(pVM, fR0Enabled, pszTraceFilePath, cbRingBuf, &pUVM->dbgf.s.pTracerR3);
1032 }
1033
1034 if (pszTraceFilePath)
1035 {
1036 MMR3HeapFree(pszTraceFilePath);
1037 pszTraceFilePath = NULL;
1038 }
1039 }
1040
1041 return rc;
1042}
1043
1044
1045/**
1046 * Terminates any configured tracer for the given VM instance.
1047 *
1048 * @param pVM The cross context VM structure.
1049 */
1050DECLHIDDEN(void) dbgfR3TracerTerm(PVM pVM)
1051{
1052 PUVM pUVM = pVM->pUVM;
1053
1054 if (pUVM->dbgf.s.pTracerR3)
1055 {
1056 PDBGFTRACERINSR3 pThis = pUVM->dbgf.s.pTracerR3;
1057 PDBGFTRACERSHARED pSharedR3 = pThis->CTX_SUFF(pShared);
1058
1059 /* Tear down the flush thread. */
1060 ASMAtomicXchgBool(&pThis->fShutdown, true);
1061 SUPSemEventSignal(pVM->pSession, pSharedR3->hSupSemEvtFlush);
1062
1063 int rc = RTThreadWait(pThis->hThrdFlush, RT_MS_30SEC, NULL);
1064 AssertLogRelMsgRC(rc, ("DBGF: Waiting for the tracer flush thread to terminate failed with %Rrc\n", rc));
1065
1066 /* Close the trace log. */
1067 rc = RTTraceLogWrDestroy(pThis->hTraceLog);
1068 AssertLogRelMsgRC(rc, ("DBGF: Closing the trace log file failed with %Rrc\n", rc));
1069
1070 SUPSemEventClose(pVM->pSession, pSharedR3->hSupSemEvtFlush);
1071 /* The instance memory is freed by MM or when the R0 component terminates. */
1072 pUVM->dbgf.s.pTracerR3 = NULL;
1073 }
1074}
1075
1076
1077/**
1078 * Registers a new event source with the given name and returns a tracer event source handle.
1079 *
1080 * @returns VBox status code.
1081 * @param pVM The cross context VM structure.
1082 * @param pszName The event source name.
1083 * @param phEvtSrc Where to return the handle to the event source on success.
1084 */
1085VMMR3_INT_DECL(int) DBGFR3TracerRegisterEvtSrc(PVM pVM, const char *pszName, PDBGFTRACEREVTSRC phEvtSrc)
1086{
1087 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
1088 AssertReturn(pszName && *pszName != '\0', VERR_INVALID_PARAMETER);
1089 AssertPtrReturn(phEvtSrc, VERR_INVALID_POINTER);
1090
1091 PUVM pUVM = pVM->pUVM;
1092 PDBGFTRACERINSR3 pThis = pUVM->dbgf.s.pTracerR3;
1093
1094 DBGFTRACEREVTSRC hEvtSrc = ASMAtomicIncU64((volatile uint64_t *)&pThis->hEvtSrcNext) - 1;
1095
1096 int rc = dbgfTracerR3EvtPostSingle(pVM, pThis, hEvtSrc, DBGFTRACEREVT_SRC_REGISTER,
1097 NULL /*pvEvtDesc*/, 0 /*cbEvtDesc*/, NULL /*pidEvt*/);
1098 if (RT_SUCCESS(rc))
1099 *phEvtSrc = hEvtSrc;
1100
1101 return rc;
1102}
1103
1104
1105/**
1106 * Deregisters the given event source handle.
1107 *
1108 * @returns VBox status code.
1109 * @param pVM The cross context VM structure.
1110 * @param hEvtSrc The event source handle to deregister.
1111 */
1112VMMR3_INT_DECL(int) DBGFR3TracerDeregisterEvtSrc(PVM pVM, DBGFTRACEREVTSRC hEvtSrc)
1113{
1114 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
1115 AssertReturn(hEvtSrc != NIL_DBGFTRACEREVTSRC, VERR_INVALID_HANDLE);
1116
1117 PUVM pUVM = pVM->pUVM;
1118 PDBGFTRACERINSR3 pThis = pUVM->dbgf.s.pTracerR3;
1119 return dbgfTracerR3EvtPostSingle(pVM, pThis, hEvtSrc, DBGFTRACEREVT_SRC_DEREGISTER,
1120 NULL /*pvEvtDesc*/, 0 /*cbEvtDesc*/, NULL /*pidEvt*/);
1121}
1122
1123
1124/**
1125 * Registers an I/O port region create event for the given event source.
1126 *
1127 * @returns VBox status code.
1128 * @param pVM The current context VM instance data.
1129 * @param hEvtSrc The event source for the posted event.
1130 * @param hRegion The I/O port region handle returned from IOM.
1131 * @param cPorts Number of ports registered.
1132 * @param fFlags Flags passed to IOM.
1133 * @param iPciRegion For a PCI device the region index used for the I/O ports.
1134 */
1135VMMR3_INT_DECL(int) DBGFR3TracerEvtIoPortCreate(PVM pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hRegion, RTIOPORT cPorts, uint32_t fFlags,
1136 uint32_t iPciRegion)
1137{
1138 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
1139 AssertReturn(hEvtSrc != NIL_DBGFTRACEREVTSRC, VERR_INVALID_HANDLE);
1140
1141 PUVM pUVM = pVM->pUVM;
1142 PDBGFTRACERINSR3 pThis = pUVM->dbgf.s.pTracerR3;
1143
1144 DBGFTRACEREVTIOPORTCREATE EvtIoPortCreate;
1145 RT_ZERO(EvtIoPortCreate);
1146 EvtIoPortCreate.hIoPorts = hRegion;
1147 EvtIoPortCreate.cPorts = cPorts;
1148 EvtIoPortCreate.fIomFlags = fFlags;
1149 EvtIoPortCreate.iPciRegion = iPciRegion;
1150 return dbgfTracerR3EvtPostSingle(pVM, pThis, hEvtSrc, DBGFTRACEREVT_IOPORT_REGION_CREATE,
1151 &EvtIoPortCreate, sizeof(EvtIoPortCreate), NULL /*pidEvt*/);
1152}
1153
1154
1155/**
1156 * Registers an MMIO region create event for the given event source.
1157 *
1158 * @returns VBox status code.
1159 * @param pVM The current context VM instance data.
1160 * @param hEvtSrc The event source for the posted event.
1161 * @param hRegion The MMIO region handle returned from IOM.
1162 * @param cbRegion Size of the MMIO region in bytes.
1163 * @param fFlags Flags passed to IOM.
1164 * @param iPciRegion For a PCI device the region index used for the MMIO region.
1165 */
1166VMMR3_INT_DECL(int) DBGFR3TracerEvtMmioCreate(PVM pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hRegion, RTGCPHYS cbRegion, uint32_t fFlags,
1167 uint32_t iPciRegion)
1168{
1169 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
1170 AssertReturn(hEvtSrc != NIL_DBGFTRACEREVTSRC, VERR_INVALID_HANDLE);
1171
1172 PUVM pUVM = pVM->pUVM;
1173 PDBGFTRACERINSR3 pThis = pUVM->dbgf.s.pTracerR3;
1174
1175 DBGFTRACEREVTMMIOCREATE EvtMmioCreate;
1176 RT_ZERO(EvtMmioCreate);
1177 EvtMmioCreate.hMmioRegion = hRegion;
1178 EvtMmioCreate.cbRegion = cbRegion;
1179 EvtMmioCreate.fIomFlags = fFlags;
1180 EvtMmioCreate.iPciRegion = iPciRegion;
1181 return dbgfTracerR3EvtPostSingle(pVM, pThis, hEvtSrc, DBGFTRACEREVT_MMIO_REGION_CREATE,
1182 &EvtMmioCreate, sizeof(EvtMmioCreate), NULL /*pidEvt*/);
1183}
1184
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