Home | History | Annotate | Line # | Download | only in xray
      1 //===-- xray_arm.cc ---------------------------------------------*- 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 ARM-specific routines (32-bit).
     13 //
     14 //===----------------------------------------------------------------------===//
     15 #include "sanitizer_common/sanitizer_common.h"
     16 #include "xray_defs.h"
     17 #include "xray_interface_internal.h"
     18 #include <atomic>
     19 #include <cassert>
     20 
     21 extern "C" void __clear_cache(void *start, void *end);
     22 
     23 namespace __xray {
     24 
     25 // The machine codes for some instructions used in runtime patching.
     26 enum class PatchOpcodes : uint32_t {
     27   PO_PushR0Lr = 0xE92D4001, // PUSH {r0, lr}
     28   PO_BlxIp = 0xE12FFF3C,    // BLX ip
     29   PO_PopR0Lr = 0xE8BD4001,  // POP {r0, lr}
     30   PO_B20 = 0xEA000005       // B #20
     31 };
     32 
     33 // 0xUUUUWXYZ -> 0x000W0XYZ
     34 inline static uint32_t getMovwMask(const uint32_t Value) XRAY_NEVER_INSTRUMENT {
     35   return (Value & 0xfff) | ((Value & 0xf000) << 4);
     36 }
     37 
     38 // 0xWXYZUUUU -> 0x000W0XYZ
     39 inline static uint32_t getMovtMask(const uint32_t Value) XRAY_NEVER_INSTRUMENT {
     40   return getMovwMask(Value >> 16);
     41 }
     42 
     43 // Writes the following instructions:
     44 //   MOVW R<regNo>, #<lower 16 bits of the |Value|>
     45 //   MOVT R<regNo>, #<higher 16 bits of the |Value|>
     46 inline static uint32_t *
     47 write32bitLoadReg(uint8_t regNo, uint32_t *Address,
     48                   const uint32_t Value) XRAY_NEVER_INSTRUMENT {
     49   // This is a fatal error: we cannot just report it and continue execution.
     50   assert(regNo <= 15 && "Register number must be 0 to 15.");
     51   // MOVW R, #0xWXYZ in machine code is 0xE30WRXYZ
     52   *Address = (0xE3000000 | (uint32_t(regNo) << 12) | getMovwMask(Value));
     53   Address++;
     54   // MOVT R, #0xWXYZ in machine code is 0xE34WRXYZ
     55   *Address = (0xE3400000 | (uint32_t(regNo) << 12) | getMovtMask(Value));
     56   return Address + 1;
     57 }
     58 
     59 // Writes the following instructions:
     60 //   MOVW r0, #<lower 16 bits of the |Value|>
     61 //   MOVT r0, #<higher 16 bits of the |Value|>
     62 inline static uint32_t *
     63 write32bitLoadR0(uint32_t *Address,
     64                  const uint32_t Value) XRAY_NEVER_INSTRUMENT {
     65   return write32bitLoadReg(0, Address, Value);
     66 }
     67 
     68 // Writes the following instructions:
     69 //   MOVW ip, #<lower 16 bits of the |Value|>
     70 //   MOVT ip, #<higher 16 bits of the |Value|>
     71 inline static uint32_t *
     72 write32bitLoadIP(uint32_t *Address,
     73                  const uint32_t Value) XRAY_NEVER_INSTRUMENT {
     74   return write32bitLoadReg(12, Address, Value);
     75 }
     76 
     77 inline static bool patchSled(const bool Enable, const uint32_t FuncId,
     78                              const XRaySledEntry &Sled,
     79                              void (*TracingHook)()) XRAY_NEVER_INSTRUMENT {
     80   // When |Enable| == true,
     81   // We replace the following compile-time stub (sled):
     82   //
     83   // xray_sled_n:
     84   //   B #20
     85   //   6 NOPs (24 bytes)
     86   //
     87   // With the following runtime patch:
     88   //
     89   // xray_sled_n:
     90   //   PUSH {r0, lr}
     91   //   MOVW r0, #<lower 16 bits of function ID>
     92   //   MOVT r0, #<higher 16 bits of function ID>
     93   //   MOVW ip, #<lower 16 bits of address of TracingHook>
     94   //   MOVT ip, #<higher 16 bits of address of TracingHook>
     95   //   BLX ip
     96   //   POP {r0, lr}
     97   //
     98   // Replacement of the first 4-byte instruction should be the last and atomic
     99   // operation, so that the user code which reaches the sled concurrently
    100   // either jumps over the whole sled, or executes the whole sled when the
    101   // latter is ready.
    102   //
    103   // When |Enable|==false, we set back the first instruction in the sled to be
    104   //   B #20
    105 
    106   uint32_t *FirstAddress = reinterpret_cast<uint32_t *>(Sled.Address);
    107   uint32_t *CurAddress = FirstAddress + 1;
    108   if (Enable) {
    109     CurAddress =
    110         write32bitLoadR0(CurAddress, reinterpret_cast<uint32_t>(FuncId));
    111     CurAddress =
    112         write32bitLoadIP(CurAddress, reinterpret_cast<uint32_t>(TracingHook));
    113     *CurAddress = uint32_t(PatchOpcodes::PO_BlxIp);
    114     CurAddress++;
    115     *CurAddress = uint32_t(PatchOpcodes::PO_PopR0Lr);
    116     CurAddress++;
    117     std::atomic_store_explicit(
    118         reinterpret_cast<std::atomic<uint32_t> *>(FirstAddress),
    119         uint32_t(PatchOpcodes::PO_PushR0Lr), std::memory_order_release);
    120   } else {
    121     std::atomic_store_explicit(
    122         reinterpret_cast<std::atomic<uint32_t> *>(FirstAddress),
    123         uint32_t(PatchOpcodes::PO_B20), std::memory_order_release);
    124   }
    125   __clear_cache(reinterpret_cast<char *>(FirstAddress),
    126                 reinterpret_cast<char *>(CurAddress));
    127   return true;
    128 }
    129 
    130 bool patchFunctionEntry(const bool Enable, const uint32_t FuncId,
    131                         const XRaySledEntry &Sled,
    132                         void (*Trampoline)()) XRAY_NEVER_INSTRUMENT {
    133   return patchSled(Enable, FuncId, Sled, Trampoline);
    134 }
    135 
    136 bool patchFunctionExit(const bool Enable, const uint32_t FuncId,
    137                        const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
    138   return patchSled(Enable, FuncId, Sled, __xray_FunctionExit);
    139 }
    140 
    141 bool patchFunctionTailExit(const bool Enable, const uint32_t FuncId,
    142                            const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
    143   return patchSled(Enable, FuncId, Sled, __xray_FunctionTailExit);
    144 }
    145 
    146 bool patchCustomEvent(const bool Enable, const uint32_t FuncId,
    147                       const XRaySledEntry &Sled)
    148     XRAY_NEVER_INSTRUMENT { // FIXME: Implement in arm?
    149   return false;
    150 }
    151 
    152 bool patchTypedEvent(const bool Enable, const uint32_t FuncId,
    153                      const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
    154   // FIXME: Implement in arm?
    155   return false;
    156 }
    157 
    158 // FIXME: Maybe implement this better?
    159 bool probeRequiredCPUFeatures() XRAY_NEVER_INSTRUMENT { return true; }
    160 
    161 } // namespace __xray
    162 
    163 extern "C" void __xray_ArgLoggerEntry() XRAY_NEVER_INSTRUMENT {
    164   // FIXME: this will have to be implemented in the trampoline assembly file
    165 }
    166