diff options
author | Dean Michael Berris <dberris@google.com> | 2016-10-13 23:56:54 +0000 |
---|---|---|
committer | Dean Michael Berris <dberris@google.com> | 2016-10-13 23:56:54 +0000 |
commit | d9e6c738682c2012e5e7e87909941becd55cfbbd (patch) | |
tree | 57003a05a0b05d90c626341da1936bc6505698c4 | |
parent | fc1639bfbc51826037ac6647c7faf280790c6bf9 (diff) |
[compiler-rt][XRay] Support tail call sleds
Summary:
This change depends on D23986 which adds tail call-specific sleds. For
now we treat them first as normal exits, and in the future leave room
for implementing this as a different kind of log entry.
The reason for deferring the change is so that we can keep the naive
logging implementation more accurate without additional complexity for
reading the log. The accuracy is gained in effectively interpreting call
stacks like:
A()
B()
C()
Which when tail-call merged will end up not having any exit entries for
A() nor B(), but effectively in turn can be reasoned about as:
A()
B()
C()
Although we lose the fact that A() had called B() then had called C()
with the naive approach, a later iteration that adds the explicit tail
call entries would be a change in the log format and thus necessitate a
version change for the header. We can do this later to have a chance at
releasing some tools (in D21987) that are able to handle the naive log
format, then support higher version numbers of the log format too.
Reviewers: echristo, kcc, rSerge, majnemer
Subscribers: mehdi_amini, llvm-commits, dberris
Differential Revision: https://reviews.llvm.org/D23988
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@284178 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/xray/xray_interface.h | 2 | ||||
-rw-r--r-- | lib/xray/xray_arm.cc | 7 | ||||
-rw-r--r-- | lib/xray/xray_interface.cc | 3 | ||||
-rw-r--r-- | lib/xray/xray_interface_internal.h | 7 | ||||
-rw-r--r-- | lib/xray/xray_x86_64.cc | 33 |
5 files changed, 48 insertions, 4 deletions
diff --git a/include/xray/xray_interface.h b/include/xray/xray_interface.h index 22f137d11..680fcfdd5 100644 --- a/include/xray/xray_interface.h +++ b/include/xray/xray_interface.h @@ -18,7 +18,7 @@ extern "C" { -enum XRayEntryType { ENTRY = 0, EXIT = 1 }; +enum XRayEntryType { ENTRY = 0, EXIT = 1, TAIL = 2 }; // Provide a function to invoke for when instrumentation points are hit. This is // a user-visible control surface that overrides the default implementation. The diff --git a/lib/xray/xray_arm.cc b/lib/xray/xray_arm.cc index d1b953e2e..4c1980364 100644 --- a/lib/xray/xray_arm.cc +++ b/lib/xray/xray_arm.cc @@ -127,4 +127,11 @@ bool patchFunctionExit(const bool Enable, const uint32_t FuncId, return patchSled(Enable, FuncId, Sled, __xray_FunctionExit); } +bool patchFunctionTailExit(const bool Enable, const uint32_t FuncId, + const XRaySledEntry &Sled) { + // FIXME: In the future we'd need to distinguish between non-tail exits and + // tail exits for better information preservation. + return patchSled(Enable, FuncId, Sled, __xray_FunctionExit); +} + } // namespace __xray diff --git a/lib/xray/xray_interface.cc b/lib/xray/xray_interface.cc index ec393b9fb..fb49ff3a8 100644 --- a/lib/xray/xray_interface.cc +++ b/lib/xray/xray_interface.cc @@ -174,6 +174,9 @@ XRayPatchingStatus ControlPatching(bool Enable) { case XRayEntryType::EXIT: Success = patchFunctionExit(Enable, FuncId, Sled); break; + case XRayEntryType::TAIL: + Success = patchFunctionTailExit(Enable, FuncId, Sled); + break; default: Report("Unsupported sled kind: %d", int(Sled.Kind)); continue; diff --git a/lib/xray/xray_interface_internal.h b/lib/xray/xray_interface_internal.h index fe58f8ad0..24a5acc97 100644 --- a/lib/xray/xray_interface_internal.h +++ b/lib/xray/xray_interface_internal.h @@ -48,10 +48,11 @@ struct XRaySledMap { size_t Entries; }; -bool patchFunctionEntry(const bool Enable, const uint32_t FuncId, +bool patchFunctionEntry(bool Enable, uint32_t FuncId, const XRaySledEntry &Sled); -bool patchFunctionExit(const bool Enable, const uint32_t FuncId, - const XRaySledEntry &Sled); +bool patchFunctionExit(bool Enable, uint32_t FuncId, const XRaySledEntry &Sled); +bool patchFunctionTailExit(bool Enable, uint32_t FuncId, + const XRaySledEntry &Sled); } // namespace __xray diff --git a/lib/xray/xray_x86_64.cc b/lib/xray/xray_x86_64.cc index 0443c5eb6..c4fead978 100644 --- a/lib/xray/xray_x86_64.cc +++ b/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 |