Path: blob/main/contrib/llvm-project/compiler-rt/lib/xray/xray_arm.cpp
35265 views
//===-- xray_arm.cpp --------------------------------------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file is a part of XRay, a dynamic runtime instrumentation system.9//10// Implementation of ARM-specific routines (32-bit).11//12//===----------------------------------------------------------------------===//13#include "sanitizer_common/sanitizer_common.h"14#include "xray_defs.h"15#include "xray_interface_internal.h"16#include <atomic>17#include <cassert>1819extern "C" void __clear_cache(void *start, void *end);2021namespace __xray {2223// The machine codes for some instructions used in runtime patching.24enum class PatchOpcodes : uint32_t {25PO_PushR0Lr = 0xE92D4001, // PUSH {r0, lr}26PO_BlxIp = 0xE12FFF3C, // BLX ip27PO_PopR0Lr = 0xE8BD4001, // POP {r0, lr}28PO_B20 = 0xEA000005 // B #2029};3031// 0xUUUUWXYZ -> 0x000W0XYZ32inline static uint32_t getMovwMask(const uint32_t Value) XRAY_NEVER_INSTRUMENT {33return (Value & 0xfff) | ((Value & 0xf000) << 4);34}3536// 0xWXYZUUUU -> 0x000W0XYZ37inline static uint32_t getMovtMask(const uint32_t Value) XRAY_NEVER_INSTRUMENT {38return getMovwMask(Value >> 16);39}4041// Writes the following instructions:42// MOVW R<regNo>, #<lower 16 bits of the |Value|>43// MOVT R<regNo>, #<higher 16 bits of the |Value|>44inline static uint32_t *45write32bitLoadReg(uint8_t regNo, uint32_t *Address,46const uint32_t Value) XRAY_NEVER_INSTRUMENT {47// This is a fatal error: we cannot just report it and continue execution.48assert(regNo <= 15 && "Register number must be 0 to 15.");49// MOVW R, #0xWXYZ in machine code is 0xE30WRXYZ50*Address = (0xE3000000 | (uint32_t(regNo) << 12) | getMovwMask(Value));51Address++;52// MOVT R, #0xWXYZ in machine code is 0xE34WRXYZ53*Address = (0xE3400000 | (uint32_t(regNo) << 12) | getMovtMask(Value));54return Address + 1;55}5657// Writes the following instructions:58// MOVW r0, #<lower 16 bits of the |Value|>59// MOVT r0, #<higher 16 bits of the |Value|>60inline static uint32_t *61write32bitLoadR0(uint32_t *Address,62const uint32_t Value) XRAY_NEVER_INSTRUMENT {63return write32bitLoadReg(0, Address, Value);64}6566// Writes the following instructions:67// MOVW ip, #<lower 16 bits of the |Value|>68// MOVT ip, #<higher 16 bits of the |Value|>69inline static uint32_t *70write32bitLoadIP(uint32_t *Address,71const uint32_t Value) XRAY_NEVER_INSTRUMENT {72return write32bitLoadReg(12, Address, Value);73}7475inline static bool patchSled(const bool Enable, const uint32_t FuncId,76const XRaySledEntry &Sled,77void (*TracingHook)()) XRAY_NEVER_INSTRUMENT {78// When |Enable| == true,79// We replace the following compile-time stub (sled):80//81// xray_sled_n:82// B #2083// 6 NOPs (24 bytes)84//85// With the following runtime patch:86//87// xray_sled_n:88// PUSH {r0, lr}89// MOVW r0, #<lower 16 bits of function ID>90// MOVT r0, #<higher 16 bits of function ID>91// MOVW ip, #<lower 16 bits of address of TracingHook>92// MOVT ip, #<higher 16 bits of address of TracingHook>93// BLX ip94// POP {r0, lr}95//96// Replacement of the first 4-byte instruction should be the last and atomic97// operation, so that the user code which reaches the sled concurrently98// either jumps over the whole sled, or executes the whole sled when the99// latter is ready.100//101// When |Enable|==false, we set back the first instruction in the sled to be102// B #20103104uint32_t *FirstAddress = reinterpret_cast<uint32_t *>(Sled.address());105uint32_t *CurAddress = FirstAddress + 1;106if (Enable) {107CurAddress =108write32bitLoadR0(CurAddress, reinterpret_cast<uint32_t>(FuncId));109CurAddress =110write32bitLoadIP(CurAddress, reinterpret_cast<uint32_t>(TracingHook));111*CurAddress = uint32_t(PatchOpcodes::PO_BlxIp);112CurAddress++;113*CurAddress = uint32_t(PatchOpcodes::PO_PopR0Lr);114CurAddress++;115std::atomic_store_explicit(116reinterpret_cast<std::atomic<uint32_t> *>(FirstAddress),117uint32_t(PatchOpcodes::PO_PushR0Lr), std::memory_order_release);118} else {119std::atomic_store_explicit(120reinterpret_cast<std::atomic<uint32_t> *>(FirstAddress),121uint32_t(PatchOpcodes::PO_B20), std::memory_order_release);122}123__clear_cache(reinterpret_cast<char *>(FirstAddress),124reinterpret_cast<char *>(CurAddress));125return true;126}127128bool patchFunctionEntry(const bool Enable, const uint32_t FuncId,129const XRaySledEntry &Sled,130void (*Trampoline)()) XRAY_NEVER_INSTRUMENT {131return patchSled(Enable, FuncId, Sled, Trampoline);132}133134bool patchFunctionExit(const bool Enable, const uint32_t FuncId,135const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {136return patchSled(Enable, FuncId, Sled, __xray_FunctionExit);137}138139bool patchFunctionTailExit(const bool Enable, const uint32_t FuncId,140const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {141return patchSled(Enable, FuncId, Sled, __xray_FunctionTailExit);142}143144bool patchCustomEvent(const bool Enable, const uint32_t FuncId,145const XRaySledEntry &Sled)146XRAY_NEVER_INSTRUMENT { // FIXME: Implement in arm?147return false;148}149150bool patchTypedEvent(const bool Enable, const uint32_t FuncId,151const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {152// FIXME: Implement in arm?153return false;154}155156// FIXME: Maybe implement this better?157bool probeRequiredCPUFeatures() XRAY_NEVER_INSTRUMENT { return true; }158159} // namespace __xray160161extern "C" void __xray_ArgLoggerEntry() XRAY_NEVER_INSTRUMENT {162// FIXME: this will have to be implemented in the trampoline assembly file163}164165166