1 //===-- xray_log_interface.cpp --------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This file is a part of XRay, a function call tracing system.
11 //===----------------------------------------------------------------------===//
12 #include "xray/xray_log_interface.h"
14 #include "sanitizer_common/sanitizer_allocator_internal.h"
15 #include "sanitizer_common/sanitizer_atomic.h"
16 #include "sanitizer_common/sanitizer_mutex.h"
17 #include "xray/xray_interface.h"
18 #include "xray_defs.h"
21 static SpinMutex XRayImplMutex
;
22 static XRayLogImpl CurrentXRayImpl
{nullptr, nullptr, nullptr, nullptr};
23 static XRayLogImpl
*GlobalXRayImpl
= nullptr;
25 // This is the default implementation of a buffer iterator, which always yields
27 XRayBuffer
NullBufferIterator(XRayBuffer
) XRAY_NEVER_INSTRUMENT
{
31 // This is the global function responsible for iterating through given buffers.
32 atomic_uintptr_t XRayBufferIterator
{
33 reinterpret_cast<uintptr_t>(&NullBufferIterator
)};
35 // We use a linked list of Mode to XRayLogImpl mappings. This is a linked list
36 // when it should be a map because we're avoiding having to depend on C++
37 // standard library data structures at this level of the implementation.
44 static ModeImpl SentinelModeImpl
{
45 nullptr, nullptr, {nullptr, nullptr, nullptr, nullptr}};
46 static ModeImpl
*ModeImpls
= &SentinelModeImpl
;
47 static const ModeImpl
*CurrentMode
= nullptr;
51 using namespace __xray
;
53 void __xray_log_set_buffer_iterator(XRayBuffer (*Iterator
)(XRayBuffer
))
54 XRAY_NEVER_INSTRUMENT
{
55 atomic_store(&__xray::XRayBufferIterator
,
56 reinterpret_cast<uintptr_t>(Iterator
), memory_order_release
);
59 void __xray_log_remove_buffer_iterator() XRAY_NEVER_INSTRUMENT
{
60 __xray_log_set_buffer_iterator(&NullBufferIterator
);
64 __xray_log_register_mode(const char *Mode
,
65 XRayLogImpl Impl
) XRAY_NEVER_INSTRUMENT
{
66 if (Impl
.flush_log
== nullptr || Impl
.handle_arg0
== nullptr ||
67 Impl
.log_finalize
== nullptr || Impl
.log_init
== nullptr)
68 return XRayLogRegisterStatus::XRAY_INCOMPLETE_IMPL
;
70 SpinMutexLock
Guard(&XRayImplMutex
);
71 // First, look for whether the mode already has a registered implementation.
72 for (ModeImpl
*it
= ModeImpls
; it
!= &SentinelModeImpl
; it
= it
->Next
) {
73 if (!internal_strcmp(Mode
, it
->Mode
))
74 return XRayLogRegisterStatus::XRAY_DUPLICATE_MODE
;
76 auto *NewModeImpl
= static_cast<ModeImpl
*>(InternalAlloc(sizeof(ModeImpl
)));
77 NewModeImpl
->Next
= ModeImpls
;
78 NewModeImpl
->Mode
= internal_strdup(Mode
);
79 NewModeImpl
->Impl
= Impl
;
80 ModeImpls
= NewModeImpl
;
81 return XRayLogRegisterStatus::XRAY_REGISTRATION_OK
;
85 __xray_log_select_mode(const char *Mode
) XRAY_NEVER_INSTRUMENT
{
86 SpinMutexLock
Guard(&XRayImplMutex
);
87 for (ModeImpl
*it
= ModeImpls
; it
!= &SentinelModeImpl
; it
= it
->Next
) {
88 if (!internal_strcmp(Mode
, it
->Mode
)) {
90 CurrentXRayImpl
= it
->Impl
;
91 GlobalXRayImpl
= &CurrentXRayImpl
;
92 __xray_set_handler(it
->Impl
.handle_arg0
);
93 return XRayLogRegisterStatus::XRAY_REGISTRATION_OK
;
96 return XRayLogRegisterStatus::XRAY_MODE_NOT_FOUND
;
99 const char *__xray_log_get_current_mode() XRAY_NEVER_INSTRUMENT
{
100 SpinMutexLock
Guard(&XRayImplMutex
);
101 if (CurrentMode
!= nullptr)
102 return CurrentMode
->Mode
;
106 void __xray_set_log_impl(XRayLogImpl Impl
) XRAY_NEVER_INSTRUMENT
{
107 if (Impl
.log_init
== nullptr || Impl
.log_finalize
== nullptr ||
108 Impl
.handle_arg0
== nullptr || Impl
.flush_log
== nullptr) {
109 SpinMutexLock
Guard(&XRayImplMutex
);
110 GlobalXRayImpl
= nullptr;
111 CurrentMode
= nullptr;
112 __xray_remove_handler();
113 __xray_remove_handler_arg1();
117 SpinMutexLock
Guard(&XRayImplMutex
);
118 CurrentXRayImpl
= Impl
;
119 GlobalXRayImpl
= &CurrentXRayImpl
;
120 __xray_set_handler(Impl
.handle_arg0
);
123 void __xray_remove_log_impl() XRAY_NEVER_INSTRUMENT
{
124 SpinMutexLock
Guard(&XRayImplMutex
);
125 GlobalXRayImpl
= nullptr;
126 __xray_remove_handler();
127 __xray_remove_handler_arg1();
130 XRayLogInitStatus
__xray_log_init(size_t BufferSize
, size_t MaxBuffers
,
132 size_t ArgsSize
) XRAY_NEVER_INSTRUMENT
{
133 SpinMutexLock
Guard(&XRayImplMutex
);
135 return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED
;
136 return GlobalXRayImpl
->log_init(BufferSize
, MaxBuffers
, Args
, ArgsSize
);
139 XRayLogInitStatus
__xray_log_init_mode(const char *Mode
, const char *Config
)
140 XRAY_NEVER_INSTRUMENT
{
141 SpinMutexLock
Guard(&XRayImplMutex
);
143 return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED
;
145 if (Config
== nullptr)
146 return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED
;
148 // Check first whether the current mode is the same as what we expect.
149 if (CurrentMode
== nullptr || internal_strcmp(CurrentMode
->Mode
, Mode
) != 0)
150 return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED
;
152 // Here we do some work to coerce the pointer we're provided, so that
153 // the implementations that still take void* pointers can handle the
154 // data provided in the Config argument.
155 return GlobalXRayImpl
->log_init(
156 0, 0, const_cast<void *>(static_cast<const void *>(Config
)), 0);
160 __xray_log_init_mode_bin(const char *Mode
, const char *Config
,
161 size_t ConfigSize
) XRAY_NEVER_INSTRUMENT
{
162 SpinMutexLock
Guard(&XRayImplMutex
);
164 return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED
;
166 if (Config
== nullptr)
167 return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED
;
169 // Check first whether the current mode is the same as what we expect.
170 if (CurrentMode
== nullptr || internal_strcmp(CurrentMode
->Mode
, Mode
) != 0)
171 return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED
;
173 // Here we do some work to coerce the pointer we're provided, so that
174 // the implementations that still take void* pointers can handle the
175 // data provided in the Config argument.
176 return GlobalXRayImpl
->log_init(
177 0, 0, const_cast<void *>(static_cast<const void *>(Config
)), ConfigSize
);
180 XRayLogInitStatus
__xray_log_finalize() XRAY_NEVER_INSTRUMENT
{
181 SpinMutexLock
Guard(&XRayImplMutex
);
183 return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED
;
184 return GlobalXRayImpl
->log_finalize();
187 XRayLogFlushStatus
__xray_log_flushLog() XRAY_NEVER_INSTRUMENT
{
188 SpinMutexLock
Guard(&XRayImplMutex
);
190 return XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING
;
191 return GlobalXRayImpl
->flush_log();
194 XRayLogFlushStatus
__xray_log_process_buffers(
195 void (*Processor
)(const char *, XRayBuffer
)) XRAY_NEVER_INSTRUMENT
{
196 // We want to make sure that there will be no changes to the global state for
197 // the log by synchronising on the XRayBufferIteratorMutex.
199 return XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING
;
200 auto Iterator
= reinterpret_cast<XRayBuffer (*)(XRayBuffer
)>(
201 atomic_load(&XRayBufferIterator
, memory_order_acquire
));
202 auto Buffer
= (*Iterator
)(XRayBuffer
{nullptr, 0});
203 auto Mode
= CurrentMode
? CurrentMode
->Mode
: nullptr;
204 while (Buffer
.Data
!= nullptr) {
205 (*Processor
)(Mode
, Buffer
);
206 Buffer
= (*Iterator
)(Buffer
);
208 return XRayLogFlushStatus::XRAY_LOG_FLUSHED
;