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