[Compiler-rt][XRAY][MIPS] Support xray on mips/mipsel/mips64/mips64el

Summary: Adds support for xray on mips/mipsel/mips64/mips64el.

Reviewed by sdardis, dberris
Differential: D27699

llvm-svn: 295166
This commit is contained in:
Sagar Thakur 2017-02-15 10:54:09 +00:00
parent ec65792910
commit ea831e4c46
10 changed files with 621 additions and 3 deletions

View File

@ -183,7 +183,7 @@ set(ALL_SAFESTACK_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM64} ${MIPS32} ${MIPS64})
set(ALL_CFI_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64})
set(ALL_ESAN_SUPPORTED_ARCH ${X86_64} ${MIPS64})
set(ALL_SCUDO_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64})
set(ALL_XRAY_SUPPORTED_ARCH ${X86_64} ${ARM32} ${ARM64})
set(ALL_XRAY_SUPPORTED_ARCH ${X86_64} ${ARM32} ${ARM64} ${MIPS32} ${MIPS64})
if(APPLE)
include(CompilerRTDarwinUtils)

View File

@ -29,6 +29,26 @@ set(aarch64_SOURCES
xray_trampoline_AArch64.S
${XRAY_SOURCES})
set(mips_SOURCES
xray_mips.cc
xray_trampoline_mips.S
${XRAY_SOURCES})
set(mipsel_SOURCES
xray_mips.cc
xray_trampoline_mips.S
${XRAY_SOURCES})
set(mips64_SOURCES
xray_mips64.cc
xray_trampoline_mips64.S
${XRAY_SOURCES})
set(mips64el_SOURCES
xray_mips64.cc
xray_trampoline_mips64.S
${XRAY_SOURCES})
include_directories(..)
include_directories(../../include)

View File

