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