]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/compiler-rt/lib/xray/xray_arm.cc
Merge clang 7.0.1 and several follow-up changes
[FreeBSD/FreeBSD.git] / contrib / compiler-rt / lib / xray / xray_arm.cc
1 //===-- xray_arm.cc ---------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file is a part of XRay, a dynamic runtime instrumentation system.
11 //
12 // Implementation of ARM-specific routines (32-bit).
13 //
14 //===----------------------------------------------------------------------===//
15 #include "sanitizer_common/sanitizer_common.h"
16 #include "xray_defs.h"
17 #include "xray_interface_internal.h"
18 #include <atomic>
19 #include <cassert>
20
21 extern "C" void __clear_cache(void *start, void *end);
22
23 namespace __xray {
24
25 // The machine codes for some instructions used in runtime patching.
26 enum class PatchOpcodes : uint32_t {
27   PO_PushR0Lr = 0xE92D4001, // PUSH {r0, lr}
28   PO_BlxIp = 0xE12FFF3C,    // BLX ip
29   PO_PopR0Lr = 0xE8BD4001,  // POP {r0, lr}
30   PO_B20 = 0xEA000005       // B #20
31 };
32
33 // 0xUUUUWXYZ -> 0x000W0XYZ
34 inline static uint32_t getMovwMask(const uint32_t Value) XRAY_NEVER_INSTRUMENT {
35   return (Value & 0xfff) | ((Value & 0xf000) << 4);
36 }
37
38 // 0xWXYZUUUU -> 0x000W0XYZ
39 inline static uint32_t getMovtMask(const uint32_t Value) XRAY_NEVER_INSTRUMENT {
40   return getMovwMask(Value >> 16);
41 }
42
43 // Writes the following instructions:
44 //   MOVW R<regNo>, #<lower 16 bits of the |Value|>
45 //   MOVT R<regNo>, #<higher 16 bits of the |Value|>
46 inline static uint32_t *
47 write32bitLoadReg(uint8_t regNo, uint32_t *Address,
48                   const uint32_t Value) XRAY_NEVER_INSTRUMENT {
49   // This is a fatal error: we cannot just report it and continue execution.
50   assert(regNo <= 15 && "Register number must be 0 to 15.");
51   // MOVW R, #0xWXYZ in machine code is 0xE30WRXYZ
52   *Address = (0xE3000000 | (uint32_t(regNo) << 12) | getMovwMask(Value));
53   Address++;
54   // MOVT R, #0xWXYZ in machine code is 0xE34WRXYZ
55   *Address = (0xE3400000 | (uint32_t(regNo) << 12) | getMovtMask(Value));
56   return Address + 1;
57 }
58
59 // Writes the following instructions:
60 //   MOVW r0, #<lower 16 bits of the |Value|>
61 //   MOVT r0, #<higher 16 bits of the |Value|>
62 inline static uint32_t *
63 write32bitLoadR0(uint32_t *Address,
64                  const uint32_t Value) XRAY_NEVER_INSTRUMENT {
65   return write32bitLoadReg(0, Address, Value);
66 }
67
68 // Writes the following instructions:
69 //   MOVW ip, #<lower 16 bits of the |Value|>
70 //   MOVT ip, #<higher 16 bits of the |Value|>
71 inline static uint32_t *
72 write32bitLoadIP(uint32_t *Address,
73                  const uint32_t Value) XRAY_NEVER_INSTRUMENT {
74   return write32bitLoadReg(12, Address, Value);
75 }
76
77 inline static bool patchSled(const bool Enable, const uint32_t FuncId,
78                              const XRaySledEntry &Sled,
79                              void (*TracingHook)()) XRAY_NEVER_INSTRUMENT {
80   // When |Enable| == true,
81   // We replace the following compile-time stub (sled):
82   //
83   // xray_sled_n:
84   //   B #20
85   //   6 NOPs (24 bytes)
86   //
87   // With the following runtime patch:
88   //
89   // xray_sled_n:
90   //   PUSH {r0, lr}
91   //   MOVW r0, #<lower 16 bits of function ID>
92   //   MOVT r0, #<higher 16 bits of function ID>
93   //   MOVW ip, #<lower 16 bits of address of TracingHook>
94   //   MOVT ip, #<higher 16 bits of address of TracingHook>
95   //   BLX ip
96   //   POP {r0, lr}
97   //
98   // Replacement of the first 4-byte instruction should be the last and atomic
99   // operation, so that the user code which reaches the sled concurrently
100   // either jumps over the whole sled, or executes the whole sled when the
101   // latter is ready.
102   //
103   // When |Enable|==false, we set back the first instruction in the sled to be
104   //   B #20
105
106   uint32_t *FirstAddress = reinterpret_cast<uint32_t *>(Sled.Address);
107   uint32_t *CurAddress = FirstAddress + 1;
108   if (Enable) {
109     CurAddress =
110         write32bitLoadR0(CurAddress, reinterpret_cast<uint32_t>(FuncId));
111     CurAddress =
112         write32bitLoadIP(CurAddress, reinterpret_cast<uint32_t>(TracingHook));
113     *CurAddress = uint32_t(PatchOpcodes::PO_BlxIp);
114     CurAddress++;
115     *CurAddress = uint32_t(PatchOpcodes::PO_PopR0Lr);
116     CurAddress++;
117     std::atomic_store_explicit(
118         reinterpret_cast<std::atomic<uint32_t> *>(FirstAddress),
119         uint32_t(PatchOpcodes::PO_PushR0Lr), std::memory_order_release);
120   } else {
121     std::atomic_store_explicit(
122         reinterpret_cast<std::atomic<uint32_t> *>(FirstAddress),
123         uint32_t(PatchOpcodes::PO_B20), std::memory_order_release);
124   }
125   __clear_cache(reinterpret_cast<char *>(FirstAddress),
126                 reinterpret_cast<char *>(CurAddress));
127   return true;
128 }
129
130 bool patchFunctionEntry(const bool Enable, const uint32_t FuncId,
131                         const XRaySledEntry &Sled,
132                         void (*Trampoline)()) XRAY_NEVER_INSTRUMENT {
133   return patchSled(Enable, FuncId, Sled, Trampoline);
134 }
135
136 bool patchFunctionExit(const bool Enable, const uint32_t FuncId,
137                        const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
138   return patchSled(Enable, FuncId, Sled, __xray_FunctionExit);
139 }
140
141 bool patchFunctionTailExit(const bool Enable, const uint32_t FuncId,
142                            const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
143   return patchSled(Enable, FuncId, Sled, __xray_FunctionTailExit);
144 }
145
146 bool patchCustomEvent(const bool Enable, const uint32_t FuncId,
147                       const XRaySledEntry &Sled)
148     XRAY_NEVER_INSTRUMENT { // FIXME: Implement in arm?
149   return false;
150 }
151
152 bool patchTypedEvent(const bool Enable, const uint32_t FuncId,
153                      const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
154   // FIXME: Implement in arm?
155   return false;
156 }
157
158 // FIXME: Maybe implement this better?
159 bool probeRequiredCPUFeatures() XRAY_NEVER_INSTRUMENT { return true; }
160
161 } // namespace __xray
162
163 extern "C" void __xray_ArgLoggerEntry() XRAY_NEVER_INSTRUMENT {
164   // FIXME: this will have to be implemented in the trampoline assembly file
165 }