VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/log/tracebuf.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: 22.3 KB
Line 
1/* $Id: tracebuf.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * IPRT - Tracebuffer common functions.
4 */
5
6/*
7 * Copyright (C) 2011-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/trace.h>
43
44
45#include <iprt/assert.h>
46#include <iprt/asm.h>
47#include <iprt/errcore.h>
48#include <iprt/log.h>
49#ifndef IN_RC
50# include <iprt/mem.h>
51#endif
52#include <iprt/mp.h>
53#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
54# include <iprt/asm-amd64-x86.h>
55#endif
56#include <iprt/path.h>
57#include <iprt/string.h>
58#include <iprt/time.h>
59
60#include "internal/magics.h"
61
62
63/*********************************************************************************************************************************
64* Structures and Typedefs *
65*********************************************************************************************************************************/
66/** Alignment used to place the trace buffer members, this should be a multiple
67 * of the cache line size if possible. (We should dynamically determine it.) */
68#define RTTRACEBUF_ALIGNMENT 64
69AssertCompile(RTTRACEBUF_ALIGNMENT >= sizeof(uint64_t) * 2);
70
71/** The maximum number of entries. */
72#define RTTRACEBUF_MAX_ENTRIES _64K
73/** The minimum number of entries. */
74#define RTTRACEBUF_MIN_ENTRIES 4
75/** The default number of entries. */
76#define RTTRACEBUF_DEF_ENTRIES 256
77
78/** The maximum entry size. */
79#define RTTRACEBUF_MAX_ENTRY_SIZE _1M
80/** The minimum entry size. */
81#define RTTRACEBUF_MIN_ENTRY_SIZE RTTRACEBUF_ALIGNMENT
82/** The default entry size. */
83#define RTTRACEBUF_DEF_ENTRY_SIZE 256
84AssertCompile(!(RTTRACEBUF_DEF_ENTRY_SIZE & (RTTRACEBUF_DEF_ENTRY_SIZE - 1)));
85
86/**
87 * The volatile trace buffer members.
88 */
89typedef struct RTTRACEBUFVOLATILE
90{
91 /** Reference counter. */
92 uint32_t volatile cRefs;
93 /** The next entry to make use of. */
94 uint32_t volatile iEntry;
95} RTTRACEBUFVOLATILE;
96/** Pointer to the volatile parts of a trace buffer. */
97typedef RTTRACEBUFVOLATILE *PRTTRACEBUFVOLATILE;
98
99
100/**
101 * Trace buffer entry.
102 */
103typedef struct RTTRACEBUFENTRY
104{
105 /** The nano second entry time stamp. */
106 uint64_t NanoTS;
107 /** The ID of the CPU the event was recorded. */
108 RTCPUID idCpu;
109 /** The message. */
110 char szMsg[RTTRACEBUF_ALIGNMENT - sizeof(uint64_t) - sizeof(RTCPUID)];
111} RTTRACEBUFENTRY;
112AssertCompile(sizeof(RTTRACEBUFENTRY) <= RTTRACEBUF_ALIGNMENT);
113/** Pointer to a trace buffer entry. */
114typedef RTTRACEBUFENTRY *PRTTRACEBUFENTRY;
115
116
117
118/**
119 * Trace buffer structure.
120 *
121 * @remarks This structure must be context agnostic, i.e. no pointers or
122 * other types that may differ between contexts (R3/R0/RC).
123 */
124typedef struct RTTRACEBUFINT
125{
126 /** Magic value (RTTRACEBUF_MAGIC). */
127 uint32_t u32Magic;
128 /** The entry size. */
129 uint32_t cbEntry;
130 /** The number of entries. */
131 uint32_t cEntries;
132 /** Flags (always zero for now). */
133 uint32_t fFlags;
134 /** The offset to the volatile members (RTTRACEBUFVOLATILE) (relative to
135 * the start of this structure). */
136 uint32_t offVolatile;
137 /** The offset to the entries (relative to the start of this structure). */
138 uint32_t offEntries;
139 /** Reserved entries. */
140 uint32_t au32Reserved[2];
141} RTTRACEBUFINT;
142/** Pointer to a const trace buffer. */
143typedef RTTRACEBUFINT const *PCRTTRACEBUFINT;
144
145
146/*********************************************************************************************************************************
147* Defined Constants And Macros *
148*********************************************************************************************************************************/
149/**
150 * Get the current CPU Id.
151 */
152#if defined(IN_RING0) \
153 || defined(RT_OS_WINDOWS) \
154 || (!defined(RT_ARCH_AMD64) && !defined(RT_ARCH_X86))
155# define RTTRACEBUF_CUR_CPU() RTMpCpuId()
156#else
157# define RTTRACEBUF_CUR_CPU() ASMGetApicId() /** @todo this isn't good enough for big boxes with lots of CPUs/cores. */
158#endif
159
160/** Calculates the address of the volatile trace buffer members. */
161#define RTTRACEBUF_TO_VOLATILE(a_pThis) ((PRTTRACEBUFVOLATILE)((uint8_t *)(a_pThis) + (a_pThis)->offVolatile))
162
163/** Calculates the address of a trace buffer entry. */
164#define RTTRACEBUF_TO_ENTRY(a_pThis, a_iEntry) \
165 ((PRTTRACEBUFENTRY)( (uint8_t *)(a_pThis) + (a_pThis)->offEntries + (a_iEntry) * (a_pThis)->cbEntry ))
166
167/** Validates a trace buffer handle and returns rc if not valid. */
168#define RTTRACEBUF_VALID_RETURN_RC(a_pThis, a_rc) \
169 do { \
170 AssertPtrReturn((a_pThis), (a_rc)); \
171 AssertReturn((a_pThis)->u32Magic == RTTRACEBUF_MAGIC, (a_rc)); \
172 AssertReturn((a_pThis)->offVolatile < RTTRACEBUF_ALIGNMENT * 2, (a_rc)); \
173 AssertReturn(RTTRACEBUF_TO_VOLATILE(a_pThis)->cRefs > 0, (a_rc)); \
174 } while (0)
175
176/**
177 * Resolves and validates a trace buffer handle and returns rc if not valid.
178 *
179 * @param a_hTraceBuf The trace buffer handle passed by the user.
180 * @param a_pThis Where to store the trace buffer pointer.
181 */
182#define RTTRACEBUF_RESOLVE_VALIDATE_RETAIN_RETURN(a_hTraceBuf, a_pThis) \
183 do { \
184 uint32_t cRefs; \
185 if ((a_hTraceBuf) == RTTRACEBUF_DEFAULT) \
186 { \
187 (a_pThis) = RTTraceGetDefaultBuf(); \
188 if (!RT_VALID_PTR(a_pThis)) \
189 return VERR_NOT_FOUND; \
190 } \
191 else \
192 { \
193 (a_pThis) = (a_hTraceBuf); \
194 AssertPtrReturn((a_pThis), VERR_INVALID_HANDLE); \
195 } \
196 AssertReturn((a_pThis)->u32Magic == RTTRACEBUF_MAGIC, VERR_INVALID_HANDLE); \
197 AssertReturn((a_pThis)->offVolatile < RTTRACEBUF_ALIGNMENT * 2, VERR_INVALID_HANDLE); \
198 \
199 cRefs = ASMAtomicIncU32(&RTTRACEBUF_TO_VOLATILE(a_pThis)->cRefs); \
200 if (RT_UNLIKELY(cRefs < 1 || cRefs >= _1M)) \
201 { \
202 ASMAtomicDecU32(&RTTRACEBUF_TO_VOLATILE(a_pThis)->cRefs); \
203 AssertFailedReturn(VERR_INVALID_HANDLE); \
204 } \
205 } while (0)
206
207
208/**
209 * Drops a trace buffer reference.
210 *
211 * @param a_pThis Pointer to the trace buffer.
212 */
213#define RTTRACEBUF_DROP_REFERENCE(a_pThis) \
214 do { \
215 uint32_t cRefs = ASMAtomicDecU32(&RTTRACEBUF_TO_VOLATILE(a_pThis)->cRefs); \
216 if (!cRefs) \
217 rtTraceBufDestroy((RTTRACEBUFINT *)a_pThis); \
218 } while (0)
219
220
221/**
222 * The prologue code for a RTTraceAddSomething function.
223 *
224 * Resolves a trace buffer handle, grabs a reference to it and allocates the
225 * next entry. Return with an appropriate error status on failure.
226 *
227 * @param a_hTraceBuf The trace buffer handle passed by the user.
228 *
229 * @remarks This is kind of ugly, sorry.
230 */
231#define RTTRACEBUF_ADD_PROLOGUE(a_hTraceBuf) \
232 int rc; \
233 uint32_t cRefs; \
234 uint32_t iEntry; \
235 PCRTTRACEBUFINT pThis; \
236 PRTTRACEBUFVOLATILE pVolatile; \
237 PRTTRACEBUFENTRY pEntry; \
238 char *pszBuf; \
239 size_t cchBuf; \
240 \
241 /* Resolve and validate the handle. */ \
242 if ((a_hTraceBuf) == RTTRACEBUF_DEFAULT) \
243 { \
244 pThis = RTTraceGetDefaultBuf(); \
245 if (!RT_VALID_PTR(pThis)) \
246 return VERR_NOT_FOUND; \
247 } \
248 else if ((a_hTraceBuf) != NIL_RTTRACEBUF) \
249 { \
250 pThis = (a_hTraceBuf); \
251 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); \
252 } \
253 else \
254 return VERR_INVALID_HANDLE; \
255 \
256 AssertReturn(pThis->u32Magic == RTTRACEBUF_MAGIC, VERR_INVALID_HANDLE); \
257 if (pThis->fFlags & RTTRACEBUF_FLAGS_DISABLED) \
258 return VINF_SUCCESS; \
259 AssertReturn(pThis->offVolatile < RTTRACEBUF_ALIGNMENT * 2, VERR_INVALID_HANDLE); \
260 pVolatile = RTTRACEBUF_TO_VOLATILE(pThis); \
261 \
262 /* Grab a reference. */ \
263 cRefs = ASMAtomicIncU32(&pVolatile->cRefs); \
264 if (RT_UNLIKELY(cRefs < 1 || cRefs >= _1M)) \
265 { \
266 ASMAtomicDecU32(&pVolatile->cRefs); \
267 AssertFailedReturn(VERR_INVALID_HANDLE); \
268 } \
269 \
270 /* Grab the next entry and set the time stamp. */ \
271 iEntry = ASMAtomicIncU32(&pVolatile->iEntry) - 1; \
272 iEntry %= pThis->cEntries; \
273 pEntry = RTTRACEBUF_TO_ENTRY(pThis, iEntry); \
274 pEntry->NanoTS = RTTimeNanoTS(); \
275 pEntry->idCpu = RTTRACEBUF_CUR_CPU(); \
276 pszBuf = &pEntry->szMsg[0]; \
277 *pszBuf = '\0'; \
278 cchBuf = pThis->cbEntry - RT_UOFFSETOF(RTTRACEBUFENTRY, szMsg) - 1; \
279 rc = VINF_SUCCESS
280
281
282/**
283 * Used by a RTTraceAddPosSomething to store the source position in the entry
284 * prior to adding the actual trace message text.
285 *
286 * Both pszBuf and cchBuf will be adjusted such that pszBuf points and the zero
287 * terminator after the source position part.
288 */
289#define RTTRACEBUF_ADD_STORE_SRC_POS() \
290 do { \
291 /* file(line): - no path */ \
292 size_t cchPos = RTStrPrintf(pszBuf, cchBuf, "%s(%d): ", RTPathFilename(pszFile), iLine); \
293 pszBuf += cchPos; \
294 cchBuf -= cchPos; \
295 NOREF(pszFunction); \
296 } while (0)
297
298
299/**
300 * The epilogue code for a RTTraceAddSomething function.
301 *
302 * This will release the trace buffer reference.
303 */
304#define RTTRACEBUF_ADD_EPILOGUE() \
305 cRefs = ASMAtomicDecU32(&pVolatile->cRefs); \
306 if (!cRefs) \
307 rtTraceBufDestroy((RTTRACEBUFINT *)pThis); \
308 return rc
309
310
311#ifndef IN_RC /* Drop this in RC context (too lazy to split the file). */
312
313RTDECL(int) RTTraceBufCreate(PRTTRACEBUF phTraceBuf, uint32_t cEntries, uint32_t cbEntry, uint32_t fFlags)
314{
315 AssertPtrReturn(phTraceBuf, VERR_INVALID_POINTER);
316 AssertReturn(!(fFlags & ~(RTTRACEBUF_FLAGS_MASK & ~ RTTRACEBUF_FLAGS_FREE_ME)), VERR_INVALID_PARAMETER);
317 AssertMsgReturn(cbEntry <= RTTRACEBUF_MAX_ENTRIES, ("%#x\n", cbEntry), VERR_OUT_OF_RANGE);
318 AssertMsgReturn(cEntries <= RTTRACEBUF_MAX_ENTRY_SIZE, ("%#x\n", cEntries), VERR_OUT_OF_RANGE);
319
320 /*
321 * Apply default and alignment adjustments.
322 */
323 if (!cbEntry)
324 cbEntry = RTTRACEBUF_DEF_ENTRY_SIZE;
325 else
326 cbEntry = RT_ALIGN_32(cbEntry, RTTRACEBUF_ALIGNMENT);
327
328 if (!cEntries)
329 cEntries = RTTRACEBUF_DEF_ENTRIES;
330 else if (cEntries < RTTRACEBUF_MIN_ENTRIES)
331 cEntries = RTTRACEBUF_MIN_ENTRIES;
332
333 /*
334 * Calculate the required buffer size, allocte it and hand it on to the
335 * carver API.
336 */
337 size_t cbBlock = cbEntry * cEntries
338 + RT_ALIGN_Z(sizeof(RTTRACEBUFINT), RTTRACEBUF_ALIGNMENT)
339 + RT_ALIGN_Z(sizeof(RTTRACEBUFVOLATILE), RTTRACEBUF_ALIGNMENT);
340 void *pvBlock = RTMemAlloc(cbBlock);
341 if (!((uintptr_t)pvBlock & (RTTRACEBUF_ALIGNMENT - 1)))
342 {
343 RTMemFree(pvBlock);
344 cbBlock += RTTRACEBUF_ALIGNMENT - 1;
345 pvBlock = RTMemAlloc(cbBlock);
346 }
347 int rc;
348 if (pvBlock)
349 {
350 rc = RTTraceBufCarve(phTraceBuf, cEntries, cbEntry, fFlags, pvBlock, &cbBlock);
351 if (RT_FAILURE(rc))
352 RTMemFree(pvBlock);
353 }
354 else
355 rc = VERR_NO_MEMORY;
356 return rc;
357}
358
359
360RTDECL(int) RTTraceBufCarve(PRTTRACEBUF phTraceBuf, uint32_t cEntries, uint32_t cbEntry, uint32_t fFlags,
361 void *pvBlock, size_t *pcbBlock)
362{
363 AssertPtrReturn(phTraceBuf, VERR_INVALID_POINTER);
364 AssertReturn(!(fFlags & ~RTTRACEBUF_FLAGS_MASK), VERR_INVALID_PARAMETER);
365 AssertMsgReturn(cbEntry <= RTTRACEBUF_MAX_ENTRIES, ("%#x\n", cbEntry), VERR_OUT_OF_RANGE);
366 AssertMsgReturn(cEntries <= RTTRACEBUF_MAX_ENTRY_SIZE, ("%#x\n", cEntries), VERR_OUT_OF_RANGE);
367 AssertPtrReturn(pcbBlock, VERR_INVALID_POINTER);
368 size_t const cbBlock = *pcbBlock;
369 AssertReturn(RT_VALID_PTR(pvBlock) || !cbBlock, VERR_INVALID_POINTER);
370
371 /*
372 * Apply defaults, align sizes and check against available buffer space.
373 * This code can be made a bit more clever, if someone feels like it.
374 */
375 size_t const cbHdr = RT_ALIGN_Z(sizeof(RTTRACEBUFINT), RTTRACEBUF_ALIGNMENT)
376 + RT_ALIGN_Z(sizeof(RTTRACEBUFVOLATILE), RTTRACEBUF_ALIGNMENT);
377 size_t const cbEntryBuf = cbBlock > cbHdr ? cbBlock - cbHdr : 0;
378 if (cbEntry)
379 cbEntry = RT_ALIGN_32(cbEntry, RTTRACEBUF_ALIGNMENT);
380 else
381 {
382 if (!cbEntryBuf)
383 {
384 cbEntry = RTTRACEBUF_DEF_ENTRY_SIZE;
385 cEntries = RTTRACEBUF_DEF_ENTRIES;
386 }
387 else if (cEntries)
388 {
389 size_t cbEntryZ = cbBlock / cEntries;
390 cbEntryZ &= ~(RTTRACEBUF_ALIGNMENT - 1);
391 if (cbEntryZ > RTTRACEBUF_MAX_ENTRIES)
392 cbEntryZ = RTTRACEBUF_MAX_ENTRIES;
393 cbEntry = (uint32_t)cbEntryZ;
394 }
395 else if (cbBlock >= RT_ALIGN_32(512, RTTRACEBUF_ALIGNMENT) * 256)
396 cbEntry = RT_ALIGN_32(512, RTTRACEBUF_ALIGNMENT);
397 else if (cbBlock >= RT_ALIGN_32(256, RTTRACEBUF_ALIGNMENT) * 64)
398 cbEntry = RT_ALIGN_32(256, RTTRACEBUF_ALIGNMENT);
399 else if (cbBlock >= RT_ALIGN_32(128, RTTRACEBUF_ALIGNMENT) * 32)
400 cbEntry = RT_ALIGN_32(128, RTTRACEBUF_ALIGNMENT);
401 else
402 cbEntry = sizeof(RTTRACEBUFENTRY);
403 }
404 Assert(RT_ALIGN_32(cbEntry, RTTRACEBUF_ALIGNMENT) == cbEntry);
405
406 if (!cEntries)
407 {
408 size_t cEntriesZ = cbEntryBuf / cbEntry;
409 if (cEntriesZ > RTTRACEBUF_MAX_ENTRIES)
410 cEntriesZ = RTTRACEBUF_MAX_ENTRIES;
411 cEntries = (uint32_t)cEntriesZ;
412 }
413 if (cEntries < RTTRACEBUF_MIN_ENTRIES)
414 cEntries = RTTRACEBUF_MIN_ENTRIES;
415
416 uint32_t offVolatile = RTTRACEBUF_ALIGNMENT - ((uintptr_t)pvBlock & (RTTRACEBUF_ALIGNMENT - 1));
417 if (offVolatile < sizeof(RTTRACEBUFINT))
418 offVolatile += RTTRACEBUF_ALIGNMENT;
419 size_t cbReqBlock = offVolatile
420 + RT_ALIGN_Z(sizeof(RTTRACEBUFVOLATILE), RTTRACEBUF_ALIGNMENT)
421 + cbEntry * cEntries;
422 if (*pcbBlock < cbReqBlock)
423 {
424 *pcbBlock = cbReqBlock;
425 return VERR_BUFFER_OVERFLOW;
426 }
427
428 /*
429 * Do the carving.
430 */
431 memset(pvBlock, 0, cbBlock);
432
433 RTTRACEBUFINT *pThis = (RTTRACEBUFINT *)pvBlock;
434 pThis->u32Magic = RTTRACEBUF_MAGIC;
435 pThis->cbEntry = cbEntry;
436 pThis->cEntries = cEntries;
437 pThis->fFlags = fFlags;
438 pThis->offVolatile = offVolatile;
439 pThis->offEntries = offVolatile + RT_ALIGN_Z(sizeof(RTTRACEBUFVOLATILE), RTTRACEBUF_ALIGNMENT);
440
441 PRTTRACEBUFVOLATILE pVolatile = (PRTTRACEBUFVOLATILE)((uint8_t *)pThis + offVolatile);
442 pVolatile->cRefs = 1;
443 pVolatile->iEntry = 0;
444
445 *pcbBlock = cbBlock - cbReqBlock;
446 *phTraceBuf = pThis;
447 return VINF_SUCCESS;
448}
449
450#endif /* !IN_RC */
451
452
453/**
454 * Destructor.
455 *
456 * @param pThis The trace buffer to destroy.
457 */
458static void rtTraceBufDestroy(RTTRACEBUFINT *pThis)
459{
460 AssertReturnVoid(ASMAtomicCmpXchgU32(&pThis->u32Magic, RTTRACEBUF_MAGIC_DEAD, RTTRACEBUF_MAGIC));
461 if (pThis->fFlags & RTTRACEBUF_FLAGS_FREE_ME)
462 {
463#ifdef IN_RC
464 AssertReleaseFailed();
465#else
466 RTMemFree(pThis);
467#endif
468 }
469}
470
471
472RTDECL(uint32_t) RTTraceBufRetain(RTTRACEBUF hTraceBuf)
473{
474 PCRTTRACEBUFINT pThis = hTraceBuf;
475 RTTRACEBUF_VALID_RETURN_RC(pThis, UINT32_MAX);
476 return ASMAtomicIncU32(&RTTRACEBUF_TO_VOLATILE(pThis)->cRefs);
477}
478
479
480RTDECL(uint32_t) RTTraceBufRelease(RTTRACEBUF hTraceBuf)
481{
482 if (hTraceBuf == NIL_RTTRACEBUF)
483 return 0;
484
485 PCRTTRACEBUFINT pThis = hTraceBuf;
486 RTTRACEBUF_VALID_RETURN_RC(pThis, UINT32_MAX);
487
488 uint32_t cRefs = ASMAtomicDecU32(&RTTRACEBUF_TO_VOLATILE(pThis)->cRefs);
489 if (!cRefs)
490 rtTraceBufDestroy((RTTRACEBUFINT *)pThis);
491 return cRefs;
492}
493
494
495RTDECL(int) RTTraceBufAddMsg(RTTRACEBUF hTraceBuf, const char *pszMsg)
496{
497 RTTRACEBUF_ADD_PROLOGUE(hTraceBuf);
498 RTStrCopy(pszBuf, cchBuf, pszMsg);
499 RTTRACEBUF_ADD_EPILOGUE();
500}
501
502
503RTDECL(int) RTTraceBufAddMsgEx( RTTRACEBUF hTraceBuf, const char *pszMsg, size_t cbMaxMsg)
504{
505 RTTRACEBUF_ADD_PROLOGUE(hTraceBuf);
506 RTStrCopyEx(pszBuf, cchBuf, pszMsg, cbMaxMsg);
507 RTTRACEBUF_ADD_EPILOGUE();
508}
509
510
511RTDECL(int) RTTraceBufAddMsgF(RTTRACEBUF hTraceBuf, const char *pszMsgFmt, ...)
512{
513 int rc;
514 va_list va;
515 va_start(va, pszMsgFmt);
516 rc = RTTraceBufAddMsgV(hTraceBuf, pszMsgFmt, va);
517 va_end(va);
518 return rc;
519}
520
521
522RTDECL(int) RTTraceBufAddMsgV(RTTRACEBUF hTraceBuf, const char *pszMsgFmt, va_list va)
523{
524 RTTRACEBUF_ADD_PROLOGUE(hTraceBuf);
525 RTStrPrintfV(pszBuf, cchBuf, pszMsgFmt, va);
526 RTTRACEBUF_ADD_EPILOGUE();
527}
528
529
530RTDECL(int) RTTraceBufAddPos(RTTRACEBUF hTraceBuf, RT_SRC_POS_DECL)
531{
532 RTTRACEBUF_ADD_PROLOGUE(hTraceBuf);
533 RTTRACEBUF_ADD_STORE_SRC_POS();
534 RTTRACEBUF_ADD_EPILOGUE();
535}
536
537
538RTDECL(int) RTTraceBufAddPosMsg(RTTRACEBUF hTraceBuf, RT_SRC_POS_DECL, const char *pszMsg)
539{
540 RTTRACEBUF_ADD_PROLOGUE(hTraceBuf);
541 RTTRACEBUF_ADD_STORE_SRC_POS();
542 RTStrCopy(pszBuf, cchBuf, pszMsg);
543 RTTRACEBUF_ADD_EPILOGUE();
544}
545
546
547RTDECL(int) RTTraceBufAddPosMsgEx(RTTRACEBUF hTraceBuf, RT_SRC_POS_DECL, const char *pszMsg, size_t cbMaxMsg)
548{
549 RTTRACEBUF_ADD_PROLOGUE(hTraceBuf);
550 RTTRACEBUF_ADD_STORE_SRC_POS();
551 RTStrCopyEx(pszBuf, cchBuf, pszMsg, cbMaxMsg);
552 RTTRACEBUF_ADD_EPILOGUE();
553}
554
555
556RTDECL(int) RTTraceBufAddPosMsgF(RTTRACEBUF hTraceBuf, RT_SRC_POS_DECL, const char *pszMsgFmt, ...)
557{
558 int rc;
559 va_list va;
560 va_start(va, pszMsgFmt);
561 rc = RTTraceBufAddPosMsgV(hTraceBuf, RT_SRC_POS_ARGS, pszMsgFmt, va);
562 va_end(va);
563 return rc;
564}
565
566
567RTDECL(int) RTTraceBufAddPosMsgV(RTTRACEBUF hTraceBuf, RT_SRC_POS_DECL, const char *pszMsgFmt, va_list va)
568{
569 RTTRACEBUF_ADD_PROLOGUE(hTraceBuf);
570 RTTRACEBUF_ADD_STORE_SRC_POS();
571 RTStrPrintfV(pszBuf, cchBuf, pszMsgFmt, va);
572 RTTRACEBUF_ADD_EPILOGUE();
573}
574
575
576RTDECL(int) RTTraceBufEnumEntries(RTTRACEBUF hTraceBuf, PFNRTTRACEBUFCALLBACK pfnCallback, void *pvUser)
577{
578 int rc = VINF_SUCCESS;
579 uint32_t iBase;
580 uint32_t cLeft;
581 PCRTTRACEBUFINT pThis;
582 RTTRACEBUF_RESOLVE_VALIDATE_RETAIN_RETURN(hTraceBuf, pThis);
583
584 iBase = ASMAtomicReadU32(&RTTRACEBUF_TO_VOLATILE(pThis)->iEntry);
585 cLeft = pThis->cEntries;
586 while (cLeft--)
587 {
588 PRTTRACEBUFENTRY pEntry;
589
590 iBase %= pThis->cEntries;
591 pEntry = RTTRACEBUF_TO_ENTRY(pThis, iBase);
592 if (pEntry->NanoTS)
593 {
594 rc = pfnCallback((RTTRACEBUF)pThis, cLeft, pEntry->NanoTS, pEntry->idCpu, pEntry->szMsg, pvUser);
595 if (rc != VINF_SUCCESS)
596 break;
597 }
598
599 /* next */
600 iBase += 1;
601 }
602
603 RTTRACEBUF_DROP_REFERENCE(pThis);
604 return rc;
605}
606
607
608RTDECL(uint32_t) RTTraceBufGetEntrySize(RTTRACEBUF hTraceBuf)
609{
610 PCRTTRACEBUFINT pThis = hTraceBuf;
611 RTTRACEBUF_VALID_RETURN_RC(pThis, 0);
612 return pThis->cbEntry;
613}
614
615
616RTDECL(uint32_t) RTTraceBufGetEntryCount(RTTRACEBUF hTraceBuf)
617{
618 PCRTTRACEBUFINT pThis = hTraceBuf;
619 RTTRACEBUF_VALID_RETURN_RC(pThis, 0);
620 return pThis->cEntries;
621}
622
623
624RTDECL(bool) RTTraceBufDisable(RTTRACEBUF hTraceBuf)
625{
626 PCRTTRACEBUFINT pThis = hTraceBuf;
627 RTTRACEBUF_VALID_RETURN_RC(pThis, false);
628 return !ASMAtomicBitTestAndSet((void volatile *)&pThis->fFlags, RTTRACEBUF_FLAGS_DISABLED_BIT);
629}
630
631
632RTDECL(bool) RTTraceBufEnable(RTTRACEBUF hTraceBuf)
633{
634 PCRTTRACEBUFINT pThis = hTraceBuf;
635 RTTRACEBUF_VALID_RETURN_RC(pThis, false);
636 return !ASMAtomicBitTestAndClear((void volatile *)&pThis->fFlags, RTTRACEBUF_FLAGS_DISABLED_BIT);
637}
638
639
640/*
641 *
642 * Move the following to a separate file, consider using the enumerator.
643 *
644 */
645
646RTDECL(int) RTTraceBufDumpToLog(RTTRACEBUF hTraceBuf)
647{
648 uint32_t iBase;
649 uint32_t cLeft;
650 PCRTTRACEBUFINT pThis;
651 RTTRACEBUF_RESOLVE_VALIDATE_RETAIN_RETURN(hTraceBuf, pThis);
652
653 iBase = ASMAtomicReadU32(&RTTRACEBUF_TO_VOLATILE(pThis)->iEntry);
654 cLeft = pThis->cEntries;
655 while (cLeft--)
656 {
657 PRTTRACEBUFENTRY pEntry;
658
659 iBase %= pThis->cEntries;
660 pEntry = RTTRACEBUF_TO_ENTRY(pThis, iBase);
661 if (pEntry->NanoTS)
662 RTLogPrintf("%04u/%'llu/%02x: %s\n", cLeft, pEntry->NanoTS, pEntry->idCpu, pEntry->szMsg);
663
664 /* next */
665 iBase += 1;
666 }
667
668 RTTRACEBUF_DROP_REFERENCE(pThis);
669 return VINF_SUCCESS;
670}
671
672
673RTDECL(int) RTTraceBufDumpToAssert(RTTRACEBUF hTraceBuf)
674{
675 uint32_t iBase;
676 uint32_t cLeft;
677 PCRTTRACEBUFINT pThis;
678 RTTRACEBUF_RESOLVE_VALIDATE_RETAIN_RETURN(hTraceBuf, pThis);
679
680 iBase = ASMAtomicReadU32(&RTTRACEBUF_TO_VOLATILE(pThis)->iEntry);
681 cLeft = pThis->cEntries;
682 while (cLeft--)
683 {
684 PRTTRACEBUFENTRY pEntry;
685
686 iBase %= pThis->cEntries;
687 pEntry = RTTRACEBUF_TO_ENTRY(pThis, iBase);
688 if (pEntry->NanoTS)
689 RTAssertMsg2AddWeak("%u/%'llu/%02x: %s\n", cLeft, pEntry->NanoTS, pEntry->idCpu, pEntry->szMsg);
690
691 /* next */
692 iBase += 1;
693 }
694
695 RTTRACEBUF_DROP_REFERENCE(pThis);
696 return VINF_SUCCESS;
697}
698
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use