xref: /openbsd-src/gnu/llvm/compiler-rt/lib/xray/xray_init.cpp (revision 810390e339a5425391477d5d41c78d7cab2424ac)
13cab2bb3Spatrick //===-- xray_init.cpp -------------------------------------------*- C++ -*-===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick //
93cab2bb3Spatrick // This file is a part of XRay, a dynamic runtime instrumentation system.
103cab2bb3Spatrick //
113cab2bb3Spatrick // XRay initialisation logic.
123cab2bb3Spatrick //===----------------------------------------------------------------------===//
133cab2bb3Spatrick 
143cab2bb3Spatrick #include <fcntl.h>
153cab2bb3Spatrick #include <strings.h>
163cab2bb3Spatrick #include <unistd.h>
173cab2bb3Spatrick 
183cab2bb3Spatrick #include "sanitizer_common/sanitizer_common.h"
193cab2bb3Spatrick #include "xray_defs.h"
203cab2bb3Spatrick #include "xray_flags.h"
213cab2bb3Spatrick #include "xray_interface_internal.h"
223cab2bb3Spatrick 
233cab2bb3Spatrick extern "C" {
243cab2bb3Spatrick void __xray_init();
253cab2bb3Spatrick extern const XRaySledEntry __start_xray_instr_map[] __attribute__((weak));
263cab2bb3Spatrick extern const XRaySledEntry __stop_xray_instr_map[] __attribute__((weak));
273cab2bb3Spatrick extern const XRayFunctionSledIndex __start_xray_fn_idx[] __attribute__((weak));
283cab2bb3Spatrick extern const XRayFunctionSledIndex __stop_xray_fn_idx[] __attribute__((weak));
293cab2bb3Spatrick 
30*810390e3Srobert #if SANITIZER_APPLE
313cab2bb3Spatrick // HACK: This is a temporary workaround to make XRay build on
323cab2bb3Spatrick // Darwin, but it will probably not work at runtime.
333cab2bb3Spatrick const XRaySledEntry __start_xray_instr_map[] = {};
343cab2bb3Spatrick extern const XRaySledEntry __stop_xray_instr_map[] = {};
353cab2bb3Spatrick extern const XRayFunctionSledIndex __start_xray_fn_idx[] = {};
363cab2bb3Spatrick extern const XRayFunctionSledIndex __stop_xray_fn_idx[] = {};
373cab2bb3Spatrick #endif
383cab2bb3Spatrick }
393cab2bb3Spatrick 
403cab2bb3Spatrick using namespace __xray;
413cab2bb3Spatrick 
423cab2bb3Spatrick // When set to 'true' this means the XRay runtime has been initialised. We use
433cab2bb3Spatrick // the weak symbols defined above (__start_xray_inst_map and
443cab2bb3Spatrick // __stop_xray_instr_map) to initialise the instrumentation map that XRay uses
453cab2bb3Spatrick // for runtime patching/unpatching of instrumentation points.
463cab2bb3Spatrick //
473cab2bb3Spatrick // FIXME: Support DSO instrumentation maps too. The current solution only works
483cab2bb3Spatrick // for statically linked executables.
493cab2bb3Spatrick atomic_uint8_t XRayInitialized{0};
503cab2bb3Spatrick 
513cab2bb3Spatrick // This should always be updated before XRayInitialized is updated.
523cab2bb3Spatrick SpinMutex XRayInstrMapMutex;
533cab2bb3Spatrick XRaySledMap XRayInstrMap;
543cab2bb3Spatrick 
553cab2bb3Spatrick // Global flag to determine whether the flags have been initialized.
563cab2bb3Spatrick atomic_uint8_t XRayFlagsInitialized{0};
573cab2bb3Spatrick 
583cab2bb3Spatrick // A mutex to allow only one thread to initialize the XRay data structures.
593cab2bb3Spatrick SpinMutex XRayInitMutex;
603cab2bb3Spatrick 
613cab2bb3Spatrick // __xray_init() will do the actual loading of the current process' memory map
623cab2bb3Spatrick // and then proceed to look for the .xray_instr_map section/segment.
__xray_init()633cab2bb3Spatrick void __xray_init() XRAY_NEVER_INSTRUMENT {
643cab2bb3Spatrick   SpinMutexLock Guard(&XRayInitMutex);
653cab2bb3Spatrick   // Short-circuit if we've already initialized XRay before.
663cab2bb3Spatrick   if (atomic_load(&XRayInitialized, memory_order_acquire))
673cab2bb3Spatrick     return;
683cab2bb3Spatrick 
693cab2bb3Spatrick   // XRAY is not compatible with PaX MPROTECT
703cab2bb3Spatrick   CheckMPROTECT();
713cab2bb3Spatrick 
723cab2bb3Spatrick   if (!atomic_load(&XRayFlagsInitialized, memory_order_acquire)) {
733cab2bb3Spatrick     initializeFlags();
743cab2bb3Spatrick     atomic_store(&XRayFlagsInitialized, true, memory_order_release);
753cab2bb3Spatrick   }
763cab2bb3Spatrick 
773cab2bb3Spatrick   if (__start_xray_instr_map == nullptr) {
783cab2bb3Spatrick     if (Verbosity())
793cab2bb3Spatrick       Report("XRay instrumentation map missing. Not initializing XRay.\n");
803cab2bb3Spatrick     return;
813cab2bb3Spatrick   }
823cab2bb3Spatrick 
833cab2bb3Spatrick   {
843cab2bb3Spatrick     SpinMutexLock Guard(&XRayInstrMapMutex);
853cab2bb3Spatrick     XRayInstrMap.Sleds = __start_xray_instr_map;
863cab2bb3Spatrick     XRayInstrMap.Entries = __stop_xray_instr_map - __start_xray_instr_map;
871f9cb04fSpatrick     if (__start_xray_fn_idx != nullptr) {
883cab2bb3Spatrick       XRayInstrMap.SledsIndex = __start_xray_fn_idx;
893cab2bb3Spatrick       XRayInstrMap.Functions = __stop_xray_fn_idx - __start_xray_fn_idx;
901f9cb04fSpatrick     } else {
911f9cb04fSpatrick       size_t CountFunctions = 0;
921f9cb04fSpatrick       uint64_t LastFnAddr = 0;
931f9cb04fSpatrick 
941f9cb04fSpatrick       for (std::size_t I = 0; I < XRayInstrMap.Entries; I++) {
951f9cb04fSpatrick         const auto &Sled = XRayInstrMap.Sleds[I];
961f9cb04fSpatrick         const auto Function = Sled.function();
971f9cb04fSpatrick         if (Function != LastFnAddr) {
981f9cb04fSpatrick           CountFunctions++;
991f9cb04fSpatrick           LastFnAddr = Function;
1001f9cb04fSpatrick         }
1011f9cb04fSpatrick       }
1021f9cb04fSpatrick 
1031f9cb04fSpatrick       XRayInstrMap.Functions = CountFunctions;
1041f9cb04fSpatrick     }
1053cab2bb3Spatrick   }
1063cab2bb3Spatrick   atomic_store(&XRayInitialized, true, memory_order_release);
1073cab2bb3Spatrick 
1083cab2bb3Spatrick #ifndef XRAY_NO_PREINIT
1093cab2bb3Spatrick   if (flags()->patch_premain)
1103cab2bb3Spatrick     __xray_patch();
1113cab2bb3Spatrick #endif
1123cab2bb3Spatrick }
1133cab2bb3Spatrick 
1143cab2bb3Spatrick // FIXME: Make check-xray tests work on FreeBSD without
1153cab2bb3Spatrick // SANITIZER_CAN_USE_PREINIT_ARRAY.
1163cab2bb3Spatrick // See sanitizer_internal_defs.h where the macro is defined.
1173cab2bb3Spatrick // Calling unresolved PLT functions in .preinit_array can lead to deadlock on
1183cab2bb3Spatrick // FreeBSD but here it seems benign.
1193cab2bb3Spatrick #if !defined(XRAY_NO_PREINIT) &&                                               \
1203cab2bb3Spatrick     (SANITIZER_CAN_USE_PREINIT_ARRAY || SANITIZER_FREEBSD)
1213cab2bb3Spatrick // Only add the preinit array initialization if the sanitizers can.
1223cab2bb3Spatrick __attribute__((section(".preinit_array"),
1233cab2bb3Spatrick                used)) void (*__local_xray_preinit)(void) = __xray_init;
1243cab2bb3Spatrick #else
1253cab2bb3Spatrick // If we cannot use the .preinit_array section, we should instead use dynamic
1263cab2bb3Spatrick // initialisation.
1273cab2bb3Spatrick __attribute__ ((constructor (0)))
__local_xray_dyninit()1283cab2bb3Spatrick static void __local_xray_dyninit() {
1293cab2bb3Spatrick   __xray_init();
1303cab2bb3Spatrick }
1313cab2bb3Spatrick #endif
132