diff options
Diffstat (limited to 'compiler-rt/lib/xray/xray_x86_64.cc')
-rw-r--r-- | compiler-rt/lib/xray/xray_x86_64.cc | 33 |
1 files changed, 33 insertions, 0 deletions
diff --git a/compiler-rt/lib/xray/xray_x86_64.cc b/compiler-rt/lib/xray/xray_x86_64.cc index 0443c5eb6d5..c4fead97871 100644 --- a/compiler-rt/lib/xray/xray_x86_64.cc +++ b/compiler-rt/lib/xray/xray_x86_64.cc @@ -111,4 +111,37 @@ bool patchFunctionExit(const bool Enable, const uint32_t FuncId, return true; } +bool patchFunctionTailExit(const bool Enable, const uint32_t FuncId, + const XRaySledEntry &Sled) { + // Here we do the dance of replacing the tail call sled with a similar + // sequence as the entry sled, but calls the exit sled instead, so we can + // treat tail call exits as if they were normal exits. + // + // FIXME: In the future we'd need to distinguish between non-tail exits and + // tail exits for better information preservation. + int64_t TrampolineOffset = reinterpret_cast<int64_t>(__xray_FunctionExit) - + (static_cast<int64_t>(Sled.Address) + 11); + if (TrampolineOffset < MinOffset || TrampolineOffset > MaxOffset) { + Report("XRay Exit trampoline (%p) too far from sled (%p); distance = " + "%ld\n", + __xray_FunctionExit, reinterpret_cast<void *>(Sled.Address), + TrampolineOffset); + return false; + } + if (Enable) { + *reinterpret_cast<uint32_t *>(Sled.Address + 2) = FuncId; + *reinterpret_cast<uint8_t *>(Sled.Address + 6) = CallOpCode; + *reinterpret_cast<uint32_t *>(Sled.Address + 7) = TrampolineOffset; + std::atomic_store_explicit( + reinterpret_cast<std::atomic<uint16_t> *>(Sled.Address), MovR10Seq, + std::memory_order_release); + } else { + std::atomic_store_explicit( + reinterpret_cast<std::atomic<uint16_t> *>(Sled.Address), Jmp9Seq, + std::memory_order_release); + // FIXME: Write out the nops still? + } + return true; +} + } // namespace __xray |