diff options
Diffstat (limited to 'src/VBox/Runtime/common/log/tracelogwriter.cpp')
-rw-r--r-- | src/VBox/Runtime/common/log/tracelogwriter.cpp | 955 |
1 files changed, 955 insertions, 0 deletions
diff --git a/src/VBox/Runtime/common/log/tracelogwriter.cpp b/src/VBox/Runtime/common/log/tracelogwriter.cpp new file mode 100644 index 00000000..43ff267c --- /dev/null +++ b/src/VBox/Runtime/common/log/tracelogwriter.cpp @@ -0,0 +1,955 @@ +/* $Id: tracelogwriter.cpp $ */ +/** @file + * IPRT - Trace log writer. + */ + +/* + * Copyright (C) 2018-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "internal/iprt.h" +#include <iprt/formats/tracelog.h> +#include <iprt/tracelog.h> + + +#include <iprt/avl.h> +#include <iprt/asm.h> +#include <iprt/assert.h> +#include <iprt/err.h> +#include <iprt/file.h> +#include <iprt/log.h> +#include <iprt/mem.h> +#include <iprt/semaphore.h> +#include <iprt/string.h> +#include <iprt/tcp.h> +#include <iprt/time.h> + +#include "internal/magics.h" + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ + + +/** + * Trace log writer internal event descriptor. + */ +typedef struct RTTRACELOGWREVTDESC +{ + /** AVL node core data */ + AVLPVNODECORE Core; + /** The ID associated with this event descriptor. */ + uint32_t u32Id; + /** Overall size of the event data not counting variable raw data items. */ + size_t cbEvtData; + /** Number of non static raw binary items in the descriptor. */ + uint32_t cRawDataNonStatic; + /** Pointer to the scratch event data buffer when adding events. */ + uint8_t *pbEvt; + /** Embedded event descriptor. */ + RTTRACELOGEVTDESC EvtDesc; + /** Array of event item descriptors, variable in size. */ + RTTRACELOGEVTITEMDESC aEvtItemDesc[1]; +} RTTRACELOGWREVTDESC; +/** Pointer to internal trace log writer event descriptor. */ +typedef RTTRACELOGWREVTDESC *PRTTRACELOGWREVTDESC; +/** Pointer to const internal trace log writer event descriptor. */ +typedef const RTTRACELOGWREVTDESC *PCRTTRACELOGWREVTDESC; + + +/** + * Trace log writer instance data. + */ +typedef struct RTTRACELOGWRINT +{ + /** Magic for identification. */ + uint32_t u32Magic; + /** Stream out callback. */ + PFNRTTRACELOGWRSTREAM pfnStreamOut; + /** Stream close callback .*/ + PFNRTTRACELOGSTREAMCLOSE pfnStreamClose; + /** Opaque user data passed to the stream callback. */ + void *pvUser; + /** Mutex protecting the structure. */ + RTSEMMUTEX hMtx; + /** Next sequence number to use. */ + volatile uint64_t u64SeqNoNext; + /** Pointer to the description if set. */ + char *pszDesc; + /** AVL tree root for event descriptor lookups. */ + AVLPVTREE pTreeEvtDescs; + /** Number of event descriptors known. */ + uint32_t cEvtDescs; +} RTTRACELOGWRINT; +/** Pointer to a trace log writer instance. */ +typedef RTTRACELOGWRINT *PRTTRACELOGWRINT; + + +/** + * The TCP server/client state. + */ +typedef struct RTTRACELOGWRTCP +{ + /** Flag whether this is a server or client instance. */ + bool fIsServer; + /** The TCP socket handle for the connection. */ + RTSOCKET hSock; + /** The TCP server. */ + PRTTCPSERVER pTcpSrv; +} RTTRACELOGWRTCP; +/** Pointer to a TCP server/client state. */ +typedef RTTRACELOGWRTCP *PRTTRACELOGWRTCP; + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ + + +/** + * Returns the size required for the internal event descriptor representation. + * + * @returns Number of bytes required. + * @param pEvtDesc Pointer to the external descriptor. + */ +static size_t rtTraceLogWrtEvtDescGetSz(PCRTTRACELOGEVTDESC pEvtDesc) +{ + size_t cbAlloc = RT_UOFFSETOF_DYN(RTTRACELOGWREVTDESC, aEvtItemDesc[pEvtDesc->cEvtItems]); + + cbAlloc += strlen(pEvtDesc->pszId) + 1; + if (pEvtDesc->pszDesc) + cbAlloc += strlen(pEvtDesc->pszDesc) + 1; + for (unsigned i = 0; i < pEvtDesc->cEvtItems; i++) + { + PCRTTRACELOGEVTITEMDESC pEvtItemDesc = &pEvtDesc->paEvtItemDesc[i]; + + cbAlloc += strlen(pEvtItemDesc->pszName) + 1; + if (pEvtItemDesc->pszDesc) + cbAlloc += strlen(pEvtItemDesc->pszDesc) + 1; + } + + return cbAlloc; +} + + +/** + * Copies a string into a supplied buffer assigning the start to the given string pointer. + * + * @returns Pointer to the memory after the destination buffer holding the string. + * @param ppsz Where to store the pointer to the start of the string. + * @param pszTo Where to copy the string including the temrinator to. + * @param pszFrom The string to copy. + */ +DECLINLINE(char *) rtTraceLogWrCopyStr(const char **ppsz, char *pszTo, const char *pszFrom) +{ + *ppsz = pszTo; + size_t cchCopy = strlen(pszFrom) + 1; + memcpy(pszTo, pszFrom, cchCopy); + + return pszTo + cchCopy; +} + + +/** + * Converts the type enum to the size of the the event item data in bytes. + * + * @returns Event item data size in bytes. + * @param pEvtItemDesc The event item descriptor. + */ +static size_t rtTraceLogWrGetEvtItemDataSz(PCRTTRACELOGEVTITEMDESC pEvtItemDesc) +{ + size_t cb = 0; + + switch (pEvtItemDesc->enmType) + { + case RTTRACELOGTYPE_BOOL: + case RTTRACELOGTYPE_UINT8: + case RTTRACELOGTYPE_INT8: + { + cb = 1; + break; + } + case RTTRACELOGTYPE_UINT16: + case RTTRACELOGTYPE_INT16: + { + cb = 2; + break; + } + case RTTRACELOGTYPE_UINT32: + case RTTRACELOGTYPE_INT32: + case RTTRACELOGTYPE_FLOAT32: + { + cb = 4; + break; + } + case RTTRACELOGTYPE_UINT64: + case RTTRACELOGTYPE_INT64: + case RTTRACELOGTYPE_FLOAT64: + { + cb = 8; + break; + } + case RTTRACELOGTYPE_RAWDATA: + { + cb = pEvtItemDesc->cbRawData; + break; + } + case RTTRACELOGTYPE_POINTER: + { + cb = sizeof(uintptr_t); + break; + } + case RTTRACELOGTYPE_SIZE: + { + cb = sizeof(size_t); + break; + } + default: + AssertMsgFailed(("Invalid type %d\n", pEvtItemDesc->enmType)); + } + + return cb; +} + + +/** + * Converts API severity enum to the stream representation. + * + * @returns Stream representation of the severity. + * @param enmSeverity The API severity. + */ +static uint32_t rtTraceLogWrConvSeverityToStream(RTTRACELOGEVTSEVERITY enmSeverity) +{ + switch (enmSeverity) + { + case RTTRACELOGEVTSEVERITY_INFO: + return TRACELOG_EVTDESC_SEVERITY_INFO; + case RTTRACELOGEVTSEVERITY_WARNING: + return TRACELOG_EVTDESC_SEVERITY_WARNING; + case RTTRACELOGEVTSEVERITY_ERROR: + return TRACELOG_EVTDESC_SEVERITY_ERROR; + case RTTRACELOGEVTSEVERITY_FATAL: + return TRACELOG_EVTDESC_SEVERITY_FATAL; + case RTTRACELOGEVTSEVERITY_DEBUG: + return TRACELOG_EVTDESC_SEVERITY_DEBUG; + default: + AssertMsgFailed(("Invalid severity %d\n", enmSeverity)); + } + + /* Should not happen. */ + return TRACELOG_EVTDESC_SEVERITY_FATAL; +} + + +/** + * Converts API type enum to the stream representation. + * + * @returns Stream representation of the type. + * @param enmType The API type. + */ +static uint32_t rtTraceLogWrConvTypeToStream(RTTRACELOGTYPE enmType) +{ + switch (enmType) + { + case RTTRACELOGTYPE_BOOL: + return TRACELOG_EVTITEMDESC_TYPE_BOOL; + case RTTRACELOGTYPE_UINT8: + return TRACELOG_EVTITEMDESC_TYPE_UINT8; + case RTTRACELOGTYPE_INT8: + return TRACELOG_EVTITEMDESC_TYPE_INT8; + case RTTRACELOGTYPE_UINT16: + return TRACELOG_EVTITEMDESC_TYPE_UINT16; + case RTTRACELOGTYPE_INT16: + return TRACELOG_EVTITEMDESC_TYPE_INT16; + case RTTRACELOGTYPE_UINT32: + return TRACELOG_EVTITEMDESC_TYPE_UINT32; + case RTTRACELOGTYPE_INT32: + return TRACELOG_EVTITEMDESC_TYPE_INT32; + case RTTRACELOGTYPE_UINT64: + return TRACELOG_EVTITEMDESC_TYPE_UINT64; + case RTTRACELOGTYPE_INT64: + return TRACELOG_EVTITEMDESC_TYPE_INT64; + case RTTRACELOGTYPE_FLOAT32: + return TRACELOG_EVTITEMDESC_TYPE_FLOAT32; + case RTTRACELOGTYPE_FLOAT64: + return TRACELOG_EVTITEMDESC_TYPE_FLOAT64; + case RTTRACELOGTYPE_RAWDATA: + return TRACELOG_EVTITEMDESC_TYPE_RAWDATA; + case RTTRACELOGTYPE_POINTER: + return TRACELOG_EVTITEMDESC_TYPE_POINTER; + case RTTRACELOGTYPE_SIZE: + return TRACELOG_EVTITEMDESC_TYPE_SIZE; + default: + AssertMsgFailed(("Invalid type %d\n", enmType)); + } + + /* Should not happen. */ + return RTTRACELOGTYPE_RAWDATA; +} + + +/** + * Initializes the internal representation of the event descriptor from the given one. + * + * @returns Pointer to the internal instance of the event descriptor. + * NULL if out of memory. + * @param pEvtDesc Pointer to the external descriptor. + */ +static PRTTRACELOGWREVTDESC rtTraceLogWrEvtDescInit(PCRTTRACELOGEVTDESC pEvtDesc) +{ + size_t cbAlloc = rtTraceLogWrtEvtDescGetSz(pEvtDesc); + size_t cbEvtData = 0; + PRTTRACELOGWREVTDESC pEvtDescInt = (PRTTRACELOGWREVTDESC)RTMemAllocZ(cbAlloc); + if (RT_LIKELY(pEvtDescInt)) + { + char *pszStrSpace = (char *)&pEvtDescInt->aEvtItemDesc[pEvtDesc->cEvtItems]; /* Get space for strings after the descriptor. */ + + pEvtDescInt->EvtDesc.enmSeverity = pEvtDesc->enmSeverity; + pEvtDescInt->EvtDesc.cEvtItems = pEvtDesc->cEvtItems; + pEvtDescInt->EvtDesc.paEvtItemDesc = &pEvtDescInt->aEvtItemDesc[0]; + + /* Copy ID and optional description over. */ + pszStrSpace = rtTraceLogWrCopyStr(&pEvtDescInt->EvtDesc.pszId, pszStrSpace, pEvtDesc->pszId); + if (pEvtDesc->pszDesc) + pszStrSpace = rtTraceLogWrCopyStr(&pEvtDescInt->EvtDesc.pszDesc, pszStrSpace, pEvtDesc->pszDesc); + + /* Go through the event item descriptors and initialize them too. */ + for (unsigned i = 0; i < pEvtDesc->cEvtItems; i++) + { + PCRTTRACELOGEVTITEMDESC pEvtItemDescFrom = &pEvtDesc->paEvtItemDesc[i]; + PRTTRACELOGEVTITEMDESC pEvtItemDescTo = &pEvtDescInt->aEvtItemDesc[i]; + + pEvtItemDescTo->enmType = pEvtItemDescFrom->enmType; + pEvtItemDescTo->cbRawData = pEvtItemDescFrom->cbRawData; + + cbEvtData += rtTraceLogWrGetEvtItemDataSz(pEvtItemDescFrom); + if ( pEvtItemDescTo->enmType == RTTRACELOGTYPE_RAWDATA + && !pEvtItemDescFrom->cbRawData) + pEvtDescInt->cRawDataNonStatic++; + + pszStrSpace = rtTraceLogWrCopyStr(&pEvtItemDescTo->pszName, pszStrSpace, pEvtItemDescFrom->pszName); + if (pEvtItemDescFrom->pszDesc) + pszStrSpace = rtTraceLogWrCopyStr(&pEvtItemDescTo->pszDesc, pszStrSpace, pEvtItemDescFrom->pszDesc); + } + + pEvtDescInt->cbEvtData = cbEvtData; + if (cbEvtData) + { + pEvtDescInt->pbEvt = (uint8_t *)RTMemAllocZ(cbEvtData); + if (!pEvtDescInt->pbEvt) + { + RTMemFree(pEvtDescInt); + pEvtDescInt = NULL; + } + } + } + + return pEvtDescInt; +} + + +/** + * Wrapper around the stream callback. + * + * @returns IPRT status code returned by the stream callback. + * @param pThis The trace log writer instance. + * @param pvBuf The data to stream. + * @param cbBuf Number of bytes to stream. + */ +DECLINLINE(int) rtTraceLogWrStream(PRTTRACELOGWRINT pThis, const void *pvBuf, size_t cbBuf) +{ + return pThis->pfnStreamOut(pThis->pvUser, pvBuf, cbBuf, NULL); +} + + +/** + * Initializes a given event structure. + * + * @returns Total number of bytes for the event data associated with this event. + * @param pEvt Pointer to the event structure to initialise. + * @param pEvtDescInt The internal event descriptor to format the data accordingly to. + * @param fFlags Flags to use for this event. + * @param uGrpId The group ID to identify grouped events. + * @param uParentGrpId The parent group ID. + * @param pacbRawData Array of raw data size indicators. + */ +DECLINLINE(size_t) rtTraceLogWrEvtInit(PTRACELOGEVT pEvt, + PRTTRACELOGWREVTDESC pEvtDescInt, uint32_t fFlags, + RTTRACELOGEVTGRPID uGrpId, RTTRACELOGEVTGRPID uParentGrpId, + size_t *pacbRawData) +{ + uint32_t cbEvtData = (uint32_t)pEvtDescInt->cbEvtData; + for (unsigned i = 0; i < pEvtDescInt->cRawDataNonStatic; i++) + cbEvtData += (uint32_t)pacbRawData[i]; + + uint32_t fEvtFlags = 0; + if (fFlags & RTTRACELOG_WR_ADD_EVT_F_GRP_START) + fEvtFlags |= TRACELOG_EVT_F_GRP_START; + if (fFlags & RTTRACELOG_WR_ADD_EVT_F_GRP_FINISH) + fEvtFlags |= TRACELOG_EVT_F_GRP_END; + + memcpy(&pEvt->szMagic[0], TRACELOG_EVT_MAGIC, sizeof(pEvt->szMagic)); + pEvt->u64Ts = RTTimeNanoTS(); + pEvt->u64EvtGrpId = uGrpId; + pEvt->u64EvtParentGrpId = uParentGrpId; + pEvt->fFlags = fEvtFlags; + pEvt->u32EvtDescId = pEvtDescInt->u32Id; + pEvt->cbEvtData = cbEvtData; + pEvt->cRawEvtDataSz = pEvtDescInt->cRawDataNonStatic; + + return cbEvtData; +} + + +/** + * Streams the whole event including associated data. + * + * @returns IPRT status code. + * @param pThis The trace log writer instance. + * @param pEvt Pointer to the initialised event structure. + * @param pvEvtData The raw event data. + * @param cbEvtData Size of the event data. + * @param pacbRawData Pointer to the array of size indicators for non static + * raw data in the event data stream. + */ +DECLINLINE(int) rtTraceLogWrEvtStream(PRTTRACELOGWRINT pThis, PTRACELOGEVT pEvt, const void *pvEvtData, + size_t cbEvtData, size_t *pacbRawData) +{ + /** @todo Get rid of locking. */ + int rc = RTSemMutexRequest(pThis->hMtx, RT_INDEFINITE_WAIT); + if (RT_SUCCESS(rc)) + { + pEvt->u64SeqNo = ASMAtomicIncU64(&pThis->u64SeqNoNext); + + /* Write the data out. */ + rc = rtTraceLogWrStream(pThis, pEvt, sizeof(TRACELOGEVT)); + if ( RT_SUCCESS(rc) + && pEvt->cRawEvtDataSz) + rc = rtTraceLogWrStream(pThis, pacbRawData, pEvt->cRawEvtDataSz * sizeof(size_t)); + if ( RT_SUCCESS(rc) + && cbEvtData) + rc = rtTraceLogWrStream(pThis, pvEvtData, cbEvtData); + RTSemMutexRelease(pThis->hMtx); + } + + return rc; +} + + +/** + * Returns the intenral event descriptor for the given event descriptor. + * + * @returns Pointer to the internal event descriptor or NULL if not found. + * @param pThis The trace log writer instance. + * @param pEvtDesc The event descriptor to search for. + */ +DECLINLINE(PRTTRACELOGWREVTDESC) rtTraceLogWrEvtDescGetInternal(PRTTRACELOGWRINT pThis, + PCRTTRACELOGEVTDESC pEvtDesc) +{ + int rc = RTSemMutexRequest(pThis->hMtx, RT_INDEFINITE_WAIT); + if (RT_SUCCESS(rc)) + { + PRTTRACELOGWREVTDESC pEvtDescInt = (PRTTRACELOGWREVTDESC)RTAvlPVGet(&pThis->pTreeEvtDescs, (void *)pEvtDesc); + RTSemMutexRelease(pThis->hMtx); + return pEvtDescInt; + } + + return NULL; +} + + +/** + * Initializes the trace log. + * + * @returns IPRT status code. + * @param pThis The trace log writer instance. + * @param pszDesc The description to use. + */ +static int rtTraceLogWrInit(PRTTRACELOGWRINT pThis, const char *pszDesc) +{ + /* Start by assembling the header. */ + TRACELOGHDR Hdr; + + RT_ZERO(Hdr); + memcpy(&Hdr.szMagic[0], TRACELOG_HDR_MAGIC, sizeof(Hdr.szMagic)); + Hdr.u32Endianess = TRACELOG_HDR_ENDIANESS; /* Endianess marker. */ + Hdr.u32Version = TRACELOG_VERSION; + Hdr.fFlags = 0; + Hdr.cbStrDesc = pszDesc ? (uint32_t)strlen(pszDesc) : 0; + Hdr.cbTypePtr = sizeof(uintptr_t); + Hdr.cbTypeSize = sizeof(size_t); + Hdr.u64TsStart = RTTimeNanoTS(); + int rc = rtTraceLogWrStream(pThis, &Hdr, sizeof(Hdr)); + if ( RT_SUCCESS(rc) + && pThis->pszDesc) + rc = rtTraceLogWrStream(pThis, pszDesc, Hdr.cbStrDesc); + + return rc; +} + + +static DECLCALLBACK(int) rtTraceLogWrCheckForOverlappingIds(PAVLPVNODECORE pCore, void *pvParam) +{ + PCRTTRACELOGEVTDESC pEvtDesc = (PCRTTRACELOGEVTDESC)pvParam; + PRTTRACELOGWREVTDESC pEvtDescInt = (PRTTRACELOGWREVTDESC)pCore; + + if (!RTStrCmp(pEvtDesc->pszId, pEvtDescInt->EvtDesc.pszId)) + return VERR_ALREADY_EXISTS; + + return VINF_SUCCESS; +} + + +static DECLCALLBACK(int) rtTraceLogWrEvtDescsDestroy(PAVLPVNODECORE pCore, void *pvParam) +{ + PRTTRACELOGWREVTDESC pEvtDesc = (PRTTRACELOGWREVTDESC)pCore; + RT_NOREF(pvParam); + + RTMemFree(pEvtDesc->pbEvt); + RTMemFree(pEvtDesc); + return VINF_SUCCESS; +} + + +/** + * Adds a new event descriptor to the trace log. + * + * @returns IPRT status code. + * @param pThis The trace log writer instance. + * @param pEvtDesc The event descriptor to add. + * @param ppEvtDescInt Where to store the pointer to the internal + * event descriptor - optional. + */ +static int rtTraceLogWrEvtDescAdd(PRTTRACELOGWRINT pThis, PCRTTRACELOGEVTDESC pEvtDesc, + PRTTRACELOGWREVTDESC *ppEvtDescInt) +{ + int rc = RTSemMutexRequest(pThis->hMtx, RT_INDEFINITE_WAIT); + if (RT_SUCCESS(rc)) + { + PRTTRACELOGWREVTDESC pEvtDescInt = (PRTTRACELOGWREVTDESC)RTAvlPVGet(&pThis->pTreeEvtDescs, (void *)pEvtDesc); + if (!pEvtDescInt) + { + rc = RTAvlPVDoWithAll(&pThis->pTreeEvtDescs, true, rtTraceLogWrCheckForOverlappingIds, (void *)pEvtDesc); + if (RT_SUCCESS(rc)) + { + pEvtDescInt = rtTraceLogWrEvtDescInit(pEvtDesc); + if (RT_LIKELY(pEvtDescInt)) + { + pEvtDescInt->Core.Key = (void *)pEvtDesc; + pEvtDescInt->u32Id = pThis->cEvtDescs++; + bool fIns = RTAvlPVInsert(&pThis->pTreeEvtDescs, &pEvtDescInt->Core); + Assert(fIns); RT_NOREF(fIns); + } + else + rc = VERR_NO_MEMORY; + + if (RT_SUCCESS(rc)) + { + TRACELOGEVTDESC EvtDesc; + + RT_ZERO(EvtDesc); + memcpy(&EvtDesc.szMagic[0], TRACELOG_EVTDESC_MAGIC, sizeof(EvtDesc.szMagic)); + EvtDesc.u32Id = pEvtDescInt->u32Id; + EvtDesc.u32Severity = rtTraceLogWrConvSeverityToStream(pEvtDescInt->EvtDesc.enmSeverity); + EvtDesc.cbStrId = (uint32_t)strlen(pEvtDescInt->EvtDesc.pszId); + EvtDesc.cbStrDesc = pEvtDescInt->EvtDesc.pszDesc ? (uint32_t)strlen(pEvtDescInt->EvtDesc.pszDesc) : 0; + EvtDesc.cEvtItems = pEvtDescInt->EvtDesc.cEvtItems; + rc = rtTraceLogWrStream(pThis, &EvtDesc, sizeof(EvtDesc)); + if (RT_SUCCESS(rc)) + rc = rtTraceLogWrStream(pThis, pEvtDescInt->EvtDesc.pszId, EvtDesc.cbStrId); + if ( RT_SUCCESS(rc) + && pEvtDescInt->EvtDesc.pszDesc) + rc = rtTraceLogWrStream(pThis, pEvtDescInt->EvtDesc.pszDesc, EvtDesc.cbStrDesc); + if (RT_SUCCESS(rc)) + { + /* Go through the event items. */ + for (unsigned idxEvtItem = 0; idxEvtItem < EvtDesc.cEvtItems && RT_SUCCESS(rc); idxEvtItem++) + { + PCRTTRACELOGEVTITEMDESC pEvtItemDesc = &pEvtDescInt->EvtDesc.paEvtItemDesc[idxEvtItem]; + TRACELOGEVTITEMDESC EvtItemDesc; + + RT_ZERO(EvtItemDesc); + memcpy(&EvtItemDesc.szMagic[0], TRACELOG_EVTITEMDESC_MAGIC, sizeof(EvtItemDesc.szMagic)); + EvtItemDesc.cbStrName = (uint32_t)strlen(pEvtItemDesc->pszName); + EvtItemDesc.cbStrDesc = pEvtItemDesc->pszDesc ? (uint32_t)strlen(pEvtItemDesc->pszDesc) : 0; + EvtItemDesc.u32Type = rtTraceLogWrConvTypeToStream(pEvtItemDesc->enmType); + EvtItemDesc.cbRawData = (uint32_t)pEvtItemDesc->cbRawData; + rc = rtTraceLogWrStream(pThis, &EvtItemDesc, sizeof(EvtItemDesc)); + if (RT_SUCCESS(rc)) + rc = rtTraceLogWrStream(pThis, pEvtItemDesc->pszName, EvtItemDesc.cbStrName); + if ( RT_SUCCESS(rc) + && pEvtItemDesc->pszDesc) + rc = rtTraceLogWrStream(pThis, pEvtItemDesc->pszDesc, EvtItemDesc.cbStrDesc); + } + } + } + } + + if ( RT_SUCCESS(rc) + && ppEvtDescInt) + *ppEvtDescInt = pEvtDescInt; + } + else + rc = VERR_ALREADY_EXISTS; + RTSemMutexRelease(pThis->hMtx); + } + + return rc; +} + + +/** + * Fills a given buffer with the given event data as described in the given descriptor. + * + * @returns IPRT status code. + * @param pThis The trace log writer instance. + * @param pEvtDescInt Pointer to the internal event descriptor. + * @param pb The byte buffer to fill. + * @param va The event data. + */ +static int rtTraceLogWrEvtFill(PRTTRACELOGWRINT pThis, PRTTRACELOGWREVTDESC pEvtDescInt, uint8_t *pb, va_list va) +{ + int rc = VINF_SUCCESS; + uint8_t *pbCur = pb; + + RT_NOREF(pThis); + + for (unsigned i = 0; i < pEvtDescInt->EvtDesc.cEvtItems; i++) + { + PCRTTRACELOGEVTITEMDESC pEvtItemDesc = &pEvtDescInt->EvtDesc.paEvtItemDesc[i]; + + size_t cbItem = rtTraceLogWrGetEvtItemDataSz(pEvtItemDesc); + switch (cbItem) + { + case sizeof(uint8_t): + *pbCur++ = va_arg(va, /*uint8_t*/ unsigned); + break; + case sizeof(uint16_t): + *(uint16_t *)pbCur = va_arg(va, /*uint16_t*/ unsigned); + pbCur += sizeof(uint16_t); + break; + case sizeof(uint32_t): + *(uint32_t *)pbCur = va_arg(va, uint32_t); + pbCur += sizeof(uint32_t); + break; + case sizeof(uint64_t): + *(uint64_t *)pbCur = va_arg(va, uint64_t); + pbCur += sizeof(uint64_t); + break; + default: + /* Some raw data item. */ + Assert(pEvtItemDesc->enmType == RTTRACELOGTYPE_RAWDATA); + if (cbItem != 0) + { + /* Static raw data. */ + void *pvSrc = va_arg(va, void *); + memcpy(pbCur, pvSrc, cbItem); + pbCur += cbItem; + } + else + { + AssertMsgFailed(("Not implemented!\n")); + rc = VERR_NOT_IMPLEMENTED; + } + } + } + + return rc; +} + + +/** + * @copydoc FNRTTRACELOGWRSTREAM + */ +static DECLCALLBACK(int) rtTraceLogWrFileStream(void *pvUser, const void *pvBuf, size_t cbBuf, size_t *pcbWritten) +{ + RTFILE hFile = (RTFILE)pvUser; + return RTFileWrite(hFile, pvBuf, cbBuf, pcbWritten); +} + + +/** + * @copydoc FNRTTRACELOGSTREAMCLOSE + */ +static DECLCALLBACK(int) rtTraceLogWrFileStreamClose(void *pvUser) +{ + RTFILE hFile = (RTFILE)pvUser; + return RTFileClose(hFile); +} + + +RTDECL(int) RTTraceLogWrCreate(PRTTRACELOGWR phTraceLogWr, const char *pszDesc, + PFNRTTRACELOGWRSTREAM pfnStreamOut, + PFNRTTRACELOGSTREAMCLOSE pfnStreamClose, void *pvUser) +{ + AssertPtrReturn(phTraceLogWr, VERR_INVALID_POINTER); + AssertPtrReturn(pfnStreamOut, VERR_INVALID_POINTER); + AssertPtrReturn(pfnStreamClose, VERR_INVALID_POINTER); + int rc = VINF_SUCCESS; + PRTTRACELOGWRINT pThis = (PRTTRACELOGWRINT)RTMemAllocZ(sizeof(*pThis)); + if (pThis) + { + rc = RTSemMutexCreate(&pThis->hMtx); + if (RT_SUCCESS(rc)) + { + pThis->u32Magic = RTTRACELOGWR_MAGIC; + pThis->pfnStreamOut = pfnStreamOut; + pThis->pfnStreamClose = pfnStreamClose; + pThis->pvUser = pvUser; + pThis->u64SeqNoNext = 0; + pThis->pTreeEvtDescs = NULL; + pThis->cEvtDescs = 0; + rc = rtTraceLogWrInit(pThis, pszDesc); + if (RT_SUCCESS(rc)) + { + *phTraceLogWr = pThis; + return VINF_SUCCESS; + } + } + RTMemFree(pThis); + } + else + rc = VERR_NO_MEMORY; + + return rc; +} + + +RTDECL(int) RTTraceLogWrCreateFile(PRTTRACELOGWR phTraceLogWr, const char *pszDesc, + const char *pszFilename) +{ + AssertPtrReturn(phTraceLogWr, VERR_INVALID_POINTER); + AssertPtrReturn(pszFilename, VERR_INVALID_POINTER); + + RTFILE hFile = NIL_RTFILE; + int rc = RTFileOpen(&hFile, pszFilename, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE); + if (RT_SUCCESS(rc)) + { + rc = RTTraceLogWrCreate(phTraceLogWr, pszDesc, rtTraceLogWrFileStream, + rtTraceLogWrFileStreamClose, hFile); + if (RT_FAILURE(rc)) + { + RTFileClose(hFile); + RTFileDelete(pszFilename); + } + } + + return rc; +} + + +/** + * @copydoc FNRTTRACELOGWRSTREAM + */ +static DECLCALLBACK(int) rtTraceLogWrTcpStream(void *pvUser, const void *pvBuf, size_t cbBuf, size_t *pcbWritten) +{ + PRTTRACELOGWRTCP pTraceLogTcp = (PRTTRACELOGWRTCP)pvUser; + int rc = RTTcpWrite(pTraceLogTcp->hSock, pvBuf, cbBuf); + if ( RT_SUCCESS(rc) + && pcbWritten) + *pcbWritten = cbBuf; + + return rc; +} + + +/** + * @copydoc FNRTTRACELOGSTREAMCLOSE + */ +static DECLCALLBACK(int) rtTraceLogWrTcpStreamClose(void *pvUser) +{ + PRTTRACELOGWRTCP pTraceLogTcp = (PRTTRACELOGWRTCP)pvUser; + if (pTraceLogTcp->fIsServer) + { + RTTcpServerDisconnectClient2(pTraceLogTcp->hSock); + RTTcpServerDestroy(pTraceLogTcp->pTcpSrv); + } + else + RTTcpClientClose(pTraceLogTcp->hSock); + + RTMemFree(pTraceLogTcp); + return VINF_SUCCESS; +} + + +RTDECL(int) RTTraceLogWrCreateTcpServer(PRTTRACELOGWR phTraceLogWr, const char *pszDesc, + const char *pszListen, unsigned uPort) +{ + int rc = VINF_SUCCESS; + PRTTRACELOGWRTCP pTraceLogTcp = (PRTTRACELOGWRTCP)RTMemAllocZ(sizeof(*pTraceLogTcp)); + if (RT_LIKELY(pTraceLogTcp)) + { + pTraceLogTcp->fIsServer = true; + + rc = RTTcpServerCreateEx(pszListen, uPort, &pTraceLogTcp->pTcpSrv); + if (RT_SUCCESS(rc)) + { + rc = RTTcpServerListen2(pTraceLogTcp->pTcpSrv, &pTraceLogTcp->hSock); + if (RT_SUCCESS(rc)) + { + rc = RTTraceLogWrCreate(phTraceLogWr, pszDesc, rtTraceLogWrTcpStream, + rtTraceLogWrTcpStreamClose, pTraceLogTcp); + if (RT_SUCCESS(rc)) + return VINF_SUCCESS; + + RTTcpServerDisconnectClient2(pTraceLogTcp->hSock); + } + + RTTcpServerDestroy(pTraceLogTcp->pTcpSrv); + } + + RTMemFree(pTraceLogTcp); + } + else + rc = VERR_NO_MEMORY; + + return rc; +} + + +RTDECL(int) RTTraceLogWrCreateTcpClient(PRTTRACELOGWR phTraceLogWr, const char *pszDesc, + const char *pszAddress, unsigned uPort) +{ + int rc = VINF_SUCCESS; + PRTTRACELOGWRTCP pTraceLogTcp = (PRTTRACELOGWRTCP)RTMemAllocZ(sizeof(*pTraceLogTcp)); + if (RT_LIKELY(pTraceLogTcp)) + { + pTraceLogTcp->fIsServer = false; + + rc = RTTcpClientConnect(pszAddress, uPort, &pTraceLogTcp->hSock); + if (RT_SUCCESS(rc)) + { + rc = RTTraceLogWrCreate(phTraceLogWr, pszDesc, rtTraceLogWrTcpStream, + rtTraceLogWrTcpStreamClose, pTraceLogTcp); + if (RT_SUCCESS(rc)) + return VINF_SUCCESS; + + RTTcpClientClose(pTraceLogTcp->hSock); + } + + RTMemFree(pTraceLogTcp); + } + else + rc = VERR_NO_MEMORY; + + return rc; +} + + +RTDECL(int) RTTraceLogWrDestroy(RTTRACELOGWR hTraceLogWr) +{ + PRTTRACELOGWRINT pThis = hTraceLogWr; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + + pThis->u32Magic = RTTRACELOGWR_MAGIC_DEAD; + pThis->pfnStreamClose(pThis->pvUser); + RTAvlPVDestroy(&pThis->pTreeEvtDescs, rtTraceLogWrEvtDescsDestroy, NULL); + RTSemMutexDestroy(pThis->hMtx); + RTMemFree(pThis); + return VINF_SUCCESS; +} + + +RTDECL(int) RTTraceLogWrAddEvtDesc(RTTRACELOGWR hTraceLogWr, PCRTTRACELOGEVTDESC pEvtDesc) +{ + PRTTRACELOGWRINT pThis = hTraceLogWr; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + AssertPtrReturn(pEvtDesc, VERR_INVALID_POINTER); + + return rtTraceLogWrEvtDescAdd(pThis, pEvtDesc, NULL); +} + + +RTDECL(int) RTTraceLogWrEvtAdd(RTTRACELOGWR hTraceLogWr, PCRTTRACELOGEVTDESC pEvtDesc, uint32_t fFlags, + RTTRACELOGEVTGRPID uGrpId, RTTRACELOGEVTGRPID uParentGrpId, + const void *pvEvtData, size_t *pacbRawData) +{ + PRTTRACELOGWRINT pThis = hTraceLogWr; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + + int rc = VINF_SUCCESS; + PRTTRACELOGWREVTDESC pEvtDescInt = rtTraceLogWrEvtDescGetInternal(pThis, pEvtDesc); + if (RT_UNLIKELY(!pEvtDescInt)) + rc = rtTraceLogWrEvtDescAdd(pThis, pEvtDesc, &pEvtDescInt); + + if ( RT_SUCCESS(rc) + && VALID_PTR(pEvtDescInt)) + { + TRACELOGEVT Evt; + size_t cbEvtData = rtTraceLogWrEvtInit(&Evt, pEvtDescInt, fFlags, uGrpId, uParentGrpId, pacbRawData); + + rc = rtTraceLogWrEvtStream(pThis, &Evt, pvEvtData, cbEvtData, pacbRawData); + } + + return rc; +} + + +RTDECL(int) RTTraceLogWrEvtAddSg(RTTRACELOGWR hTraceLogWr, PCRTTRACELOGEVTDESC pEvtDesc, uint32_t fFlags, + RTTRACELOGEVTGRPID uGrpId, RTTRACELOGEVTGRPID uParentGrpId, + PRTSGBUF *pSgBufEvtData, size_t *pacbRawData) +{ + RT_NOREF(hTraceLogWr, pEvtDesc, fFlags, uGrpId, uParentGrpId, pSgBufEvtData, pacbRawData); + return VERR_NOT_IMPLEMENTED; +} + + +RTDECL(int) RTTraceLogWrEvtAddLV(RTTRACELOGWR hTraceLogWr, PCRTTRACELOGEVTDESC pEvtDesc, uint32_t fFlags, + RTTRACELOGEVTGRPID uGrpId, RTTRACELOGEVTGRPID uParentGrpId, va_list va) +{ + PRTTRACELOGWRINT pThis = hTraceLogWr; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + + int rc = VINF_SUCCESS; + PRTTRACELOGWREVTDESC pEvtDescInt = rtTraceLogWrEvtDescGetInternal(pThis, pEvtDesc); + if (RT_UNLIKELY(!pEvtDescInt)) + rc = rtTraceLogWrEvtDescAdd(pThis, pEvtDesc, &pEvtDescInt); + + if ( RT_SUCCESS(rc) + && VALID_PTR(pEvtDescInt)) + { + TRACELOGEVT Evt; + size_t cbEvtData = rtTraceLogWrEvtInit(&Evt, pEvtDescInt, fFlags, uGrpId, uParentGrpId, NULL); + + if (cbEvtData) + rc = rtTraceLogWrEvtFill(pThis, pEvtDescInt, pEvtDescInt->pbEvt, va); + if (RT_SUCCESS(rc)) + rc = rtTraceLogWrEvtStream(pThis, &Evt, pEvtDescInt->pbEvt, cbEvtData, NULL); + } + + return rc; +} + + +RTDECL(int) RTTraceLogWrEvtAddL(RTTRACELOGWR hTraceLogWr, PCRTTRACELOGEVTDESC pEvtDesc, uint32_t fFlags, + RTTRACELOGEVTGRPID uGrpId, RTTRACELOGEVTGRPID uParentGrpId, ...) +{ + va_list va; + va_start(va, uParentGrpId); + int rc = RTTraceLogWrEvtAddLV(hTraceLogWr, pEvtDesc, fFlags, uGrpId, uParentGrpId, va); + va_end(va); + return rc; +} + |