blob: d1b953e2e8a2e9b98925200e8471dcb001cda22c [file] [log] [blame]
Dean Michael Berrisd1617cd2016-09-20 14:35:57 +00001//===-- 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//===----------------------------------------------------------------------===//
Dean Michael Berrisd1617cd2016-09-20 14:35:57 +000015#include "sanitizer_common/sanitizer_common.h"
Dean Michael Berris4ef1a692016-10-06 07:09:40 +000016#include "xray_interface_internal.h"
Dean Michael Berrisd1617cd2016-09-20 14:35:57 +000017#include <atomic>
18#include <cassert>
19
20namespace __xray {
21
22// The machine codes for some instructions used in runtime patching.
Dean Michael Berris4ef1a692016-10-06 07:09:40 +000023enum class PatchOpcodes : uint32_t {
Dean Michael Berrisd1617cd2016-09-20 14:35:57 +000024 PO_PushR0Lr = 0xE92D4001, // PUSH {r0, lr}
Dean Michael Berris4ef1a692016-10-06 07:09:40 +000025 PO_BlxIp = 0xE12FFF3C, // BLX ip
26 PO_PopR0Lr = 0xE8BD4001, // POP {r0, lr}
27 PO_B20 = 0xEA000005 // B #20
Dean Michael Berrisd1617cd2016-09-20 14:35:57 +000028};
29
30// 0xUUUUWXYZ -> 0x000W0XYZ
31inline static uint32_t getMovwMask(const uint32_t Value) {
32 return (Value & 0xfff) | ((Value & 0xf000) << 4);
33}
34
35// 0xWXYZUUUU -> 0x000W0XYZ
36inline static uint32_t getMovtMask(const uint32_t Value) {
37 return getMovwMask(Value >> 16);
38}
39
40// Writes the following instructions:
41// MOVW R<regNo>, #<lower 16 bits of the |Value|>
42// MOVT R<regNo>, #<higher 16 bits of the |Value|>
Dean Michael Berris4ef1a692016-10-06 07:09:40 +000043inline static uint32_t *write32bitLoadReg(uint8_t regNo, uint32_t *Address,
44 const uint32_t Value) {
45 // This is a fatal error: we cannot just report it and continue execution.
Dean Michael Berrisd1617cd2016-09-20 14:35:57 +000046 assert(regNo <= 15 && "Register number must be 0 to 15.");
47 // MOVW R, #0xWXYZ in machine code is 0xE30WRXYZ
Dean Michael Berris4ef1a692016-10-06 07:09:40 +000048 *Address = (0xE3000000 | (uint32_t(regNo) << 12) | getMovwMask(Value));
Dean Michael Berrisd1617cd2016-09-20 14:35:57 +000049 Address++;
50 // MOVT R, #0xWXYZ in machine code is 0xE34WRXYZ
Dean Michael Berris4ef1a692016-10-06 07:09:40 +000051 *Address = (0xE3400000 | (uint32_t(regNo) << 12) | getMovtMask(Value));
Dean Michael Berrisd1617cd2016-09-20 14:35:57 +000052 return Address + 1;
53}
54
55// Writes the following instructions:
56// MOVW r0, #<lower 16 bits of the |Value|>
57// MOVT r0, #<higher 16 bits of the |Value|>
58inline static uint32_t *Write32bitLoadR0(uint32_t *Address,
59 const uint32_t Value) {
60 return write32bitLoadReg(0, Address, Value);
61}
62
63// Writes the following instructions:
64// MOVW ip, #<lower 16 bits of the |Value|>
65// MOVT ip, #<higher 16 bits of the |Value|>
66inline static uint32_t *Write32bitLoadIP(uint32_t *Address,
67 const uint32_t Value) {
68 return write32bitLoadReg(12, Address, Value);
69}
70
71inline static bool patchSled(const bool Enable, const uint32_t FuncId,
72 const XRaySledEntry &Sled, void (*TracingHook)()) {
73 // When |Enable| == true,
74 // We replace the following compile-time stub (sled):
75 //
76 // xray_sled_n:
77 // B #20
78 // 6 NOPs (24 bytes)
79 //
80 // With the following runtime patch:
81 //
82 // xray_sled_n:
83 // PUSH {r0, lr}
84 // MOVW r0, #<lower 16 bits of function ID>
85 // MOVT r0, #<higher 16 bits of function ID>
86 // MOVW ip, #<lower 16 bits of address of TracingHook>
87 // MOVT ip, #<higher 16 bits of address of TracingHook>
88 // BLX ip
89 // POP {r0, lr}
90 //
91 // Replacement of the first 4-byte instruction should be the last and atomic
92 // operation, so that the user code which reaches the sled concurrently
93 // either jumps over the whole sled, or executes the whole sled when the
94 // latter is ready.
95 //
96 // When |Enable|==false, we set back the first instruction in the sled to be
97 // B #20
98
99 uint32_t *FirstAddress = reinterpret_cast<uint32_t *>(Sled.Address);
100 if (Enable) {
101 uint32_t *CurAddress = FirstAddress + 1;
102 CurAddress =
103 Write32bitLoadR0(CurAddress, reinterpret_cast<uint32_t>(FuncId));
104 CurAddress =
105 Write32bitLoadIP(CurAddress, reinterpret_cast<uint32_t>(TracingHook));
106 *CurAddress = uint32_t(PatchOpcodes::PO_BlxIp);
107 CurAddress++;
108 *CurAddress = uint32_t(PatchOpcodes::PO_PopR0Lr);
109 std::atomic_store_explicit(
110 reinterpret_cast<std::atomic<uint32_t> *>(FirstAddress),
111 uint32_t(PatchOpcodes::PO_PushR0Lr), std::memory_order_release);
112 } else {
113 std::atomic_store_explicit(
114 reinterpret_cast<std::atomic<uint32_t> *>(FirstAddress),
115 uint32_t(PatchOpcodes::PO_B20), std::memory_order_release);
116 }
117 return true;
118}
119
120bool patchFunctionEntry(const bool Enable, const uint32_t FuncId,
121 const XRaySledEntry &Sled) {
122 return patchSled(Enable, FuncId, Sled, __xray_FunctionEntry);
123}
124
125bool patchFunctionExit(const bool Enable, const uint32_t FuncId,
126 const XRaySledEntry &Sled) {
127 return patchSled(Enable, FuncId, Sled, __xray_FunctionExit);
128}
129
130} // namespace __xray