forked from OSchip/llvm-project
211 lines
7.5 KiB
C++
211 lines
7.5 KiB
C++
//===-- xray_log_interface.cc ---------------------------------------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file is a part of XRay, a function call tracing system.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
#include "xray/xray_log_interface.h"
|
|
|
|
#include "sanitizer_common/sanitizer_allocator_internal.h"
|
|
#include "sanitizer_common/sanitizer_atomic.h"
|
|
#include "sanitizer_common/sanitizer_mutex.h"
|
|
#include "xray/xray_interface.h"
|
|
#include "xray_defs.h"
|
|
|
|
namespace __xray {
|
|
static SpinMutex XRayImplMutex;
|
|
static XRayLogImpl CurrentXRayImpl{nullptr, nullptr, nullptr, nullptr};
|
|
static XRayLogImpl *GlobalXRayImpl = nullptr;
|
|
|
|
// This is the default implementation of a buffer iterator, which always yields
|
|
// a null buffer.
|
|
XRayBuffer NullBufferIterator(XRayBuffer) XRAY_NEVER_INSTRUMENT {
|
|
return {nullptr, 0};
|
|
}
|
|
|
|
// This is the global function responsible for iterating through given buffers.
|
|
atomic_uintptr_t XRayBufferIterator{
|
|
reinterpret_cast<uintptr_t>(&NullBufferIterator)};
|
|
|
|
// We use a linked list of Mode to XRayLogImpl mappings. This is a linked list
|
|
// when it should be a map because we're avoiding having to depend on C++
|
|
// standard library data structures at this level of the implementation.
|
|
struct ModeImpl {
|
|
ModeImpl *Next;
|
|
const char *Mode;
|
|
XRayLogImpl Impl;
|
|
};
|
|
|
|
static ModeImpl SentinelModeImpl{
|
|
nullptr, nullptr, {nullptr, nullptr, nullptr, nullptr}};
|
|
static ModeImpl *ModeImpls = &SentinelModeImpl;
|
|
static const ModeImpl *CurrentMode = nullptr;
|
|
|
|
} // namespace __xray
|
|
|
|
using namespace __xray;
|
|
|
|
void __xray_log_set_buffer_iterator(XRayBuffer (*Iterator)(XRayBuffer))
|
|
XRAY_NEVER_INSTRUMENT {
|
|
atomic_store(&__xray::XRayBufferIterator,
|
|
reinterpret_cast<uintptr_t>(Iterator), memory_order_release);
|
|
}
|
|
|
|
void __xray_log_remove_buffer_iterator() XRAY_NEVER_INSTRUMENT {
|
|
__xray_log_set_buffer_iterator(&NullBufferIterator);
|
|
}
|
|
|
|
XRayLogRegisterStatus
|
|
__xray_log_register_mode(const char *Mode,
|
|
XRayLogImpl Impl) XRAY_NEVER_INSTRUMENT {
|
|
if (Impl.flush_log == nullptr || Impl.handle_arg0 == nullptr ||
|
|
Impl.log_finalize == nullptr || Impl.log_init == nullptr)
|
|
return XRayLogRegisterStatus::XRAY_INCOMPLETE_IMPL;
|
|
|
|
SpinMutexLock Guard(&XRayImplMutex);
|
|
// First, look for whether the mode already has a registered implementation.
|
|
for (ModeImpl *it = ModeImpls; it != &SentinelModeImpl; it = it->Next) {
|
|
if (!internal_strcmp(Mode, it->Mode))
|
|
return XRayLogRegisterStatus::XRAY_DUPLICATE_MODE;
|
|
}
|
|
auto *NewModeImpl = static_cast<ModeImpl *>(InternalAlloc(sizeof(ModeImpl)));
|
|
NewModeImpl->Next = ModeImpls;
|
|
NewModeImpl->Mode = internal_strdup(Mode);
|
|
NewModeImpl->Impl = Impl;
|
|
ModeImpls = NewModeImpl;
|
|
return XRayLogRegisterStatus::XRAY_REGISTRATION_OK;
|
|
}
|
|
|
|
XRayLogRegisterStatus
|
|
__xray_log_select_mode(const char *Mode) XRAY_NEVER_INSTRUMENT {
|
|
SpinMutexLock Guard(&XRayImplMutex);
|
|
for (ModeImpl *it = ModeImpls; it != &SentinelModeImpl; it = it->Next) {
|
|
if (!internal_strcmp(Mode, it->Mode)) {
|
|
CurrentMode = it;
|
|
CurrentXRayImpl = it->Impl;
|
|
GlobalXRayImpl = &CurrentXRayImpl;
|
|
__xray_set_handler(it->Impl.handle_arg0);
|
|
return XRayLogRegisterStatus::XRAY_REGISTRATION_OK;
|
|
}
|
|
}
|
|
return XRayLogRegisterStatus::XRAY_MODE_NOT_FOUND;
|
|
}
|
|
|
|
const char *__xray_log_get_current_mode() XRAY_NEVER_INSTRUMENT {
|
|
SpinMutexLock Guard(&XRayImplMutex);
|
|
if (CurrentMode != nullptr)
|
|
return CurrentMode->Mode;
|
|
return nullptr;
|
|
}
|
|
|
|
void __xray_set_log_impl(XRayLogImpl Impl) XRAY_NEVER_INSTRUMENT {
|
|
if (Impl.log_init == nullptr || Impl.log_finalize == nullptr ||
|
|
Impl.handle_arg0 == nullptr || Impl.flush_log == nullptr) {
|
|
SpinMutexLock Guard(&XRayImplMutex);
|
|
GlobalXRayImpl = nullptr;
|
|
CurrentMode = nullptr;
|
|
__xray_remove_handler();
|
|
__xray_remove_handler_arg1();
|
|
return;
|
|
}
|
|
|
|
SpinMutexLock Guard(&XRayImplMutex);
|
|
CurrentXRayImpl = Impl;
|
|
GlobalXRayImpl = &CurrentXRayImpl;
|
|
__xray_set_handler(Impl.handle_arg0);
|
|
}
|
|
|
|
void __xray_remove_log_impl() XRAY_NEVER_INSTRUMENT {
|
|
SpinMutexLock Guard(&XRayImplMutex);
|
|
GlobalXRayImpl = nullptr;
|
|
__xray_remove_handler();
|
|
__xray_remove_handler_arg1();
|
|
}
|
|
|
|
XRayLogInitStatus __xray_log_init(size_t BufferSize, size_t MaxBuffers,
|
|
void *Args,
|
|
size_t ArgsSize) XRAY_NEVER_INSTRUMENT {
|
|
SpinMutexLock Guard(&XRayImplMutex);
|
|
if (!GlobalXRayImpl)
|
|
return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED;
|
|
return GlobalXRayImpl->log_init(BufferSize, MaxBuffers, Args, ArgsSize);
|
|
}
|
|
|
|
XRayLogInitStatus __xray_log_init_mode(const char *Mode, const char *Config)
|
|
XRAY_NEVER_INSTRUMENT {
|
|
SpinMutexLock Guard(&XRayImplMutex);
|
|
if (!GlobalXRayImpl)
|
|
return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED;
|
|
|
|
if (Config == nullptr)
|
|
return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED;
|
|
|
|
// Check first whether the current mode is the same as what we expect.
|
|
if (CurrentMode == nullptr || internal_strcmp(CurrentMode->Mode, Mode) != 0)
|
|
return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED;
|
|
|
|
// Here we do some work to coerce the pointer we're provided, so that
|
|
// the implementations that still take void* pointers can handle the
|
|
// data provided in the Config argument.
|
|
return GlobalXRayImpl->log_init(
|
|
0, 0, const_cast<void *>(static_cast<const void *>(Config)), 0);
|
|
}
|
|
|
|
XRayLogInitStatus
|
|
__xray_log_init_mode_bin(const char *Mode, const char *Config,
|
|
size_t ConfigSize) XRAY_NEVER_INSTRUMENT {
|
|
SpinMutexLock Guard(&XRayImplMutex);
|
|
if (!GlobalXRayImpl)
|
|
return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED;
|
|
|
|
if (Config == nullptr)
|
|
return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED;
|
|
|
|
// Check first whether the current mode is the same as what we expect.
|
|
if (CurrentMode == nullptr || internal_strcmp(CurrentMode->Mode, Mode) != 0)
|
|
return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED;
|
|
|
|
// Here we do some work to coerce the pointer we're provided, so that
|
|
// the implementations that still take void* pointers can handle the
|
|
// data provided in the Config argument.
|
|
return GlobalXRayImpl->log_init(
|
|
0, 0, const_cast<void *>(static_cast<const void *>(Config)), ConfigSize);
|
|
}
|
|
|
|
XRayLogInitStatus __xray_log_finalize() XRAY_NEVER_INSTRUMENT {
|
|
SpinMutexLock Guard(&XRayImplMutex);
|
|
if (!GlobalXRayImpl)
|
|
return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED;
|
|
return GlobalXRayImpl->log_finalize();
|
|
}
|
|
|
|
XRayLogFlushStatus __xray_log_flushLog() XRAY_NEVER_INSTRUMENT {
|
|
SpinMutexLock Guard(&XRayImplMutex);
|
|
if (!GlobalXRayImpl)
|
|
return XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING;
|
|
return GlobalXRayImpl->flush_log();
|
|
}
|
|
|
|
XRayLogFlushStatus __xray_log_process_buffers(
|
|
void (*Processor)(const char *, XRayBuffer)) XRAY_NEVER_INSTRUMENT {
|
|
// We want to make sure that there will be no changes to the global state for
|
|
// the log by synchronising on the XRayBufferIteratorMutex.
|
|
if (!GlobalXRayImpl)
|
|
return XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING;
|
|
auto Iterator = reinterpret_cast<XRayBuffer (*)(XRayBuffer)>(
|
|
atomic_load(&XRayBufferIterator, memory_order_acquire));
|
|
auto Buffer = (*Iterator)(XRayBuffer{nullptr, 0});
|
|
auto Mode = CurrentMode ? CurrentMode->Mode : nullptr;
|
|
while (Buffer.Data != nullptr) {
|
|
(*Processor)(Mode, Buffer);
|
|
Buffer = (*Iterator)(Buffer);
|
|
}
|
|
return XRayLogFlushStatus::XRAY_LOG_FLUSHED;
|
|
}
|