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(Imm: FuncId, DestReg: 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(Addr: FirstAddress, NewInstruction: uint32_t(encodeConstantExtender(Imm: FuncId))); |
130 | } else { |
131 | WriteInstFlushCache(Addr: FirstAddress, NewInstruction: 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, TracingHook: 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, TracingHook: __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, TracingHook: __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 | |