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