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 <securec.h>
20 #include <stdint.h>
21 #include <sys/ptrace.h>
22 #include <sys/uio.h>
23 #include "dfx_define.h"
24 #include "dfx_log.h"
25 #include "string_printf.h"
26
27 namespace OHOS {
28 namespace HiviewDFX {
SetFromUcontext(const ucontext_t & context)29 void DfxRegsLoongArch64::SetFromUcontext(const ucontext_t &context)
30 {
31 if (regsData_.size() < REG_LAST) {
32 return;
33 }
34 for (uint16_t index = REG_LOONGARCH64_R0; index <= REG_LOONGARCH64_R31; index++) {
35 regsData_[index] = static_cast<uintptr_t>(context.uc_mcontext.__gregs[index]);
36 }
37 regsData_[REG_LOONGARCH64_PC] = (static_cast<uintptr_t>(context.uc_mcontext.__pc)); // 32:pc
38 }
39
SetFromFpMiniRegs(const uintptr_t * regs,const size_t size)40 void DfxRegsLoongArch64::SetFromFpMiniRegs(const uintptr_t* regs, const size_t size)
41 {
42 if (size < FP_MINI_REGS_SIZE) {
43 return;
44 }
45 regsData_[REG_FP] = regs[0]; // 0 : fp offset
46 regsData_[REG_LR] = regs[1]; // 1 : lr offset
47 regsData_[REG_SP] = regs[2]; // 2 : sp offset
48 regsData_[REG_PC] = regs[3]; // 3 : pc offset
49 }
50
SetFromQutMiniRegs(const uintptr_t * regs,const size_t size)51 void DfxRegsLoongArch64::SetFromQutMiniRegs(const uintptr_t* regs, const size_t size)
52 {
53 if (size < QUT_MINI_REGS_SIZE) {
54 return;
55 }
56
57 regsData_[REG_FP] = regs[3]; // 3 : fp offset
58 regsData_[REG_SP] = regs[4]; // 4 : sp offset
59 regsData_[REG_PC] = regs[5]; // 5 : pc offset
60 regsData_[REG_LR] = regs[6]; // 6 : lr offset
61 }
62
SetPcFromReturnAddress(MAYBE_UNUSED std::shared_ptr<DfxMemory> memory)63 bool DfxRegsLoongArch64::SetPcFromReturnAddress(MAYBE_UNUSED std::shared_ptr<DfxMemory> memory)
64 {
65 uintptr_t lr = regsData_[REG_LR];
66 if (regsData_[REG_PC] == lr) {
67 return false;
68 }
69 regsData_[REG_PC] = lr;
70 return true;
71 }
72
PrintRegs() const73 std::string DfxRegsLoongArch64::PrintRegs() const
74 {
75 char buf[REGS_PRINT_LEN] = {0};
76 std::vector<uintptr_t> regs = GetRegsData();
77
78 BufferPrintf(buf, sizeof(buf), "r0:%016lx r1:%016lx r2:%016lx r3:%016lx\n", \
79 regs[REG_LOONGARCH64_R0], regs[REG_LOONGARCH64_R1], regs[REG_LOONGARCH64_R2], regs[REG_LOONGARCH64_R3]);
80
81 BufferPrintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "r4:%016lx r5:%016lx r6:%016lx r7:%016lx\n", \
82 regs[REG_LOONGARCH64_R4], regs[REG_LOONGARCH64_R5], regs[REG_LOONGARCH64_R6], regs[REG_LOONGARCH64_R7]);
83
84 BufferPrintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "r8:%016lx r9:%016lx r10:%016lx r11:%016lx\n", \
85 regs[REG_LOONGARCH64_R8], regs[REG_LOONGARCH64_R9], regs[REG_LOONGARCH64_R10], regs[REG_LOONGARCH64_R11]);
86
87 BufferPrintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "r12:%016lx r13:%016lx r14:%016lx r15:%016lx\n", \
88 regs[REG_LOONGARCH64_R12], regs[REG_LOONGARCH64_R13], regs[REG_LOONGARCH64_R14], regs[REG_LOONGARCH64_R15]);
89
90 BufferPrintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "r16:%016lx r17:%016lx r18:%016lx r19:%016lx\n", \
91 regs[REG_LOONGARCH64_R16], regs[REG_LOONGARCH64_R17], regs[REG_LOONGARCH64_R18], regs[REG_LOONGARCH64_R19]);
92
93 BufferPrintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "r20:%016lx r21:%016lx x22:%016lx r23:%016lx\n", \
94 regs[REG_LOONGARCH64_R20], regs[REG_LOONGARCH64_R21], regs[REG_LOONGARCH64_R22], regs[REG_LOONGARCH64_R23]);
95
96 BufferPrintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "r24:%016lx r25:%016lx r26:%016lx r27:%016lx\n", \
97 regs[REG_LOONGARCH64_R24], regs[REG_LOONGARCH64_R25], regs[REG_LOONGARCH64_R26], regs[REG_LOONGARCH64_R27]);
98
99 BufferPrintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "r28:%016lx r29:%016lx r30:%016lx r31:%016lx\n", \
100 regs[REG_LOONGARCH64_R28], regs[REG_LOONGARCH64_R29], regs[REG_LOONGARCH64_R30], regs[REG_LOONGARCH64_R31]);
101
102 BufferPrintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "lr:%016lx sp:%016lx pc:%016lx\n", \
103 regs[REG_LR], regs[REG_SP], regs[REG_PC]);
104
105 std::string regString = StringPrintf("Registers:\n%s", buf);
106 return regString;
107 }
108
StepIfSignalFrame(uintptr_t pc,std::shared_ptr<DfxMemory> memory)109 bool DfxRegsLoongArch64::StepIfSignalFrame(uintptr_t pc, std::shared_ptr<DfxMemory> memory)
110 {
111 uint64_t data;
112 if (!memory->Read<uint64_t>(pc, &data, false)) {
113 return false;
114 }
115 DFXLOGU("data: %llx", data);
116
117 // Look for the kernel sigreturn function.
118 // arch/loongarch/vdso/sigreturn.S:
119 // 0000000000000000 <__vdso_rt_sigreturn>:
120 // 0: 03822c0b ori $r11,$r0,0x8b
121 // 4: 002b0000 syscall 0x0
122
123 if (data != 0x002b000003822c0bULL) {
124 return false;
125 }
126
127 // SP + sizeof(siginfo_t) + mcontext_gregs offset.
128 uintptr_t scAddr = regsData_[REG_SP] + sizeof(siginfo_t) + 0xb8;
129 DFXLOGU("scAddr: %llx", scAddr);
130 memory->Read(scAddr, regsData_.data(), sizeof(uint64_t) * REG_LAST, false);
131 return true;
132 }
133 } // namespace HiviewDFX
134 } // namespace OHOS
135 #endif
136