#include "sanitizer_common/sanitizer_common.h"
#include "xray_defs.h"
#include "xray_interface_internal.h"
#include <assert.h>
#include <atomic>
namespace __xray {
enum PatchOpcodes : uint32_t {
PO_JUMPI_14 = 0x5800c00a,
PO_CALLR_R6 = 0x50a6c000,
PO_TFR_IMM = 0x78000000,
PO_IMMEXT = 0x00000000,
};
enum PacketWordParseBits : uint32_t {
PP_DUPLEX = 0x00 << 14,
PP_NOT_END = 0x01 << 14,
PP_PACKET_END = 0x03 << 14,
};
enum RegNum : uint32_t {
RN_R6 = 0x6,
RN_R7 = 0x7,
};
inline static uint32_t
encodeExtendedTransferImmediate(uint32_t Imm, RegNum DestReg,
bool PacketEnd = false) XRAY_NEVER_INSTRUMENT {
static const uint32_t REG_MASK = 0x1f;
assert((DestReg & (~REG_MASK)) == 0);
Imm = Imm & 0x03f;
const PacketWordParseBits ParseBits = PacketEnd ? PP_PACKET_END : PP_NOT_END;
return PO_TFR_IMM | ParseBits | (Imm << 5) | (DestReg & REG_MASK);
}
inline static uint32_t
encodeConstantExtender(uint32_t Imm) XRAY_NEVER_INSTRUMENT {
static const uint32_t IMM_MASK_LOW = 0x03fff;
static const uint32_t IMM_MASK_HIGH = 0x00fff << 14;
Imm = Imm >> 6;
const uint32_t high = (Imm & IMM_MASK_HIGH) << 16;
const uint32_t low = Imm & IMM_MASK_LOW;
return PO_IMMEXT | high | PP_NOT_END | low;
}
static void WriteInstFlushCache(void *Addr, uint32_t NewInstruction) {
asm volatile("icinva(%[inst_addr])\n\t"
"isync\n\t"
"memw(%[inst_addr]) = %[new_inst]\n\t"
"dccleaninva(%[inst_addr])\n\t"
"syncht\n\t"
:
: [ inst_addr ] "r"(Addr), [ new_inst ] "r"(NewInstruction)
: "memory");
}
inline static bool patchSled(const bool Enable, const uint32_t FuncId,
const XRaySledEntry &Sled,
void (*TracingHook)()) XRAY_NEVER_INSTRUMENT {
uint32_t *FirstAddress = reinterpret_cast<uint32_t *>(Sled.address());
if (Enable) {
uint32_t *CurAddress = FirstAddress + 1;
*CurAddress = encodeExtendedTransferImmediate(FuncId, RN_R7);
CurAddress++;
*CurAddress = encodeConstantExtender(reinterpret_cast<uint32_t>(TracingHook));
CurAddress++;
*CurAddress =
encodeExtendedTransferImmediate(reinterpret_cast<uint32_t>(TracingHook), RN_R6, true);
CurAddress++;
*CurAddress = uint32_t(PO_CALLR_R6);
WriteInstFlushCache(FirstAddress, uint32_t(encodeConstantExtender(FuncId)));
} else {
WriteInstFlushCache(FirstAddress, uint32_t(PatchOpcodes::PO_JUMPI_14));
}
return true;
}
bool patchFunctionEntry(const bool Enable, const uint32_t FuncId,
const XRaySledEntry &Sled,
void (*Trampoline)()) XRAY_NEVER_INSTRUMENT {
return patchSled(Enable, FuncId, Sled, Trampoline);
}
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 {
return patchSled(Enable, FuncId, Sled, __xray_FunctionExit);
}
bool patchCustomEvent(const bool Enable, const uint32_t FuncId,
const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
return false;
}
bool patchTypedEvent(const bool Enable, const uint32_t FuncId,
const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
return false;
}
}
extern "C" void __xray_ArgLoggerEntry() XRAY_NEVER_INSTRUMENT {
}