VirtualBox

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

Last change on this file since 95259 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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