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
encodeExtendedTransferImmediate(uint32_t Imm,RegNum DestReg,bool PacketEnd=false)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
encodeConstantExtender(uint32_t Imm)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 
WriteInstFlushCache(void * Addr,uint32_t NewInstruction)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 
patchSled(const bool Enable,const uint32_t FuncId,const XRaySledEntry & Sled,void (* TracingHook)())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 
patchFunctionEntry(const bool Enable,const uint32_t FuncId,const XRaySledEntry & Sled,void (* Trampoline)())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 
patchFunctionExit(const bool Enable,const uint32_t FuncId,const XRaySledEntry & Sled)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 
patchFunctionTailExit(const bool Enable,const uint32_t FuncId,const XRaySledEntry & Sled)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 
patchCustomEvent(const bool Enable,const uint32_t FuncId,const XRaySledEntry & Sled)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 
patchTypedEvent(const bool Enable,const uint32_t FuncId,const XRaySledEntry & Sled)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 
__xray_ArgLoggerEntry()166 extern "C" void __xray_ArgLoggerEntry() XRAY_NEVER_INSTRUMENT {
167   // FIXME: this will have to be implemented in the trampoline assembly file
168 }
169