brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.4 KiB · e3a7cdb Raw
267 lines · cpp
1//===-- xray_riscv.cpp ----------------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file is a part of XRay, a dynamic runtime instrumentation system.10//11// Implementation of RISC-V specific routines (32- and 64-bit).12//13//===----------------------------------------------------------------------===//14#include "sanitizer_common/sanitizer_common.h"15#include "xray_defs.h"16#include "xray_interface_internal.h"17#include <atomic>18 19namespace __xray {20 21// The machine codes for some instructions used in runtime patching.22enum PatchOpcodes : uint32_t {23  PO_ADDI = 0x00000013, // addi rd, rs1, imm24  PO_ADD = 0x00000033,  // add rd, rs1, rs225  PO_SW = 0x00002023,   // sw rs2, imm(rs1)26  PO_SD = 0x00003023,   // sd rs2, imm(rs1)27  PO_LUI = 0x00000037,  // lui rd, imm28  PO_OR = 0x00006033,   // or rd, rs1, rs229  PO_SLLI = 0x00001013, // slli rd, rs1, shamt30  PO_JALR = 0x00000067, // jalr rd, rs131  PO_LW = 0x00002003,   // lw rd, imm(rs1)32  PO_LD = 0x00003003,   // ld rd, imm(rs1)33  PO_J = 0x0000006f,    // jal imm34  PO_NOP = PO_ADDI,     // addi x0, x0, 035};36 37enum RegNum : uint32_t {38  RN_X0 = 0,39  RN_RA = 1,40  RN_SP = 2,41  RN_T1 = 6,42  RN_A0 = 10,43};44 45static inline uint32_t encodeRTypeInstruction(uint32_t Opcode, uint32_t Rs1,46                                              uint32_t Rs2, uint32_t Rd) {47  return Rs2 << 20 | Rs1 << 15 | Rd << 7 | Opcode;48}49 50static inline uint32_t encodeITypeInstruction(uint32_t Opcode, uint32_t Rs1,51                                              uint32_t Rd, uint32_t Imm) {52  return Imm << 20 | Rs1 << 15 | Rd << 7 | Opcode;53}54 55static inline uint32_t encodeSTypeInstruction(uint32_t Opcode, uint32_t Rs1,56                                              uint32_t Rs2, uint32_t Imm) {57  uint32_t ImmMSB = (Imm & 0xfe0) << 20;58  uint32_t ImmLSB = (Imm & 0x01f) << 7;59  return ImmMSB | Rs2 << 20 | Rs1 << 15 | ImmLSB | Opcode;60}61 62static inline uint32_t encodeUTypeInstruction(uint32_t Opcode, uint32_t Rd,63                                              uint32_t Imm) {64  return Imm << 12 | Rd << 7 | Opcode;65}66 67static inline uint32_t encodeJTypeInstruction(uint32_t Opcode, uint32_t Rd,68                                              uint32_t Imm) {69  uint32_t ImmMSB = (Imm & 0x100000) << 11;70  uint32_t ImmLSB = (Imm & 0x7fe) << 20;71  uint32_t Imm11 = (Imm & 0x800) << 9;72  uint32_t Imm1912 = (Imm & 0xff000);73  return ImmMSB | ImmLSB | Imm11 | Imm1912 | Rd << 7 | Opcode;74}75 76static uint32_t hi20(uint32_t val) { return (val + 0x800) >> 12; }77static uint32_t lo12(uint32_t val) { return val & 0xfff; }78 79static inline bool patchSled(const bool Enable, const uint32_t FuncId,80                             const XRaySledEntry &Sled,81                             void (*TracingHook)()) XRAY_NEVER_INSTRUMENT {82  // When |Enable| == true,83  // We replace the following compile-time stub (sled):84  //85  // xray_sled_n:86  //	J .tmpN87  //	21 or 33 C.NOPs (42 or 66 bytes)88  //	.tmpN89  //90  // With one of the following runtime patches:91  //92  // xray_sled_n (32-bit):93  //    addi sp, sp, -16                                ;create stack frame94  //    sw ra, 12(sp)                                   ;save return address95  //    sw a0, 8(sp)                                    ;save register a096  //    lui ra, %hi(__xray_FunctionEntry/Exit)97  //    addi ra, ra, %lo(__xray_FunctionEntry/Exit)98  //    lui a0, %hi(function_id)99  //    addi a0, a0, %lo(function_id)                   ;pass function id100  //    jalr ra                                         ;call Tracing hook101  //    lw a0, 8(sp)                                    ;restore register a0102  //    lw ra, 12(sp)                                   ;restore return address103  //    addi sp, sp, 16                                 ;delete stack frame104  //105  // xray_sled_n (64-bit):106  //    addi sp, sp, -32                                ;create stack frame107  //    sd ra, 24(sp)                                   ;save return address108  //    sd a0, 16(sp)                                   ;save register a0109  //    sd t1, 8(sp)                                    ;save register t1110  //    lui t1, %highest(__xray_FunctionEntry/Exit)111  //    addi t1, t1, %higher(__xray_FunctionEntry/Exit)112  //    slli t1, t1, 32113  //    lui ra, ra, %hi(__xray_FunctionEntry/Exit)114  //    addi ra, ra, %lo(__xray_FunctionEntry/Exit)115  //    add ra, t1, ra116  //    lui a0, %hi(function_id)117  //    addi a0, a0, %lo(function_id)                   ;pass function id118  //    jalr ra                                         ;call Tracing hook119  //    ld t1, 8(sp)                                    ;restore register t1120  //    ld a0, 16(sp)                                   ;restore register a0121  //    ld ra, 24(sp)                                   ;restore return address122  //    addi sp, sp, 32                                 ;delete stack frame123  //124  // Replacement of the first 4-byte instruction should be the last and atomic125  // operation, so that the user code which reaches the sled concurrently126  // either jumps over the whole sled, or executes the whole sled when the127  // latter is ready.128  //129  // When |Enable|==false, we set back the first instruction in the sled to be130  //   J 44 bytes (rv32)131  //   J 68 bytes (rv64)132 133  uint32_t *Address = reinterpret_cast<uint32_t *>(Sled.address());134  if (Enable) {135#if __riscv_xlen == 64136    // If the ISA is RV64, the Tracing Hook needs to be typecast to a 64 bit137    // value.138    uint32_t LoTracingHookAddr = lo12(reinterpret_cast<uint64_t>(TracingHook));139    uint32_t HiTracingHookAddr = hi20(reinterpret_cast<uint64_t>(TracingHook));140    uint32_t HigherTracingHookAddr =141        lo12((reinterpret_cast<uint64_t>(TracingHook) + 0x80000000) >> 32);142    uint32_t HighestTracingHookAddr =143        hi20((reinterpret_cast<uint64_t>(TracingHook) + 0x80000000) >> 32);144#elif __riscv_xlen == 32145    // We typecast the Tracing Hook to a 32 bit value for RV32146    uint32_t LoTracingHookAddr = lo12(reinterpret_cast<uint32_t>(TracingHook));147    uint32_t HiTracingHookAddr = hi20((reinterpret_cast<uint32_t>(TracingHook));148#endif149    uint32_t LoFunctionID = lo12(FuncId);150    uint32_t HiFunctionID = hi20(FuncId);151 152    // The sled that is patched in for RISCV64 defined below. We need the entire153    // sleds corresponding to both ISAs to be protected by defines because the154    // first few instructions are all different, because we store doubles in155    // case of RV64 and store words for RV32. Subsequently, we have LUI - and in156    // case of RV64, we need extra instructions from this point on, so we see157    // differences in addresses to which instructions are stored.158    size_t Idx = 1U;159    const uint32_t XLenBytes = __riscv_xlen / 8;160#if __riscv_xlen == 64161    const uint32_t LoadOp = PatchOpcodes::PO_LD;162    const uint32_t StoreOp = PatchOpcodes::PO_SD;163#elif __riscv_xlen == 32164    const uint32_t LoadOp = PatchOpcodes::PO_LW;165    const uint32_t StoreOp = PatchOpcodes::PO_SW;166#endif167 168    Address[Idx++] = encodeSTypeInstruction(StoreOp, RegNum::RN_SP,169                                            RegNum::RN_RA, 3 * XLenBytes);170    Address[Idx++] = encodeSTypeInstruction(StoreOp, RegNum::RN_SP,171                                            RegNum::RN_A0, 2 * XLenBytes);172 173#if __riscv_xlen == 64174    Address[Idx++] = encodeSTypeInstruction(StoreOp, RegNum::RN_SP,175                                            RegNum::RN_T1, XLenBytes);176    Address[Idx++] = encodeUTypeInstruction(PatchOpcodes::PO_LUI, RegNum::RN_T1,177                                            HighestTracingHookAddr);178    Address[Idx++] =179        encodeITypeInstruction(PatchOpcodes::PO_ADDI, RegNum::RN_T1,180                               RegNum::RN_T1, HigherTracingHookAddr);181    Address[Idx++] = encodeITypeInstruction(PatchOpcodes::PO_SLLI,182                                            RegNum::RN_T1, RegNum::RN_T1, 32);183#endif184    Address[Idx++] = encodeUTypeInstruction(PatchOpcodes::PO_LUI, RegNum::RN_RA,185                                            HiTracingHookAddr);186    Address[Idx++] = encodeITypeInstruction(187        PatchOpcodes::PO_ADDI, RegNum::RN_RA, RegNum::RN_RA, LoTracingHookAddr);188#if __riscv_xlen == 64189    Address[Idx++] = encodeRTypeInstruction(PatchOpcodes::PO_ADD, RegNum::RN_RA,190                                            RegNum::RN_T1, RegNum::RN_RA);191#endif192    Address[Idx++] = encodeUTypeInstruction(PatchOpcodes::PO_LUI, RegNum::RN_A0,193                                            HiFunctionID);194    Address[Idx++] = encodeITypeInstruction(195        PatchOpcodes::PO_ADDI, RegNum::RN_A0, RegNum::RN_A0, LoFunctionID);196    Address[Idx++] = encodeITypeInstruction(PatchOpcodes::PO_JALR,197                                            RegNum::RN_RA, RegNum::RN_RA, 0);198 199#if __riscv_xlen == 64200    Address[Idx++] =201        encodeITypeInstruction(LoadOp, RegNum::RN_SP, RegNum::RN_T1, XLenBytes);202#endif203    Address[Idx++] = encodeITypeInstruction(LoadOp, RegNum::RN_SP,204                                            RegNum::RN_A0, 2 * XLenBytes);205    Address[Idx++] = encodeITypeInstruction(LoadOp, RegNum::RN_SP,206                                            RegNum::RN_RA, 3 * XLenBytes);207    Address[Idx++] = encodeITypeInstruction(208        PatchOpcodes::PO_ADDI, RegNum::RN_SP, RegNum::RN_SP, 4 * XLenBytes);209 210    uint32_t CreateStackSpace = encodeITypeInstruction(211        PatchOpcodes::PO_ADDI, RegNum::RN_SP, RegNum::RN_SP, -4 * XLenBytes);212 213    std::atomic_store_explicit(214        reinterpret_cast<std::atomic<uint32_t> *>(Address), CreateStackSpace,215        std::memory_order_release);216  } else {217    uint32_t CreateBranch = encodeJTypeInstruction(218    // Jump distance is different in both ISAs due to difference in size of219    // sleds220#if __riscv_xlen == 64221        PatchOpcodes::PO_J, RegNum::RN_X0,222        68); // jump encodes an offset of 68223#elif __riscv_xlen == 32224        PatchOpcodes::PO_J, RegNum::RN_X0,225        44); // jump encodes an offset of 44226#endif227    std::atomic_store_explicit(228        reinterpret_cast<std::atomic<uint32_t> *>(Address), CreateBranch,229        std::memory_order_release);230  }231  return true;232}233 234bool patchFunctionEntry(const bool Enable, const uint32_t FuncId,235                        const XRaySledEntry &Sled,236                        const XRayTrampolines &Trampolines,237                        bool LogArgs) XRAY_NEVER_INSTRUMENT {238  // We don't support logging argument at this moment, so we always239  // use EntryTrampoline.240  return patchSled(Enable, FuncId, Sled, Trampolines.EntryTrampoline);241}242 243bool patchFunctionExit(244    const bool Enable, const uint32_t FuncId, const XRaySledEntry &Sled,245    const XRayTrampolines &Trampolines) XRAY_NEVER_INSTRUMENT {246  return patchSled(Enable, FuncId, Sled, Trampolines.ExitTrampoline);247}248 249bool patchFunctionTailExit(250    const bool Enable, const uint32_t FuncId, const XRaySledEntry &Sled,251    const XRayTrampolines &Trampolines) XRAY_NEVER_INSTRUMENT {252  return patchSled(Enable, FuncId, Sled, Trampolines.TailExitTrampoline);253}254 255bool patchCustomEvent(const bool Enable, const uint32_t FuncId,256                      const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {257  return false;258}259 260bool patchTypedEvent(const bool Enable, const uint32_t FuncId,261                     const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {262  return false;263}264} // namespace __xray265 266extern "C" void __xray_ArgLoggerEntry() XRAY_NEVER_INSTRUMENT {}267