168d75effSDimitry Andric //===-- xray_AArch64.cpp ----------------------------------------*- C++ -*-===// 268d75effSDimitry Andric // 368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 668d75effSDimitry Andric // 768d75effSDimitry Andric //===----------------------------------------------------------------------===// 868d75effSDimitry Andric // 968d75effSDimitry Andric // This file is a part of XRay, a dynamic runtime instrumentation system. 1068d75effSDimitry Andric // 1168d75effSDimitry Andric // Implementation of AArch64-specific routines (64-bit). 1268d75effSDimitry Andric // 1368d75effSDimitry Andric //===----------------------------------------------------------------------===// 1468d75effSDimitry Andric #include "sanitizer_common/sanitizer_common.h" 1568d75effSDimitry Andric #include "xray_defs.h" 1668d75effSDimitry Andric #include "xray_interface_internal.h" 1768d75effSDimitry Andric #include <atomic> 1868d75effSDimitry Andric #include <cassert> 1968d75effSDimitry Andric 2068d75effSDimitry Andric extern "C" void __clear_cache(void *start, void *end); 2168d75effSDimitry Andric 2268d75effSDimitry Andric namespace __xray { 2368d75effSDimitry Andric 2468d75effSDimitry Andric // The machine codes for some instructions used in runtime patching. 2568d75effSDimitry Andric enum class PatchOpcodes : uint32_t { 2668d75effSDimitry Andric PO_StpX0X30SP_m16e = 0xA9BF7BE0, // STP X0, X30, [SP, #-16]! 2768d75effSDimitry Andric PO_LdrW0_12 = 0x18000060, // LDR W0, #12 2868d75effSDimitry Andric PO_LdrX16_12 = 0x58000070, // LDR X16, #12 2968d75effSDimitry Andric PO_BlrX16 = 0xD63F0200, // BLR X16 3068d75effSDimitry Andric PO_LdpX0X30SP_16 = 0xA8C17BE0, // LDP X0, X30, [SP], #16 3168d75effSDimitry Andric PO_B32 = 0x14000008 // B #32 3268d75effSDimitry Andric }; 3368d75effSDimitry Andric 3468d75effSDimitry Andric inline static bool patchSled(const bool Enable, const uint32_t FuncId, 3568d75effSDimitry Andric const XRaySledEntry &Sled, 3668d75effSDimitry Andric void (*TracingHook)()) XRAY_NEVER_INSTRUMENT { 3768d75effSDimitry Andric // When |Enable| == true, 3868d75effSDimitry Andric // We replace the following compile-time stub (sled): 3968d75effSDimitry Andric // 4068d75effSDimitry Andric // xray_sled_n: 4168d75effSDimitry Andric // B #32 4268d75effSDimitry Andric // 7 NOPs (24 bytes) 4368d75effSDimitry Andric // 4468d75effSDimitry Andric // With the following runtime patch: 4568d75effSDimitry Andric // 4668d75effSDimitry Andric // xray_sled_n: 4768d75effSDimitry Andric // STP X0, X30, [SP, #-16]! ; PUSH {r0, lr} 4868d75effSDimitry Andric // LDR W0, #12 ; W0 := function ID 4968d75effSDimitry Andric // LDR X16,#12 ; X16 := address of the trampoline 5068d75effSDimitry Andric // BLR X16 5168d75effSDimitry Andric // ;DATA: 32 bits of function ID 5268d75effSDimitry Andric // ;DATA: lower 32 bits of the address of the trampoline 5368d75effSDimitry Andric // ;DATA: higher 32 bits of the address of the trampoline 5468d75effSDimitry Andric // LDP X0, X30, [SP], #16 ; POP {r0, lr} 5568d75effSDimitry Andric // 5668d75effSDimitry Andric // Replacement of the first 4-byte instruction should be the last and atomic 5768d75effSDimitry Andric // operation, so that the user code which reaches the sled concurrently 5868d75effSDimitry Andric // either jumps over the whole sled, or executes the whole sled when the 5968d75effSDimitry Andric // latter is ready. 6068d75effSDimitry Andric // 6168d75effSDimitry Andric // When |Enable|==false, we set back the first instruction in the sled to be 6268d75effSDimitry Andric // B #32 6368d75effSDimitry Andric 64*5ffd83dbSDimitry Andric uint32_t *FirstAddress = reinterpret_cast<uint32_t *>(Sled.address()); 6568d75effSDimitry Andric uint32_t *CurAddress = FirstAddress + 1; 6668d75effSDimitry Andric if (Enable) { 6768d75effSDimitry Andric *CurAddress = uint32_t(PatchOpcodes::PO_LdrW0_12); 6868d75effSDimitry Andric CurAddress++; 6968d75effSDimitry Andric *CurAddress = uint32_t(PatchOpcodes::PO_LdrX16_12); 7068d75effSDimitry Andric CurAddress++; 7168d75effSDimitry Andric *CurAddress = uint32_t(PatchOpcodes::PO_BlrX16); 7268d75effSDimitry Andric CurAddress++; 7368d75effSDimitry Andric *CurAddress = FuncId; 7468d75effSDimitry Andric CurAddress++; 7568d75effSDimitry Andric *reinterpret_cast<void (**)()>(CurAddress) = TracingHook; 7668d75effSDimitry Andric CurAddress += 2; 7768d75effSDimitry Andric *CurAddress = uint32_t(PatchOpcodes::PO_LdpX0X30SP_16); 7868d75effSDimitry Andric CurAddress++; 7968d75effSDimitry Andric std::atomic_store_explicit( 8068d75effSDimitry Andric reinterpret_cast<std::atomic<uint32_t> *>(FirstAddress), 8168d75effSDimitry Andric uint32_t(PatchOpcodes::PO_StpX0X30SP_m16e), std::memory_order_release); 8268d75effSDimitry Andric } else { 8368d75effSDimitry Andric std::atomic_store_explicit( 8468d75effSDimitry Andric reinterpret_cast<std::atomic<uint32_t> *>(FirstAddress), 8568d75effSDimitry Andric uint32_t(PatchOpcodes::PO_B32), std::memory_order_release); 8668d75effSDimitry Andric } 8768d75effSDimitry Andric __clear_cache(reinterpret_cast<char *>(FirstAddress), 8868d75effSDimitry Andric reinterpret_cast<char *>(CurAddress)); 8968d75effSDimitry Andric return true; 9068d75effSDimitry Andric } 9168d75effSDimitry Andric 9268d75effSDimitry Andric bool patchFunctionEntry(const bool Enable, const uint32_t FuncId, 9368d75effSDimitry Andric const XRaySledEntry &Sled, 9468d75effSDimitry Andric void (*Trampoline)()) XRAY_NEVER_INSTRUMENT { 9568d75effSDimitry Andric return patchSled(Enable, FuncId, Sled, Trampoline); 9668d75effSDimitry Andric } 9768d75effSDimitry Andric 9868d75effSDimitry Andric bool patchFunctionExit(const bool Enable, const uint32_t FuncId, 9968d75effSDimitry Andric const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { 10068d75effSDimitry Andric return patchSled(Enable, FuncId, Sled, __xray_FunctionExit); 10168d75effSDimitry Andric } 10268d75effSDimitry Andric 10368d75effSDimitry Andric bool patchFunctionTailExit(const bool Enable, const uint32_t FuncId, 10468d75effSDimitry Andric const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { 10568d75effSDimitry Andric return patchSled(Enable, FuncId, Sled, __xray_FunctionTailExit); 10668d75effSDimitry Andric } 10768d75effSDimitry Andric 10868d75effSDimitry Andric bool patchCustomEvent(const bool Enable, const uint32_t FuncId, 10968d75effSDimitry Andric const XRaySledEntry &Sled) 11068d75effSDimitry Andric XRAY_NEVER_INSTRUMENT { // FIXME: Implement in aarch64? 11168d75effSDimitry Andric return false; 11268d75effSDimitry Andric } 11368d75effSDimitry Andric 11468d75effSDimitry Andric bool patchTypedEvent(const bool Enable, const uint32_t FuncId, 11568d75effSDimitry Andric const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { 11668d75effSDimitry Andric // FIXME: Implement in aarch64? 11768d75effSDimitry Andric return false; 11868d75effSDimitry Andric } 11968d75effSDimitry Andric 12068d75effSDimitry Andric // FIXME: Maybe implement this better? 12168d75effSDimitry Andric bool probeRequiredCPUFeatures() XRAY_NEVER_INSTRUMENT { return true; } 12268d75effSDimitry Andric 12368d75effSDimitry Andric } // namespace __xray 12468d75effSDimitry Andric 12568d75effSDimitry Andric extern "C" void __xray_ArgLoggerEntry() XRAY_NEVER_INSTRUMENT { 12668d75effSDimitry Andric // FIXME: this will have to be implemented in the trampoline assembly file 12768d75effSDimitry Andric } 128