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