summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/Trace
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:17:27 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:17:27 +0000
commitf215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch)
tree6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/Devices/Trace
parentInitial commit. (diff)
downloadvirtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz
virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Devices/Trace')
-rw-r--r--src/VBox/Devices/Trace/DrvIfsTrace-serial.cpp451
-rw-r--r--src/VBox/Devices/Trace/DrvIfsTrace.cpp199
-rw-r--r--src/VBox/Devices/Trace/DrvIfsTraceInternal.h76
-rw-r--r--src/VBox/Devices/Trace/README.txt32
4 files changed, 758 insertions, 0 deletions
diff --git a/src/VBox/Devices/Trace/DrvIfsTrace-serial.cpp b/src/VBox/Devices/Trace/DrvIfsTrace-serial.cpp
new file mode 100644
index 00000000..fbca14a8
--- /dev/null
+++ b/src/VBox/Devices/Trace/DrvIfsTrace-serial.cpp
@@ -0,0 +1,451 @@
+/* $Id: DrvIfsTrace-serial.cpp $ */
+/** @file
+ * VBox interface callback tracing driver.
+ */
+
+/*
+ * Copyright (C) 2020-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_MISC
+#include <VBox/log.h>
+#include <VBox/version.h>
+
+#include <iprt/errcore.h>
+#include <iprt/tracelog.h>
+
+#include "DrvIfsTraceInternal.h"
+
+
+/*
+ *
+ * ISerialPort Implementation.
+ *
+ */
+static const RTTRACELOGEVTITEMDESC g_ISerialPortDataAvailRdrNotifyEvtItems[] =
+{
+ {"cbAvail", "Number of bytes available", RTTRACELOGTYPE_SIZE, 0},
+ {"rc", "Status code returned by the upper device/driver", RTTRACELOGTYPE_INT32, 0}
+};
+
+static const RTTRACELOGEVTDESC g_ISerialPortDataAvailRdrNotifyEvtDesc =
+{
+ "ISerialPort.DataAvailRdrNotify",
+ "",
+ RTTRACELOGEVTSEVERITY_DEBUG,
+ RT_ELEMENTS(g_ISerialPortDataAvailRdrNotifyEvtItems),
+ g_ISerialPortDataAvailRdrNotifyEvtItems
+};
+
+/**
+ * @interface_method_impl{PDMISERIALPORT,pfnDataAvailRdrNotify}
+ */
+static DECLCALLBACK(int) drvIfTraceISerialPort_DataAvailRdrNotify(PPDMISERIALPORT pInterface, size_t cbAvail)
+{
+ PDRVIFTRACE pThis = RT_FROM_MEMBER(pInterface, DRVIFTRACE, ISerialPort);
+ int rc = pThis->pISerialPortAbove->pfnDataAvailRdrNotify(pThis->pISerialPortAbove, cbAvail);
+
+ int rcTraceLog = RTTraceLogWrEvtAddL(pThis->hTraceLog, &g_ISerialPortDataAvailRdrNotifyEvtDesc, 0, 0, 0, cbAvail, rc);
+ if (RT_FAILURE(rcTraceLog))
+ LogRelMax(10, ("DrvIfTrace#%d: Failed to add event to trace log %Rrc\n", pThis->pDrvIns->iInstance, rcTraceLog));
+
+ return rc;
+}
+
+
+static const RTTRACELOGEVTITEMDESC g_ISerialPortDataSentNotifyEvtItems[] =
+{
+ {"rc", "Status code returned by the upper device/driver", RTTRACELOGTYPE_INT32, 0}
+};
+
+static const RTTRACELOGEVTDESC g_ISerialPortDataSentNotifyEvtDesc =
+{
+ "ISerialPort.DataSentNotify",
+ "",
+ RTTRACELOGEVTSEVERITY_DEBUG,
+ RT_ELEMENTS(g_ISerialPortDataSentNotifyEvtItems),
+ g_ISerialPortDataSentNotifyEvtItems
+};
+
+/**
+ * @interface_method_impl{PDMISERIALPORT,pfnDataSentNotify}
+ */
+static DECLCALLBACK(int) drvIfTraceISerialPort_DataSentNotify(PPDMISERIALPORT pInterface)
+{
+ PDRVIFTRACE pThis = RT_FROM_MEMBER(pInterface, DRVIFTRACE, ISerialPort);
+ int rc = pThis->pISerialPortAbove->pfnDataSentNotify(pThis->pISerialPortAbove);
+
+ int rcTraceLog = RTTraceLogWrEvtAddL(pThis->hTraceLog, &g_ISerialPortDataSentNotifyEvtDesc, 0, 0, 0, rc);
+ if (RT_FAILURE(rcTraceLog))
+ LogRelMax(10, ("DrvIfTrace#%d: Failed to add event to trace log %Rrc\n", pThis->pDrvIns->iInstance, rcTraceLog));
+
+ return rc;
+}
+
+
+static const RTTRACELOGEVTITEMDESC g_ISerialPortReadWrEvtItems[] =
+{
+ {"cbRead", "Number of bytes to read max", RTTRACELOGTYPE_SIZE, 0},
+ {"pcbRead", "Number of bytes actually read", RTTRACELOGTYPE_SIZE, 0},
+ {"rc", "Status code returned by the upper device/driver", RTTRACELOGTYPE_INT32, 0}
+};
+
+static const RTTRACELOGEVTDESC g_ISerialPortReadWrEvtDesc =
+{
+ "ISerialPort.ReadWr",
+ "",
+ RTTRACELOGEVTSEVERITY_DEBUG,
+ RT_ELEMENTS(g_ISerialPortReadWrEvtItems),
+ g_ISerialPortReadWrEvtItems
+};
+
+/**
+ * @interface_method_impl{PDMISERIALPORT,pfnReadWr}
+ */
+static DECLCALLBACK(int) drvIfTraceISerialPort_ReadWr(PPDMISERIALPORT pInterface, void *pvBuf, size_t cbRead, size_t *pcbRead)
+{
+ PDRVIFTRACE pThis = RT_FROM_MEMBER(pInterface, DRVIFTRACE, ISerialPort);
+ int rc = pThis->pISerialPortAbove->pfnReadWr(pThis->pISerialPortAbove, pvBuf, cbRead, pcbRead);
+
+ int rcTraceLog = RTTraceLogWrEvtAddL(pThis->hTraceLog, &g_ISerialPortReadWrEvtDesc, 0, 0, 0, cbRead, *pcbRead, rc);
+ if (RT_FAILURE(rcTraceLog))
+ LogRelMax(10, ("DrvIfTrace#%d: Failed to add event to trace log %Rrc\n", pThis->pDrvIns->iInstance, rcTraceLog));
+
+ return rc;
+}
+
+
+static const RTTRACELOGEVTITEMDESC g_ISerialPortNotifyStsLinesChangedEvtItems[] =
+{
+ {"fNewStsLines", "Status line mask", RTTRACELOGTYPE_UINT32, 0},
+ {"rc", "Status code returned by the upper device/driver", RTTRACELOGTYPE_INT32, 0}
+};
+
+static const RTTRACELOGEVTDESC g_ISerialPortNotifyStsLinesChangedEvtDesc =
+{
+ "ISerialPort.NotifyStsLinesChanged",
+ "",
+ RTTRACELOGEVTSEVERITY_DEBUG,
+ RT_ELEMENTS(g_ISerialPortNotifyStsLinesChangedEvtItems),
+ g_ISerialPortNotifyStsLinesChangedEvtItems
+};
+
+/**
+ * @interface_method_impl{PDMISERIALPORT,pfnNotifyStsLinesChanged}
+ */
+static DECLCALLBACK(int) drvIfTraceISerialPort_NotifyStsLinesChanged(PPDMISERIALPORT pInterface, uint32_t fNewStatusLines)
+{
+ PDRVIFTRACE pThis = RT_FROM_MEMBER(pInterface, DRVIFTRACE, ISerialPort);
+ int rc = pThis->pISerialPortAbove->pfnNotifyStsLinesChanged(pThis->pISerialPortAbove, fNewStatusLines);
+
+ int rcTraceLog = RTTraceLogWrEvtAddL(pThis->hTraceLog, &g_ISerialPortNotifyStsLinesChangedEvtDesc, 0, 0, 0, fNewStatusLines, rc);
+ if (RT_FAILURE(rcTraceLog))
+ LogRelMax(10, ("DrvIfTrace#%d: Failed to add event to trace log %Rrc\n", pThis->pDrvIns->iInstance, rcTraceLog));
+
+ return rc;
+}
+
+
+static const RTTRACELOGEVTITEMDESC g_ISerialPortNotifyBrkEvtItems[] =
+{
+ {"rc", "Status code returned by the upper device/driver", RTTRACELOGTYPE_INT32, 0}
+};
+
+static const RTTRACELOGEVTDESC g_ISerialPortNotifyBrkEvtDesc =
+{
+ "ISerialPort.NotifyBrk",
+ "",
+ RTTRACELOGEVTSEVERITY_DEBUG,
+ RT_ELEMENTS(g_ISerialPortNotifyBrkEvtItems),
+ g_ISerialPortNotifyBrkEvtItems
+};
+
+/**
+ * @interface_method_impl{PDMISERIALPORT,pfnNotifyBrk}
+ */
+static DECLCALLBACK(int) drvIfTraceISerialPort_NotifyBrk(PPDMISERIALPORT pInterface)
+{
+ PDRVIFTRACE pThis = RT_FROM_MEMBER(pInterface, DRVIFTRACE, ISerialPort);
+ int rc = pThis->pISerialPortAbove->pfnNotifyBrk(pThis->pISerialPortAbove);
+
+ int rcTraceLog = RTTraceLogWrEvtAddL(pThis->hTraceLog, &g_ISerialPortNotifyBrkEvtDesc, 0, 0, 0, rc);
+ if (RT_FAILURE(rcTraceLog))
+ LogRelMax(10, ("DrvIfTrace#%d: Failed to add event to trace log %Rrc\n", pThis->pDrvIns->iInstance, rcTraceLog));
+
+ return rc;
+}
+
+
+/*
+ *
+ * ISerialConnector Implementation.
+ *
+ */
+static const RTTRACELOGEVTITEMDESC g_ISerialConnectorDataAvailWrNotifyEvtItems[] =
+{
+ {"rc", "Status code returned by the lower driver", RTTRACELOGTYPE_INT32, 0}
+};
+
+static const RTTRACELOGEVTDESC g_ISerialConnectorDataAvailWrNotifyEvtDesc =
+{
+ "ISerialConnector.DataAvailWrNotify",
+ "",
+ RTTRACELOGEVTSEVERITY_DEBUG,
+ RT_ELEMENTS(g_ISerialConnectorDataAvailWrNotifyEvtItems),
+ g_ISerialConnectorDataAvailWrNotifyEvtItems
+};
+
+/** @interface_method_impl{PDMISERIALCONNECTOR,pfnDataAvailWrNotify} */
+static DECLCALLBACK(int) drvIfTraceISerialConnector_DataAvailWrNotify(PPDMISERIALCONNECTOR pInterface)
+{
+ PDRVIFTRACE pThis = RT_FROM_MEMBER(pInterface, DRVIFTRACE, ISerialConnector);
+ int rc = pThis->pISerialConBelow->pfnDataAvailWrNotify(pThis->pISerialConBelow);
+
+ int rcTraceLog = RTTraceLogWrEvtAddL(pThis->hTraceLog, &g_ISerialConnectorDataAvailWrNotifyEvtDesc, 0, 0, 0, rc);
+ if (RT_FAILURE(rcTraceLog))
+ LogRelMax(10, ("DrvIfTrace#%d: Failed to add event to trace log %Rrc\n", pThis->pDrvIns->iInstance, rcTraceLog));
+
+ return rc;
+}
+
+
+static const RTTRACELOGEVTITEMDESC g_ISerialConnectorReadRdrEvtItems[] =
+{
+ {"cbRead", "Number of bytes to read max", RTTRACELOGTYPE_SIZE, 0},
+ {"pcbRead", "Number of bytes actually read", RTTRACELOGTYPE_SIZE, 0},
+ {"rc", "Status code returned by the lower driver", RTTRACELOGTYPE_INT32, 0}
+};
+
+static const RTTRACELOGEVTDESC g_ISerialConnectorReadRdrEvtDesc =
+{
+ "ISerialConnector.ReadRdr",
+ "",
+ RTTRACELOGEVTSEVERITY_DEBUG,
+ RT_ELEMENTS(g_ISerialConnectorReadRdrEvtItems),
+ g_ISerialConnectorReadRdrEvtItems
+};
+
+/**
+ * @interface_method_impl{PDMISERIALCONNECTOR,pfnReadRdr}
+ */
+static DECLCALLBACK(int) drvIfTraceISerialConnector_ReadRdr(PPDMISERIALCONNECTOR pInterface, void *pvBuf,
+ size_t cbRead, size_t *pcbRead)
+{
+ PDRVIFTRACE pThis = RT_FROM_MEMBER(pInterface, DRVIFTRACE, ISerialConnector);
+ int rc = pThis->pISerialConBelow->pfnReadRdr(pThis->pISerialConBelow, pvBuf, cbRead, pcbRead);
+
+ int rcTraceLog = RTTraceLogWrEvtAddL(pThis->hTraceLog, &g_ISerialConnectorReadRdrEvtDesc, 0, 0, 0, cbRead, *pcbRead, rc);
+ if (RT_FAILURE(rcTraceLog))
+ LogRelMax(10, ("DrvIfTrace#%d: Failed to add event to trace log %Rrc\n", pThis->pDrvIns->iInstance, rcTraceLog));
+
+ return rc;
+}
+
+
+static const RTTRACELOGEVTITEMDESC g_ISerialConnectorChgParamsEvtItems[] =
+{
+ {"uBps", "Baudrate", RTTRACELOGTYPE_UINT32, 0},
+ {"enmParity", "The parity to configure", RTTRACELOGTYPE_UINT32, 0},
+ {"cDataBits", "Number of data bits for each symbol", RTTRACELOGTYPE_UINT32, 0},
+ {"enmStopBits", "Number of stop bits for each symbol", RTTRACELOGTYPE_UINT32, 0},
+ {"rc", "Status code returned by the lower driver", RTTRACELOGTYPE_INT32, 0}
+};
+
+static const RTTRACELOGEVTDESC g_ISerialConnectorChgParamsEvtDesc =
+{
+ "ISerialConnector.ChgParams",
+ "",
+ RTTRACELOGEVTSEVERITY_DEBUG,
+ RT_ELEMENTS(g_ISerialConnectorChgParamsEvtItems),
+ g_ISerialConnectorChgParamsEvtItems
+};
+
+/**
+ * @interface_method_impl{PDMISERIALCONNECTOR,pfnChgParams}
+ */
+static DECLCALLBACK(int) drvIfTraceISerialConnector_ChgParams(PPDMISERIALCONNECTOR pInterface, uint32_t uBps,
+ PDMSERIALPARITY enmParity, unsigned cDataBits,
+ PDMSERIALSTOPBITS enmStopBits)
+{
+ PDRVIFTRACE pThis = RT_FROM_MEMBER(pInterface, DRVIFTRACE, ISerialConnector);
+ int rc = pThis->pISerialConBelow->pfnChgParams(pThis->pISerialConBelow, uBps, enmParity, cDataBits, enmStopBits);
+
+ int rcTraceLog = RTTraceLogWrEvtAddL(pThis->hTraceLog, &g_ISerialConnectorChgParamsEvtDesc, 0, 0, 0,
+ uBps, enmParity, cDataBits, enmStopBits, rc);
+ if (RT_FAILURE(rcTraceLog))
+ LogRelMax(10, ("DrvIfTrace#%d: Failed to add event to trace log %Rrc\n", pThis->pDrvIns->iInstance, rcTraceLog));
+
+ return rc;
+}
+
+
+static const RTTRACELOGEVTITEMDESC g_ISerialConnectorChgModemLinesEvtItems[] =
+{
+ {"fRts", "State of RTS line", RTTRACELOGTYPE_BOOL, 0},
+ {"fDtr", "State of DTR line", RTTRACELOGTYPE_BOOL, 0},
+ {"rc", "Status code returned by the lower driver", RTTRACELOGTYPE_INT32, 0}
+};
+
+static const RTTRACELOGEVTDESC g_ISerialConnectorChgModemLinesEvtDesc =
+{
+ "ISerialConnector.ChgModemLines",
+ "",
+ RTTRACELOGEVTSEVERITY_DEBUG,
+ RT_ELEMENTS(g_ISerialConnectorChgModemLinesEvtItems),
+ g_ISerialConnectorChgModemLinesEvtItems
+};
+
+/**
+ * @interface_method_impl{PDMISERIALCONNECTOR,pfnChgModemLines}
+ */
+static DECLCALLBACK(int) drvIfTraceISerialConnector_ChgModemLines(PPDMISERIALCONNECTOR pInterface, bool fRts, bool fDtr)
+{
+ PDRVIFTRACE pThis = RT_FROM_MEMBER(pInterface, DRVIFTRACE, ISerialConnector);
+ int rc = pThis->pISerialConBelow->pfnChgModemLines(pThis->pISerialConBelow, fRts, fDtr);
+
+ int rcTraceLog = RTTraceLogWrEvtAddL(pThis->hTraceLog, &g_ISerialConnectorChgModemLinesEvtDesc, 0, 0, 0, fRts, fDtr, rc);
+ if (RT_FAILURE(rcTraceLog))
+ LogRelMax(10, ("DrvIfTrace#%d: Failed to add event to trace log %Rrc\n", pThis->pDrvIns->iInstance, rcTraceLog));
+
+ return rc;
+}
+
+
+static const RTTRACELOGEVTITEMDESC g_ISerialConnectorChgBrkEvtItems[] =
+{
+ {"fBrk", "Signal break flag", RTTRACELOGTYPE_BOOL, 0},
+ {"rc", "Status code returned by the lower driver", RTTRACELOGTYPE_INT32, 0}
+};
+
+static const RTTRACELOGEVTDESC g_ISerialConnectorChgBrkEvtDesc =
+{
+ "ISerialConnector.ChgBrk",
+ "",
+ RTTRACELOGEVTSEVERITY_DEBUG,
+ RT_ELEMENTS(g_ISerialConnectorChgBrkEvtItems),
+ g_ISerialConnectorChgBrkEvtItems
+};
+
+/**
+ * @interface_method_impl{PDMISERIALCONNECTOR,pfnChgBrk}
+ */
+static DECLCALLBACK(int) drvIfTraceISerialConnector_ChgBrk(PPDMISERIALCONNECTOR pInterface, bool fBrk)
+{
+ PDRVIFTRACE pThis = RT_FROM_MEMBER(pInterface, DRVIFTRACE, ISerialConnector);
+ int rc = pThis->pISerialConBelow->pfnChgBrk(pThis->pISerialConBelow, fBrk);
+
+ int rcTraceLog = RTTraceLogWrEvtAddL(pThis->hTraceLog, &g_ISerialConnectorChgBrkEvtDesc, 0, 0, 0, fBrk, rc);
+ if (RT_FAILURE(rcTraceLog))
+ LogRelMax(10, ("DrvIfTrace#%d: Failed to add event to trace log %Rrc\n", pThis->pDrvIns->iInstance, rcTraceLog));
+
+ return rc;
+}
+
+
+static const RTTRACELOGEVTITEMDESC g_ISerialConnectorQueryStsLinesEvtItems[] =
+{
+ {"fStsLines", "Status line flags", RTTRACELOGTYPE_UINT32, 0},
+ {"rc", "Status code returned by the lower driver", RTTRACELOGTYPE_INT32, 0}
+};
+
+static const RTTRACELOGEVTDESC g_ISerialConnectorQueryStsLinesEvtDesc =
+{
+ "ISerialConnector.QueryStsLines",
+ "",
+ RTTRACELOGEVTSEVERITY_DEBUG,
+ RT_ELEMENTS(g_ISerialConnectorQueryStsLinesEvtItems),
+ g_ISerialConnectorQueryStsLinesEvtItems
+};
+
+/**
+ * @interface_method_impl{PDMISERIALCONNECTOR,pfnQueryStsLines}
+ */
+static DECLCALLBACK(int) drvIfTraceISerialConnector_QueryStsLines(PPDMISERIALCONNECTOR pInterface, uint32_t *pfStsLines)
+{
+ PDRVIFTRACE pThis = RT_FROM_MEMBER(pInterface, DRVIFTRACE, ISerialConnector);
+ int rc = pThis->pISerialConBelow->pfnQueryStsLines(pThis->pISerialConBelow, pfStsLines);
+
+ int rcTraceLog = RTTraceLogWrEvtAddL(pThis->hTraceLog, &g_ISerialConnectorQueryStsLinesEvtDesc, 0, 0, 0, *pfStsLines, rc);
+ if (RT_FAILURE(rcTraceLog))
+ LogRelMax(10, ("DrvIfTrace#%d: Failed to add event to trace log %Rrc\n", pThis->pDrvIns->iInstance, rcTraceLog));
+
+ return rc;
+}
+
+
+static const RTTRACELOGEVTITEMDESC g_ISerialConnectorQueuesFlushEvtItems[] =
+{
+ {"fQueueRecv", "Whether to flush the receive queue", RTTRACELOGTYPE_BOOL, 0},
+ {"fQueueXmit", "Whether to flush the transmit queue", RTTRACELOGTYPE_BOOL, 0},
+ {"rc", "Status code returned by the lower driver", RTTRACELOGTYPE_INT32, 0}
+};
+
+static const RTTRACELOGEVTDESC g_ISerialConnectorQueuesFlushEvtDesc =
+{
+ "ISerialConnector.QueuesFlush",
+ "",
+ RTTRACELOGEVTSEVERITY_DEBUG,
+ RT_ELEMENTS(g_ISerialConnectorQueuesFlushEvtItems),
+ g_ISerialConnectorQueuesFlushEvtItems
+};
+
+/**
+ * @callback_method_impl{PDMISERIALCONNECTOR,pfnQueuesFlush}
+ */
+static DECLCALLBACK(int) drvIfTraceISerialConnector_QueuesFlush(PPDMISERIALCONNECTOR pInterface, bool fQueueRecv, bool fQueueXmit)
+{
+ PDRVIFTRACE pThis = RT_FROM_MEMBER(pInterface, DRVIFTRACE, ISerialConnector);
+ int rc = pThis->pISerialConBelow->pfnQueuesFlush(pThis->pISerialConBelow, fQueueRecv, fQueueXmit);
+
+ int rcTraceLog = RTTraceLogWrEvtAddL(pThis->hTraceLog, &g_ISerialConnectorQueuesFlushEvtDesc, 0, 0, 0, fQueueRecv, fQueueXmit, rc);
+ if (RT_FAILURE(rcTraceLog))
+ LogRelMax(10, ("DrvIfTrace#%d: Failed to add event to trace log %Rrc\n", pThis->pDrvIns->iInstance, rcTraceLog));
+
+ return rc;
+}
+
+
+/**
+ * Initializes serial port relaated interfaces.
+ *
+ * @param pThis The interface callback trace driver instance.
+ */
+DECLHIDDEN(void) drvIfsTrace_SerialIfInit(PDRVIFTRACE pThis)
+{
+ pThis->ISerialPort.pfnDataAvailRdrNotify = drvIfTraceISerialPort_DataAvailRdrNotify;
+ pThis->ISerialPort.pfnDataSentNotify = drvIfTraceISerialPort_DataSentNotify;
+ pThis->ISerialPort.pfnReadWr = drvIfTraceISerialPort_ReadWr;
+ pThis->ISerialPort.pfnNotifyStsLinesChanged = drvIfTraceISerialPort_NotifyStsLinesChanged;
+ pThis->ISerialPort.pfnNotifyBrk = drvIfTraceISerialPort_NotifyBrk;
+
+ pThis->ISerialConnector.pfnDataAvailWrNotify = drvIfTraceISerialConnector_DataAvailWrNotify;
+ pThis->ISerialConnector.pfnReadRdr = drvIfTraceISerialConnector_ReadRdr;
+ pThis->ISerialConnector.pfnChgParams = drvIfTraceISerialConnector_ChgParams;
+ pThis->ISerialConnector.pfnChgModemLines = drvIfTraceISerialConnector_ChgModemLines;
+ pThis->ISerialConnector.pfnChgBrk = drvIfTraceISerialConnector_ChgBrk;
+ pThis->ISerialConnector.pfnQueryStsLines = drvIfTraceISerialConnector_QueryStsLines;
+ pThis->ISerialConnector.pfnQueuesFlush = drvIfTraceISerialConnector_QueuesFlush;
+}
+
diff --git a/src/VBox/Devices/Trace/DrvIfsTrace.cpp b/src/VBox/Devices/Trace/DrvIfsTrace.cpp
new file mode 100644
index 00000000..474ed13f
--- /dev/null
+++ b/src/VBox/Devices/Trace/DrvIfsTrace.cpp
@@ -0,0 +1,199 @@
+/* $Id: DrvIfsTrace.cpp $ */
+/** @file
+ * VBox interface callback tracing driver.
+ */
+
+/*
+ * Copyright (C) 2020-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_MISC
+#include <VBox/log.h>
+#include <VBox/version.h>
+
+#include <iprt/errcore.h>
+#include <iprt/buildconfig.h>
+#include <iprt/tracelog.h>
+#include <iprt/uuid.h>
+
+#include "VBoxDD.h"
+#include "DrvIfsTraceInternal.h"
+
+
+/*
+ *
+ * IBase Implementation.
+ *
+ */
+
+
+static DECLCALLBACK(void *) drvIfTraceIBase_QueryInterface(PPDMIBASE pInterface, const char *pszIID)
+{
+ PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
+ PDRVIFTRACE pThis = PDMINS_2_DATA(pDrvIns, PDRVIFTRACE);
+
+ PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
+ if (pThis->pISerialConBelow)
+ PDMIBASE_RETURN_INTERFACE(pszIID, PDMISERIALCONNECTOR, &pThis->ISerialConnector);
+ if (pThis->pISerialPortAbove)
+ PDMIBASE_RETURN_INTERFACE(pszIID, PDMISERIALPORT, &pThis->ISerialPort);
+
+ return NULL;
+}
+
+
+/*
+ *
+ * PDMDRVREG Methods
+ *
+ */
+
+/**
+ * Destroys a interface filter driver instance.
+ *
+ * @copydoc FNPDMDRVDESTRUCT
+ */
+static DECLCALLBACK(void) drvIfTrace_Destruct(PPDMDRVINS pDrvIns)
+{
+ PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
+ PDRVIFTRACE pThis = PDMINS_2_DATA(pDrvIns, PDRVIFTRACE);
+ LogFlow(("%s: iInstance=%d\n", __FUNCTION__, pDrvIns->iInstance));
+
+ if (pThis->hTraceLog != NIL_RTTRACELOGWR)
+ {
+ RTTraceLogWrDestroy(pThis->hTraceLog);
+ pThis->hTraceLog = NIL_RTTRACELOGWR;
+ }
+
+ if (pThis->pszTraceFilePath)
+ {
+ PDMDrvHlpMMHeapFree(pDrvIns, pThis->pszTraceFilePath);
+ pThis->pszTraceFilePath = NULL;
+ }
+}
+
+
+/**
+ * Construct a interface filter driver instance.
+ *
+ * @copydoc FNPDMDRVCONSTRUCT
+ */
+static DECLCALLBACK(int) drvIfTrace_Construct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
+{
+ PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
+ PDRVIFTRACE pThis = PDMINS_2_DATA(pDrvIns, PDRVIFTRACE);
+ PCPDMDRVHLPR3 pHlp = pDrvIns->pHlpR3;
+
+
+ /*
+ * Initialize the instance data.
+ */
+ pThis->pDrvIns = pDrvIns;
+ pThis->hTraceLog = NIL_RTTRACELOGWR;
+ pDrvIns->IBase.pfnQueryInterface = drvIfTraceIBase_QueryInterface;
+
+ drvIfsTrace_SerialIfInit(pThis);
+
+ /*
+ * Validate and read config.
+ */
+ PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns, "TraceFilePath|", "");
+
+ int rc = pHlp->pfnCFGMQueryStringAlloc(pCfg, "TraceFilePath", &pThis->pszTraceFilePath);
+ AssertLogRelRCReturn(rc, rc);
+
+ /* Try to create a file based trace log. */
+ rc = RTTraceLogWrCreateFile(&pThis->hTraceLog, RTBldCfgVersion(), pThis->pszTraceFilePath);
+ AssertLogRelRCReturn(rc, rc);
+
+ /*
+ * Query interfaces from the driver/device above us.
+ */
+ pThis->pISerialPortAbove = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMISERIALPORT);
+
+ /*
+ * Attach driver below us.
+ */
+ PPDMIBASE pIBaseBelow;
+ rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pIBaseBelow);
+ AssertLogRelRCReturn(rc, rc);
+
+ pThis->pISerialConBelow = PDMIBASE_QUERY_INTERFACE(pIBaseBelow, PDMISERIALCONNECTOR);
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Storage filter driver registration record.
+ */
+const PDMDRVREG g_DrvIfTrace =
+{
+ /* u32Version */
+ PDM_DRVREG_VERSION,
+ /* szName */
+ "IfTrace",
+ /* szRCMod */
+ "",
+ /* szR0Mod */
+ "",
+ /* pszDescription */
+ "Interface callback tracing driver",
+ /* fFlags */
+ PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
+ /* fClass. */
+ PDM_DRVREG_CLASS_STATUS,
+ /* cMaxInstances */
+ ~0U,
+ /* cbInstance */
+ sizeof(DRVIFTRACE),
+ /* pfnConstruct */
+ drvIfTrace_Construct,
+ /* pfnDestruct */
+ drvIfTrace_Destruct,
+ /* pfnRelocate */
+ NULL,
+ /* pfnIOCtl */
+ NULL,
+ /* pfnPowerOn */
+ NULL,
+ /* pfnReset */
+ NULL,
+ /* pfnSuspend */
+ NULL,
+ /* pfnResume */
+ NULL,
+ /* pfnAttach */
+ NULL,
+ /* pfnDetach */
+ NULL,
+ /* pfnPowerOff */
+ NULL,
+ /* pfnSoftReset */
+ NULL,
+ /* u32EndVersion */
+ PDM_DRVREG_VERSION
+};
+
diff --git a/src/VBox/Devices/Trace/DrvIfsTraceInternal.h b/src/VBox/Devices/Trace/DrvIfsTraceInternal.h
new file mode 100644
index 00000000..a0a1a5db
--- /dev/null
+++ b/src/VBox/Devices/Trace/DrvIfsTraceInternal.h
@@ -0,0 +1,76 @@
+/* $Id: DrvIfsTraceInternal.h $ */
+/** @file
+ * VBox interface callback tracing driver - internal header.
+ */
+
+/*
+ * Copyright (C) 2020-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#ifndef VBOX_INCLUDED_SRC_Trace_DrvIfsTraceInternal_h
+#define VBOX_INCLUDED_SRC_Trace_DrvIfsTraceInternal_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <VBox/vmm/pdmdrv.h>
+#include <VBox/vmm/pdmserialifs.h>
+
+#include <iprt/types.h>
+
+
+/**
+ * Interface Tracing Driver Instance Data.
+ */
+typedef struct DRVIFTRACE
+{
+ /** @name Interfaces exposed by this driver.
+ * @{ */
+ PDMIBASE IBase;
+ PDMISERIALPORT ISerialPort;
+ PDMISERIALCONNECTOR ISerialConnector;
+ /** @} */
+
+ /** @name Interfaces exposed by the driver below us.
+ * @{ */
+ PPDMISERIALCONNECTOR pISerialConBelow;
+ /** @} */
+
+ /** @name Interfaces exposed by the driver/device above us.
+ * @{ */
+ PPDMISERIALPORT pISerialPortAbove;
+ /** @} */
+
+ /** PDM device driver instance pointer. */
+ PPDMDRVINS pDrvIns;
+ /** The trace log writer handle. */
+ RTTRACELOGWR hTraceLog;
+ /** Path of the trace log file. */
+ char *pszTraceFilePath;
+
+} DRVIFTRACE;
+/** Pointer to a interface tracing driver instance. */
+typedef DRVIFTRACE *PDRVIFTRACE;
+
+
+DECLHIDDEN(void) drvIfsTrace_SerialIfInit(PDRVIFTRACE pThis);
+
+#endif /* !VBOX_INCLUDED_SRC_Trace_DrvIfsTraceInternal_h */
diff --git a/src/VBox/Devices/Trace/README.txt b/src/VBox/Devices/Trace/README.txt
new file mode 100644
index 00000000..e12efb2a
--- /dev/null
+++ b/src/VBox/Devices/Trace/README.txt
@@ -0,0 +1,32 @@
+/* $Id: README.txt $ */
+Introduction:
+
+ This is a simple tracing driver which hooks into a driver chain and logs all executed callbacks for a particular interface
+ with their parameters.
+ It uses the RTTraceLog API to write the data into a compact binary log file which can be examined using RTTraceLogTool
+ (which is still very basic at this point but will be enhanced when certain features are required).
+
+ Currently implemented interfaces are (implement more on a need basis and add them here):
+ - PDMISERIALPORT and PDMISERIALCONNECTOR
+
+Benefits:
+
+ This driver allows to gather more detailed information about the interaction between devices and attached drivers without
+ the need to add additional debug/logging code. This is especially useful for debugging user reported issues as it can avoid
+ having to send a special testbuil to the user (provided the interfaces are implemented by the trace driver),
+ the user just requires instructions on how to enable the tracing for her particular setup.
+
+ Later on this might also come in handy for a driver testbench because it allows recording the interaction from a complicated setup and
+ allows replaying it in a more controlled/compact environment for unit testing or fuzzing.
+
+Setup:
+
+ To inject the driver into an existing driver chain the PDM driver transformations feature is used.
+ The following example injects the trace driver right before every instance of the "Host Serial" driver:
+
+ VBoxManage setextradata <VM name> "VBoxInternal/PDM/DriverTransformations/SerialTrace/AboveDriver" "Host Serial"
+ VBoxManage setextradata <VM name> "VBoxInternal/PDM/DriverTransformations/SerialTrace/AttachedDriver/Config/TraceFilePath" "<trace/log/file/path>"
+ VBoxManage setextradata <VM name> "VBoxInternal/PDM/DriverTransformations/SerialTrace/AttachedDriver/Driver" "IfTrace"/>
+
+
+