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(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 64
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
24 #include "dfx_define.h"
25 #include "dfx_log.h"
26 #include "string_printf.h"
27
28 namespace OHOS {
29 namespace HiviewDFX {
SetFromUcontext(const ucontext_t & context)30 void DfxRegsRiscv64::SetFromUcontext(const ucontext_t &context)
31 {
32 if (regsData_.size() < REG_LAST) {
33 return;
34 }
35 for (uint16_t index = REG_RISCV64_X0; index <= REG_RISCV64_X31; index++) {
36 regsData_[index] = static_cast<uintptr_t>(context.uc_mcontext.__gregs[index]);
37 }
38 }
39
SetFromFpMiniRegs(const uintptr_t * regs,const size_t size)40 void DfxRegsRiscv64::SetFromFpMiniRegs(const uintptr_t* regs, const size_t size)
41 {
42 if (regs == nullptr || 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 DfxRegsRiscv64::SetFromQutMiniRegs(const uintptr_t* regs, const size_t size)
52 {
53 if (regs == nullptr || size < QUT_MINI_REGS_SIZE) {
54 return;
55 }
56 regsData_[REG_RISCV64_X20] = regs[1]; // 1 : X20 offset
57 regsData_[REG_RISCV64_X28] = regs[2]; // 2 : X28 offset
58 regsData_[REG_FP] = regs[3]; // 3 : fp offset
59 regsData_[REG_SP] = regs[4]; // 4 : sp offset
60 regsData_[REG_PC] = regs[5]; // 5 : pc offset
61 regsData_[REG_LR] = regs[6]; // 6 : lr offset
62 }
63
SetPcFromReturnAddress(MAYBE_UNUSED std::shared_ptr<DfxMemory> memory)64 bool DfxRegsRiscv64::SetPcFromReturnAddress(MAYBE_UNUSED std::shared_ptr<DfxMemory> memory)
65 {
66 uintptr_t lr = regsData_[REG_LR];
67 if (regsData_[REG_PC] == lr) {
68 return false;
69 }
70 regsData_[REG_PC] = lr;
71 return true;
72 }
73
PrintRegs() const74 std::string DfxRegsRiscv64::PrintRegs() const
75 {
76 char buf[REGS_PRINT_LEN] = {0};
77 auto regs = GetRegsData();
78
79 BufferPrintf(buf, sizeof(buf), "x0:%016lx x1:%016lx x2:%016lx x3:%016lx\n", \
80 regs[REG_RISCV64_X0], regs[REG_RISCV64_X1], regs[REG_RISCV64_X2], regs[REG_RISCV64_X3]);
81
82 BufferPrintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "x4:%016lx x5:%016lx x6:%016lx x7:%016lx\n", \
83 regs[REG_RISCV64_X4], regs[REG_RISCV64_X5], regs[REG_RISCV64_X6], regs[REG_RISCV64_X7]);
84
85 BufferPrintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "x8:%016lx x9:%016lx x10:%016lx x11:%016lx\n", \
86 regs[REG_RISCV64_X8], regs[REG_RISCV64_X9], regs[REG_RISCV64_X10], regs[REG_RISCV64_X11]);
87
88 BufferPrintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "x12:%016lx x13:%016lx x14:%016lx x15:%016lx\n", \
89 regs[REG_RISCV64_X12], regs[REG_RISCV64_X13], regs[REG_RISCV64_X14], regs[REG_RISCV64_X15]);
90
91 BufferPrintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "x16:%016lx x17:%016lx x18:%016lx x19:%016lx\n", \
92 regs[REG_RISCV64_X16], regs[REG_RISCV64_X17], regs[REG_RISCV64_X18], regs[REG_RISCV64_X19]);
93
94 BufferPrintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "x20:%016lx x21:%016lx x22:%016lx x23:%016lx\n", \
95 regs[REG_RISCV64_X20], regs[REG_RISCV64_X21], regs[REG_RISCV64_X22], regs[REG_RISCV64_X23]);
96
97 BufferPrintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "x24:%016lx x25:%016lx x26:%016lx x27:%016lx\n", \
98 regs[REG_RISCV64_X24], regs[REG_RISCV64_X25], regs[REG_RISCV64_X26], regs[REG_RISCV64_X27]);
99
100 BufferPrintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "x28:%016lx x29:%016lx\n", \
101 regs[REG_RISCV64_X28], regs[REG_RISCV64_X29]);
102
103 BufferPrintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "lr:%016lx sp:%016lx pc:%016lx\n", \
104 regs[REG_RISCV64_X30], regs[REG_SP], regs[REG_PC]);
105
106 std::string regString = StringPrintf("Registers:\n%s", buf);
107 return regString;
108 }
109
StepIfSignalFrame(uintptr_t pc,std::shared_ptr<DfxMemory> memory)110 bool DfxRegsRiscv64::StepIfSignalFrame(uintptr_t pc, std::shared_ptr<DfxMemory> memory)
111 {
112 uint64_t data;
113 if (!memory->Read<uint64_t>(pc, &data, false)) {
114 return false;
115 }
116 DFXLOGU("[%{public}d]: data: %{public}llx", __LINE__, data);
117
118 // Look for the kernel sigreturn function.
119 // __kernel_rt_sigreturn:
120 // li a7, __NR_rt_sigreturn
121 // scall
122 const int scallSize = 8;
123 const uint8_t liScall[] = {0x93, 0x08, 0xb0, 0x08, 0x73, 0x00, 0x00, 0x00};
124 if (memcmp(&data, &liScall, scallSize) != 0) {
125 return false;
126 }
127 // SP + sizeof(siginfo_t) + uc_mcontext offset + X0 offset.
128 uintptr_t scAddr = regsData_[REG_SP] + sizeof(siginfo_t) + 0xb0 + 0x00;
129 DFXLOGU("[%{public}d]: scAddr: %{public}llx", __LINE__, 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