VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/log/tracelogwriter.cpp

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 33.5 KB
Line 
1/* $Id: tracelogwriter.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * IPRT - Trace log writer.
4 */
5
6/*
7 * Copyright (C) 2018-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include "internal/iprt.h"
42#include <iprt/formats/tracelog.h>
43#include <iprt/tracelog.h>
44
45
46#include <iprt/avl.h>
47#include <iprt/asm.h>
48#include <iprt/assert.h>
49#include <iprt/err.h>
50#include <iprt/file.h>
51#include <iprt/log.h>
52#include <iprt/mem.h>
53#include <iprt/semaphore.h>
54#include <iprt/string.h>
55#include <iprt/tcp.h>
56#include <iprt/time.h>
57
58#include "internal/magics.h"
59
60
61/*********************************************************************************************************************************
62* Structures and Typedefs *
63*********************************************************************************************************************************/
64
65
66/**
67 * Trace log writer internal event descriptor.
68 */
69typedef struct RTTRACELOGWREVTDESC
70{
71 /** AVL node core data */
72 AVLPVNODECORE Core;
73 /** The ID associated with this event descriptor. */
74 uint32_t u32Id;
75 /** Overall size of the event data not counting variable raw data items. */
76 size_t cbEvtData;
77 /** Number of non static raw binary items in the descriptor. */
78 uint32_t cRawDataNonStatic;
79 /** Pointer to the scratch event data buffer when adding events. */
80 uint8_t *pbEvt;
81 /** Embedded event descriptor. */
82 RTTRACELOGEVTDESC EvtDesc;
83 /** Array of event item descriptors, variable in size. */
84 RTTRACELOGEVTITEMDESC aEvtItemDesc[1];
85} RTTRACELOGWREVTDESC;
86/** Pointer to internal trace log writer event descriptor. */
87typedef RTTRACELOGWREVTDESC *PRTTRACELOGWREVTDESC;
88/** Pointer to const internal trace log writer event descriptor. */
89typedef const RTTRACELOGWREVTDESC *PCRTTRACELOGWREVTDESC;
90
91
92/**
93 * Trace log writer instance data.
94 */
95typedef struct RTTRACELOGWRINT
96{
97 /** Magic for identification. */
98 uint32_t u32Magic;
99 /** Stream out callback. */
100 PFNRTTRACELOGWRSTREAM pfnStreamOut;
101 /** Stream close callback .*/
102 PFNRTTRACELOGSTREAMCLOSE pfnStreamClose;
103 /** Opaque user data passed to the stream callback. */
104 void *pvUser;
105 /** Mutex protecting the structure. */
106 RTSEMMUTEX hMtx;
107 /** Next sequence number to use. */
108 volatile uint64_t u64SeqNoNext;
109 /** AVL tree root for event descriptor lookups. */
110 AVLPVTREE pTreeEvtDescs;
111 /** Number of event descriptors known. */
112 uint32_t cEvtDescs;
113} RTTRACELOGWRINT;
114/** Pointer to a trace log writer instance. */
115typedef RTTRACELOGWRINT *PRTTRACELOGWRINT;
116
117
118/**
119 * The TCP server/client state.
120 */
121typedef struct RTTRACELOGWRTCP
122{
123 /** Flag whether this is a server or client instance. */
124 bool fIsServer;
125 /** The TCP socket handle for the connection. */
126 RTSOCKET hSock;
127 /** The TCP server. */
128 PRTTCPSERVER pTcpSrv;
129} RTTRACELOGWRTCP;
130/** Pointer to a TCP server/client state. */
131typedef RTTRACELOGWRTCP *PRTTRACELOGWRTCP;
132
133
134/*********************************************************************************************************************************
135* Defined Constants And Macros *
136*********************************************************************************************************************************/
137
138
139/**
140 * Returns the size required for the internal event descriptor representation.
141 *
142 * @returns Number of bytes required.
143 * @param pEvtDesc Pointer to the external descriptor.
144 */
145static size_t rtTraceLogWrtEvtDescGetSz(PCRTTRACELOGEVTDESC pEvtDesc)
146{
147 size_t cbAlloc = RT_UOFFSETOF_DYN(RTTRACELOGWREVTDESC, aEvtItemDesc[pEvtDesc->cEvtItems]);
148
149 cbAlloc += strlen(pEvtDesc->pszId) + 1;
150 if (pEvtDesc->pszDesc)
151 cbAlloc += strlen(pEvtDesc->pszDesc) + 1;
152 for (unsigned i = 0; i < pEvtDesc->cEvtItems; i++)
153 {
154 PCRTTRACELOGEVTITEMDESC pEvtItemDesc = &pEvtDesc->paEvtItemDesc[i];
155
156 cbAlloc += strlen(pEvtItemDesc->pszName) + 1;
157 if (pEvtItemDesc->pszDesc)
158 cbAlloc += strlen(pEvtItemDesc->pszDesc) + 1;
159 }
160
161 return cbAlloc;
162}
163
164
165/**
166 * Copies a string into a supplied buffer assigning the start to the given string pointer.
167 *
168 * @returns Pointer to the memory after the destination buffer holding the string.
169 * @param ppsz Where to store the pointer to the start of the string.
170 * @param pszTo Where to copy the string including the temrinator to.
171 * @param pszFrom The string to copy.
172 */
173DECLINLINE(char *) rtTraceLogWrCopyStr(const char **ppsz, char *pszTo, const char *pszFrom)
174{
175 *ppsz = pszTo;
176 size_t cchCopy = strlen(pszFrom) + 1;
177 memcpy(pszTo, pszFrom, cchCopy);
178
179 return pszTo + cchCopy;
180}
181
182
183/**
184 * Converts the type enum to the size of the the event item data in bytes.
185 *
186 * @returns Event item data size in bytes.
187 * @param pEvtItemDesc The event item descriptor.
188 */
189static size_t rtTraceLogWrGetEvtItemDataSz(PCRTTRACELOGEVTITEMDESC pEvtItemDesc)
190{
191 size_t cb = 0;
192
193 switch (pEvtItemDesc->enmType)
194 {
195 case RTTRACELOGTYPE_BOOL:
196 case RTTRACELOGTYPE_UINT8:
197 case RTTRACELOGTYPE_INT8:
198 {
199 cb = 1;
200 break;
201 }
202 case RTTRACELOGTYPE_UINT16:
203 case RTTRACELOGTYPE_INT16:
204 {
205 cb = 2;
206 break;
207 }
208 case RTTRACELOGTYPE_UINT32:
209 case RTTRACELOGTYPE_INT32:
210 case RTTRACELOGTYPE_FLOAT32:
211 {
212 cb = 4;
213 break;
214 }
215 case RTTRACELOGTYPE_UINT64:
216 case RTTRACELOGTYPE_INT64:
217 case RTTRACELOGTYPE_FLOAT64:
218 {
219 cb = 8;
220 break;
221 }
222 case RTTRACELOGTYPE_RAWDATA:
223 {
224 cb = pEvtItemDesc->cbRawData;
225 break;
226 }
227 case RTTRACELOGTYPE_POINTER:
228 {
229 cb = sizeof(uintptr_t);
230 break;
231 }
232 case RTTRACELOGTYPE_SIZE:
233 {
234 cb = sizeof(size_t);
235 break;
236 }
237 default:
238 AssertMsgFailed(("Invalid type %d\n", pEvtItemDesc->enmType));
239 }
240
241 return cb;
242}
243
244
245/**
246 * Converts API severity enum to the stream representation.
247 *
248 * @returns Stream representation of the severity.
249 * @param enmSeverity The API severity.
250 */
251static uint32_t rtTraceLogWrConvSeverityToStream(RTTRACELOGEVTSEVERITY enmSeverity)
252{
253 switch (enmSeverity)
254 {
255 case RTTRACELOGEVTSEVERITY_INFO:
256 return TRACELOG_EVTDESC_SEVERITY_INFO;
257 case RTTRACELOGEVTSEVERITY_WARNING:
258 return TRACELOG_EVTDESC_SEVERITY_WARNING;
259 case RTTRACELOGEVTSEVERITY_ERROR:
260 return TRACELOG_EVTDESC_SEVERITY_ERROR;
261 case RTTRACELOGEVTSEVERITY_FATAL:
262 return TRACELOG_EVTDESC_SEVERITY_FATAL;
263 case RTTRACELOGEVTSEVERITY_DEBUG:
264 return TRACELOG_EVTDESC_SEVERITY_DEBUG;
265 default:
266 AssertMsgFailed(("Invalid severity %d\n", enmSeverity));
267 }
268
269 /* Should not happen. */
270 return TRACELOG_EVTDESC_SEVERITY_FATAL;
271}
272
273
274/**
275 * Converts API type enum to the stream representation.
276 *
277 * @returns Stream representation of the type.
278 * @param enmType The API type.
279 */
280static uint32_t rtTraceLogWrConvTypeToStream(RTTRACELOGTYPE enmType)
281{
282 switch (enmType)
283 {
284 case RTTRACELOGTYPE_BOOL:
285 return TRACELOG_EVTITEMDESC_TYPE_BOOL;
286 case RTTRACELOGTYPE_UINT8:
287 return TRACELOG_EVTITEMDESC_TYPE_UINT8;
288 case RTTRACELOGTYPE_INT8:
289 return TRACELOG_EVTITEMDESC_TYPE_INT8;
290 case RTTRACELOGTYPE_UINT16:
291 return TRACELOG_EVTITEMDESC_TYPE_UINT16;
292 case RTTRACELOGTYPE_INT16:
293 return TRACELOG_EVTITEMDESC_TYPE_INT16;
294 case RTTRACELOGTYPE_UINT32:
295 return TRACELOG_EVTITEMDESC_TYPE_UINT32;
296 case RTTRACELOGTYPE_INT32:
297 return TRACELOG_EVTITEMDESC_TYPE_INT32;
298 case RTTRACELOGTYPE_UINT64:
299 return TRACELOG_EVTITEMDESC_TYPE_UINT64;
300 case RTTRACELOGTYPE_INT64:
301 return TRACELOG_EVTITEMDESC_TYPE_INT64;
302 case RTTRACELOGTYPE_FLOAT32:
303 return TRACELOG_EVTITEMDESC_TYPE_FLOAT32;
304 case RTTRACELOGTYPE_FLOAT64:
305 return TRACELOG_EVTITEMDESC_TYPE_FLOAT64;
306 case RTTRACELOGTYPE_RAWDATA:
307 return TRACELOG_EVTITEMDESC_TYPE_RAWDATA;
308 case RTTRACELOGTYPE_POINTER:
309 return TRACELOG_EVTITEMDESC_TYPE_POINTER;
310 case RTTRACELOGTYPE_SIZE:
311 return TRACELOG_EVTITEMDESC_TYPE_SIZE;
312 default:
313 AssertMsgFailed(("Invalid type %d\n", enmType));
314 }
315
316 /* Should not happen. */
317 return RTTRACELOGTYPE_RAWDATA;
318}
319
320
321/**
322 * Initializes the internal representation of the event descriptor from the given one.
323 *
324 * @returns Pointer to the internal instance of the event descriptor.
325 * NULL if out of memory.
326 * @param pEvtDesc Pointer to the external descriptor.
327 */
328static PRTTRACELOGWREVTDESC rtTraceLogWrEvtDescInit(PCRTTRACELOGEVTDESC pEvtDesc)
329{
330 size_t cbAlloc = rtTraceLogWrtEvtDescGetSz(pEvtDesc);
331 size_t cbEvtData = 0;
332 PRTTRACELOGWREVTDESC pEvtDescInt = (PRTTRACELOGWREVTDESC)RTMemAllocZ(cbAlloc);
333 if (RT_LIKELY(pEvtDescInt))
334 {
335 char *pszStrSpace = (char *)&pEvtDescInt->aEvtItemDesc[pEvtDesc->cEvtItems]; /* Get space for strings after the descriptor. */
336
337 pEvtDescInt->EvtDesc.enmSeverity = pEvtDesc->enmSeverity;
338 pEvtDescInt->EvtDesc.cEvtItems = pEvtDesc->cEvtItems;
339 pEvtDescInt->EvtDesc.paEvtItemDesc = &pEvtDescInt->aEvtItemDesc[0];
340
341 /* Copy ID and optional description over. */
342 pszStrSpace = rtTraceLogWrCopyStr(&pEvtDescInt->EvtDesc.pszId, pszStrSpace, pEvtDesc->pszId);
343 if (pEvtDesc->pszDesc)
344 pszStrSpace = rtTraceLogWrCopyStr(&pEvtDescInt->EvtDesc.pszDesc, pszStrSpace, pEvtDesc->pszDesc);
345
346 /* Go through the event item descriptors and initialize them too. */
347 for (unsigned i = 0; i < pEvtDesc->cEvtItems; i++)
348 {
349 PCRTTRACELOGEVTITEMDESC pEvtItemDescFrom = &pEvtDesc->paEvtItemDesc[i];
350 PRTTRACELOGEVTITEMDESC pEvtItemDescTo = &pEvtDescInt->aEvtItemDesc[i];
351
352 pEvtItemDescTo->enmType = pEvtItemDescFrom->enmType;
353 pEvtItemDescTo->cbRawData = pEvtItemDescFrom->cbRawData;
354
355 cbEvtData += rtTraceLogWrGetEvtItemDataSz(pEvtItemDescFrom);
356 if ( pEvtItemDescTo->enmType == RTTRACELOGTYPE_RAWDATA
357 && !pEvtItemDescFrom->cbRawData)
358 pEvtDescInt->cRawDataNonStatic++;
359
360 pszStrSpace = rtTraceLogWrCopyStr(&pEvtItemDescTo->pszName, pszStrSpace, pEvtItemDescFrom->pszName);
361 if (pEvtItemDescFrom->pszDesc)
362 pszStrSpace = rtTraceLogWrCopyStr(&pEvtItemDescTo->pszDesc, pszStrSpace, pEvtItemDescFrom->pszDesc);
363 }
364
365 pEvtDescInt->cbEvtData = cbEvtData;
366 if (cbEvtData)
367 {
368 pEvtDescInt->pbEvt = (uint8_t *)RTMemAllocZ(cbEvtData);
369 if (!pEvtDescInt->pbEvt)
370 {
371 RTMemFree(pEvtDescInt);
372 pEvtDescInt = NULL;
373 }
374 }
375 }
376
377 return pEvtDescInt;
378}
379
380
381/**
382 * Wrapper around the stream callback.
383 *
384 * @returns IPRT status code returned by the stream callback.
385 * @param pThis The trace log writer instance.
386 * @param pvBuf The data to stream.
387 * @param cbBuf Number of bytes to stream.
388 */
389DECLINLINE(int) rtTraceLogWrStream(PRTTRACELOGWRINT pThis, const void *pvBuf, size_t cbBuf)
390{
391 return pThis->pfnStreamOut(pThis->pvUser, pvBuf, cbBuf, NULL);
392}
393
394
395/**
396 * Initializes a given event structure.
397 *
398 * @returns Total number of bytes for the event data associated with this event.
399 * @param pEvt Pointer to the event structure to initialise.
400 * @param pEvtDescInt The internal event descriptor to format the data accordingly to.
401 * @param fFlags Flags to use for this event.
402 * @param uGrpId The group ID to identify grouped events.
403 * @param uParentGrpId The parent group ID.
404 * @param pacbRawData Array of raw data size indicators.
405 */
406DECLINLINE(size_t) rtTraceLogWrEvtInit(PTRACELOGEVT pEvt,
407 PRTTRACELOGWREVTDESC pEvtDescInt, uint32_t fFlags,
408 RTTRACELOGEVTGRPID uGrpId, RTTRACELOGEVTGRPID uParentGrpId,
409 size_t *pacbRawData)
410{
411 uint32_t cbEvtData = (uint32_t)pEvtDescInt->cbEvtData;
412 for (unsigned i = 0; i < pEvtDescInt->cRawDataNonStatic; i++)
413 cbEvtData += (uint32_t)pacbRawData[i];
414
415 uint32_t fEvtFlags = 0;
416 if (fFlags & RTTRACELOG_WR_ADD_EVT_F_GRP_START)
417 fEvtFlags |= TRACELOG_EVT_F_GRP_START;
418 if (fFlags & RTTRACELOG_WR_ADD_EVT_F_GRP_FINISH)
419 fEvtFlags |= TRACELOG_EVT_F_GRP_END;
420
421 memcpy(&pEvt->szMagic[0], TRACELOG_EVT_MAGIC, sizeof(pEvt->szMagic));
422 pEvt->u64Ts = RTTimeNanoTS();
423 pEvt->u64EvtGrpId = uGrpId;
424 pEvt->u64EvtParentGrpId = uParentGrpId;
425 pEvt->fFlags = fEvtFlags;
426 pEvt->u32EvtDescId = pEvtDescInt->u32Id;
427 pEvt->cbEvtData = cbEvtData;
428 pEvt->cRawEvtDataSz = pEvtDescInt->cRawDataNonStatic;
429
430 return cbEvtData;
431}
432
433
434/**
435 * Streams the whole event including associated data.
436 *
437 * @returns IPRT status code.
438 * @param pThis The trace log writer instance.
439 * @param pEvt Pointer to the initialised event structure.
440 * @param pvEvtData The raw event data.
441 * @param cbEvtData Size of the event data.
442 * @param pacbRawData Pointer to the array of size indicators for non static
443 * raw data in the event data stream.
444 */
445DECLINLINE(int) rtTraceLogWrEvtStream(PRTTRACELOGWRINT pThis, PTRACELOGEVT pEvt, const void *pvEvtData,
446 size_t cbEvtData, size_t *pacbRawData)
447{
448 /** @todo Get rid of locking. */
449 int rc = RTSemMutexRequest(pThis->hMtx, RT_INDEFINITE_WAIT);
450 if (RT_SUCCESS(rc))
451 {
452 pEvt->u64SeqNo = ASMAtomicIncU64(&pThis->u64SeqNoNext);
453
454 /* Write the data out. */
455 rc = rtTraceLogWrStream(pThis, pEvt, sizeof(TRACELOGEVT));
456 if ( RT_SUCCESS(rc)
457 && pEvt->cRawEvtDataSz)
458 rc = rtTraceLogWrStream(pThis, pacbRawData, pEvt->cRawEvtDataSz * sizeof(size_t));
459 if ( RT_SUCCESS(rc)
460 && cbEvtData)
461 rc = rtTraceLogWrStream(pThis, pvEvtData, cbEvtData);
462 RTSemMutexRelease(pThis->hMtx);
463 }
464
465 return rc;
466}
467
468
469/**
470 * Returns the intenral event descriptor for the given event descriptor.
471 *
472 * @returns Pointer to the internal event descriptor or NULL if not found.
473 * @param pThis The trace log writer instance.
474 * @param pEvtDesc The event descriptor to search for.
475 */
476DECLINLINE(PRTTRACELOGWREVTDESC) rtTraceLogWrEvtDescGetInternal(PRTTRACELOGWRINT pThis,
477 PCRTTRACELOGEVTDESC pEvtDesc)
478{
479 int rc = RTSemMutexRequest(pThis->hMtx, RT_INDEFINITE_WAIT);
480 if (RT_SUCCESS(rc))
481 {
482 PRTTRACELOGWREVTDESC pEvtDescInt = (PRTTRACELOGWREVTDESC)RTAvlPVGet(&pThis->pTreeEvtDescs, (void *)pEvtDesc);
483 RTSemMutexRelease(pThis->hMtx);
484 return pEvtDescInt;
485 }
486
487 return NULL;
488}
489
490
491/**
492 * Initializes the trace log.
493 *
494 * @returns IPRT status code.
495 * @param pThis The trace log writer instance.
496 * @param pszDesc The description to use.
497 */
498static int rtTraceLogWrInit(PRTTRACELOGWRINT pThis, const char *pszDesc)
499{
500 /* Start by assembling the header. */
501 TRACELOGHDR Hdr;
502
503 RT_ZERO(Hdr);
504 memcpy(&Hdr.szMagic[0], TRACELOG_HDR_MAGIC, sizeof(Hdr.szMagic));
505 Hdr.u32Endianess = TRACELOG_HDR_ENDIANESS; /* Endianess marker. */
506 Hdr.u32Version = TRACELOG_VERSION;
507 Hdr.fFlags = 0;
508 Hdr.cbStrDesc = pszDesc ? (uint32_t)strlen(pszDesc) : 0;
509 Hdr.cbTypePtr = sizeof(uintptr_t);
510 Hdr.cbTypeSize = sizeof(size_t);
511 Hdr.u64TsStart = RTTimeNanoTS();
512 int rc = rtTraceLogWrStream(pThis, &Hdr, sizeof(Hdr));
513 if ( RT_SUCCESS(rc)
514 && pszDesc)
515 rc = rtTraceLogWrStream(pThis, pszDesc, Hdr.cbStrDesc);
516
517 return rc;
518}
519
520
521static DECLCALLBACK(int) rtTraceLogWrCheckForOverlappingIds(PAVLPVNODECORE pCore, void *pvParam)
522{
523 PCRTTRACELOGEVTDESC pEvtDesc = (PCRTTRACELOGEVTDESC)pvParam;
524 PRTTRACELOGWREVTDESC pEvtDescInt = (PRTTRACELOGWREVTDESC)pCore;
525
526 if (!RTStrCmp(pEvtDesc->pszId, pEvtDescInt->EvtDesc.pszId))
527 return VERR_ALREADY_EXISTS;
528
529 return VINF_SUCCESS;
530}
531
532
533static DECLCALLBACK(int) rtTraceLogWrEvtDescsDestroy(PAVLPVNODECORE pCore, void *pvParam)
534{
535 PRTTRACELOGWREVTDESC pEvtDesc = (PRTTRACELOGWREVTDESC)pCore;
536 RT_NOREF(pvParam);
537
538 RTMemFree(pEvtDesc->pbEvt);
539 RTMemFree(pEvtDesc);
540 return VINF_SUCCESS;
541}
542
543
544/**
545 * Adds a new event descriptor to the trace log.
546 *
547 * @returns IPRT status code.
548 * @param pThis The trace log writer instance.
549 * @param pEvtDesc The event descriptor to add.
550 * @param ppEvtDescInt Where to store the pointer to the internal
551 * event descriptor - optional.
552 */
553static int rtTraceLogWrEvtDescAdd(PRTTRACELOGWRINT pThis, PCRTTRACELOGEVTDESC pEvtDesc,
554 PRTTRACELOGWREVTDESC *ppEvtDescInt)
555{
556 int rc = RTSemMutexRequest(pThis->hMtx, RT_INDEFINITE_WAIT);
557 if (RT_SUCCESS(rc))
558 {
559 PRTTRACELOGWREVTDESC pEvtDescInt = (PRTTRACELOGWREVTDESC)RTAvlPVGet(&pThis->pTreeEvtDescs, (void *)pEvtDesc);
560 if (!pEvtDescInt)
561 {
562 rc = RTAvlPVDoWithAll(&pThis->pTreeEvtDescs, true, rtTraceLogWrCheckForOverlappingIds, (void *)pEvtDesc);
563 if (RT_SUCCESS(rc))
564 {
565 pEvtDescInt = rtTraceLogWrEvtDescInit(pEvtDesc);
566 if (RT_LIKELY(pEvtDescInt))
567 {
568 pEvtDescInt->Core.Key = (void *)pEvtDesc;
569 pEvtDescInt->u32Id = pThis->cEvtDescs++;
570 bool fIns = RTAvlPVInsert(&pThis->pTreeEvtDescs, &pEvtDescInt->Core);
571 Assert(fIns); RT_NOREF(fIns);
572 }
573 else
574 rc = VERR_NO_MEMORY;
575
576 if (RT_SUCCESS(rc))
577 {
578 TRACELOGEVTDESC EvtDesc;
579
580 RT_ZERO(EvtDesc);
581 memcpy(&EvtDesc.szMagic[0], TRACELOG_EVTDESC_MAGIC, sizeof(EvtDesc.szMagic));
582 EvtDesc.u32Id = pEvtDescInt->u32Id;
583 EvtDesc.u32Severity = rtTraceLogWrConvSeverityToStream(pEvtDescInt->EvtDesc.enmSeverity);
584 EvtDesc.cbStrId = (uint32_t)strlen(pEvtDescInt->EvtDesc.pszId);
585 EvtDesc.cbStrDesc = pEvtDescInt->EvtDesc.pszDesc ? (uint32_t)strlen(pEvtDescInt->EvtDesc.pszDesc) : 0;
586 EvtDesc.cEvtItems = pEvtDescInt->EvtDesc.cEvtItems;
587 rc = rtTraceLogWrStream(pThis, &EvtDesc, sizeof(EvtDesc));
588 if (RT_SUCCESS(rc))
589 rc = rtTraceLogWrStream(pThis, pEvtDescInt->EvtDesc.pszId, EvtDesc.cbStrId);
590 if ( RT_SUCCESS(rc)
591 && pEvtDescInt->EvtDesc.pszDesc)
592 rc = rtTraceLogWrStream(pThis, pEvtDescInt->EvtDesc.pszDesc, EvtDesc.cbStrDesc);
593 if (RT_SUCCESS(rc))
594 {
595 /* Go through the event items. */
596 for (unsigned idxEvtItem = 0; idxEvtItem < EvtDesc.cEvtItems && RT_SUCCESS(rc); idxEvtItem++)
597 {
598 PCRTTRACELOGEVTITEMDESC pEvtItemDesc = &pEvtDescInt->EvtDesc.paEvtItemDesc[idxEvtItem];
599 TRACELOGEVTITEMDESC EvtItemDesc;
600
601 RT_ZERO(EvtItemDesc);
602 memcpy(&EvtItemDesc.szMagic[0], TRACELOG_EVTITEMDESC_MAGIC, sizeof(EvtItemDesc.szMagic));
603 EvtItemDesc.cbStrName = (uint32_t)strlen(pEvtItemDesc->pszName);
604 EvtItemDesc.cbStrDesc = pEvtItemDesc->pszDesc ? (uint32_t)strlen(pEvtItemDesc->pszDesc) : 0;
605 EvtItemDesc.u32Type = rtTraceLogWrConvTypeToStream(pEvtItemDesc->enmType);
606 EvtItemDesc.cbRawData = (uint32_t)pEvtItemDesc->cbRawData;
607 rc = rtTraceLogWrStream(pThis, &EvtItemDesc, sizeof(EvtItemDesc));
608 if (RT_SUCCESS(rc))
609 rc = rtTraceLogWrStream(pThis, pEvtItemDesc->pszName, EvtItemDesc.cbStrName);
610 if ( RT_SUCCESS(rc)
611 && pEvtItemDesc->pszDesc)
612 rc = rtTraceLogWrStream(pThis, pEvtItemDesc->pszDesc, EvtItemDesc.cbStrDesc);
613 }
614 }
615 }
616 }
617
618 if ( RT_SUCCESS(rc)
619 && ppEvtDescInt)
620 *ppEvtDescInt = pEvtDescInt;
621 }
622 else
623 rc = VERR_ALREADY_EXISTS;
624 RTSemMutexRelease(pThis->hMtx);
625 }
626
627 return rc;
628}
629
630
631/**
632 * Fills a given buffer with the given event data as described in the given descriptor.
633 *
634 * @returns IPRT status code.
635 * @param pThis The trace log writer instance.
636 * @param pEvtDescInt Pointer to the internal event descriptor.
637 * @param pb The byte buffer to fill.
638 * @param va The event data.
639 */
640static int rtTraceLogWrEvtFill(PRTTRACELOGWRINT pThis, PRTTRACELOGWREVTDESC pEvtDescInt, uint8_t *pb, va_list va)
641{
642 int rc = VINF_SUCCESS;
643 uint8_t *pbCur = pb;
644
645 RT_NOREF(pThis);
646
647 for (unsigned i = 0; i < pEvtDescInt->EvtDesc.cEvtItems; i++)
648 {
649 PCRTTRACELOGEVTITEMDESC pEvtItemDesc = &pEvtDescInt->EvtDesc.paEvtItemDesc[i];
650
651 size_t cbItem = rtTraceLogWrGetEvtItemDataSz(pEvtItemDesc);
652 switch (cbItem)
653 {
654 case sizeof(uint8_t):
655 *pbCur++ = va_arg(va, /*uint8_t*/ unsigned);
656 break;
657 case sizeof(uint16_t):
658 *(uint16_t *)pbCur = va_arg(va, /*uint16_t*/ unsigned);
659 pbCur += sizeof(uint16_t);
660 break;
661 case sizeof(uint32_t):
662 *(uint32_t *)pbCur = va_arg(va, uint32_t);
663 pbCur += sizeof(uint32_t);
664 break;
665 case sizeof(uint64_t):
666 *(uint64_t *)pbCur = va_arg(va, uint64_t);
667 pbCur += sizeof(uint64_t);
668 break;
669 default:
670 /* Some raw data item. */
671 Assert(pEvtItemDesc->enmType == RTTRACELOGTYPE_RAWDATA);
672 if (cbItem != 0)
673 {
674 /* Static raw data. */
675 void *pvSrc = va_arg(va, void *);
676 memcpy(pbCur, pvSrc, cbItem);
677 pbCur += cbItem;
678 }
679 else
680 {
681 AssertMsgFailed(("Not implemented!\n"));
682 rc = VERR_NOT_IMPLEMENTED;
683 }
684 }
685 }
686
687 return rc;
688}
689
690
691/**
692 * @copydoc FNRTTRACELOGWRSTREAM
693 */
694static DECLCALLBACK(int) rtTraceLogWrFileStream(void *pvUser, const void *pvBuf, size_t cbBuf, size_t *pcbWritten)
695{
696 RTFILE hFile = (RTFILE)pvUser;
697 return RTFileWrite(hFile, pvBuf, cbBuf, pcbWritten);
698}
699
700
701/**
702 * @copydoc FNRTTRACELOGSTREAMCLOSE
703 */
704static DECLCALLBACK(int) rtTraceLogWrFileStreamClose(void *pvUser)
705{
706 RTFILE hFile = (RTFILE)pvUser;
707 return RTFileClose(hFile);
708}
709
710
711RTDECL(int) RTTraceLogWrCreate(PRTTRACELOGWR phTraceLogWr, const char *pszDesc,
712 PFNRTTRACELOGWRSTREAM pfnStreamOut,
713 PFNRTTRACELOGSTREAMCLOSE pfnStreamClose, void *pvUser)
714{
715 AssertPtrReturn(phTraceLogWr, VERR_INVALID_POINTER);
716 AssertPtrReturn(pfnStreamOut, VERR_INVALID_POINTER);
717 AssertPtrReturn(pfnStreamClose, VERR_INVALID_POINTER);
718 int rc = VINF_SUCCESS;
719 PRTTRACELOGWRINT pThis = (PRTTRACELOGWRINT)RTMemAllocZ(sizeof(*pThis));
720 if (pThis)
721 {
722 rc = RTSemMutexCreate(&pThis->hMtx);
723 if (RT_SUCCESS(rc))
724 {
725 pThis->u32Magic = RTTRACELOGWR_MAGIC;
726 pThis->pfnStreamOut = pfnStreamOut;
727 pThis->pfnStreamClose = pfnStreamClose;
728 pThis->pvUser = pvUser;
729 pThis->u64SeqNoNext = 0;
730 pThis->pTreeEvtDescs = NULL;
731 pThis->cEvtDescs = 0;
732 rc = rtTraceLogWrInit(pThis, pszDesc);
733 if (RT_SUCCESS(rc))
734 {
735 *phTraceLogWr = pThis;
736 return VINF_SUCCESS;
737 }
738 }
739 RTMemFree(pThis);
740 }
741 else
742 rc = VERR_NO_MEMORY;
743
744 return rc;
745}
746
747
748RTDECL(int) RTTraceLogWrCreateFile(PRTTRACELOGWR phTraceLogWr, const char *pszDesc,
749 const char *pszFilename)
750{
751 AssertPtrReturn(phTraceLogWr, VERR_INVALID_POINTER);
752 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
753
754 RTFILE hFile = NIL_RTFILE;
755 int rc = RTFileOpen(&hFile, pszFilename, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
756 if (RT_SUCCESS(rc))
757 {
758 rc = RTTraceLogWrCreate(phTraceLogWr, pszDesc, rtTraceLogWrFileStream,
759 rtTraceLogWrFileStreamClose, hFile);
760 if (RT_FAILURE(rc))
761 {
762 RTFileClose(hFile);
763 RTFileDelete(pszFilename);
764 }
765 }
766
767 return rc;
768}
769
770
771/**
772 * @copydoc FNRTTRACELOGWRSTREAM
773 */
774static DECLCALLBACK(int) rtTraceLogWrTcpStream(void *pvUser, const void *pvBuf, size_t cbBuf, size_t *pcbWritten)
775{
776 PRTTRACELOGWRTCP pTraceLogTcp = (PRTTRACELOGWRTCP)pvUser;
777 int rc = RTTcpWrite(pTraceLogTcp->hSock, pvBuf, cbBuf);
778 if ( RT_SUCCESS(rc)
779 && pcbWritten)
780 *pcbWritten = cbBuf;
781
782 return rc;
783}
784
785
786/**
787 * @copydoc FNRTTRACELOGSTREAMCLOSE
788 */
789static DECLCALLBACK(int) rtTraceLogWrTcpStreamClose(void *pvUser)
790{
791 PRTTRACELOGWRTCP pTraceLogTcp = (PRTTRACELOGWRTCP)pvUser;
792 if (pTraceLogTcp->fIsServer)
793 {
794 RTTcpServerDisconnectClient2(pTraceLogTcp->hSock);
795 RTTcpServerDestroy(pTraceLogTcp->pTcpSrv);
796 }
797 else
798 RTTcpClientClose(pTraceLogTcp->hSock);
799
800 RTMemFree(pTraceLogTcp);
801 return VINF_SUCCESS;
802}
803
804
805RTDECL(int) RTTraceLogWrCreateTcpServer(PRTTRACELOGWR phTraceLogWr, const char *pszDesc,
806 const char *pszListen, unsigned uPort)
807{
808 int rc = VINF_SUCCESS;
809 PRTTRACELOGWRTCP pTraceLogTcp = (PRTTRACELOGWRTCP)RTMemAllocZ(sizeof(*pTraceLogTcp));
810 if (RT_LIKELY(pTraceLogTcp))
811 {
812 pTraceLogTcp->fIsServer = true;
813
814 rc = RTTcpServerCreateEx(pszListen, uPort, &pTraceLogTcp->pTcpSrv);
815 if (RT_SUCCESS(rc))
816 {
817 rc = RTTcpServerListen2(pTraceLogTcp->pTcpSrv, &pTraceLogTcp->hSock);
818 if (RT_SUCCESS(rc))
819 {
820 rc = RTTraceLogWrCreate(phTraceLogWr, pszDesc, rtTraceLogWrTcpStream,
821 rtTraceLogWrTcpStreamClose, pTraceLogTcp);
822 if (RT_SUCCESS(rc))
823 return VINF_SUCCESS;
824
825 RTTcpServerDisconnectClient2(pTraceLogTcp->hSock);
826 }
827
828 RTTcpServerDestroy(pTraceLogTcp->pTcpSrv);
829 }
830
831 RTMemFree(pTraceLogTcp);
832 }
833 else
834 rc = VERR_NO_MEMORY;
835
836 return rc;
837}
838
839
840RTDECL(int) RTTraceLogWrCreateTcpClient(PRTTRACELOGWR phTraceLogWr, const char *pszDesc,
841 const char *pszAddress, unsigned uPort)
842{
843 int rc = VINF_SUCCESS;
844 PRTTRACELOGWRTCP pTraceLogTcp = (PRTTRACELOGWRTCP)RTMemAllocZ(sizeof(*pTraceLogTcp));
845 if (RT_LIKELY(pTraceLogTcp))
846 {
847 pTraceLogTcp->fIsServer = false;
848
849 rc = RTTcpClientConnect(pszAddress, uPort, &pTraceLogTcp->hSock);
850 if (RT_SUCCESS(rc))
851 {
852 rc = RTTraceLogWrCreate(phTraceLogWr, pszDesc, rtTraceLogWrTcpStream,
853 rtTraceLogWrTcpStreamClose, pTraceLogTcp);
854 if (RT_SUCCESS(rc))
855 return VINF_SUCCESS;
856
857 RTTcpClientClose(pTraceLogTcp->hSock);
858 }
859
860 RTMemFree(pTraceLogTcp);
861 }
862 else
863 rc = VERR_NO_MEMORY;
864
865 return rc;
866}
867
868
869RTDECL(int) RTTraceLogWrDestroy(RTTRACELOGWR hTraceLogWr)
870{
871 if (hTraceLogWr == NIL_RTTRACELOGWR)
872 return VINF_SUCCESS;
873 PRTTRACELOGWRINT pThis = hTraceLogWr;
874 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
875 AssertReturn(pThis->u32Magic == RTTRACELOGWR_MAGIC, VERR_INVALID_HANDLE);
876
877 pThis->u32Magic = RTTRACELOGWR_MAGIC_DEAD;
878 pThis->pfnStreamClose(pThis->pvUser);
879 RTAvlPVDestroy(&pThis->pTreeEvtDescs, rtTraceLogWrEvtDescsDestroy, NULL);
880 RTSemMutexDestroy(pThis->hMtx);
881 RTMemFree(pThis);
882 return VINF_SUCCESS;
883}
884
885
886RTDECL(int) RTTraceLogWrAddEvtDesc(RTTRACELOGWR hTraceLogWr, PCRTTRACELOGEVTDESC pEvtDesc)
887{
888 PRTTRACELOGWRINT pThis = hTraceLogWr;
889 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
890 AssertReturn(pThis->u32Magic == RTTRACELOGWR_MAGIC, VERR_INVALID_HANDLE);
891 AssertPtrReturn(pEvtDesc, VERR_INVALID_POINTER);
892
893 return rtTraceLogWrEvtDescAdd(pThis, pEvtDesc, NULL);
894}
895
896
897RTDECL(int) RTTraceLogWrEvtAdd(RTTRACELOGWR hTraceLogWr, PCRTTRACELOGEVTDESC pEvtDesc, uint32_t fFlags,
898 RTTRACELOGEVTGRPID uGrpId, RTTRACELOGEVTGRPID uParentGrpId,
899 const void *pvEvtData, size_t *pacbRawData)
900{
901 PRTTRACELOGWRINT pThis = hTraceLogWr;
902 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
903 AssertReturn(pThis->u32Magic == RTTRACELOGWR_MAGIC, VERR_INVALID_HANDLE);
904
905 int rc = VINF_SUCCESS;
906 PRTTRACELOGWREVTDESC pEvtDescInt = rtTraceLogWrEvtDescGetInternal(pThis, pEvtDesc);
907 if (RT_UNLIKELY(!pEvtDescInt))
908 rc = rtTraceLogWrEvtDescAdd(pThis, pEvtDesc, &pEvtDescInt);
909
910 if ( RT_SUCCESS(rc)
911 && RT_VALID_PTR(pEvtDescInt))
912 {
913 TRACELOGEVT Evt;
914 size_t cbEvtData = rtTraceLogWrEvtInit(&Evt, pEvtDescInt, fFlags, uGrpId, uParentGrpId, pacbRawData);
915
916 rc = rtTraceLogWrEvtStream(pThis, &Evt, pvEvtData, cbEvtData, pacbRawData);
917 }
918
919 return rc;
920}
921
922
923RTDECL(int) RTTraceLogWrEvtAddSg(RTTRACELOGWR hTraceLogWr, PCRTTRACELOGEVTDESC pEvtDesc, uint32_t fFlags,
924 RTTRACELOGEVTGRPID uGrpId, RTTRACELOGEVTGRPID uParentGrpId,
925 PRTSGBUF *pSgBufEvtData, size_t *pacbRawData)
926{
927 RT_NOREF(hTraceLogWr, pEvtDesc, fFlags, uGrpId, uParentGrpId, pSgBufEvtData, pacbRawData);
928 return VERR_NOT_IMPLEMENTED;
929}
930
931
932RTDECL(int) RTTraceLogWrEvtAddLV(RTTRACELOGWR hTraceLogWr, PCRTTRACELOGEVTDESC pEvtDesc, uint32_t fFlags,
933 RTTRACELOGEVTGRPID uGrpId, RTTRACELOGEVTGRPID uParentGrpId, va_list va)
934{
935 PRTTRACELOGWRINT pThis = hTraceLogWr;
936 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
937 AssertReturn(pThis->u32Magic == RTTRACELOGWR_MAGIC, VERR_INVALID_HANDLE);
938
939 int rc = VINF_SUCCESS;
940 PRTTRACELOGWREVTDESC pEvtDescInt = rtTraceLogWrEvtDescGetInternal(pThis, pEvtDesc);
941 if (RT_UNLIKELY(!pEvtDescInt))
942 rc = rtTraceLogWrEvtDescAdd(pThis, pEvtDesc, &pEvtDescInt);
943
944 if ( RT_SUCCESS(rc)
945 && RT_VALID_PTR(pEvtDescInt))
946 {
947 TRACELOGEVT Evt;
948 size_t cbEvtData = rtTraceLogWrEvtInit(&Evt, pEvtDescInt, fFlags, uGrpId, uParentGrpId, NULL);
949
950 if (cbEvtData)
951 rc = rtTraceLogWrEvtFill(pThis, pEvtDescInt, pEvtDescInt->pbEvt, va);
952 if (RT_SUCCESS(rc))
953 rc = rtTraceLogWrEvtStream(pThis, &Evt, pEvtDescInt->pbEvt, cbEvtData, NULL);
954 }
955
956 return rc;
957}
958
959
960RTDECL(int) RTTraceLogWrEvtAddL(RTTRACELOGWR hTraceLogWr, PCRTTRACELOGEVTDESC pEvtDesc, uint32_t fFlags,
961 RTTRACELOGEVTGRPID uGrpId, RTTRACELOGEVTGRPID uParentGrpId, ...)
962{
963 va_list va;
964 va_start(va, uParentGrpId);
965 int rc = RTTraceLogWrEvtAddLV(hTraceLogWr, pEvtDesc, fFlags, uGrpId, uParentGrpId, va);
966 va_end(va);
967 return rc;
968}
969
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use