VirtualBox

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

Last change on this file since 82788 was 82788, checked in by vboxsync, 5 years ago

Runtime/tracelogwriter.cpp: Fix passing the trace log description in the stream

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