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