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 21extern "C" void __clear_cache(void *start, void *end); 22 23namespace __xray { 24 25// The machine codes for some instructions used in runtime patching. 26enum 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 34inline static uint32_t getMovwMask(const uint32_t Value) XRAY_NEVER_INSTRUMENT { 35 return (Value & 0xfff) | ((Value & 0xf000) << 4); 36} 37 38// 0xWXYZUUUU -> 0x000W0XYZ 39inline 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|> 46inline static uint32_t * 47write32bitLoadReg(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|> 62inline static uint32_t * 63write32bitLoadR0(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|> 71inline static uint32_t * 72write32bitLoadIP(uint32_t *Address, 73 const uint32_t Value) XRAY_NEVER_INSTRUMENT { 74 return write32bitLoadReg(12, Address, Value); 75} 76 77inline 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 130bool 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 136bool 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 141bool 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 146bool 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 152bool 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? 159bool probeRequiredCPUFeatures() XRAY_NEVER_INSTRUMENT { return true; } 160 161} // namespace __xray 162 163extern "C" void __xray_ArgLoggerEntry() XRAY_NEVER_INSTRUMENT { 164 // FIXME: this will have to be implemented in the trampoline assembly file 165} 166