1 //===-- xray_hexagon.cpp --------------------------------------*- C++ ---*-===//
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
7 //===----------------------------------------------------------------------===//
9 // This file is a part of XRay, a dynamic runtime instrumentation system.
11 // Implementation of hexagon-specific routines (32-bit).
13 //===----------------------------------------------------------------------===//
14 #include "sanitizer_common/sanitizer_common.h"
15 #include "xray_defs.h"
16 #include "xray_interface_internal.h"
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
31 enum PacketWordParseBits
: uint32_t {
32 PP_DUPLEX
= 0x00 << 14,
33 PP_NOT_END
= 0x01 << 14,
34 PP_PACKET_END
= 0x03 << 14,
37 enum RegNum
: uint32_t {
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:
50 const PacketWordParseBits ParseBits
= PacketEnd
? PP_PACKET_END
: PP_NOT_END
;
52 return PO_TFR_IMM
| ParseBits
| (Imm
<< 5) | (DestReg
& REG_MASK
);
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;
66 // The extender encodes the 26 most significant bits of the effective
70 const uint32_t high
= (Imm
& IMM_MASK_HIGH
) << 16;
71 const uint32_t low
= Imm
& IMM_MASK_LOW
;
73 return PO_IMMEXT
| high
| PP_NOT_END
| low
;
76 static void WriteInstFlushCache(void *Addr
, uint32_t NewInstruction
) {
77 asm volatile("icinva(%[inst_addr])\n\t"
79 "memw(%[inst_addr]) = %[new_inst]\n\t"
80 "dccleaninva(%[inst_addr])\n\t"
83 : [ inst_addr
] "r"(Addr
), [ new_inst
] "r"(NewInstruction
)
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):
102 // With the following runtime patch:
104 // xray_sled_n (32-bit):
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
113 // When |Enable|==false, we set back the first instruction in the sled to be
116 uint32_t *FirstAddress
= reinterpret_cast<uint32_t *>(Sled
.address());
118 uint32_t *CurAddress
= FirstAddress
+ 1;
119 *CurAddress
= encodeExtendedTransferImmediate(FuncId
, RN_R7
);
121 *CurAddress
= encodeConstantExtender(reinterpret_cast<uint32_t>(TracingHook
));
124 encodeExtendedTransferImmediate(reinterpret_cast<uint32_t>(TracingHook
), RN_R6
, true);
127 *CurAddress
= uint32_t(PO_CALLR_R6
);
129 WriteInstFlushCache(FirstAddress
, uint32_t(encodeConstantExtender(FuncId
)));
131 WriteInstFlushCache(FirstAddress
, uint32_t(PatchOpcodes::PO_JUMPI_14
));
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
);
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
);
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
);
152 bool patchCustomEvent(const bool Enable
, const uint32_t FuncId
,
153 const XRaySledEntry
&Sled
) XRAY_NEVER_INSTRUMENT
{
154 // FIXME: Implement in hexagon?
158 bool patchTypedEvent(const bool Enable
, const uint32_t FuncId
,
159 const XRaySledEntry
&Sled
) XRAY_NEVER_INSTRUMENT
{
160 // FIXME: Implement in hexagon?
164 } // namespace __xray
166 extern "C" void __xray_ArgLoggerEntry() XRAY_NEVER_INSTRUMENT
{
167 // FIXME: this will have to be implemented in the trampoline assembly file