1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
|
//===-- xray_log_interface.h ----------------------------------------------===//
//
// 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 function call tracing system.
//
// APIs for installing a new logging implementation.
//
//===----------------------------------------------------------------------===//
///
/// XRay allows users to implement their own logging handlers and install them
/// to replace the default runtime-controllable implementation that comes with
/// compiler-rt/xray. The "flight data recorder" (FDR) mode implementation uses
/// this API to install itself in an XRay-enabled binary. See
/// compiler-rt/lib/xray_fdr_logging.{h,cc} for details of that implementation.
///
/// The high-level usage pattern for these APIs look like the following:
///
/// // We choose the mode which we'd like to install, and check whether this
/// // has succeeded. Each mode will have their own set of flags they will
/// // support, outside of the global XRay configuration options that are
/// // defined in the XRAY_OPTIONS environment variable.
/// auto select_status = __xray_log_select_mode("xray-fdr");
/// if (select_status != XRayLogRegisterStatus::XRAY_REGISTRATION_OK) {
/// // This failed, we should not proceed with attempting to initialise
/// // the currently selected mode.
/// return;
/// }
///
/// // Once that's done, we can now attempt to configure the implementation.
/// // To do this, we provide the string flags configuration for the mode.
/// auto config_status = __xray_log_init_mode(
/// "xray-fdr", "verbosity=1 some_flag=1 another_flag=2");
/// if (config_status != XRayLogInitStatus::XRAY_LOG_INITIALIZED) {
/// // deal with the error here, if there is one.
/// }
///
/// // When the log implementation has had the chance to initialize, we can
/// // now patch the instrumentation points. Note that we could have patched
/// // the instrumentation points first, but there's no strict ordering to
/// // these operations.
/// auto patch_status = __xray_patch();
/// if (patch_status != XRayPatchingStatus::SUCCESS) {
/// // deal with the error here, if it is an error.
/// }
///
/// // If we want to stop the implementation, we can then finalize it (before
/// // optionally flushing the log).
/// auto fin_status = __xray_log_finalize();
/// if (fin_status != XRayLogInitStatus::XRAY_LOG_FINALIZED) {
/// // deal with the error here, if it is an error.
/// }
///
/// // We can optionally wait before flushing the log to give other threads a
/// // chance to see that the implementation is already finalized. Also, at
/// // this point we can optionally unpatch the instrumentation points to
/// // reduce overheads at runtime.
/// auto unpatch_status = __xray_unpatch();
/// if (unpatch_status != XRayPatchingStatus::SUCCESS) {
/// // deal with the error here, if it is an error.
/// }
///
/// // If there are logs or data to be flushed somewhere, we can do so only
/// // after we've finalized the log. Some implementations may not actually
/// // have anything to log (it might keep the data in memory, or periodically
/// // be logging the data anyway).
/// auto flush_status = __xray_log_flushLog();
/// if (flush_status != XRayLogFlushStatus::XRAY_LOG_FLUSHED) {
/// // deal with the error here, if it is an error.
/// }
///
/// // Alternatively, we can go through the buffers ourselves without
/// // relying on the implementations' flushing semantics (if the
/// // implementation supports exporting this data directly).
/// auto MyBufferProcessor = +[](const char* mode, XRayBuffer buffer) {
/// // Check the "mode" to see if it's something we know how to handle...
/// // and/or do something with an XRayBuffer instance.
/// };
/// auto process_status = __xray_log_process_buffers(MyBufferProcessor);
/// if (process_status != XRayLogFlushStatus::XRAY_LOG_FLUSHED) {
/// // deal with the error here, if it is an error.
/// }
///
/// NOTE: Before calling __xray_patch() again, consider re-initializing the
/// implementation first. Some implementations might stay in an "off" state when
/// they are finalized, while some might be in an invalid/unknown state.
///
#ifndef XRAY_XRAY_LOG_INTERFACE_H
#define XRAY_XRAY_LOG_INTERFACE_H
#include "xray/xray_interface.h"
#include <stddef.h>
extern "C" {
/// This enum defines the valid states in which the logging implementation can
/// be at.
enum XRayLogInitStatus {
/// The default state is uninitialized, and in case there were errors in the
/// initialization, the implementation MUST return XRAY_LOG_UNINITIALIZED.
XRAY_LOG_UNINITIALIZED = 0,
/// Some implementations support multi-stage init (or asynchronous init), and
/// may return XRAY_LOG_INITIALIZING to signal callers of the API that
/// there's an ongoing initialization routine running. This allows
/// implementations to support concurrent threads attempting to initialize,
/// while only signalling success in one.
XRAY_LOG_INITIALIZING = 1,
/// When an implementation is done initializing, it MUST return
/// XRAY_LOG_INITIALIZED. When users call `__xray_patch()`, they are
/// guaranteed that the implementation installed with
/// `__xray_set_log_impl(...)` has been initialized.
XRAY_LOG_INITIALIZED = 2,
/// Some implementations might support multi-stage finalization (or
/// asynchronous finalization), and may return XRAY_LOG_FINALIZING to signal
/// callers of the API that there's an ongoing finalization routine running.
/// This allows implementations to support concurrent threads attempting to
/// finalize, while only signalling success/completion in one.
XRAY_LOG_FINALIZING = 3,
/// When an implementation is done finalizing, it MUST return
/// XRAY_LOG_FINALIZED. It is up to the implementation to determine what the
/// semantics of a finalized implementation is. Some implementations might
/// allow re-initialization once the log is finalized, while some might always
/// be on (and that finalization is a no-op).
XRAY_LOG_FINALIZED = 4,
};
/// This enum allows an implementation to signal log flushing operations via
/// `__xray_log_flushLog()`, and the state of flushing the log.
enum XRayLogFlushStatus {
XRAY_LOG_NOT_FLUSHING = 0,
XRAY_LOG_FLUSHING = 1,
XRAY_LOG_FLUSHED = 2,
};
/// This enum indicates the installation state of a logging implementation, when
/// associating a mode to a particular logging implementation through
/// `__xray_log_register_impl(...)` or through `__xray_log_select_mode(...`.
enum XRayLogRegisterStatus {
XRAY_REGISTRATION_OK = 0,
XRAY_DUPLICATE_MODE = 1,
XRAY_MODE_NOT_FOUND = 2,
XRAY_INCOMPLETE_IMPL = 3,
};
/// A valid XRay logging implementation MUST provide all of the function
/// pointers in XRayLogImpl when being installed through `__xray_set_log_impl`.
/// To be precise, ALL the functions pointers MUST NOT be nullptr.
struct XRayLogImpl {
/// The log initialization routine provided by the implementation, always
/// provided with the following parameters:
///
/// - buffer size (unused)
/// - maximum number of buffers (unused)
/// - a pointer to an argument struct that the implementation MUST handle
/// - the size of the argument struct
///
/// See XRayLogInitStatus for details on what the implementation MUST return
/// when called.
///
/// If the implementation needs to install handlers aside from the 0-argument
/// function call handler, it MUST do so in this initialization handler.
///
/// See xray_interface.h for available handler installation routines.
XRayLogInitStatus (*log_init)(size_t, size_t, void *, size_t);
/// The log finalization routine provided by the implementation.
///
/// See XRayLogInitStatus for details on what the implementation MUST return
/// when called.
XRayLogInitStatus (*log_finalize)();
/// The 0-argument function call handler. XRay logging implementations MUST
/// always have a handler for function entry and exit events. In case the
/// implementation wants to support arg1 (or other future extensions to XRay
/// logging) those MUST be installed by the installed 'log_init' handler.
///
/// Because we didn't want to change the ABI of this struct, the arg1 handler
/// may be silently overwritten during initialization as well.
void (*handle_arg0)(int32_t, XRayEntryType);
/// The log implementation provided routine for when __xray_log_flushLog() is
/// called.
///
/// See XRayLogFlushStatus for details on what the implementation MUST return
/// when called.
XRayLogFlushStatus (*flush_log)();
};
/// DEPRECATED: Use the mode registration workflow instead with
/// __xray_log_register_mode(...) and __xray_log_select_mode(...). See the
/// documentation for those function.
///
/// This function installs a new logging implementation that XRay will use. In
/// case there are any nullptr members in Impl, XRay will *uninstall any
/// existing implementations*. It does NOT patch the instrumentation points.
///
/// NOTE: This function does NOT attempt to finalize the currently installed
/// implementation. Use with caution.
///
/// It is guaranteed safe to call this function in the following states:
///
/// - When the implementation is UNINITIALIZED.
/// - When the implementation is FINALIZED.
/// - When there is no current implementation installed.
///
/// It is logging implementation defined what happens when this function is
/// called while in any other states.
void __xray_set_log_impl(XRayLogImpl Impl);
/// This function registers a logging implementation against a "mode"
/// identifier. This allows multiple modes to be registered, and chosen at
/// runtime using the same mode identifier through
/// `__xray_log_select_mode(...)`.
///
/// We treat the Mode identifier as a null-terminated byte string, as the
/// identifier used when retrieving the log impl.
///
/// Returns:
/// - XRAY_REGISTRATION_OK on success.
/// - XRAY_DUPLICATE_MODE when an implementation is already associated with
/// the provided Mode; does not update the already-registered
/// implementation.
XRayLogRegisterStatus __xray_log_register_mode(const char *Mode,
XRayLogImpl Impl);
/// This function selects the implementation associated with Mode that has been
/// registered through __xray_log_register_mode(...) and installs that
/// implementation (as if through calling __xray_set_log_impl(...)). The same
/// caveats apply to __xray_log_select_mode(...) as with
/// __xray_log_set_log_impl(...).
///
/// Returns:
/// - XRAY_REGISTRATION_OK on success.
/// - XRAY_MODE_NOT_FOUND if there is no implementation associated with Mode;
/// does not update the currently installed implementation.
XRayLogRegisterStatus __xray_log_select_mode(const char *Mode);
/// Returns an identifier for the currently selected XRay mode chosen through
/// the __xray_log_select_mode(...) function call. Returns nullptr if there is
/// no currently installed mode.
const char *__xray_log_get_current_mode();
/// This function removes the currently installed implementation. It will also
/// uninstall any handlers that have been previously installed. It does NOT
/// unpatch the instrumentation points.
///
/// NOTE: This function does NOT attempt to finalize the currently installed
/// implementation. Use with caution.
///
/// It is guaranteed safe to call this function in the following states:
///
/// - When the implementation is UNINITIALIZED.
/// - When the implementation is FINALIZED.
/// - When there is no current implementation installed.
///
/// It is logging implementation defined what happens when this function is
/// called while in any other states.
void __xray_remove_log_impl();
/// DEPRECATED: Use __xray_log_init_mode() instead, and provide all the options
/// in string form.
/// Invokes the installed implementation initialization routine. See
/// XRayLogInitStatus for what the return values mean.
XRayLogInitStatus __xray_log_init(size_t BufferSize, size_t MaxBuffers,
void *Args, size_t ArgsSize);
/// Invokes the installed initialization routine, which *must* support the
/// string based form.
///
/// NOTE: When this API is used, we still invoke the installed initialization
/// routine, but we will call it with the following convention to signal that we
/// are using the string form:
///
/// - BufferSize = 0
/// - MaxBuffers = 0
/// - ArgsSize = 0
/// - Args will be the pointer to the character buffer representing the
/// configuration.
///
/// FIXME: Updating the XRayLogImpl struct is an ABI breaking change. When we
/// are ready to make a breaking change, we should clean this up appropriately.
XRayLogInitStatus __xray_log_init_mode(const char *Mode, const char *Config);
/// Like __xray_log_init_mode(...) this version allows for providing
/// configurations that might have non-null-terminated strings. This will
/// operate similarly to __xray_log_init_mode, with the exception that
/// |ArgsSize| will be what |ConfigSize| is.
XRayLogInitStatus __xray_log_init_mode_bin(const char *Mode, const char *Config,
size_t ConfigSize);
/// Invokes the installed implementation finalization routine. See
/// XRayLogInitStatus for what the return values mean.
XRayLogInitStatus __xray_log_finalize();
/// Invokes the install implementation log flushing routine. See
/// XRayLogFlushStatus for what the return values mean.
XRayLogFlushStatus __xray_log_flushLog();
/// An XRayBuffer represents a section of memory which can be treated by log
/// processing functions as bytes stored in the logging implementation's
/// buffers.
struct XRayBuffer {
const void *Data;
size_t Size;
};
/// Registers an iterator function which takes an XRayBuffer argument, then
/// returns another XRayBuffer function representing the next buffer. When the
/// Iterator function returns an empty XRayBuffer (Data = nullptr, Size = 0),
/// this signifies the end of the buffers.
///
/// The first invocation of this Iterator function will always take an empty
/// XRayBuffer (Data = nullptr, Size = 0).
void __xray_log_set_buffer_iterator(XRayBuffer (*Iterator)(XRayBuffer));
/// Removes the currently registered buffer iterator function.
void __xray_log_remove_buffer_iterator();
/// Invokes the provided handler to process data maintained by the logging
/// handler. This API will be provided raw access to the data available in
/// memory from the logging implementation. The callback function must:
///
/// 1) Not modify the data, to avoid running into undefined behaviour.
///
/// 2) Either know the data layout, or treat the data as raw bytes for later
/// interpretation.
///
/// This API is best used in place of the `__xray_log_flushLog()` implementation
/// above to enable the caller to provide an alternative means of extracting the
/// data from the XRay implementation.
///
/// Implementations MUST then provide:
///
/// 1) A function that will return an XRayBuffer. Functions that return an
/// "empty" XRayBuffer signifies that there are no more buffers to be
/// processed. This function should be registered through the
/// `__xray_log_set_buffer_iterator(...)` function.
///
/// 2) Its own means of converting data it holds in memory into an XRayBuffer
/// structure.
///
/// See XRayLogFlushStatus for what the return values mean.
///
XRayLogFlushStatus __xray_log_process_buffers(void (*Processor)(const char *,
XRayBuffer));
} // extern "C"
#endif // XRAY_XRAY_LOG_INTERFACE_H
|