llvm/compiler-rt/lib/xray/xray_fdr_logging.cpp

//===-- xray_fdr_logging.cpp -----------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file is a part of XRay, a dynamic runtime instrumentation system.
//
// Here we implement the Flight Data Recorder mode for XRay, where we use
// compact structures to store records in memory as well as when writing out the
// data to files.
//
//===----------------------------------------------------------------------===//
#include "xray_fdr_logging.h"
#include <cassert>
#include <cstddef>
#include <errno.h>
#include <limits>
#include <memory>
#include <pthread.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>

#include "sanitizer_common/sanitizer_allocator_internal.h"
#include "sanitizer_common/sanitizer_atomic.h"
#include "sanitizer_common/sanitizer_common.h"
#include "xray/xray_interface.h"
#include "xray/xray_records.h"
#include "xray_allocator.h"
#include "xray_buffer_queue.h"
#include "xray_defs.h"
#include "xray_fdr_controller.h"
#include "xray_fdr_flags.h"
#include "xray_fdr_log_writer.h"
#include "xray_flags.h"
#include "xray_recursion_guard.h"
#include "xray_tsc.h"
#include "xray_utils.h"

namespace __xray {

static atomic_sint32_t LoggingStatus =;

namespace {

// Group together thread-local-data in a struct, then hide it behind a function
// call so that it can be initialized on first use instead of as a global. We
// force the alignment to 64-bytes for x86 cache line alignment, as this
// structure is used in the hot path of implementation.
struct XRAY_TLS_ALIGNAS(64) ThreadLocalData {};

} // namespace

static_assert;

// Use a global pthread key to identify thread-local data for logging.
static pthread_key_t Key;

// Global BufferQueue.
static std::byte BufferQueueStorage[sizeof(BufferQueue)];
static BufferQueue *BQ =;

// Global thresholds for function durations.
static atomic_uint64_t ThresholdTicks{};

// Global for ticks per second.
static atomic_uint64_t TicksPerSec{};

static atomic_sint32_t LogFlushStatus =;

// This function will initialize the thread-local data structure used by the FDR
// logging implementation and return a reference to it. The implementation
// details require a bit of care to maintain.
//
// First, some requirements on the implementation in general:
//
//   - XRay handlers should not call any memory allocation routines that may
//     delegate to an instrumented implementation. This means functions like
//     malloc() and free() should not be called while instrumenting.
//
//   - We would like to use some thread-local data initialized on first-use of
//     the XRay instrumentation. These allow us to implement unsynchronized
//     routines that access resources associated with the thread.
//
// The implementation here uses a few mechanisms that allow us to provide both
// the requirements listed above. We do this by:
//
//   1. Using a thread-local aligned storage buffer for representing the
//      ThreadLocalData struct. This data will be uninitialized memory by
//      design.
//
//   2. Not requiring a thread exit handler/implementation, keeping the
//      thread-local as purely a collection of references/data that do not
//      require cleanup.
//
// We're doing this to avoid using a `thread_local` object that has a
// non-trivial destructor, because the C++ runtime might call std::malloc(...)
// to register calls to destructors. Deadlocks may arise when, for example, an
// externally provided malloc implementation is XRay instrumented, and
// initializing the thread-locals involves calling into malloc. A malloc
// implementation that does global synchronization might be holding a lock for a
// critical section, calling a function that might be XRay instrumented (and
// thus in turn calling into malloc by virtue of registration of the
// thread_local's destructor).
#if XRAY_HAS_TLS_ALIGNAS
static_assert;
#endif
static ThreadLocalData &getThreadLocalData() {}

static XRayFileHeader &fdrCommonHeaderInfo() {}

// This is the iterator implementation, which knows how to handle FDR-mode
// specific buffers. This is used as an implementation of the iterator function
// needed by __xray_set_buffer_iterator(...). It maintains a global state of the
// buffer iteration for the currently installed FDR mode buffers. In particular:
//
//   - If the argument represents the initial state of XRayBuffer ({nullptr, 0})
//     then the iterator returns the header information.
//   - If the argument represents the header information ({address of header
//     info, size of the header info}) then it returns the first FDR buffer's
//     address and extents.
//   - It will keep returning the next buffer and extents as there are more
//     buffers to process. When the input represents the last buffer, it will
//     return the initial state to signal completion ({nullptr, 0}).
//
// See xray/xray_log_interface.h for more details on the requirements for the
// implementations of __xray_set_buffer_iterator(...) and
// __xray_log_process_buffers(...).
XRayBuffer fdrIterator(const XRayBuffer B) {}

// Must finalize before flushing.
XRayLogFlushStatus fdrLoggingFlush() XRAY_NEVER_INSTRUMENT {}

XRayLogInitStatus fdrLoggingFinalize() XRAY_NEVER_INSTRUMENT {}

struct TSCAndCPU {};

static TSCAndCPU getTimestamp() XRAY_NEVER_INSTRUMENT {}

thread_local atomic_uint8_t Running{};

static bool setupTLD(ThreadLocalData &TLD) XRAY_NEVER_INSTRUMENT {}

void fdrLoggingHandleArg0(int32_t FuncId,
                          XRayEntryType Entry) XRAY_NEVER_INSTRUMENT {}

void fdrLoggingHandleArg1(int32_t FuncId, XRayEntryType Entry,
                          uint64_t Arg) XRAY_NEVER_INSTRUMENT {}

void fdrLoggingHandleCustomEvent(void *Event,
                                 std::size_t EventSize) XRAY_NEVER_INSTRUMENT {}

void fdrLoggingHandleTypedEvent(size_t EventType, const void *Event,
                                size_t EventSize) noexcept
    XRAY_NEVER_INSTRUMENT {}

XRayLogInitStatus fdrLoggingInit(size_t, size_t, void *Options,
                                 size_t OptionsSize) XRAY_NEVER_INSTRUMENT {}

bool fdrLogDynamicInitializer() XRAY_NEVER_INSTRUMENT {}

} // namespace __xray

static auto UNUSED Unused =;