diff options
author | Dean Michael Berris <dberris@google.com> | 2016-09-20 14:35:57 +0000 |
---|---|---|
committer | Dean Michael Berris <dberris@google.com> | 2016-09-20 14:35:57 +0000 |
commit | 2bc83b9afa200d0bd2e877d6bdd055c83bf55b40 (patch) | |
tree | 19c4b3d21d3f8e42f7b5d830533741ded603eaca /lib/xray/xray_arm.cc | |
parent | d1742d24df19dad2f5b1674fbeedcbdb72c38bde (diff) |
[XRay] ARM 32-bit no-Thumb support in compiler-rt
This is a port of XRay to ARM 32-bit, without Thumb support yet.
This is one of 3 commits to different repositories of XRay ARM port. The other 2 are:
https://reviews.llvm.org/D23931 (LLVM)
https://reviews.llvm.org/D23932 (Clang test)
Differential Revision: https://reviews.llvm.org/D23933
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@281971 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/xray/xray_arm.cc')
-rw-r--r-- | lib/xray/xray_arm.cc | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/lib/xray/xray_arm.cc b/lib/xray/xray_arm.cc new file mode 100644 index 000000000..00150f62c --- /dev/null +++ b/lib/xray/xray_arm.cc @@ -0,0 +1,131 @@ +//===-- xray_arm.cc ---------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of XRay, a dynamic runtime instrumentation system. +// +// Implementation of ARM-specific routines (32-bit). +// +//===----------------------------------------------------------------------===// +#include "xray_interface_internal.h" +#include "sanitizer_common/sanitizer_common.h" +#include <atomic> +#include <cassert> + +namespace __xray { + +// The machine codes for some instructions used in runtime patching. +enum class PatchOpcodes : uint32_t +{ + PO_PushR0Lr = 0xE92D4001, // PUSH {r0, lr} + PO_BlxIp = 0xE12FFF3C, // BLX ip + PO_PopR0Lr = 0xE8BD4001, // POP {r0, lr} + PO_B20 = 0xEA000005 // B #20 +}; + +// 0xUUUUWXYZ -> 0x000W0XYZ +inline static uint32_t getMovwMask(const uint32_t Value) { + return (Value & 0xfff) | ((Value & 0xf000) << 4); +} + +// 0xWXYZUUUU -> 0x000W0XYZ +inline static uint32_t getMovtMask(const uint32_t Value) { + return getMovwMask(Value >> 16); +} + +// Writes the following instructions: +// MOVW R<regNo>, #<lower 16 bits of the |Value|> +// MOVT R<regNo>, #<higher 16 bits of the |Value|> +inline static uint32_t* write32bitLoadReg(uint8_t regNo, uint32_t* Address, + const uint32_t Value) { + //This is a fatal error: we cannot just report it and continue execution. + assert(regNo <= 15 && "Register number must be 0 to 15."); + // MOVW R, #0xWXYZ in machine code is 0xE30WRXYZ + *Address = (0xE3000000 | (uint32_t(regNo)<<12) | getMovwMask(Value)); + Address++; + // MOVT R, #0xWXYZ in machine code is 0xE34WRXYZ + *Address = (0xE3400000 | (uint32_t(regNo)<<12) | getMovtMask(Value)); + return Address + 1; +} + +// Writes the following instructions: +// MOVW r0, #<lower 16 bits of the |Value|> +// MOVT r0, #<higher 16 bits of the |Value|> +inline static uint32_t *Write32bitLoadR0(uint32_t *Address, + const uint32_t Value) { + return write32bitLoadReg(0, Address, Value); +} + +// Writes the following instructions: +// MOVW ip, #<lower 16 bits of the |Value|> +// MOVT ip, #<higher 16 bits of the |Value|> +inline static uint32_t *Write32bitLoadIP(uint32_t *Address, + const uint32_t Value) { + return write32bitLoadReg(12, Address, Value); +} + +inline static bool patchSled(const bool Enable, const uint32_t FuncId, + const XRaySledEntry &Sled, void (*TracingHook)()) { + // When |Enable| == true, + // We replace the following compile-time stub (sled): + // + // xray_sled_n: + // B #20 + // 6 NOPs (24 bytes) + // + // With the following runtime patch: + // + // xray_sled_n: + // PUSH {r0, lr} + // MOVW r0, #<lower 16 bits of function ID> + // MOVT r0, #<higher 16 bits of function ID> + // MOVW ip, #<lower 16 bits of address of TracingHook> + // MOVT ip, #<higher 16 bits of address of TracingHook> + // BLX ip + // POP {r0, lr} + // + // Replacement of the first 4-byte instruction should be the last and atomic + // operation, so that the user code which reaches the sled concurrently + // either jumps over the whole sled, or executes the whole sled when the + // latter is ready. + // + // When |Enable|==false, we set back the first instruction in the sled to be + // B #20 + + uint32_t *FirstAddress = reinterpret_cast<uint32_t *>(Sled.Address); + if (Enable) { + uint32_t *CurAddress = FirstAddress + 1; + CurAddress = + Write32bitLoadR0(CurAddress, reinterpret_cast<uint32_t>(FuncId)); + CurAddress = + Write32bitLoadIP(CurAddress, reinterpret_cast<uint32_t>(TracingHook)); + *CurAddress = uint32_t(PatchOpcodes::PO_BlxIp); + CurAddress++; + *CurAddress = uint32_t(PatchOpcodes::PO_PopR0Lr); + std::atomic_store_explicit( + reinterpret_cast<std::atomic<uint32_t> *>(FirstAddress), + uint32_t(PatchOpcodes::PO_PushR0Lr), std::memory_order_release); + } else { + std::atomic_store_explicit( + reinterpret_cast<std::atomic<uint32_t> *>(FirstAddress), + uint32_t(PatchOpcodes::PO_B20), std::memory_order_release); + } + return true; +} + +bool patchFunctionEntry(const bool Enable, const uint32_t FuncId, + const XRaySledEntry &Sled) { + return patchSled(Enable, FuncId, Sled, __xray_FunctionEntry); +} + +bool patchFunctionExit(const bool Enable, const uint32_t FuncId, + const XRaySledEntry &Sled) { + return patchSled(Enable, FuncId, Sled, __xray_FunctionExit); +} + +} // namespace __xray |