xray_AArch64.cpp revision 360784
1//===-- xray_AArch64.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 AArch64-specific routines (64-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
20extern "C" void __clear_cache(void *start, void *end);
21
22namespace __xray {
23
24// The machine codes for some instructions used in runtime patching.
25enum class PatchOpcodes : uint32_t {
26  PO_StpX0X30SP_m16e = 0xA9BF7BE0, // STP X0, X30, [SP, #-16]!
27  PO_LdrW0_12 = 0x18000060,        // LDR W0, #12
28  PO_LdrX16_12 = 0x58000070,       // LDR X16, #12
29  PO_BlrX16 = 0xD63F0200,          // BLR X16
30  PO_LdpX0X30SP_16 = 0xA8C17BE0,   // LDP X0, X30, [SP], #16
31  PO_B32 = 0x14000008              // B #32
32};
33
34inline static bool patchSled(const bool Enable, const uint32_t FuncId,
35                             const XRaySledEntry &Sled,
36                             void (*TracingHook)()) XRAY_NEVER_INSTRUMENT {
37  // When |Enable| == true,
38  // We replace the following compile-time stub (sled):
39  //
40  // xray_sled_n:
41  //   B #32
42  //   7 NOPs (24 bytes)
43  //
44  // With the following runtime patch:
45  //
46  // xray_sled_n:
47  //   STP X0, X30, [SP, #-16]! ; PUSH {r0, lr}
48  //   LDR W0, #12 ; W0 := function ID
49  //   LDR X16,#12 ; X16 := address of the trampoline
50  //   BLR X16
51  //   ;DATA: 32 bits of function ID
52  //   ;DATA: lower 32 bits of the address of the trampoline
53  //   ;DATA: higher 32 bits of the address of the trampoline
54  //   LDP X0, X30, [SP], #16 ; POP {r0, lr}
55  //
56  // Replacement of the first 4-byte instruction should be the last and atomic
57  // operation, so that the user code which reaches the sled concurrently
58  // either jumps over the whole sled, or executes the whole sled when the
59  // latter is ready.
60  //
61  // When |Enable|==false, we set back the first instruction in the sled to be
62  //   B #32
63
64  uint32_t *FirstAddress = reinterpret_cast<uint32_t *>(Sled.Address);
65  uint32_t *CurAddress = FirstAddress + 1;
66  if (Enable) {
67    *CurAddress = uint32_t(PatchOpcodes::PO_LdrW0_12);
68    CurAddress++;
69    *CurAddress = uint32_t(PatchOpcodes::PO_LdrX16_12);
70    CurAddress++;
71    *CurAddress = uint32_t(PatchOpcodes::PO_BlrX16);
72    CurAddress++;
73    *CurAddress = FuncId;
74    CurAddress++;
75    *reinterpret_cast<void (**)()>(CurAddress) = TracingHook;
76    CurAddress += 2;
77    *CurAddress = uint32_t(PatchOpcodes::PO_LdpX0X30SP_16);
78    CurAddress++;
79    std::atomic_store_explicit(
80        reinterpret_cast<std::atomic<uint32_t> *>(FirstAddress),
81        uint32_t(PatchOpcodes::PO_StpX0X30SP_m16e), std::memory_order_release);
82  } else {
83    std::atomic_store_explicit(
84        reinterpret_cast<std::atomic<uint32_t> *>(FirstAddress),
85        uint32_t(PatchOpcodes::PO_B32), std::memory_order_release);
86  }
87  __clear_cache(reinterpret_cast<char *>(FirstAddress),
88                reinterpret_cast<char *>(CurAddress));
89  return true;
90}
91
92bool patchFunctionEntry(const bool Enable, const uint32_t FuncId,
93                        const XRaySledEntry &Sled,
94                        void (*Trampoline)()) XRAY_NEVER_INSTRUMENT {
95  return patchSled(Enable, FuncId, Sled, Trampoline);
96}
97
98bool patchFunctionExit(const bool Enable, const uint32_t FuncId,
99                       const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
100  return patchSled(Enable, FuncId, Sled, __xray_FunctionExit);
101}
102
103bool patchFunctionTailExit(const bool Enable, const uint32_t FuncId,
104                           const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
105  return patchSled(Enable, FuncId, Sled, __xray_FunctionTailExit);
106}
107
108bool patchCustomEvent(const bool Enable, const uint32_t FuncId,
109                      const XRaySledEntry &Sled)
110    XRAY_NEVER_INSTRUMENT { // FIXME: Implement in aarch64?
111  return false;
112}
113
114bool patchTypedEvent(const bool Enable, const uint32_t FuncId,
115                     const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
116  // FIXME: Implement in aarch64?
117  return false;
118}
119
120// FIXME: Maybe implement this better?
121bool probeRequiredCPUFeatures() XRAY_NEVER_INSTRUMENT { return true; }
122
123} // namespace __xray
124
125extern "C" void __xray_ArgLoggerEntry() XRAY_NEVER_INSTRUMENT {
126  // FIXME: this will have to be implemented in the trampoline assembly file
127}
128