1 /*
2 * Copyright 2024 Institute of Software, Chinese Academy of Sciences.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #if defined(__loongarch_lp64)
17 #include "dfx_regs.h"
18
19 #include <elf.h>
20 #include <securec.h>
21 #include <stdint.h>
22 #include <sys/ptrace.h>
23 #include <sys/uio.h>
24 #include "dfx_define.h"
25 #include "dfx_log.h"
26 #include "dfx_elf.h"
27 #include "string_printf.h"
28
29 namespace OHOS {
30 namespace HiviewDFX {
SetFromUcontext(const ucontext_t & context)31 void DfxRegsLoongArch64::SetFromUcontext(const ucontext_t &context)
32 {
33 std::vector<uintptr_t> regs;
34 regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R0])); // 0:r0
35 regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R1])); // 1:r1
36 regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R2])); // 2:r2
37 regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R3])); // 3:r3
38 regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R4])); // 4:r4
39 regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R5])); // 5:r5
40 regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R6])); // 6:r6
41 regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R7])); // 7:r7
42 regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R8])); // 8:r8
43 regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R9])); // 9:r9
44 regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R10])); // 10:r10
45 regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R11])); // 11:r11
46 regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R12])); // 12:r12
47 regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R13])); // 13:r13
48 regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R14])); // 14:r14
49 regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R15])); // 15:r15
50 regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R16])); // 16:r16
51 regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R17])); // 17:r17
52 regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R18])); // 18:r18
53 regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R19])); // 19:r19
54 regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R20])); // 20:r20
55 regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R21])); // 21:r21
56 regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R22])); // 22:r22
57 regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R23])); // 23:r23
58 regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R24])); // 24:r24
59 regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R25])); // 25:r25
60 regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R26])); // 26:r26
61 regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R27])); // 27:r27
62 regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R28])); // 28:r28
63 regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R29])); // 29:r29
64 regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R30])); // 30:r30
65 regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R31])); // 31:r31
66 regs.emplace_back(uintptr_t(context.uc_mcontext.__pc)); // 32:pc
67
68 SetRegsData(regs);
69 }
70
SetFromFpMiniRegs(const uintptr_t * regs,const size_t size)71 void DfxRegsLoongArch64::SetFromFpMiniRegs(const uintptr_t* regs, const size_t size)
72 {
73 if (size < FP_MINI_REGS_SIZE) {
74 return;
75 }
76 regsData_[REG_FP] = regs[0]; // 0 : fp offset
77 regsData_[REG_LR] = regs[1]; // 1 : lr offset
78 regsData_[REG_SP] = regs[2]; // 2 : sp offset
79 regsData_[REG_PC] = regs[3]; // 3 : pc offset
80 }
81
SetFromQutMiniRegs(const uintptr_t * regs,const size_t size)82 void DfxRegsLoongArch64::SetFromQutMiniRegs(const uintptr_t* regs, const size_t size)
83 {
84 if (size < QUT_MINI_REGS_SIZE) {
85 return;
86 }
87
88 regsData_[REG_FP] = regs[3]; // 3 : fp offset
89 regsData_[REG_SP] = regs[4]; // 4 : sp offset
90 regsData_[REG_PC] = regs[5]; // 5 : pc offset
91 regsData_[REG_LR] = regs[6]; // 6 : lr offset
92 }
93
SetPcFromReturnAddress(MAYBE_UNUSED std::shared_ptr<DfxMemory> memory)94 bool DfxRegsLoongArch64::SetPcFromReturnAddress(MAYBE_UNUSED std::shared_ptr<DfxMemory> memory)
95 {
96 uintptr_t lr = regsData_[REG_LR];
97 if (regsData_[REG_PC] == lr) {
98 return false;
99 }
100 regsData_[REG_PC] = lr;
101 return true;
102 }
103
PrintRegs() const104 std::string DfxRegsLoongArch64::PrintRegs() const
105 {
106 char buf[REGS_PRINT_LEN] = {0};
107 std::vector<uintptr_t> regs = GetRegsData();
108
109 BufferPrintf(buf, sizeof(buf), "r0:%016lx r1:%016lx r2:%016lx r3:%016lx\n", \
110 regs[REG_LOONGARCH64_R0], regs[REG_LOONGARCH64_R1], regs[REG_LOONGARCH64_R2], regs[REG_LOONGARCH64_R3]);
111
112 BufferPrintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "r4:%016lx r5:%016lx r6:%016lx r7:%016lx\n", \
113 regs[REG_LOONGARCH64_R4], regs[REG_LOONGARCH64_R5], regs[REG_LOONGARCH64_R6], regs[REG_LOONGARCH64_R7]);
114
115 BufferPrintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "r8:%016lx r9:%016lx r10:%016lx r11:%016lx\n", \
116 regs[REG_LOONGARCH64_R8], regs[REG_LOONGARCH64_R9], regs[REG_LOONGARCH64_R10], regs[REG_LOONGARCH64_R11]);
117
118 BufferPrintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "r12:%016lx r13:%016lx r14:%016lx r15:%016lx\n", \
119 regs[REG_LOONGARCH64_R12], regs[REG_LOONGARCH64_R13], regs[REG_LOONGARCH64_R14], regs[REG_LOONGARCH64_R15]);
120
121 BufferPrintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "r16:%016lx r17:%016lx r18:%016lx r19:%016lx\n", \
122 regs[REG_LOONGARCH64_R16], regs[REG_LOONGARCH64_R17], regs[REG_LOONGARCH64_R18], regs[REG_LOONGARCH64_R19]);
123
124 BufferPrintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "r20:%016lx r21:%016lx x22:%016lx r23:%016lx\n", \
125 regs[REG_LOONGARCH64_R20], regs[REG_LOONGARCH64_R21], regs[REG_LOONGARCH64_R22], regs[REG_LOONGARCH64_R23]);
126
127 BufferPrintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "r24:%016lx r25:%016lx r26:%016lx r27:%016lx\n", \
128 regs[REG_LOONGARCH64_R24], regs[REG_LOONGARCH64_R25], regs[REG_LOONGARCH64_R26], regs[REG_LOONGARCH64_R27]);
129
130 BufferPrintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "r28:%016lx r29:%016lx r30:%016lx r31:%016lx\n", \
131 regs[REG_LOONGARCH64_R28], regs[REG_LOONGARCH64_R29], regs[REG_LOONGARCH64_R30], regs[REG_LOONGARCH64_R31]);
132
133 BufferPrintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "lr:%016lx sp:%016lx pc:%016lx\n", \
134 regs[REG_LR], regs[REG_SP], regs[REG_PC]);
135
136 std::string regString = StringPrintf("Registers:\n%s", buf);
137 return regString;
138 }
139
StepIfSignalFrame(uintptr_t pc,std::shared_ptr<DfxMemory> memory)140 bool DfxRegsLoongArch64::StepIfSignalFrame(uintptr_t pc, std::shared_ptr<DfxMemory> memory)
141 {
142 uint64_t data;
143 if (!memory->Read<uint64_t>(pc, &data, false)) {
144 return false;
145 }
146 DFXLOGU("data: %llx", data);
147
148 // Look for the kernel sigreturn function.
149 // arch/loongarch/vdso/sigreturn.S:
150 // 0000000000000000 <__vdso_rt_sigreturn>:
151 // 0: 03822c0b ori $r11,$r0,0x8b
152 // 4: 002b0000 syscall 0x0
153
154 if (data != 0x002b000003822c0bULL) {
155 return false;
156 }
157
158 // SP + sizeof(siginfo_t) + mcontext_gregs offset.
159 uintptr_t scAddr = regsData_[REG_SP] + sizeof(siginfo_t) + 0xb8;
160 DFXLOGU("scAddr: %llx", scAddr);
161 memory->Read(scAddr, regsData_.data(), sizeof(uint64_t) * REG_LAST, false);
162 return true;
163 }
164 } // namespace HiviewDFX
165 } // namespace OHOS
166 #endif
167