VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/log/tracebuf.cpp@ 62477

Last change on this file since 62477 was 62477, checked in by vboxsync, 8 years ago

(C) 2016

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