| //===-- xray_log_interface.h ----------------------------------------------===// | |
| // | |
| // 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. | |
| // | |
| // 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: | |
| /// | |
| /// // Before we try initializing the log implementation, we must set it as | |
| /// // the log implementation. We provide the function pointers that define | |
| /// // the various initialization, finalization, and other pluggable hooks | |
| /// // that we need. | |
| /// __xray_set_log_impl({...}); | |
| /// | |
| /// // Once that's done, we can now initialize the implementation. Each | |
| /// // implementation has a chance to let users customize the implementation | |
| /// // with a struct that their implementation supports. Roughly this might | |
| /// // look like: | |
| /// MyImplementationOptions opts; | |
| /// opts.enable_feature = true; | |
| /// ... | |
| /// auto init_status = __xray_log_init( | |
| /// BufferSize, MaxBuffers, &opts, sizeof opts); | |
| /// if (init_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 sleds. | |
| /// 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 sleds 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. | |
| /// } | |
| /// | |
| /// | |
| /// 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, | |
| }; | |
| /// 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 | |
| /// - maximum number of buffers | |
| /// - 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. | |
| 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)(); | |
| }; | |
| /// 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 sleds. | |
| /// | |
| /// 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 removes the currently installed implementation. It will also | |
| /// uninstall any handlers that have been previously installed. It does NOT | |
| /// unpatch the instrumentation sleds. | |
| /// | |
| /// 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(); | |
| /// 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 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(); | |
| } // extern "C" | |
| namespace __xray { | |
| // Options used by the LLVM XRay FDR implementation. | |
| struct FDRLoggingOptions { | |
| bool ReportErrors = false; | |
| int Fd = -1; | |
| }; | |
| } // namespace __xray | |
| #endif // XRAY_XRAY_LOG_INTERFACE_H |