Dean Michael Berris | 938c503 | 2016-07-21 07:39:55 +0000 | [diff] [blame] | 1 | //===-- xray_interface.cpp --------------------------------------*- C++ -*-===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This file is a part of XRay, a dynamic runtime instrumentation system. |
| 11 | // |
| 12 | // Implementation of the API functions. |
| 13 | // |
| 14 | //===----------------------------------------------------------------------===// |
| 15 | |
| 16 | #include "xray_interface_internal.h" |
Dean Michael Berris | 17a586e | 2016-07-29 07:11:58 +0000 | [diff] [blame] | 17 | |
Dean Michael Berris | 938c503 | 2016-07-21 07:39:55 +0000 | [diff] [blame] | 18 | #include <cstdint> |
| 19 | #include <cstdio> |
| 20 | #include <errno.h> |
| 21 | #include <limits> |
Keith Wyss | adb092e | 2018-04-17 21:28:53 +0000 | [diff] [blame] | 22 | #include <string.h> |
Dean Michael Berris | 938c503 | 2016-07-21 07:39:55 +0000 | [diff] [blame] | 23 | #include <sys/mman.h> |
| 24 | |
Keith Wyss | adb092e | 2018-04-17 21:28:53 +0000 | [diff] [blame] | 25 | #include "sanitizer_common/sanitizer_addrhashmap.h" |
Dean Michael Berris | 17a586e | 2016-07-29 07:11:58 +0000 | [diff] [blame] | 26 | #include "sanitizer_common/sanitizer_common.h" |
Keith Wyss | adb092e | 2018-04-17 21:28:53 +0000 | [diff] [blame] | 27 | |
Dean Michael Berris | 4031e4b | 2016-11-16 01:01:13 +0000 | [diff] [blame] | 28 | #include "xray_defs.h" |
Dean Michael Berris | 504b0c2 | 2017-12-14 02:51:20 +0000 | [diff] [blame] | 29 | #include "xray_flags.h" |
| 30 | |
| 31 | extern __sanitizer::SpinMutex XRayInstrMapMutex; |
| 32 | extern __sanitizer::atomic_uint8_t XRayInitialized; |
| 33 | extern __xray::XRaySledMap XRayInstrMap; |
Dean Michael Berris | 17a586e | 2016-07-29 07:11:58 +0000 | [diff] [blame] | 34 | |
Dean Michael Berris | 938c503 | 2016-07-21 07:39:55 +0000 | [diff] [blame] | 35 | namespace __xray { |
| 36 | |
Dean Michael Berris | d1617cd | 2016-09-20 14:35:57 +0000 | [diff] [blame] | 37 | #if defined(__x86_64__) |
Dean Michael Berris | 4ef1a69 | 2016-10-06 07:09:40 +0000 | [diff] [blame] | 38 | static const int16_t cSledLength = 12; |
Dean Michael Berris | bad8f0f | 2016-11-21 03:20:43 +0000 | [diff] [blame] | 39 | #elif defined(__aarch64__) |
| 40 | static const int16_t cSledLength = 32; |
Serge Rogatch | 882fc5d | 2016-12-05 23:29:56 +0000 | [diff] [blame] | 41 | #elif defined(__arm__) |
| 42 | static const int16_t cSledLength = 28; |
Sagar Thakur | ea831e4 | 2017-02-15 10:54:09 +0000 | [diff] [blame] | 43 | #elif SANITIZER_MIPS32 |
| 44 | static const int16_t cSledLength = 48; |
| 45 | #elif SANITIZER_MIPS64 |
| 46 | static const int16_t cSledLength = 64; |
Tim Shen | c6ce73b | 2017-02-15 22:40:29 +0000 | [diff] [blame] | 47 | #elif defined(__powerpc64__) |
| 48 | static const int16_t cSledLength = 8; |
Dean Michael Berris | d1617cd | 2016-09-20 14:35:57 +0000 | [diff] [blame] | 49 | #else |
Dean Michael Berris | 4ef1a69 | 2016-10-06 07:09:40 +0000 | [diff] [blame] | 50 | #error "Unsupported CPU Architecture" |
Dean Michael Berris | d1617cd | 2016-09-20 14:35:57 +0000 | [diff] [blame] | 51 | #endif /* CPU architecture */ |
| 52 | |
Dean Michael Berris | 938c503 | 2016-07-21 07:39:55 +0000 | [diff] [blame] | 53 | // This is the function to call when we encounter the entry or exit sleds. |
Dean Michael Berris | 5eaaff6 | 2018-06-05 06:12:42 +0000 | [diff] [blame] | 54 | atomic_uintptr_t XRayPatchedFunction{0}; |
Dean Michael Berris | 938c503 | 2016-07-21 07:39:55 +0000 | [diff] [blame] | 55 | |
Dean Michael Berris | a814c94 | 2017-03-06 07:25:41 +0000 | [diff] [blame] | 56 | // This is the function to call from the arg1-enabled sleds/trampolines. |
Dean Michael Berris | 5eaaff6 | 2018-06-05 06:12:42 +0000 | [diff] [blame] | 57 | atomic_uintptr_t XRayArgLogger{0}; |
Dean Michael Berris | a814c94 | 2017-03-06 07:25:41 +0000 | [diff] [blame] | 58 | |
Dean Michael Berris | 29e16de | 2017-05-12 01:07:41 +0000 | [diff] [blame] | 59 | // This is the function to call when we encounter a custom event log call. |
Dean Michael Berris | 5eaaff6 | 2018-06-05 06:12:42 +0000 | [diff] [blame] | 60 | atomic_uintptr_t XRayPatchedCustomEvent{0}; |
Dean Michael Berris | 29e16de | 2017-05-12 01:07:41 +0000 | [diff] [blame] | 61 | |
Keith Wyss | adb092e | 2018-04-17 21:28:53 +0000 | [diff] [blame] | 62 | // This is the function to call when we encounter a typed event log call. |
Dean Michael Berris | 5eaaff6 | 2018-06-05 06:12:42 +0000 | [diff] [blame] | 63 | atomic_uintptr_t XRayPatchedTypedEvent{0}; |
Keith Wyss | adb092e | 2018-04-17 21:28:53 +0000 | [diff] [blame] | 64 | |
Dean Michael Berris | 504b0c2 | 2017-12-14 02:51:20 +0000 | [diff] [blame] | 65 | // This is the global status to determine whether we are currently |
| 66 | // patching/unpatching. |
Dean Michael Berris | 5eaaff6 | 2018-06-05 06:12:42 +0000 | [diff] [blame] | 67 | atomic_uint8_t XRayPatching{0}; |
Dean Michael Berris | 504b0c2 | 2017-12-14 02:51:20 +0000 | [diff] [blame] | 68 | |
Keith Wyss | adb092e | 2018-04-17 21:28:53 +0000 | [diff] [blame] | 69 | struct TypeDescription { |
| 70 | uint32_t type_id; |
| 71 | std::size_t description_string_length; |
| 72 | }; |
| 73 | |
Dean Michael Berris | 5eaaff6 | 2018-06-05 06:12:42 +0000 | [diff] [blame] | 74 | using TypeDescriptorMapType = AddrHashMap<TypeDescription, 11>; |
Keith Wyss | adb092e | 2018-04-17 21:28:53 +0000 | [diff] [blame] | 75 | // An address map from immutable descriptors to type ids. |
| 76 | TypeDescriptorMapType TypeDescriptorAddressMap{}; |
| 77 | |
Dean Michael Berris | 5eaaff6 | 2018-06-05 06:12:42 +0000 | [diff] [blame] | 78 | atomic_uint32_t TypeEventDescriptorCounter{0}; |
Keith Wyss | adb092e | 2018-04-17 21:28:53 +0000 | [diff] [blame] | 79 | |
| 80 | // MProtectHelper is an RAII wrapper for calls to mprotect(...) that will |
| 81 | // undo any successful mprotect(...) changes. This is used to make a page |
| 82 | // writeable and executable, and upon destruction if it was successful in |
| 83 | // doing so returns the page into a read-only and executable page. |
Dean Michael Berris | 9a0c446 | 2016-07-27 04:30:25 +0000 | [diff] [blame] | 84 | // |
| 85 | // This is only used specifically for runtime-patching of the XRay |
Keith Wyss | adb092e | 2018-04-17 21:28:53 +0000 | [diff] [blame] | 86 | // instrumentation points. This assumes that the executable pages are |
| 87 | // originally read-and-execute only. |
Dean Michael Berris | 9a0c446 | 2016-07-27 04:30:25 +0000 | [diff] [blame] | 88 | class MProtectHelper { |
| 89 | void *PageAlignedAddr; |
| 90 | std::size_t MProtectLen; |
| 91 | bool MustCleanup; |
| 92 | |
| 93 | public: |
Dean Michael Berris | 4031e4b | 2016-11-16 01:01:13 +0000 | [diff] [blame] | 94 | explicit MProtectHelper(void *PageAlignedAddr, |
| 95 | std::size_t MProtectLen) XRAY_NEVER_INSTRUMENT |
| 96 | : PageAlignedAddr(PageAlignedAddr), |
| 97 | MProtectLen(MProtectLen), |
Dean Michael Berris | 9a0c446 | 2016-07-27 04:30:25 +0000 | [diff] [blame] | 98 | MustCleanup(false) {} |
| 99 | |
Dean Michael Berris | 4031e4b | 2016-11-16 01:01:13 +0000 | [diff] [blame] | 100 | int MakeWriteable() XRAY_NEVER_INSTRUMENT { |
Dean Michael Berris | 9a0c446 | 2016-07-27 04:30:25 +0000 | [diff] [blame] | 101 | auto R = mprotect(PageAlignedAddr, MProtectLen, |
| 102 | PROT_READ | PROT_WRITE | PROT_EXEC); |
| 103 | if (R != -1) |
| 104 | MustCleanup = true; |
| 105 | return R; |
| 106 | } |
| 107 | |
Dean Michael Berris | 4031e4b | 2016-11-16 01:01:13 +0000 | [diff] [blame] | 108 | ~MProtectHelper() XRAY_NEVER_INSTRUMENT { |
Dean Michael Berris | 9a0c446 | 2016-07-27 04:30:25 +0000 | [diff] [blame] | 109 | if (MustCleanup) { |
| 110 | mprotect(PageAlignedAddr, MProtectLen, PROT_READ | PROT_EXEC); |
| 111 | } |
| 112 | } |
| 113 | }; |
| 114 | |
Dean Michael Berris | 504b0c2 | 2017-12-14 02:51:20 +0000 | [diff] [blame] | 115 | namespace { |
Dean Michael Berris | 938c503 | 2016-07-21 07:39:55 +0000 | [diff] [blame] | 116 | |
Dean Michael Berris | 504b0c2 | 2017-12-14 02:51:20 +0000 | [diff] [blame] | 117 | bool patchSled(const XRaySledEntry &Sled, bool Enable, |
| 118 | int32_t FuncId) XRAY_NEVER_INSTRUMENT { |
Dean Michael Berris | 5cc4632 | 2017-05-04 04:59:20 +0000 | [diff] [blame] | 119 | bool Success = false; |
| 120 | switch (Sled.Kind) { |
| 121 | case XRayEntryType::ENTRY: |
| 122 | Success = patchFunctionEntry(Enable, FuncId, Sled, __xray_FunctionEntry); |
| 123 | break; |
| 124 | case XRayEntryType::EXIT: |
| 125 | Success = patchFunctionExit(Enable, FuncId, Sled); |
| 126 | break; |
| 127 | case XRayEntryType::TAIL: |
| 128 | Success = patchFunctionTailExit(Enable, FuncId, Sled); |
| 129 | break; |
| 130 | case XRayEntryType::LOG_ARGS_ENTRY: |
| 131 | Success = patchFunctionEntry(Enable, FuncId, Sled, __xray_ArgLoggerEntry); |
| 132 | break; |
Dean Michael Berris | 29e16de | 2017-05-12 01:07:41 +0000 | [diff] [blame] | 133 | case XRayEntryType::CUSTOM_EVENT: |
| 134 | Success = patchCustomEvent(Enable, FuncId, Sled); |
| 135 | break; |
Keith Wyss | adb092e | 2018-04-17 21:28:53 +0000 | [diff] [blame] | 136 | case XRayEntryType::TYPED_EVENT: |
| 137 | Success = patchTypedEvent(Enable, FuncId, Sled); |
| 138 | break; |
Dean Michael Berris | 5cc4632 | 2017-05-04 04:59:20 +0000 | [diff] [blame] | 139 | default: |
| 140 | Report("Unsupported sled kind '%d' @%04x\n", Sled.Address, int(Sled.Kind)); |
| 141 | return false; |
| 142 | } |
| 143 | return Success; |
| 144 | } |
| 145 | |
Dean Michael Berris | 5cc4632 | 2017-05-04 04:59:20 +0000 | [diff] [blame] | 146 | XRayPatchingStatus patchFunction(int32_t FuncId, |
| 147 | bool Enable) XRAY_NEVER_INSTRUMENT { |
Dean Michael Berris | 5eaaff6 | 2018-06-05 06:12:42 +0000 | [diff] [blame] | 148 | if (!atomic_load(&XRayInitialized, |
| 149 | memory_order_acquire)) |
Dean Michael Berris | 5cc4632 | 2017-05-04 04:59:20 +0000 | [diff] [blame] | 150 | return XRayPatchingStatus::NOT_INITIALIZED; // Not initialized. |
| 151 | |
| 152 | uint8_t NotPatching = false; |
Dean Michael Berris | 5eaaff6 | 2018-06-05 06:12:42 +0000 | [diff] [blame] | 153 | if (!atomic_compare_exchange_strong( |
| 154 | &XRayPatching, &NotPatching, true, memory_order_acq_rel)) |
Dean Michael Berris | 5cc4632 | 2017-05-04 04:59:20 +0000 | [diff] [blame] | 155 | return XRayPatchingStatus::ONGOING; // Already patching. |
| 156 | |
| 157 | // Next, we look for the function index. |
| 158 | XRaySledMap InstrMap; |
| 159 | { |
Dean Michael Berris | 5eaaff6 | 2018-06-05 06:12:42 +0000 | [diff] [blame] | 160 | SpinMutexLock Guard(&XRayInstrMapMutex); |
Dean Michael Berris | 5cc4632 | 2017-05-04 04:59:20 +0000 | [diff] [blame] | 161 | InstrMap = XRayInstrMap; |
| 162 | } |
| 163 | |
| 164 | // If we don't have an index, we can't patch individual functions. |
| 165 | if (InstrMap.Functions == 0) |
| 166 | return XRayPatchingStatus::NOT_INITIALIZED; |
| 167 | |
| 168 | // FuncId must be a positive number, less than the number of functions |
| 169 | // instrumented. |
Dean Michael Berris | d45003c | 2017-05-05 01:27:11 +0000 | [diff] [blame] | 170 | if (FuncId <= 0 || static_cast<size_t>(FuncId) > InstrMap.Functions) { |
Dean Michael Berris | 5cc4632 | 2017-05-04 04:59:20 +0000 | [diff] [blame] | 171 | Report("Invalid function id provided: %d\n", FuncId); |
| 172 | return XRayPatchingStatus::FAILED; |
| 173 | } |
| 174 | |
| 175 | // Now we patch ths sleds for this specific function. |
| 176 | auto SledRange = InstrMap.SledsIndex[FuncId - 1]; |
| 177 | auto *f = SledRange.Begin; |
| 178 | auto *e = SledRange.End; |
| 179 | |
| 180 | bool SucceedOnce = false; |
| 181 | while (f != e) |
| 182 | SucceedOnce |= patchSled(*f++, Enable, FuncId); |
| 183 | |
Dean Michael Berris | 5eaaff6 | 2018-06-05 06:12:42 +0000 | [diff] [blame] | 184 | atomic_store(&XRayPatching, false, |
| 185 | memory_order_release); |
Dean Michael Berris | 5cc4632 | 2017-05-04 04:59:20 +0000 | [diff] [blame] | 186 | |
| 187 | if (!SucceedOnce) { |
| 188 | Report("Failed patching any sled for function '%d'.", FuncId); |
| 189 | return XRayPatchingStatus::FAILED; |
| 190 | } |
| 191 | |
| 192 | return XRayPatchingStatus::SUCCESS; |
| 193 | } |
| 194 | |
Dean Michael Berris | 504b0c2 | 2017-12-14 02:51:20 +0000 | [diff] [blame] | 195 | // controlPatching implements the common internals of the patching/unpatching |
| 196 | // implementation. |Enable| defines whether we're enabling or disabling the |
| 197 | // runtime XRay instrumentation. |
| 198 | XRayPatchingStatus controlPatching(bool Enable) XRAY_NEVER_INSTRUMENT { |
Dean Michael Berris | 5eaaff6 | 2018-06-05 06:12:42 +0000 | [diff] [blame] | 199 | if (!atomic_load(&XRayInitialized, |
| 200 | memory_order_acquire)) |
Dean Michael Berris | 504b0c2 | 2017-12-14 02:51:20 +0000 | [diff] [blame] | 201 | return XRayPatchingStatus::NOT_INITIALIZED; // Not initialized. |
| 202 | |
| 203 | uint8_t NotPatching = false; |
Dean Michael Berris | 5eaaff6 | 2018-06-05 06:12:42 +0000 | [diff] [blame] | 204 | if (!atomic_compare_exchange_strong( |
| 205 | &XRayPatching, &NotPatching, true, memory_order_acq_rel)) |
Dean Michael Berris | 504b0c2 | 2017-12-14 02:51:20 +0000 | [diff] [blame] | 206 | return XRayPatchingStatus::ONGOING; // Already patching. |
| 207 | |
| 208 | uint8_t PatchingSuccess = false; |
| 209 | auto XRayPatchingStatusResetter = |
Dean Michael Berris | 5eaaff6 | 2018-06-05 06:12:42 +0000 | [diff] [blame] | 210 | at_scope_exit([&PatchingSuccess] { |
Dean Michael Berris | 504b0c2 | 2017-12-14 02:51:20 +0000 | [diff] [blame] | 211 | if (!PatchingSuccess) |
Dean Michael Berris | 5eaaff6 | 2018-06-05 06:12:42 +0000 | [diff] [blame] | 212 | atomic_store(&XRayPatching, false, |
| 213 | memory_order_release); |
Dean Michael Berris | 504b0c2 | 2017-12-14 02:51:20 +0000 | [diff] [blame] | 214 | }); |
| 215 | |
| 216 | XRaySledMap InstrMap; |
| 217 | { |
Dean Michael Berris | 5eaaff6 | 2018-06-05 06:12:42 +0000 | [diff] [blame] | 218 | SpinMutexLock Guard(&XRayInstrMapMutex); |
Dean Michael Berris | 504b0c2 | 2017-12-14 02:51:20 +0000 | [diff] [blame] | 219 | InstrMap = XRayInstrMap; |
| 220 | } |
| 221 | if (InstrMap.Entries == 0) |
| 222 | return XRayPatchingStatus::NOT_INITIALIZED; |
| 223 | |
| 224 | uint32_t FuncId = 1; |
| 225 | uint64_t CurFun = 0; |
| 226 | |
| 227 | // First we want to find the bounds for which we have instrumentation points, |
| 228 | // and try to get as few calls to mprotect(...) as possible. We're assuming |
| 229 | // that all the sleds for the instrumentation map are contiguous as a single |
| 230 | // set of pages. When we do support dynamic shared object instrumentation, |
| 231 | // we'll need to do this for each set of page load offsets per DSO loaded. For |
| 232 | // now we're assuming we can mprotect the whole section of text between the |
| 233 | // minimum sled address and the maximum sled address (+ the largest sled |
| 234 | // size). |
| 235 | auto MinSled = InstrMap.Sleds[0]; |
| 236 | auto MaxSled = InstrMap.Sleds[InstrMap.Entries - 1]; |
| 237 | for (std::size_t I = 0; I < InstrMap.Entries; I++) { |
| 238 | const auto &Sled = InstrMap.Sleds[I]; |
| 239 | if (Sled.Address < MinSled.Address) |
| 240 | MinSled = Sled; |
| 241 | if (Sled.Address > MaxSled.Address) |
| 242 | MaxSled = Sled; |
| 243 | } |
| 244 | |
| 245 | const size_t PageSize = flags()->xray_page_size_override > 0 |
| 246 | ? flags()->xray_page_size_override |
| 247 | : GetPageSizeCached(); |
| 248 | if ((PageSize == 0) || ((PageSize & (PageSize - 1)) != 0)) { |
| 249 | Report("System page size is not a power of two: %lld\n", PageSize); |
| 250 | return XRayPatchingStatus::FAILED; |
| 251 | } |
| 252 | |
| 253 | void *PageAlignedAddr = |
| 254 | reinterpret_cast<void *>(MinSled.Address & ~(PageSize - 1)); |
| 255 | size_t MProtectLen = |
| 256 | (MaxSled.Address - reinterpret_cast<uptr>(PageAlignedAddr)) + cSledLength; |
| 257 | MProtectHelper Protector(PageAlignedAddr, MProtectLen); |
| 258 | if (Protector.MakeWriteable() == -1) { |
| 259 | Report("Failed mprotect: %d\n", errno); |
| 260 | return XRayPatchingStatus::FAILED; |
| 261 | } |
| 262 | |
| 263 | for (std::size_t I = 0; I < InstrMap.Entries; ++I) { |
| 264 | auto &Sled = InstrMap.Sleds[I]; |
| 265 | auto F = Sled.Function; |
| 266 | if (CurFun == 0) |
| 267 | CurFun = F; |
| 268 | if (F != CurFun) { |
| 269 | ++FuncId; |
| 270 | CurFun = F; |
| 271 | } |
| 272 | patchSled(Sled, Enable, FuncId); |
| 273 | } |
Dean Michael Berris | 5eaaff6 | 2018-06-05 06:12:42 +0000 | [diff] [blame] | 274 | atomic_store(&XRayPatching, false, |
| 275 | memory_order_release); |
Dean Michael Berris | 504b0c2 | 2017-12-14 02:51:20 +0000 | [diff] [blame] | 276 | PatchingSuccess = true; |
| 277 | return XRayPatchingStatus::SUCCESS; |
| 278 | } |
| 279 | |
| 280 | XRayPatchingStatus mprotectAndPatchFunction(int32_t FuncId, |
| 281 | bool Enable) XRAY_NEVER_INSTRUMENT { |
| 282 | XRaySledMap InstrMap; |
| 283 | { |
Dean Michael Berris | 5eaaff6 | 2018-06-05 06:12:42 +0000 | [diff] [blame] | 284 | SpinMutexLock Guard(&XRayInstrMapMutex); |
Dean Michael Berris | 504b0c2 | 2017-12-14 02:51:20 +0000 | [diff] [blame] | 285 | InstrMap = XRayInstrMap; |
| 286 | } |
| 287 | |
| 288 | // FuncId must be a positive number, less than the number of functions |
| 289 | // instrumented. |
| 290 | if (FuncId <= 0 || static_cast<size_t>(FuncId) > InstrMap.Functions) { |
| 291 | Report("Invalid function id provided: %d\n", FuncId); |
| 292 | return XRayPatchingStatus::FAILED; |
| 293 | } |
| 294 | |
| 295 | const size_t PageSize = flags()->xray_page_size_override > 0 |
| 296 | ? flags()->xray_page_size_override |
| 297 | : GetPageSizeCached(); |
| 298 | if ((PageSize == 0) || ((PageSize & (PageSize - 1)) != 0)) { |
| 299 | Report("Provided page size is not a power of two: %lld\n", PageSize); |
| 300 | return XRayPatchingStatus::FAILED; |
| 301 | } |
| 302 | |
| 303 | // Here we compute the minumum sled and maximum sled associated with a |
| 304 | // particular function ID. |
| 305 | auto SledRange = InstrMap.SledsIndex[FuncId - 1]; |
| 306 | auto *f = SledRange.Begin; |
| 307 | auto *e = SledRange.End; |
| 308 | auto MinSled = *f; |
| 309 | auto MaxSled = *(SledRange.End - 1); |
| 310 | while (f != e) { |
| 311 | if (f->Address < MinSled.Address) |
| 312 | MinSled = *f; |
| 313 | if (f->Address > MaxSled.Address) |
| 314 | MaxSled = *f; |
| 315 | ++f; |
| 316 | } |
| 317 | |
| 318 | void *PageAlignedAddr = |
| 319 | reinterpret_cast<void *>(MinSled.Address & ~(PageSize - 1)); |
| 320 | size_t MProtectLen = |
| 321 | (MaxSled.Address - reinterpret_cast<uptr>(PageAlignedAddr)) + cSledLength; |
| 322 | MProtectHelper Protector(PageAlignedAddr, MProtectLen); |
| 323 | if (Protector.MakeWriteable() == -1) { |
| 324 | Report("Failed mprotect: %d\n", errno); |
| 325 | return XRayPatchingStatus::FAILED; |
| 326 | } |
| 327 | return patchFunction(FuncId, Enable); |
| 328 | } |
| 329 | |
| 330 | } // namespace |
| 331 | |
| 332 | } // namespace __xray |
| 333 | |
| 334 | using namespace __xray; |
| 335 | |
| 336 | // The following functions are declared `extern "C" {...}` in the header, hence |
| 337 | // they're defined in the global namespace. |
| 338 | |
| 339 | int __xray_set_handler(void (*entry)(int32_t, |
| 340 | XRayEntryType)) XRAY_NEVER_INSTRUMENT { |
Dean Michael Berris | 5eaaff6 | 2018-06-05 06:12:42 +0000 | [diff] [blame] | 341 | if (atomic_load(&XRayInitialized, |
| 342 | memory_order_acquire)) { |
Dean Michael Berris | 504b0c2 | 2017-12-14 02:51:20 +0000 | [diff] [blame] | 343 | |
Dean Michael Berris | 5eaaff6 | 2018-06-05 06:12:42 +0000 | [diff] [blame] | 344 | atomic_store(&__xray::XRayPatchedFunction, |
Dean Michael Berris | 504b0c2 | 2017-12-14 02:51:20 +0000 | [diff] [blame] | 345 | reinterpret_cast<uintptr_t>(entry), |
Dean Michael Berris | 5eaaff6 | 2018-06-05 06:12:42 +0000 | [diff] [blame] | 346 | memory_order_release); |
Dean Michael Berris | 504b0c2 | 2017-12-14 02:51:20 +0000 | [diff] [blame] | 347 | return 1; |
| 348 | } |
| 349 | return 0; |
| 350 | } |
| 351 | |
| 352 | int __xray_set_customevent_handler(void (*entry)(void *, size_t)) |
| 353 | XRAY_NEVER_INSTRUMENT { |
Dean Michael Berris | 5eaaff6 | 2018-06-05 06:12:42 +0000 | [diff] [blame] | 354 | if (atomic_load(&XRayInitialized, |
| 355 | memory_order_acquire)) { |
| 356 | atomic_store(&__xray::XRayPatchedCustomEvent, |
Dean Michael Berris | 504b0c2 | 2017-12-14 02:51:20 +0000 | [diff] [blame] | 357 | reinterpret_cast<uintptr_t>(entry), |
Dean Michael Berris | 5eaaff6 | 2018-06-05 06:12:42 +0000 | [diff] [blame] | 358 | memory_order_release); |
Dean Michael Berris | 504b0c2 | 2017-12-14 02:51:20 +0000 | [diff] [blame] | 359 | return 1; |
| 360 | } |
| 361 | return 0; |
| 362 | } |
| 363 | |
Keith Wyss | adb092e | 2018-04-17 21:28:53 +0000 | [diff] [blame] | 364 | int __xray_set_typedevent_handler(void (*entry)( |
Richard Smith | c1aaf8e | 2018-04-24 20:33:37 +0000 | [diff] [blame] | 365 | uint16_t, const void *, size_t)) XRAY_NEVER_INSTRUMENT { |
Dean Michael Berris | 5eaaff6 | 2018-06-05 06:12:42 +0000 | [diff] [blame] | 366 | if (atomic_load(&XRayInitialized, |
| 367 | memory_order_acquire)) { |
| 368 | atomic_store(&__xray::XRayPatchedTypedEvent, |
Keith Wyss | adb092e | 2018-04-17 21:28:53 +0000 | [diff] [blame] | 369 | reinterpret_cast<uintptr_t>(entry), |
Dean Michael Berris | 5eaaff6 | 2018-06-05 06:12:42 +0000 | [diff] [blame] | 370 | memory_order_release); |
Keith Wyss | adb092e | 2018-04-17 21:28:53 +0000 | [diff] [blame] | 371 | return 1; |
| 372 | } |
| 373 | return 0; |
| 374 | } |
| 375 | |
Dean Michael Berris | 504b0c2 | 2017-12-14 02:51:20 +0000 | [diff] [blame] | 376 | int __xray_remove_handler() XRAY_NEVER_INSTRUMENT { |
| 377 | return __xray_set_handler(nullptr); |
| 378 | } |
| 379 | |
| 380 | int __xray_remove_customevent_handler() XRAY_NEVER_INSTRUMENT { |
| 381 | return __xray_set_customevent_handler(nullptr); |
| 382 | } |
| 383 | |
Richard Smith | c1aaf8e | 2018-04-24 20:33:37 +0000 | [diff] [blame] | 384 | int __xray_remove_typedevent_handler() XRAY_NEVER_INSTRUMENT { |
Keith Wyss | adb092e | 2018-04-17 21:28:53 +0000 | [diff] [blame] | 385 | return __xray_set_typedevent_handler(nullptr); |
| 386 | } |
| 387 | |
| 388 | uint16_t __xray_register_event_type( |
Richard Smith | c1aaf8e | 2018-04-24 20:33:37 +0000 | [diff] [blame] | 389 | const char *const event_type) XRAY_NEVER_INSTRUMENT { |
Keith Wyss | adb092e | 2018-04-17 21:28:53 +0000 | [diff] [blame] | 390 | TypeDescriptorMapType::Handle h(&TypeDescriptorAddressMap, (uptr)event_type); |
| 391 | if (h.created()) { |
Dean Michael Berris | 5eaaff6 | 2018-06-05 06:12:42 +0000 | [diff] [blame] | 392 | h->type_id = atomic_fetch_add( |
| 393 | &TypeEventDescriptorCounter, 1, memory_order_acq_rel); |
Keith Wyss | adb092e | 2018-04-17 21:28:53 +0000 | [diff] [blame] | 394 | h->description_string_length = strnlen(event_type, 1024); |
| 395 | } |
| 396 | return h->type_id; |
| 397 | } |
| 398 | |
Dean Michael Berris | 504b0c2 | 2017-12-14 02:51:20 +0000 | [diff] [blame] | 399 | XRayPatchingStatus __xray_patch() XRAY_NEVER_INSTRUMENT { |
| 400 | return controlPatching(true); |
| 401 | } |
| 402 | |
| 403 | XRayPatchingStatus __xray_unpatch() XRAY_NEVER_INSTRUMENT { |
| 404 | return controlPatching(false); |
| 405 | } |
| 406 | |
Dean Michael Berris | 5cc4632 | 2017-05-04 04:59:20 +0000 | [diff] [blame] | 407 | XRayPatchingStatus __xray_patch_function(int32_t FuncId) XRAY_NEVER_INSTRUMENT { |
Dean Michael Berris | 504b0c2 | 2017-12-14 02:51:20 +0000 | [diff] [blame] | 408 | return mprotectAndPatchFunction(FuncId, true); |
Dean Michael Berris | 5cc4632 | 2017-05-04 04:59:20 +0000 | [diff] [blame] | 409 | } |
| 410 | |
| 411 | XRayPatchingStatus |
| 412 | __xray_unpatch_function(int32_t FuncId) XRAY_NEVER_INSTRUMENT { |
Dean Michael Berris | 504b0c2 | 2017-12-14 02:51:20 +0000 | [diff] [blame] | 413 | return mprotectAndPatchFunction(FuncId, false); |
Dean Michael Berris | 5cc4632 | 2017-05-04 04:59:20 +0000 | [diff] [blame] | 414 | } |
| 415 | |
Dean Michael Berris | 043d3f8 | 2017-06-19 01:30:04 +0000 | [diff] [blame] | 416 | int __xray_set_handler_arg1(void (*entry)(int32_t, XRayEntryType, uint64_t)) { |
Dean Michael Berris | 5eaaff6 | 2018-06-05 06:12:42 +0000 | [diff] [blame] | 417 | if (!atomic_load(&XRayInitialized, |
| 418 | memory_order_acquire)) |
Dean Michael Berris | a814c94 | 2017-03-06 07:25:41 +0000 | [diff] [blame] | 419 | return 0; |
Dean Michael Berris | 1dcec25 | 2017-03-27 07:13:35 +0000 | [diff] [blame] | 420 | |
Dean Michael Berris | a814c94 | 2017-03-06 07:25:41 +0000 | [diff] [blame] | 421 | // A relaxed write might not be visible even if the current thread gets |
| 422 | // scheduled on a different CPU/NUMA node. We need to wait for everyone to |
| 423 | // have this handler installed for consistency of collected data across CPUs. |
Dean Michael Berris | 5eaaff6 | 2018-06-05 06:12:42 +0000 | [diff] [blame] | 424 | atomic_store(&XRayArgLogger, reinterpret_cast<uint64_t>(entry), |
| 425 | memory_order_release); |
Dean Michael Berris | a814c94 | 2017-03-06 07:25:41 +0000 | [diff] [blame] | 426 | return 1; |
| 427 | } |
Dean Michael Berris | 29e16de | 2017-05-12 01:07:41 +0000 | [diff] [blame] | 428 | |
Dean Michael Berris | a814c94 | 2017-03-06 07:25:41 +0000 | [diff] [blame] | 429 | int __xray_remove_handler_arg1() { return __xray_set_handler_arg1(nullptr); } |
Dean Michael Berris | d45003c | 2017-05-05 01:27:11 +0000 | [diff] [blame] | 430 | |
| 431 | uintptr_t __xray_function_address(int32_t FuncId) XRAY_NEVER_INSTRUMENT { |
Dean Michael Berris | 5eaaff6 | 2018-06-05 06:12:42 +0000 | [diff] [blame] | 432 | SpinMutexLock Guard(&XRayInstrMapMutex); |
Dean Michael Berris | d45003c | 2017-05-05 01:27:11 +0000 | [diff] [blame] | 433 | if (FuncId <= 0 || static_cast<size_t>(FuncId) > XRayInstrMap.Functions) |
| 434 | return 0; |
Dean Michael Berris | 66faace | 2017-08-28 03:58:23 +0000 | [diff] [blame] | 435 | return XRayInstrMap.SledsIndex[FuncId - 1].Begin->Function |
Tim Shen | af3ffcc | 2017-05-17 21:20:00 +0000 | [diff] [blame] | 436 | // On PPC, function entries are always aligned to 16 bytes. The beginning of a |
| 437 | // sled might be a local entry, which is always +8 based on the global entry. |
| 438 | // Always return the global entry. |
| 439 | #ifdef __PPC__ |
| 440 | & ~0xf |
| 441 | #endif |
| 442 | ; |
Dean Michael Berris | d45003c | 2017-05-05 01:27:11 +0000 | [diff] [blame] | 443 | } |
| 444 | |
| 445 | size_t __xray_max_function_id() XRAY_NEVER_INSTRUMENT { |
Dean Michael Berris | 5eaaff6 | 2018-06-05 06:12:42 +0000 | [diff] [blame] | 446 | SpinMutexLock Guard(&XRayInstrMapMutex); |
Dean Michael Berris | d45003c | 2017-05-05 01:27:11 +0000 | [diff] [blame] | 447 | return XRayInstrMap.Functions; |
| 448 | } |