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