1 /*
2 * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
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(__arm__)
17 #include "dfx_regs.h"
18
19 #include <securec.h>
20 #include "dfx_define.h"
21 #include "dfx_log.h"
22 #include "string_printf.h"
23
24 #define ARM_NR_sigreturn 119
25 #define ARM_NR_rt_sigreturn 173
26 #define ARM_NR_OABI_SYSCALL_BASE 0x900000
27
28 /* ARM EABI sigreturn (the syscall number is loaded into r7) */
29 #define MOV_R7_SIGRETURN (0xe3a07000UL | ARM_NR_sigreturn)
30 #define MOV_R7_RT_SIGRETURN (0xe3a07000UL | ARM_NR_rt_sigreturn)
31
32 /* ARM OABI sigreturn (using SWI) */
33 #define ARM_SIGRETURN (0xef000000UL | ARM_NR_sigreturn | ARM_NR_OABI_SYSCALL_BASE)
34 #define ARM_RT_SIGRETURN (0xef000000UL | ARM_NR_rt_sigreturn | ARM_NR_OABI_SYSCALL_BASE)
35
36 /* Thumb sigreturn (two insns, syscall number is loaded into r7) */
37 #define THUMB_SIGRETURN (0xdf00UL << 16 | 0x2700 | ARM_NR_sigreturn)
38 #define THUMB_RT_SIGRETURN (0xdf00UL << 16 | 0x2700 | ARM_NR_rt_sigreturn)
39
40 /* Thumb2 sigreturn (mov.w r7, $SYS_ify(rt_sigreturn/sigreturn)) */
41 #define THUMB2_SIGRETURN (((0x0700 | ARM_NR_sigreturn) << 16) | 0xf04f)
42 #define THUMB2_RT_SIGRETURN (((0x0700 | ARM_NR_rt_sigreturn) << 16) | 0xf04f)
43
44 namespace OHOS {
45 namespace HiviewDFX {
SetFromUcontext(const ucontext_t & context)46 void DfxRegsArm::SetFromUcontext(const ucontext_t& context)
47 {
48 if (regsData_.size() < REG_LAST) {
49 return;
50 }
51 regsData_[REG_ARM_R0] = static_cast<uintptr_t>(context.uc_mcontext.arm_r0);
52 regsData_[REG_ARM_R1] = static_cast<uintptr_t>(context.uc_mcontext.arm_r1);
53 regsData_[REG_ARM_R2] = static_cast<uintptr_t>(context.uc_mcontext.arm_r2);
54 regsData_[REG_ARM_R3] = static_cast<uintptr_t>(context.uc_mcontext.arm_r3);
55 regsData_[REG_ARM_R4] = static_cast<uintptr_t>(context.uc_mcontext.arm_r4);
56 regsData_[REG_ARM_R5] = static_cast<uintptr_t>(context.uc_mcontext.arm_r5);
57 regsData_[REG_ARM_R6] = static_cast<uintptr_t>(context.uc_mcontext.arm_r6);
58 regsData_[REG_ARM_R7] = static_cast<uintptr_t>(context.uc_mcontext.arm_r7);
59 regsData_[REG_ARM_R8] = static_cast<uintptr_t>(context.uc_mcontext.arm_r8);
60 regsData_[REG_ARM_R9] = static_cast<uintptr_t>(context.uc_mcontext.arm_r9);
61 regsData_[REG_ARM_R10] = static_cast<uintptr_t>(context.uc_mcontext.arm_r10);
62 regsData_[REG_ARM_R11] = static_cast<uintptr_t>(context.uc_mcontext.arm_fp);
63 regsData_[REG_ARM_R12] = static_cast<uintptr_t>(context.uc_mcontext.arm_ip);
64 regsData_[REG_ARM_R13] = static_cast<uintptr_t>(context.uc_mcontext.arm_sp);
65 regsData_[REG_ARM_R14] = static_cast<uintptr_t>(context.uc_mcontext.arm_lr);
66 regsData_[REG_ARM_R15] = static_cast<uintptr_t>(context.uc_mcontext.arm_pc);
67 regsData_[REG_ARM_CPSR] = static_cast<uintptr_t>(context.uc_mcontext.arm_cpsr);
68 }
69
SetFromFpMiniRegs(const uintptr_t * regs,const size_t size)70 void DfxRegsArm::SetFromFpMiniRegs(const uintptr_t* regs, const size_t size)
71 {
72 if (size < FP_MINI_REGS_SIZE) {
73 return;
74 }
75 regsData_[REG_ARM_R7] = regs[0]; // 0: R7 offset
76 regsData_[REG_ARM_R11] = regs[1]; // 1: R11 offset
77 regsData_[REG_SP] = regs[2]; // 2 : sp offset
78 regsData_[REG_PC] = regs[3]; // 3 : pc offset
79 }
80
SetFromQutMiniRegs(const uintptr_t * regs,const size_t size)81 void DfxRegsArm::SetFromQutMiniRegs(const uintptr_t* regs, const size_t size)
82 {
83 if (size < QUT_MINI_REGS_SIZE) {
84 return;
85 }
86 regsData_[REG_ARM_R4] = regs[0]; // 0 : r4 offset
87 regsData_[REG_ARM_R7] = regs[1]; // 1 : r7 offset
88 regsData_[REG_ARM_R10] = regs[2]; // 2 : r10 offset
89 regsData_[REG_ARM_R11] = regs[3]; // 3 : r11 offset
90 regsData_[REG_SP] = regs[4]; // 4 : sp offset
91 regsData_[REG_PC] = regs[5]; // 5 : pc offset
92 regsData_[REG_LR] = regs[6]; // 6 : lr offset
93 }
94
SetPcFromReturnAddress(MAYBE_UNUSED std::shared_ptr<DfxMemory> memory)95 bool DfxRegsArm::SetPcFromReturnAddress(MAYBE_UNUSED std::shared_ptr<DfxMemory> memory)
96 {
97 uintptr_t lr = regsData_[REG_LR];
98 if (regsData_[REG_PC] == lr) {
99 return false;
100 }
101 regsData_[REG_PC] = lr;
102 return true;
103 }
104
PrintRegs() const105 std::string DfxRegsArm::PrintRegs() const
106 {
107 char buf[REGS_PRINT_LEN] = {0};
108 auto regs = GetRegsData();
109
110 BufferPrintf(buf, sizeof(buf), "r0:%08x r1:%08x r2:%08x r3:%08x\n", \
111 regs[REG_ARM_R0], regs[REG_ARM_R1], regs[REG_ARM_R2], regs[REG_ARM_R3]);
112
113 BufferPrintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "r4:%08x r5:%08x r6:%08x r7:%08x\n", \
114 regs[REG_ARM_R4], regs[REG_ARM_R5], regs[REG_ARM_R6], regs[REG_ARM_R7]);
115
116 BufferPrintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "r8:%08x r9:%08x r10:%08x\n", \
117 regs[REG_ARM_R8], regs[REG_ARM_R9], regs[REG_ARM_R10]);
118
119 BufferPrintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "fp:%08x ip:%08x sp:%08x lr:%08x pc:%08x\n", \
120 regs[REG_ARM_R11], regs[REG_ARM_R12], regs[REG_ARM_R13], regs[REG_ARM_R14], regs[REG_ARM_R15]);
121
122 BufferPrintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "cpsr:%08x\n", regs[REG_ARM_CPSR]);
123 std::string regString = StringPrintf("Registers:\n%s", buf);
124 return regString;
125 }
126
StepIfSignalFrame(uintptr_t pc,std::shared_ptr<DfxMemory> memory)127 bool DfxRegsArm::StepIfSignalFrame(uintptr_t pc, std::shared_ptr<DfxMemory> memory)
128 {
129 // The least bit denotes thumb/arm mode. Do not read there.
130 pc = pc & ~0x1;
131
132 uint32_t data;
133 if (!memory->Read<uint32_t>(pc, &data, false)) {
134 return false;
135 }
136 DFXLOGU("data: %{public}x", data);
137
138 uintptr_t scAddr = 0;
139 if (data == MOV_R7_SIGRETURN || data == ARM_SIGRETURN
140 || data == THUMB_SIGRETURN || data == THUMB2_SIGRETURN) {
141 uintptr_t spAddr = regsData_[REG_SP];
142 // non-RT sigreturn call.
143 // __restore:
144 //
145 // Form 1 (arm):
146 // 0x77 0x70 mov r7, #0x77
147 // 0xa0 0xe3 svc 0x00000000
148 //
149 // Form 2 (arm):
150 // 0x77 0x00 0x90 0xef svc 0x00900077
151 //
152 // Form 3 (thumb):
153 // 0x77 0x27 movs r7, #77
154 // 0x00 0xdf svc 0
155 if (!memory->Read<uint32_t>(spAddr, &data, false)) {
156 return false;
157 }
158 if (data == 0x5ac3c35a) {
159 // SP + uc_mcontext offset + r0 offset.
160 scAddr = spAddr + 0x14 + 0xc;
161 } else {
162 // SP + r0 offset
163 scAddr = spAddr + 0xc;
164 }
165 } else if (data == MOV_R7_RT_SIGRETURN || data == ARM_RT_SIGRETURN
166 || data == THUMB_RT_SIGRETURN || data == THUMB2_RT_SIGRETURN) {
167 uintptr_t spAddr = regsData_[REG_SP];
168 // RT sigreturn call.
169 // __restore_rt:
170 //
171 // Form 1 (arm):
172 // 0xad 0x70 mov r7, #0xad
173 // 0xa0 0xe3 svc 0x00000000
174 //
175 // Form 2 (arm):
176 // 0xad 0x00 0x90 0xef svc 0x009000ad
177 //
178 // Form 3 (thumb):
179 // 0xad 0x27 movs r7, #ad
180 // 0x00 0xdf svc 0
181 if (!memory->Read<uint32_t>(spAddr, &data, false)) {
182 return false;
183 }
184 if (data == spAddr + 8) { // 8 : eight bytes offset
185 // SP + 8 + sizeof(siginfo_t) + uc_mcontext_offset + r0 offset
186 scAddr = spAddr + 8 + sizeof(siginfo_t) + 0x14 + 0xc; // 8 : eight bytes offset
187 } else {
188 // SP + sizeof(siginfo_t) + uc_mcontext_offset + r0 offset
189 scAddr = spAddr + sizeof(siginfo_t) + 0x14 + 0xc;
190 }
191 }
192 if (scAddr == 0) {
193 return false;
194 }
195 DFXLOGU("scAddr: %{public}x", scAddr);
196 memory->Read(scAddr, regsData_.data(), sizeof(uint32_t) * REG_LAST, false);
197 return true;
198 }
199 } // namespace HiviewDFX
200 } // namespace OHOS
201 #endif
202