[compiler-rt] r302112 - [XRay][compiler-rt] Support patching/unpatching specific functions

Bill Seurer via llvm-commits llvm-commits at lists.llvm.org
Fri May 5 06:41:00 PDT 2017


On 05/04/2017 09:19 PM, Dean Michael Berris wrote:
> In the meantime, I think it's fine if we XFAIL this for now on powerpc,
> while Tim has a look.

I'll do that then in a few minutes here.

>
> Cheers
>
> On Fri, May 5, 2017 at 9:36 AM Dean Michael Berris <dberris at google.com
> <mailto:dberris at google.com>> wrote:
>
>     Huh. +Tim Shen <mailto:timshen at google.com> -- any ideas why the
>     recursion guard in the example wouldn't work?
>
>     Bill, do you think the fact that the set is a global, that we're
>     running into weird init/destruction issues on ppc?
>
>     On Fri, May 5, 2017 at 2:18 AM Bill Seurer
>     <seurer at linux.vnet.ibm.com <mailto:seurer at linux.vnet.ibm.com>> wrote:
>
>         The new test case doesn't work on powerpc64le:
>
>         http://lab.llvm.org:8011/builders/clang-ppc64le-linux/builds/6031/steps/ninja%20check%201/logs/FAIL%3A%20XRay-powerpc64le-linux%3A%3Acoverage-sample.cc
>
>         When I run it locally it segfaults.
>
>         Program received signal SIGSEGV, Segmentation fault.
>         0x00003fffb7e39868 in std::_Rb_tree_insert_and_rebalance
>         (__insert_left=<optimized out>, __x=<optimized out>, __p=<optimized
>         out>, __header=...)
>              at
>         /home/seurer/gcc/gcc-6.2.0/libstdc++-v3/src/c++98/tree.cc:282
>         282         __root->_M_color = _S_black;
>         (gdb) where
>         #0  0x00003fffb7e39868 in std::_Rb_tree_insert_and_rebalance
>         (__insert_left=<optimized out>, __x=<optimized out>, __p=<optimized
>         out>, __header=...)
>              at
>         /home/seurer/gcc/gcc-6.2.0/libstdc++-v3/src/c++98/tree.cc:282
>         #1  0x000000001003644c in std::_Rb_tree<int, int,
>         std::_Identity<int>,
>         std::less<int>, std::allocator<int> >::_M_insert_<int const&,
>         std::_Rb_tree<int, int, std::_Identity<int>, std::less<int>,
>         std::allocator<int> >::_Alloc_node> (this=0x10ab48a0 <function_ids>,
>         __x=0x0, __p=0x3fffffffef60, __v=@0x3ffffffff104: 3, __node_gen=...)
>              at
>         /home/seurer/gcc/install/gcc-6.2.0/lib/gcc/powerpc64le-unknown-linux-gnu/6.1.1/../../../../include/c++/6.1.1/bits/stl_tree.h:1512
>         #2  0x0000000010035f4c in std::_Rb_tree<int, int,
>         std::_Identity<int>,
>         std::less<int>, std::allocator<int> >::_M_insert_unique<int const&>
>         (this=0x10ab48a0 <function_ids>,
>              __v=@0x3ffffffff104: 3) at
>         /home/seurer/gcc/install/gcc-6.2.0/lib/gcc/powerpc64le-unknown-linux-gnu/6.1.1/../../../../include/c++/6.1.1/bits/stl_tree.h:1869
>         #3  0x00000000100353dc in std::set<int, std::less<int>,
>         std::allocator<int> >::insert (this=0x10ab48a0 <function_ids>,
>         __x=@0x3ffffffff104: 3)
>              at
>         /home/seurer/gcc/install/gcc-6.2.0/lib/gcc/powerpc64le-unknown-linux-gnu/6.1.1/../../../../include/c++/6.1.1/bits/stl_set.h:483
>         #4  0x0000000010034d50 in coverage_handler (fid=3) at
>         /home/seurer/llvm/llvm-test/projects/compiler-rt/test/xray/TestCases/Linux/coverage-sample.cc:18
>         #5  0x000000001002db78 in __xray::CallXRayPatchedFunction
>         (FuncId=<optimized out>, Type=<optimized out>)
>              at
>         /home/seurer/llvm/llvm-test/projects/compiler-rt/lib/xray/xray_trampoline_powerpc64.cc:12
>         #6  0x000000001002dca8 in __xray_FunctionEntry () at
>         /home/seurer/llvm/llvm-test/projects/compiler-rt/lib/xray/xray_trampoline_powerpc64_asm.S:75
>
>
>         On 05/03/2017 11:59 PM, Dean Michael Berris via llvm-commits wrote:
>         > Author: dberris
>         > Date: Wed May  3 23:59:20 2017
>         > New Revision: 302112
>         >
>         > URL: http://llvm.org/viewvc/llvm-project?rev=302112&view=rev
>         > Log:
>         > [XRay][compiler-rt] Support patching/unpatching specific functions
>         >
>         > Summary:
>         > This change allows us to patch/unpatch specific functions
>         using the
>         > function ID. This is useful in cases where implementations
>         might want to
>         > do coverage-style, or more fine-grained control of which
>         functions to
>         > patch or un-patch at runtime.
>         >
>         > Depends on D32693.
>         >
>         > Reviewers: dblaikie, echristo, kpw
>         >
>         > Subscribers: llvm-commits
>         >
>         > Differential Revision: https://reviews.llvm.org/D32695
>         >
>         > Added:
>         >     compiler-rt/trunk/test/xray/TestCases/Linux/coverage-sample.cc
>         > Modified:
>         >     compiler-rt/trunk/include/xray/xray_interface.h
>         >     compiler-rt/trunk/lib/xray/xray_init.cc
>         >     compiler-rt/trunk/lib/xray/xray_interface.cc
>         >     compiler-rt/trunk/lib/xray/xray_interface_internal.h
>         >
>         > Modified: compiler-rt/trunk/include/xray/xray_interface.h
>         > URL:
>         http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/include/xray/xray_interface.h?rev=302112&r1=302111&r2=302112&view=diff
>         >
>         ==============================================================================
>         > --- compiler-rt/trunk/include/xray/xray_interface.h (original)
>         > +++ compiler-rt/trunk/include/xray/xray_interface.h Wed May  3
>         23:59:20 2017
>         > @@ -67,6 +67,14 @@ extern XRayPatchingStatus __xray_patch()
>         >  // result values.
>         >  extern XRayPatchingStatus __xray_unpatch();
>         >
>         > +// This patches a specific function id. See
>         XRayPatchingStatus for possible
>         > +// result values.
>         > +extern XRayPatchingStatus __xray_patch_function(int32_t FuncId);
>         > +
>         > +// This unpatches a specific function id. See
>         XRayPatchingStatus for possible
>         > +// result values.
>         > +extern XRayPatchingStatus __xray_unpatch_function(int32_t
>         FuncId);
>         > +
>         >  // Use XRay to log the first argument of each (instrumented)
>         function call.
>         >  // When this function exits, all threads will have observed
>         the effect and
>         >  // start logging their subsequent affected function calls (if
>         patched).
>         >
>         > Modified: compiler-rt/trunk/lib/xray/xray_init.cc
>         > URL:
>         http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/xray/xray_init.cc?rev=302112&r1=302111&r2=302112&view=diff
>         >
>         ==============================================================================
>         > --- compiler-rt/trunk/lib/xray/xray_init.cc (original)
>         > +++ compiler-rt/trunk/lib/xray/xray_init.cc Wed May  3
>         23:59:20 2017
>         > @@ -25,6 +25,8 @@ extern "C" {
>         >  void __xray_init();
>         >  extern const XRaySledEntry __start_xray_instr_map[]
>         __attribute__((weak));
>         >  extern const XRaySledEntry __stop_xray_instr_map[]
>         __attribute__((weak));
>         > +extern const XRayFunctionSledIndex __start_xray_fn_idx[]
>         __attribute__((weak));
>         > +extern const XRayFunctionSledIndex __stop_xray_fn_idx[]
>         __attribute__((weak));
>         >  }
>         >
>         >  using namespace __xray;
>         > @@ -55,6 +57,8 @@ void __xray_init() XRAY_NEVER_INSTRUMENT
>         >      __sanitizer::SpinMutexLock Guard(&XRayInstrMapMutex);
>         >      XRayInstrMap.Sleds = __start_xray_instr_map;
>         >      XRayInstrMap.Entries = __stop_xray_instr_map -
>         __start_xray_instr_map;
>         > +    XRayInstrMap.SledsIndex = __start_xray_fn_idx;
>         > +    XRayInstrMap.Functions = __stop_xray_fn_idx -
>         __start_xray_fn_idx;
>         >    }
>         >    __sanitizer::atomic_store(&XRayInitialized, true,
>         >                              __sanitizer::memory_order_release);
>         >
>         > Modified: compiler-rt/trunk/lib/xray/xray_interface.cc
>         > URL:
>         http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/xray/xray_interface.cc?rev=302112&r1=302111&r2=302112&view=diff
>         >
>         ==============================================================================
>         > --- compiler-rt/trunk/lib/xray/xray_interface.cc (original)
>         > +++ compiler-rt/trunk/lib/xray/xray_interface.cc Wed May  3
>         23:59:20 2017
>         > @@ -132,12 +132,48 @@ CleanupInvoker<Function> scopeCleanup(Fu
>         >    return CleanupInvoker<Function>{Fn};
>         >  }
>         >
>         > +inline bool patchSled(const XRaySledEntry &Sled, bool Enable,
>         > +                      int32_t FuncId) XRAY_NEVER_INSTRUMENT {
>         > +  // While we're here, we should patch the nop sled. To do
>         that we mprotect
>         > +  // the page containing the function to be writeable.
>         > +  const uint64_t PageSize = GetPageSizeCached();
>         > +  void *PageAlignedAddr =
>         > +      reinterpret_cast<void *>(Sled.Address & ~(PageSize - 1));
>         > +  std::size_t MProtectLen = (Sled.Address + cSledLength) -
>         > +
>         reinterpret_cast<uint64_t>(PageAlignedAddr);
>         > +  MProtectHelper Protector(PageAlignedAddr, MProtectLen);
>         > +  if (Protector.MakeWriteable() == -1) {
>         > +    printf("Failed mprotect: %d\n", errno);
>         > +    return XRayPatchingStatus::FAILED;
>         > +  }
>         > +
>         > +  bool Success = false;
>         > +  switch (Sled.Kind) {
>         > +  case XRayEntryType::ENTRY:
>         > +    Success = patchFunctionEntry(Enable, FuncId, Sled,
>         __xray_FunctionEntry);
>         > +    break;
>         > +  case XRayEntryType::EXIT:
>         > +    Success = patchFunctionExit(Enable, FuncId, Sled);
>         > +    break;
>         > +  case XRayEntryType::TAIL:
>         > +    Success = patchFunctionTailExit(Enable, FuncId, Sled);
>         > +    break;
>         > +  case XRayEntryType::LOG_ARGS_ENTRY:
>         > +    Success = patchFunctionEntry(Enable, FuncId, Sled,
>         __xray_ArgLoggerEntry);
>         > +    break;
>         > +  default:
>         > +    Report("Unsupported sled kind '%d' @%04x\n",
>         Sled.Address, int(Sled.Kind));
>         > +    return false;
>         > +  }
>         > +  return Success;
>         > +}
>         > +
>         >  // controlPatching implements the common internals of the
>         patching/unpatching
>         >  // implementation. |Enable| defines whether we're enabling or
>         disabling the
>         >  // runtime XRay instrumentation.
>         >  XRayPatchingStatus controlPatching(bool Enable)
>         XRAY_NEVER_INSTRUMENT {
>         >    if (!__sanitizer::atomic_load(&XRayInitialized,
>         > -
>          __sanitizer::memory_order_acquire))
>         > +
>         __sanitizer::memory_order_acquire))
>         >      return XRayPatchingStatus::NOT_INITIALIZED; // Not
>         initialized.
>         >
>         >    uint8_t NotPatching = false;
>         > @@ -179,38 +215,7 @@ XRayPatchingStatus controlPatching(bool
>         >        ++FuncId;
>         >        CurFun = F;
>         >      }
>         > -
>         > -    // While we're here, we should patch the nop sled. To do
>         that we mprotect
>         > -    // the page containing the function to be writeable.
>         > -    void *PageAlignedAddr =
>         > -        reinterpret_cast<void *>(Sled.Address & ~(PageSize - 1));
>         > -    std::size_t MProtectLen = (Sled.Address + cSledLength) -
>         > -
>         reinterpret_cast<uint64_t>(PageAlignedAddr);
>         > -    MProtectHelper Protector(PageAlignedAddr, MProtectLen);
>         > -    if (Protector.MakeWriteable() == -1) {
>         > -      printf("Failed mprotect: %d\n", errno);
>         > -      return XRayPatchingStatus::FAILED;
>         > -    }
>         > -
>         > -    bool Success = false;
>         > -    switch (Sled.Kind) {
>         > -    case XRayEntryType::ENTRY:
>         > -      Success = patchFunctionEntry(Enable, FuncId, Sled,
>         __xray_FunctionEntry);
>         > -      break;
>         > -    case XRayEntryType::EXIT:
>         > -      Success = patchFunctionExit(Enable, FuncId, Sled);
>         > -      break;
>         > -    case XRayEntryType::TAIL:
>         > -      Success = patchFunctionTailExit(Enable, FuncId, Sled);
>         > -      break;
>         > -    case XRayEntryType::LOG_ARGS_ENTRY:
>         > -      Success = patchFunctionEntry(Enable, FuncId, Sled,
>         __xray_ArgLoggerEntry);
>         > -      break;
>         > -    default:
>         > -      Report("Unsupported sled kind: %d\n", int(Sled.Kind));
>         > -      continue;
>         > -    }
>         > -    (void)Success;
>         > +    patchSled(Sled, Enable, FuncId);
>         >    }
>         >    __sanitizer::atomic_store(&XRayPatching, false,
>         >                              __sanitizer::memory_order_release);
>         > @@ -226,6 +231,64 @@ XRayPatchingStatus __xray_unpatch() XRAY
>         >    return controlPatching(false);
>         >  }
>         >
>         > +XRayPatchingStatus patchFunction(int32_t FuncId,
>         > +                                 bool Enable)
>         XRAY_NEVER_INSTRUMENT {
>         > +  if (!__sanitizer::atomic_load(&XRayInitialized,
>         > +
>         __sanitizer::memory_order_acquire))
>         > +    return XRayPatchingStatus::NOT_INITIALIZED; // Not
>         initialized.
>         > +
>         > +  uint8_t NotPatching = false;
>         > +  if (!__sanitizer::atomic_compare_exchange_strong(
>         > +          &XRayPatching, &NotPatching, true,
>         __sanitizer::memory_order_acq_rel))
>         > +    return XRayPatchingStatus::ONGOING; // Already patching.
>         > +
>         > +  // Next, we look for the function index.
>         > +  XRaySledMap InstrMap;
>         > +  {
>         > +    __sanitizer::SpinMutexLock Guard(&XRayInstrMapMutex);
>         > +    InstrMap = XRayInstrMap;
>         > +  }
>         > +
>         > +  // If we don't have an index, we can't patch individual
>         functions.
>         > +  if (InstrMap.Functions == 0)
>         > +    return XRayPatchingStatus::NOT_INITIALIZED;
>         > +
>         > +  // FuncId must be a positive number, less than the number
>         of functions
>         > +  // instrumented.
>         > +  if (FuncId <= 0 || static_cast<size_t>(FuncId) >=
>         InstrMap.Functions) {
>         > +    Report("Invalid function id provided: %d\n", FuncId);
>         > +    return XRayPatchingStatus::FAILED;
>         > +  }
>         > +
>         > +  // Now we patch ths sleds for this specific function.
>         > +  auto SledRange = InstrMap.SledsIndex[FuncId - 1];
>         > +  auto *f = SledRange.Begin;
>         > +  auto *e = SledRange.End;
>         > +
>         > +  bool SucceedOnce = false;
>         > +  while (f != e)
>         > +    SucceedOnce |= patchSled(*f++, Enable, FuncId);
>         > +
>         > +  __sanitizer::atomic_store(&XRayPatching, false,
>         > +                            __sanitizer::memory_order_release);
>         > +
>         > +  if (!SucceedOnce) {
>         > +    Report("Failed patching any sled for function '%d'.",
>         FuncId);
>         > +    return XRayPatchingStatus::FAILED;
>         > +  }
>         > +
>         > +  return XRayPatchingStatus::SUCCESS;
>         > +}
>         > +
>         > +XRayPatchingStatus __xray_patch_function(int32_t FuncId)
>         XRAY_NEVER_INSTRUMENT {
>         > +  return patchFunction(FuncId, true);
>         > +}
>         > +
>         > +XRayPatchingStatus
>         > +__xray_unpatch_function(int32_t FuncId) XRAY_NEVER_INSTRUMENT {
>         > +  return patchFunction(FuncId, false);
>         > +}
>         > +
>         >  int __xray_set_handler_arg1(void (*Handler)(int32_t,
>         XRayEntryType, uint64_t)) {
>         >    if (!__sanitizer::atomic_load(&XRayInitialized,
>         >
>         __sanitizer::memory_order_acquire))
>         >
>         > Modified: compiler-rt/trunk/lib/xray/xray_interface_internal.h
>         > URL:
>         http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/xray/xray_interface_internal.h?rev=302112&r1=302111&r2=302112&view=diff
>         >
>         ==============================================================================
>         > --- compiler-rt/trunk/lib/xray/xray_interface_internal.h
>         (original)
>         > +++ compiler-rt/trunk/lib/xray/xray_interface_internal.h Wed
>         May  3 23:59:20 2017
>         > @@ -39,6 +39,11 @@ struct XRaySledEntry {
>         >  #error "Unsupported word size."
>         >  #endif
>         >  };
>         > +
>         > +struct XRayFunctionSledIndex {
>         > +  const XRaySledEntry* Begin;
>         > +  const XRaySledEntry* End;
>         > +};
>         >  }
>         >
>         >  namespace __xray {
>         > @@ -46,6 +51,8 @@ namespace __xray {
>         >  struct XRaySledMap {
>         >    const XRaySledEntry *Sleds;
>         >    size_t Entries;
>         > +  const XRayFunctionSledIndex *SledsIndex;
>         > +  size_t Functions;
>         >  };
>         >
>         >  bool patchFunctionEntry(bool Enable, uint32_t FuncId,
>         >
>         > Added:
>         compiler-rt/trunk/test/xray/TestCases/Linux/coverage-sample.cc
>         > URL:
>         http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/xray/TestCases/Linux/coverage-sample.cc?rev=302112&view=auto
>         >
>         ==============================================================================
>         > ---
>         compiler-rt/trunk/test/xray/TestCases/Linux/coverage-sample.cc
>         (added)
>         > +++
>         compiler-rt/trunk/test/xray/TestCases/Linux/coverage-sample.cc
>         Wed May  3 23:59:20 2017
>         > @@ -0,0 +1,88 @@
>         > +// Check that we can patch and unpatch specific function ids.
>         > +//
>         > +// RUN: %clangxx_xray -std=c++11 %s -o %t
>         > +// RUN: XRAY_OPTIONS="patch_premain=false
>         xray_naive_log=false" %run %t | FileCheck %s
>         > +
>         > +#include "xray/xray_interface.h"
>         > +
>         > +#include <set>
>         > +#include <cstdio>
>         > +
>         > +std::set<int32_t> function_ids;
>         > +
>         > +[[clang::xray_never_instrument]] void
>         coverage_handler(int32_t fid,
>         > +
>          XRayEntryType) {
>         > +  thread_local bool patching = false;
>         > +  if (patching) return;
>         > +  patching = true;
>         > +  function_ids.insert(fid);
>         > +  __xray_unpatch_function(fid);
>         > +  patching = false;
>         > +}
>         > +
>         > +[[clang::xray_always_instrument]] void baz() {
>         > +  // do nothing!
>         > +}
>         > +
>         > +[[clang::xray_always_instrument]] void bar() {
>         > +  baz();
>         > +}
>         > +
>         > +[[clang::xray_always_instrument]] void foo() {
>         > +  bar();
>         > +}
>         > +
>         > +[[clang::xray_always_instrument]] int main(int argc, char
>         *argv[]) {
>         > +  __xray_set_handler(coverage_handler);
>         > +  __xray_patch();
>         > +  foo();
>         > +  __xray_unpatch();
>         > +
>         > +  // print out the function_ids.
>         > +  printf("first pass.\n");
>         > +  for (const auto id : function_ids)
>         > +    printf("patched: %d\n", id);
>         > +
>         > +  // CHECK-LABEL: first pass.
>         > +  // CHECK-DAG: patched: [[F1:.*]]
>         > +  // CHECK-DAG: patched: [[F2:.*]]
>         > +  // CHECK-DAG: patched: [[F3:.*]]
>         > +
>         > +  // make a copy of the function_ids, then patch them later.
>         > +  auto called_fns = function_ids;
>         > +
>         > +  // clear the function_ids.
>         > +  function_ids.clear();
>         > +
>         > +  // patch the functions we've called before.
>         > +  for (const auto id : called_fns)
>         > +    __xray_patch_function(id);
>         > +
>         > +  // then call them again.
>         > +  foo();
>         > +  __xray_unpatch();
>         > +
>         > +  // confirm that we've seen the same functions again.
>         > +  printf("second pass.\n");
>         > +  for (const auto id : function_ids)
>         > +    printf("patched: %d\n", id);
>         > +  // CHECK-LABEL: second pass.
>         > +  // CHECK-DAG: patched: [[F1]]
>         > +  // CHECK-DAG: patched: [[F2]]
>         > +  // CHECK-DAG: patched: [[F3]]
>         > +
>         > +  // Now we want to make sure that if we unpatch one, that
>         we're only going to
>         > +  // see two calls of the coverage_handler.
>         > +  function_ids.clear();
>         > +  __xray_patch();
>         > +  __xray_unpatch_function(1);
>         > +  foo();
>         > +  __xray_unpatch();
>         > +
>         > +  // confirm that we don't see function id one called anymore.
>         > +  printf("missing 1.\n");
>         > +  for (const auto id : function_ids)
>         > +    printf("patched: %d\n", id);
>         > +  // CHECK-LABEL: missing 1.
>         > +  // CHECK-NOT: patched: 1
>         > +}
>         >
>         >
>         > _______________________________________________
>         > llvm-commits mailing list
>         > llvm-commits at lists.llvm.org <mailto:llvm-commits at lists.llvm.org>
>         > http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>         >
>
>
>         --
>
>         -Bill Seurer
>


-- 

-Bill Seurer



More information about the llvm-commits mailing list