1 //===-------- xray_loongarch64.cpp ------------------------------*- C++ -*-===//
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-exception
7 //===----------------------------------------------------------------------===//
9 // This file is a part of XRay, a dynamic runtime instrumentation system.
11 // Implementation of loongarch-specific routines.
13 //===----------------------------------------------------------------------===//
14 #include "sanitizer_common/sanitizer_common.h"
15 #include "xray_defs.h"
16 #include "xray_interface_internal.h"
21 enum RegNum
: uint32_t {
28 // Encode instructions in the 2RIx format, where the primary formats here
29 // are 2RI12-type and 2RI16-type.
30 static inline uint32_t
31 encodeInstruction2RIx(uint32_t Opcode
, uint32_t Rd
, uint32_t Rj
,
32 uint32_t Imm
) XRAY_NEVER_INSTRUMENT
{
33 return Opcode
| (Imm
<< 10) | (Rj
<< 5) | Rd
;
36 // Encode instructions in 1RI20 format, e.g. lu12i.w/lu32i.d.
37 static inline uint32_t
38 encodeInstruction1RI20(uint32_t Opcode
, uint32_t Rd
,
39 uint32_t Imm
) XRAY_NEVER_INSTRUMENT
{
40 return Opcode
| (Imm
<< 5) | Rd
;
43 static inline bool patchSled(const bool Enable
, const uint32_t FuncId
,
44 const XRaySledEntry
&Sled
,
45 void (*TracingHook
)()) XRAY_NEVER_INSTRUMENT
{
46 // When |Enable| == true,
47 // We replace the following compile-time stub (sled):
49 // .Lxray_sled_beginN:
54 // With the following runtime patch:
57 // addi.d sp, sp, -16 ; create the stack frame
58 // st.d ra, sp, 8 ; save the return address
59 // lu12i.w t0, %abs_hi20(__xray_FunctionEntry/Exit)
60 // ori t0, t0, %abs_lo12(__xray_FunctionEntry/Exit)
61 // lu32i.d t0, %abs64_lo20(__xray_FunctionEntry/Exit)
62 // lu52i.d t0, t0, %abs64_hi12(__xray_FunctionEntry/Exit)
63 // lu12i.w t1, %abs_hi20(function_id)
64 // ori t1, t1, %abs_lo12(function_id) ; pass the function id
65 // jirl ra, t0, 0 ; call the tracing hook
66 // ld.d ra, sp, 8 ; restore the return address
67 // addi.d sp, sp, 16 ; de-allocate the stack frame
69 // Replacement of the first 4-byte instruction should be the last and atomic
70 // operation, so that the user code which reaches the sled concurrently
71 // either jumps over the whole sled, or executes the whole sled when the
74 // When |Enable|==false, we set the first instruction in the sled back to
77 uint32_t *Address
= reinterpret_cast<uint32_t *>(Sled
.address());
79 uint32_t LoTracingHookAddr
= reinterpret_cast<int64_t>(TracingHook
) & 0xfff;
80 uint32_t HiTracingHookAddr
=
81 (reinterpret_cast<int64_t>(TracingHook
) >> 12) & 0xfffff;
82 uint32_t HigherTracingHookAddr
=
83 (reinterpret_cast<int64_t>(TracingHook
) >> 32) & 0xfffff;
84 uint32_t HighestTracingHookAddr
=
85 (reinterpret_cast<int64_t>(TracingHook
) >> 52) & 0xfff;
86 uint32_t LoFunctionID
= FuncId
& 0xfff;
87 uint32_t HiFunctionID
= (FuncId
>> 12) & 0xfffff;
88 Address
[1] = encodeInstruction2RIx(0x29c00000, RegNum::RN_RA
, RegNum::RN_SP
,
89 0x8); // st.d ra, sp, 8
90 Address
[2] = encodeInstruction1RI20(
91 0x14000000, RegNum::RN_T0
,
92 HiTracingHookAddr
); // lu12i.w t0, HiTracingHookAddr
93 Address
[3] = encodeInstruction2RIx(
94 0x03800000, RegNum::RN_T0
, RegNum::RN_T0
,
95 LoTracingHookAddr
); // ori t0, t0, LoTracingHookAddr
96 Address
[4] = encodeInstruction1RI20(
97 0x16000000, RegNum::RN_T0
,
98 HigherTracingHookAddr
); // lu32i.d t0, HigherTracingHookAddr
99 Address
[5] = encodeInstruction2RIx(
100 0x03000000, RegNum::RN_T0
, RegNum::RN_T0
,
101 HighestTracingHookAddr
); // lu52i.d t0, t0, HighestTracingHookAddr
103 encodeInstruction1RI20(0x14000000, RegNum::RN_T1
,
104 HiFunctionID
); // lu12i.w t1, HiFunctionID
106 encodeInstruction2RIx(0x03800000, RegNum::RN_T1
, RegNum::RN_T1
,
107 LoFunctionID
); // ori t1, t1, LoFunctionID
108 Address
[8] = encodeInstruction2RIx(0x4c000000, RegNum::RN_RA
, RegNum::RN_T0
,
109 0); // jirl ra, t0, 0
110 Address
[9] = encodeInstruction2RIx(0x28c00000, RegNum::RN_RA
, RegNum::RN_SP
,
111 0x8); // ld.d ra, sp, 8
112 Address
[10] = encodeInstruction2RIx(
113 0x02c00000, RegNum::RN_SP
, RegNum::RN_SP
, 0x10); // addi.d sp, sp, 16
114 uint32_t CreateStackSpace
= encodeInstruction2RIx(
115 0x02c00000, RegNum::RN_SP
, RegNum::RN_SP
, 0xff0); // addi.d sp, sp, -16
116 std::atomic_store_explicit(
117 reinterpret_cast<std::atomic
<uint32_t> *>(Address
), CreateStackSpace
,
118 std::memory_order_release
);
120 std::atomic_store_explicit(
121 reinterpret_cast<std::atomic
<uint32_t> *>(Address
),
122 uint32_t(0x50003000), std::memory_order_release
); // b #48
127 bool patchFunctionEntry(const bool Enable
, const uint32_t FuncId
,
128 const XRaySledEntry
&Sled
,
129 void (*Trampoline
)()) XRAY_NEVER_INSTRUMENT
{
130 return patchSled(Enable
, FuncId
, Sled
, Trampoline
);
133 bool patchFunctionExit(const bool Enable
, const uint32_t FuncId
,
134 const XRaySledEntry
&Sled
) XRAY_NEVER_INSTRUMENT
{
135 return patchSled(Enable
, FuncId
, Sled
, __xray_FunctionExit
);
138 bool patchFunctionTailExit(const bool Enable
, const uint32_t FuncId
,
139 const XRaySledEntry
&Sled
) XRAY_NEVER_INSTRUMENT
{
140 // TODO: In the future we'd need to distinguish between non-tail exits and
141 // tail exits for better information preservation.
142 return patchSled(Enable
, FuncId
, Sled
, __xray_FunctionExit
);
145 bool patchCustomEvent(const bool Enable
, const uint32_t FuncId
,
146 const XRaySledEntry
&Sled
) XRAY_NEVER_INSTRUMENT
{
147 // FIXME: Implement in loongarch?
151 bool patchTypedEvent(const bool Enable
, const uint32_t FuncId
,
152 const XRaySledEntry
&Sled
) XRAY_NEVER_INSTRUMENT
{
153 // FIXME: Implement in loongarch?
156 } // namespace __xray
158 extern "C" void __xray_ArgLoggerEntry() XRAY_NEVER_INSTRUMENT
{
159 // TODO: This will have to be implemented in the trampoline assembly file.