1 //===-- xray_hexagon.cpp --------------------------------------*- C++ ---*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file is a part of XRay, a dynamic runtime instrumentation system. 10 // 11 // Implementation of hexagon-specific routines (32-bit). 12 // 13 //===----------------------------------------------------------------------===// 14 #include "sanitizer_common/sanitizer_common.h" 15 #include "xray_defs.h" 16 #include "xray_interface_internal.h" 17 #include <assert.h> 18 #include <atomic> 19 20 namespace __xray { 21 22 // The machine codes for some instructions used in runtime patching. 23 enum PatchOpcodes : uint32_t { 24 PO_JUMPI_14 = 0x5800c00a, // jump #0x014 (PC + 0x014) 25 PO_CALLR_R6 = 0x50a6c000, // indirect call: callr r6 26 PO_TFR_IMM = 0x78000000, // transfer immed 27 // ICLASS 0x7 - S2-type A-type 28 PO_IMMEXT = 0x00000000, // constant extender 29 }; 30 31 enum PacketWordParseBits : uint32_t { 32 PP_DUPLEX = 0x00 << 14, 33 PP_NOT_END = 0x01 << 14, 34 PP_PACKET_END = 0x03 << 14, 35 }; 36 37 enum RegNum : uint32_t { 38 RN_R6 = 0x6, 39 RN_R7 = 0x7, 40 }; 41 42 inline static uint32_t 43 encodeExtendedTransferImmediate(uint32_t Imm, RegNum DestReg, 44 bool PacketEnd = false) XRAY_NEVER_INSTRUMENT { 45 static const uint32_t REG_MASK = 0x1f; 46 assert((DestReg & (~REG_MASK)) == 0); 47 // The constant-extended register transfer encodes the 6 least 48 // significant bits of the effective constant: 49 Imm = Imm & 0x03f; 50 const PacketWordParseBits ParseBits = PacketEnd ? PP_PACKET_END : PP_NOT_END; 51 52 return PO_TFR_IMM | ParseBits | (Imm << 5) | (DestReg & REG_MASK); 53 } 54 55 inline static uint32_t 56 encodeConstantExtender(uint32_t Imm) XRAY_NEVER_INSTRUMENT { 57 // Bits Name Description 58 // ----- ------- ------------------------------------------ 59 // 31:28 ICLASS Instruction class = 0000 60 // 27:16 high High 12 bits of 26-bit constant extension 61 // 15:14 Parse Parse bits 62 // 13:0 low Low 14 bits of 26-bit constant extension 63 static const uint32_t IMM_MASK_LOW = 0x03fff; 64 static const uint32_t IMM_MASK_HIGH = 0x00fff << 14; 65 66 // The extender encodes the 26 most significant bits of the effective 67 // constant: 68 Imm = Imm >> 6; 69 70 const uint32_t high = (Imm & IMM_MASK_HIGH) << 16; 71 const uint32_t low = Imm & IMM_MASK_LOW; 72 73 return PO_IMMEXT | high | PP_NOT_END | low; 74 } 75 76 static void WriteInstFlushCache(void *Addr, uint32_t NewInstruction) { 77 asm volatile("icinva(%[inst_addr])\n\t" 78 "isync\n\t" 79 "memw(%[inst_addr]) = %[new_inst]\n\t" 80 "dccleaninva(%[inst_addr])\n\t" 81 "syncht\n\t" 82 : 83 : [ inst_addr ] "r"(Addr), [ new_inst ] "r"(NewInstruction) 84 : "memory"); 85 } 86 87 inline static bool patchSled(const bool Enable, const uint32_t FuncId, 88 const XRaySledEntry &Sled, 89 void (*TracingHook)()) XRAY_NEVER_INSTRUMENT { 90 // When |Enable| == true, 91 // We replace the following compile-time stub (sled): 92 // 93 // .L_xray_sled_N: 94 // <xray_sled_base>: 95 // { jump .Ltmp0 } 96 // { nop 97 // nop 98 // nop 99 // nop } 100 // .Ltmp0: 101 102 // With the following runtime patch: 103 // 104 // xray_sled_n (32-bit): 105 // 106 // <xray_sled_n>: 107 // { immext(#...) // upper 26-bits of func id 108 // r7 = ##... // lower 6-bits of func id 109 // immext(#...) // upper 26-bits of trampoline 110 // r6 = ##... } // lower 6 bits of trampoline 111 // { callr r6 } 112 // 113 // When |Enable|==false, we set back the first instruction in the sled to be 114 // { jump .Ltmp0 } 115 116 uint32_t *FirstAddress = reinterpret_cast<uint32_t *>(Sled.address()); 117 if (Enable) { 118 uint32_t *CurAddress = FirstAddress + 1; 119 *CurAddress = encodeExtendedTransferImmediate(FuncId, RN_R7); 120 CurAddress++; 121 *CurAddress = encodeConstantExtender(reinterpret_cast<uint32_t>(TracingHook)); 122 CurAddress++; 123 *CurAddress = 124 encodeExtendedTransferImmediate(reinterpret_cast<uint32_t>(TracingHook), RN_R6, true); 125 CurAddress++; 126 127 *CurAddress = uint32_t(PO_CALLR_R6); 128 129 WriteInstFlushCache(FirstAddress, uint32_t(encodeConstantExtender(FuncId))); 130 } else { 131 WriteInstFlushCache(FirstAddress, uint32_t(PatchOpcodes::PO_JUMPI_14)); 132 } 133 return true; 134 } 135 136 bool patchFunctionEntry(const bool Enable, const uint32_t FuncId, 137 const XRaySledEntry &Sled, 138 void (*Trampoline)()) XRAY_NEVER_INSTRUMENT { 139 return patchSled(Enable, FuncId, Sled, Trampoline); 140 } 141 142 bool patchFunctionExit(const bool Enable, const uint32_t FuncId, 143 const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { 144 return patchSled(Enable, FuncId, Sled, __xray_FunctionExit); 145 } 146 147 bool patchFunctionTailExit(const bool Enable, const uint32_t FuncId, 148 const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { 149 return patchSled(Enable, FuncId, Sled, __xray_FunctionExit); 150 } 151 152 bool patchCustomEvent(const bool Enable, const uint32_t FuncId, 153 const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { 154 // FIXME: Implement in hexagon? 155 return false; 156 } 157 158 bool patchTypedEvent(const bool Enable, const uint32_t FuncId, 159 const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { 160 // FIXME: Implement in hexagon? 161 return false; 162 } 163 164 } // namespace __xray 165 166 extern "C" void __xray_ArgLoggerEntry() XRAY_NEVER_INSTRUMENT { 167 // FIXME: this will have to be implemented in the trampoline assembly file 168 } 169