@ -42,7 +42,7 @@ macro(add_xray_unittest testname)
list(APPEND TEST_DEPS gtest_main xray)
endif()
if(NOT APPLE)
add_compiler_rt_test(XRayUnitTests ${testname}
add_compiler_rt_test(XRayUnitTests ${testname}-${arch}
OBJECTS ${TEST_OBJECTS}
DEPS ${TEST_DEPS}
LINK_FLAGS ${TARGET_LINK_FLAGS}

View File

@ -35,6 +35,10 @@ static const int16_t cSledLength = 12;
static const int16_t cSledLength = 32;
#elif defined(__arm__)
static const int16_t cSledLength = 28;
#elif SANITIZER_MIPS32
static const int16_t cSledLength = 48;
#elif SANITIZER_MIPS64
static const int16_t cSledLength = 64;
#else
#error "Unsupported CPU Architecture"
#endif /* CPU architecture */

View File

@ -0,0 +1,153 @@
//===-- xray_mips.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 MIPS-specific routines (32-bit).
//
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_common.h"
#include "xray_defs.h"
#include "xray_interface_internal.h"
#include <atomic>
namespace __xray {
// The machine codes for some instructions used in runtime patching.
enum PatchOpcodes : uint32_t {
PO_ADDIU = 0x24000000, // addiu rt, rs, imm
PO_SW = 0xAC000000, // sw rt, offset(sp)
PO_LUI = 0x3C000000, // lui rs, %hi(address)
PO_ORI = 0x34000000, // ori rt, rs, %lo(address)
PO_JALR = 0x0000F809, // jalr rs
PO_LW = 0x8C000000, // lw rt, offset(address)
PO_B44 = 0x1000000b, // b #44
PO_NOP = 0x0, // nop
};
enum RegNum : uint32_t {
RN_T0 = 0x8,
RN_T9 = 0x19,
RN_RA = 0x1F,
RN_SP = 0x1D,
};
inline static uint32_t encodeInstruction(uint32_t Opcode, uint32_t Rs,
uint32_t Rt,
uint32_t Imm) XRAY_NEVER_INSTRUMENT {
return (Opcode | Rs << 21 | Rt << 16 | Imm);
}
inline static uint32_t
encodeSpecialInstruction(uint32_t Opcode, uint32_t Rs, uint32_t Rt, uint32_t Rd,
uint32_t Imm) XRAY_NEVER_INSTRUMENT {
return (Rs << 21 | Rt << 16 | Rd << 11 | Imm << 6 | Opcode);
}
inline static bool patchSled(const bool Enable, const uint32_t FuncId,
const XRaySledEntry &Sled,
void (*TracingHook)()) XRAY_NEVER_INSTRUMENT {
// When |Enable| == true,
// We replace the following compile-time stub (sled):
//
// xray_sled_n:
// B .tmpN
// 11 NOPs (44 bytes)
// .tmpN
// ADDIU T9, T9, 44
//
// With the following runtime patch:
//
// xray_sled_n (32-bit):
// addiu sp, sp, -8 ;create stack frame
// nop
// sw ra, 4(sp) ;save return address
// sw t9, 0(sp) ;save register t9
// lui t9, %hi(__xray_FunctionEntry/Exit)
// ori t9, t9, %lo(__xray_FunctionEntry/Exit)
// lui t0, %hi(function_id)
// jalr t9 ;call Tracing hook
// ori t0, t0, %lo(function_id) ;pass function id (delay slot)
// lw t9, 0(sp) ;restore register t9
// lw ra, 4(sp) ;restore return address
// addiu sp, sp, 8 ;delete stack frame
//
// We add 44 bytes to t9 because we want to adjust the function pointer to
// the actual start of function i.e. the address just after the noop sled.
// We do this because gp displacement relocation is emitted at the start of
// of the function i.e after the nop sled and to correctly calculate the
// global offset table address, t9 must hold the address of the instruction
// containing the gp displacement relocation.
// FIXME: Is this correct for the static relocation model?
//
// 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 #44
if (Enable) {
uint32_t LoTracingHookAddr = reinterpret_cast<int32_t>(TracingHook) & 0xffff;
uint32_t HiTracingHookAddr =
(reinterpret_cast<int32_t>(TracingHook) >> 16) & 0xffff;
uint32_t LoFunctionID = FuncId & 0xffff;
uint32_t HiFunctionID = (FuncId >> 16) & 0xffff;
*reinterpret_cast<uint32_t *>(Sled.Address + 8) = encodeInstruction(
PatchOpcodes::PO_SW, RegNum::RN_SP, RegNum::RN_RA, 0x4);
*reinterpret_cast<uint32_t *>(Sled.Address + 12) = encodeInstruction(
PatchOpcodes::PO_SW, RegNum::RN_SP, RegNum::RN_T9, 0x0);
*reinterpret_cast<uint32_t *>(Sled.Address + 16) = encodeInstruction(
PatchOpcodes::PO_LUI, 0x0, RegNum::RN_T9, HiTracingHookAddr);
*reinterpret_cast<uint32_t *>(Sled.Address + 20) = encodeInstruction(
PatchOpcodes::PO_ORI, RegNum::RN_T9, RegNum::RN_T9, LoTracingHookAddr);
*reinterpret_cast<uint32_t *>(Sled.Address + 24) = encodeInstruction(
PatchOpcodes::PO_LUI, 0x0, RegNum::RN_T0, HiFunctionID);
*reinterpret_cast<uint32_t *>(Sled.Address + 28) = encodeSpecialInstruction(
PatchOpcodes::PO_JALR, RegNum::RN_T9, 0x0, RegNum::RN_RA, 0X0);
*reinterpret_cast<uint32_t *>(Sled.Address + 32) = encodeInstruction(
PatchOpcodes::PO_ORI, RegNum::RN_T0, RegNum::RN_T0, LoFunctionID);
*reinterpret_cast<uint32_t *>(Sled.Address + 36) = encodeInstruction(
PatchOpcodes::PO_LW, RegNum::RN_SP, RegNum::RN_T9, 0x0);
*reinterpret_cast<uint32_t *>(Sled.Address + 40) = encodeInstruction(
PatchOpcodes::PO_LW, RegNum::RN_SP, RegNum::RN_RA, 0x4);
*reinterpret_cast<uint32_t *>(Sled.Address + 44) = encodeInstruction(
PatchOpcodes::PO_ADDIU, RegNum::RN_SP, RegNum::RN_SP, 0x8);
uint32_t CreateStackSpaceInstr = encodeInstruction(
PatchOpcodes::PO_ADDIU, RegNum::RN_SP, RegNum::RN_SP, 0xFFF8);
std::atomic_store_explicit(
reinterpret_cast<std::atomic<uint32_t> *>(Sled.Address),
uint32_t(CreateStackSpaceInstr), std::memory_order_release);
} else {
std::atomic_store_explicit(
reinterpret_cast<std::atomic<uint32_t> *>(Sled.Address),
uint32_t(PatchOpcodes::PO_B44), std::memory_order_release);
}
return true;
}
bool patchFunctionEntry(const bool Enable, const uint32_t FuncId,
const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
return patchSled(Enable, FuncId, Sled, __xray_FunctionEntry);
}
bool patchFunctionExit(const bool Enable, const uint32_t FuncId,
const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
return patchSled(Enable, FuncId, Sled, __xray_FunctionExit);
}
bool patchFunctionTailExit(const bool Enable, const uint32_t FuncId,
const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
// FIXME: In the future we'd need to distinguish between non-tail exits and
// tail exits for better information preservation.
return patchSled(Enable, FuncId, Sled, __xray_FunctionExit);
}
} // namespace __xray

View File

@ -0,0 +1,162 @@
//===-- xray_mips64.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 MIPS64-specific routines.
//
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_common.h"
#include "xray_defs.h"
#include "xray_interface_internal.h"
#include <atomic>
namespace __xray {
// The machine codes for some instructions used in runtime patching.
enum PatchOpcodes : uint32_t {
PO_DADDIU = 0x64000000, // daddiu rt, rs, imm
PO_SD = 0xFC000000, // sd rt, base(offset)
PO_LUI = 0x3C000000, // lui rt, imm
PO_ORI = 0x34000000, // ori rt, rs, imm
PO_DSLL = 0x00000038, // dsll rd, rt, sa
PO_JALR = 0x00000009, // jalr rs
PO_LD = 0xDC000000, // ld rt, base(offset)
PO_B60 = 0x1000000f, // b #60
PO_NOP = 0x0, // nop
};
enum RegNum : uint32_t {
RN_T0 = 0xC,
RN_T9 = 0x19,
RN_RA = 0x1F,
RN_SP = 0x1D,
};
inline static uint32_t encodeInstruction(uint32_t Opcode, uint32_t Rs,
uint32_t Rt,
uint32_t Imm) XRAY_NEVER_INSTRUMENT {
return (Opcode | Rs << 21 | Rt << 16 | Imm);
}
inline static uint32_t
encodeSpecialInstruction(uint32_t Opcode, uint32_t Rs, uint32_t Rt, uint32_t Rd,
uint32_t Imm) XRAY_NEVER_INSTRUMENT {
return (Rs << 21 | Rt << 16 | Rd << 11 | Imm << 6 | Opcode);
}
inline static bool patchSled(const bool Enable, const uint32_t FuncId,
const XRaySledEntry &Sled,
void (*TracingHook)()) XRAY_NEVER_INSTRUMENT {
// When |Enable| == true,
// We replace the following compile-time stub (sled):
//
// xray_sled_n:
// B .tmpN
// 15 NOPs (60 bytes)
// .tmpN
//
// With the following runtime patch:
//
// xray_sled_n (64-bit):
// daddiu sp, sp, -16 ;create stack frame
// nop
// sd ra, 8(sp) ;save return address
// sd t9, 0(sp) ;save register t9
// lui t9, %highest(__xray_FunctionEntry/Exit)
// ori t9, t9, %higher(__xray_FunctionEntry/Exit)
// dsll t9, t9, 16
// ori t9, t9, %hi(__xray_FunctionEntry/Exit)
// dsll t9, t9, 16
// ori t9, t9, %lo(__xray_FunctionEntry/Exit)
// lui t0, %hi(function_id)
// jalr t9 ;call Tracing hook
// ori t0, t0, %lo(function_id) ;pass function id (delay slot)
// ld t9, 0(sp) ;restore register t9
// ld ra, 8(sp) ;restore return address
// daddiu sp, sp, 16 ;delete stack frame
//
// 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 #60
if (Enable) {
uint32_t LoTracingHookAddr =
reinterpret_cast<int64_t>(TracingHook) & 0xffff;
uint32_t HiTracingHookAddr = (reinterpret_cast<int64_t>(TracingHook) >> 16) & 0xffff;
uint32_t HigherTracingHookAddr =
(reinterpret_cast<int64_t>(TracingHook) >> 32) & 0xffff;
uint32_t HighestTracingHookAddr =
(reinterpret_cast<int64_t>(TracingHook) >> 48) & 0xffff;
uint32_t LoFunctionID = FuncId & 0xffff;
uint32_t HiFunctionID = (FuncId >> 16) & 0xffff;
*reinterpret_cast<uint32_t *>(Sled.Address + 8) = encodeInstruction(
PatchOpcodes::PO_SD, RegNum::RN_SP, RegNum::RN_RA, 0x8);
*reinterpret_cast<uint32_t *>(Sled.Address + 12) = encodeInstruction(
PatchOpcodes::PO_SD, RegNum::RN_SP, RegNum::RN_T9, 0x0);
*reinterpret_cast<uint32_t *>(Sled.Address + 16) = encodeInstruction(
PatchOpcodes::PO_LUI, 0x0, RegNum::RN_T9, HighestTracingHookAddr);
*reinterpret_cast<uint32_t *>(Sled.Address + 20) =
encodeInstruction(PatchOpcodes::PO_ORI, RegNum::RN_T9, RegNum::RN_T9,
HigherTracingHookAddr);
*reinterpret_cast<uint32_t *>(Sled.Address + 24) = encodeSpecialInstruction(
PatchOpcodes::PO_DSLL, 0x0, RegNum::RN_T9, RegNum::RN_T9, 0x10);
*reinterpret_cast<uint32_t *>(Sled.Address + 28) = encodeInstruction(
PatchOpcodes::PO_ORI, RegNum::RN_T9, RegNum::RN_T9, HiTracingHookAddr);
*reinterpret_cast<uint32_t *>(Sled.Address + 32) = encodeSpecialInstruction(
PatchOpcodes::PO_DSLL, 0x0, RegNum::RN_T9, RegNum::RN_T9, 0x10);
*reinterpret_cast<uint32_t *>(Sled.Address + 36) = encodeInstruction(
PatchOpcodes::PO_ORI, RegNum::RN_T9, RegNum::RN_T9, LoTracingHookAddr);
*reinterpret_cast<uint32_t *>(Sled.Address + 40) = encodeInstruction(
PatchOpcodes::PO_LUI, 0x0, RegNum::RN_T0, HiFunctionID);
*reinterpret_cast<uint32_t *>(Sled.Address + 44) = encodeSpecialInstruction(
PatchOpcodes::PO_JALR, RegNum::RN_T9, 0x0, RegNum::RN_RA, 0X0);
*reinterpret_cast<uint32_t *>(Sled.Address + 48) = encodeInstruction(
PatchOpcodes::PO_ORI, RegNum::RN_T0, RegNum::RN_T0, LoFunctionID);
*reinterpret_cast<uint32_t *>(Sled.Address + 52) = encodeInstruction(
PatchOpcodes::PO_LD, RegNum::RN_SP, RegNum::RN_T9, 0x0);
*reinterpret_cast<uint32_t *>(Sled.Address + 56) = encodeInstruction(
PatchOpcodes::PO_LD, RegNum::RN_SP, RegNum::RN_RA, 0x8);
*reinterpret_cast<uint32_t *>(Sled.Address + 60) = encodeInstruction(
PatchOpcodes::PO_DADDIU, RegNum::RN_SP, RegNum::RN_SP, 0x10);
uint32_t CreateStackSpace = encodeInstruction(
PatchOpcodes::PO_DADDIU, RegNum::RN_SP, RegNum::RN_SP, 0xfff0);
std::atomic_store_explicit(
reinterpret_cast<std::atomic<uint32_t> *>(Sled.Address),
CreateStackSpace, std::memory_order_release);
} else {
std::atomic_store_explicit(
reinterpret_cast<std::atomic<uint32_t> *>(Sled.Address),
uint32_t(PatchOpcodes::PO_B60), std::memory_order_release);
}
return true;
}
bool patchFunctionEntry(const bool Enable, const uint32_t FuncId,
const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
return patchSled(Enable, FuncId, Sled, __xray_FunctionEntry);
}
bool patchFunctionExit(const bool Enable, const uint32_t FuncId,
const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
return patchSled(Enable, FuncId, Sled, __xray_FunctionExit);
}
bool patchFunctionTailExit(const bool Enable, const uint32_t FuncId,
const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
// FIXME: In the future we'd need to distinguish between non-tail exits and
// tail exits for better information preservation.
return patchSled(Enable, FuncId, Sled, __xray_FunctionExit);
}
} // namespace __xray

View File

@ -0,0 +1,110 @@
//===-- xray_trampoline_mips.s ----------------------------------*- ASM -*-===//
//
// 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.
//
// This implements the MIPS-specific assembler for the trampolines.
//
//===----------------------------------------------------------------------===//
.text
.file "xray_trampoline_mips.S"
.globl __xray_FunctionEntry
.p2align 2
.type __xray_FunctionEntry,@function
__xray_FunctionEntry:
.cfi_startproc
.set noreorder
.cpload $t9
.set reorder
// Save argument registers before doing any actual work
.cfi_def_cfa_offset 36
addiu $sp, $sp, -36
sw $ra, 32($sp)
.cfi_offset 31, -4
sw $a3, 28($sp)
sw $a2, 24($sp)
sw $a1, 20($sp)
sw $a0, 16($sp)
sdc1 $f14, 8($sp)
sdc1 $f12, 0($sp)
la $t9, _ZN6__xray19XRayPatchedFunctionE
lw $t9, 0($t9)
beqz $t9, FunctionEntry_restore
// a1=0 means that we are tracing an entry event
move $a1, $zero
// Function ID is in t0 (the first parameter).
move $a0, $t0
jalr $t9
FunctionEntry_restore:
// Restore argument registers
ldc1 $f12, 0($sp)
ldc1 $f14, 8($sp)
lw $a0, 16($sp)
lw $a1, 20($sp)
lw $a2, 24($sp)
lw $a3, 28($sp)
lw $ra, 32($sp)
addiu $sp, $sp, 36
jr $ra
FunctionEntry_end:
.size __xray_FunctionEntry, FunctionEntry_end-__xray_FunctionEntry
.cfi_endproc
.text
.globl __xray_FunctionExit
.p2align 2
.type __xray_FunctionExit,@function
__xray_FunctionExit:
.cfi_startproc
.set noreorder
.cpload $t9
.set reorder
// Save return registers before doing any actual work.
.cfi_def_cfa_offset 36
addiu $sp, $sp, -36
sw $ra, 32($sp)
.cfi_offset 31, -4
sw $a1, 28($sp)
sw $a0, 24($sp)
sw $v1, 20($sp)
sw $v0, 16($sp)
sdc1 $f2, 8($sp)
sdc1 $f0, 0($sp)
la $t9, _ZN6__xray19XRayPatchedFunctionE
lw $t9, 0($t9)
beqz $t9, FunctionExit_restore
// a1=1 means that we are tracing an exit event
li $a1, 1
// Function ID is in t0 (the first parameter).
move $a0, $t0
jalr $t9
FunctionExit_restore:
// Restore return registers
ldc1 $f0, 0($sp)
ldc1 $f2, 8($sp)
lw $v0, 16($sp)
lw $v1, 20($sp)
lw $a0, 24($sp)
lw $a1, 28($sp)
lw $ra, 32($sp)
addiu $sp, $sp, 36
jr $ra
FunctionExit_end:
.size __xray_FunctionExit, FunctionExit_end-__xray_FunctionExit
.cfi_endproc

View File

@ -0,0 +1,136 @@
//===-- xray_trampoline_mips64.s --------------------------------*- ASM -*-===//
//
// 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.
//
// This implements the MIPS64-specific assembler for the trampolines.
//
//===----------------------------------------------------------------------===//
.text
.file "xray_trampoline_mips64.S"
.globl __xray_FunctionEntry
.p2align 2
.type __xray_FunctionEntry,@function
__xray_FunctionEntry:
.cfi_startproc
// Save argument registers before doing any actual work.
.cfi_def_cfa_offset 144
daddiu $sp, $sp, -144
sd $ra, 136($sp)
.cfi_offset 31, -8
sd $gp, 128($sp)
sd $a7, 120($sp)
sd $a6, 112($sp)
sd $a5, 104($sp)
sd $a4, 96($sp)
sd $a3, 88($sp)
sd $a2, 80($sp)
sd $a1, 72($sp)
sd $a0, 64($sp)
sdc1 $f19, 56($sp)
sdc1 $f18, 48($sp)
sdc1 $f17, 40($sp)
sdc1 $f16, 32($sp)
sdc1 $f15, 24($sp)
sdc1 $f14, 16($sp)
sdc1 $f13, 8($sp)
sdc1 $f12, 0($sp)
lui $gp, %hi(%neg(%gp_rel(__xray_FunctionEntry)))
daddu $gp, $gp, $t9
daddiu $gp ,$gp, %lo(%neg(%gp_rel(__xray_FunctionEntry)))
dla $t9, _ZN6__xray19XRayPatchedFunctionE
ld $t9, 0($t9)
beqz $t9, FunctionEntry_restore
// a1=0 means that we are tracing an entry event
move $a1, $zero
// Function ID is in t0 (the first parameter).
move $a0, $t0
jalr $t9
FunctionEntry_restore:
// Restore argument registers
ldc1 $f12, 0($sp)
ldc1 $f13, 8($sp)
ldc1 $f14, 16($sp)
ldc1 $f15, 24($sp)
ldc1 $f16, 32($sp)
ldc1 $f17, 40($sp)
ldc1 $f18, 48($sp)
ldc1 $f19, 56($sp)
ld $a0, 64($sp)
ld $a1, 72($sp)
ld $a2, 80($sp)
ld $a3, 88($sp)
ld $a4, 96($sp)
ld $a5, 104($sp)
ld $a6, 112($sp)
ld $a7, 120($sp)
ld $gp, 128($sp)
ld $ra, 136($sp)
daddiu $sp, $sp, 144
jr $ra
FunctionEntry_end:
.size __xray_FunctionEntry, FunctionEntry_end-__xray_FunctionEntry
.cfi_endproc
.text
.globl __xray_FunctionExit
.p2align 2
.type __xray_FunctionExit,@function
__xray_FunctionExit:
.cfi_startproc
// Save return registers before doing any actual work.
.cfi_def_cfa_offset 64
daddiu $sp, $sp, -64
sd $ra, 56($sp)
.cfi_offset 31, -8
sd $gp, 48($sp)
sd $a0, 40($sp)
sd $v1, 32($sp)
sd $v0, 24($sp)
sdc1 $f2, 16($sp)
sdc1 $f1, 8($sp)
sdc1 $f0, 0($sp)
lui $gp, %hi(%neg(%gp_rel(__xray_FunctionExit)))
daddu $gp, $gp, $t9
daddiu $gp ,$gp, %lo(%neg(%gp_rel(__xray_FunctionExit)))
dla $t9, _ZN6__xray19XRayPatchedFunctionE
ld $t9, 0($t9)
beqz $t9, FunctionExit_restore
// a1=1 means that we are tracing an exit event
li $a1, 1
// Function ID is in t0 (the first parameter).
move $a0, $t0
jalr $t9
FunctionExit_restore:
// Restore return registers
ldc1 $f0, 0($sp)
ldc1 $f1, 8($sp)
ldc1 $f2, 16($sp)
ld $v0, 24($sp)
ld $v1, 32($sp)
ld $a0, 40($sp)
ld $gp, 48($sp)
ld $ra, 56($sp)
daddiu $sp, $sp, 64
jr $ra
FunctionExit_end:
.size __xray_FunctionExit, FunctionExit_end-__xray_FunctionExit
.cfi_endproc

View File

@ -15,7 +15,7 @@
#if defined(__x86_64__)
#include "xray_x86_64.inc"
#elif defined(__arm__) || defined(__aarch64__)
#elif defined(__arm__) || defined(__aarch64__) || defined(__mips__)
// Emulated TSC.
// There is no instruction like RDTSCP in user mode on ARM. ARM's CP15 does
// not have a constant frequency like TSC on x86(_64), it may go faster

View File

@ -0,0 +1,33 @@
// Test to check if we handle pic code properly.
// RUN: %clangxx_xray -fxray-instrument -std=c++11 -fpic %s -o %t
// RUN: XRAY_OPTIONS="verbosity=1 xray_logfile_base=pic-test-logging-" %run %t 2>&1 | FileCheck %s
// After all that, clean up the output xray log.
//
// RUN: rm pic-test-logging-*
#include <cstdio>
[[clang::xray_always_instrument]]
unsigned short foo (unsigned b);
[[clang::xray_always_instrument]]
unsigned short bar (unsigned short a)
{
printf("bar() is always instrumented!\n");
return foo(a);
}
unsigned short foo (unsigned b)
{
printf("foo() is always instrumented!\n");
return b + b + 5;
}
int main ()
{
// CHECK: XRay: Log file in 'pic-test-logging-{{.*}}'
bar(10);
// CHECK: bar() is always instrumented!
// CHECK-NEXT: foo() is always instrumented!
}