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
20namespace __xray {
21
22// The machine codes for some instructions used in runtime patching.
23enum 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
31enum PacketWordParseBits : uint32_t {
32 PP_DUPLEX = 0x00 << 14,
33 PP_NOT_END = 0x01 << 14,
34 PP_PACKET_END = 0x03 << 14,
35};
36
37enum RegNum : uint32_t {
38 RN_R6 = 0x6,
39 RN_R7 = 0x7,
40};
41
42inline static uint32_t
43encodeExtendedTransferImmediate(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
55inline static uint32_t
56encodeConstantExtender(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
76static 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
87inline 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
136bool 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
142bool 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
147bool 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
152bool 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
158bool 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
166extern "C" void __xray_ArgLoggerEntry() XRAY_NEVER_INSTRUMENT {
167 // FIXME: this will have to be implemented in the trampoline assembly file
168}
169

source code of compiler-rt/lib/xray/xray_hexagon.cpp