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 "dfx_elf.h"
23 #include "string_printf.h"
24
25 #define ARM_NR_sigreturn 119
26 #define ARM_NR_rt_sigreturn 173
27 #define ARM_NR_OABI_SYSCALL_BASE 0x900000
28
29 /* ARM EABI sigreturn (the syscall number is loaded into r7) */
30 #define MOV_R7_SIGRETURN (0xe3a07000UL | ARM_NR_sigreturn)
31 #define MOV_R7_RT_SIGRETURN (0xe3a07000UL | ARM_NR_rt_sigreturn)
32
33 /* ARM OABI sigreturn (using SWI) */
34 #define ARM_SIGRETURN (0xef000000UL | ARM_NR_sigreturn | ARM_NR_OABI_SYSCALL_BASE)
35 #define ARM_RT_SIGRETURN (0xef000000UL | ARM_NR_rt_sigreturn | ARM_NR_OABI_SYSCALL_BASE)
36
37 /* Thumb sigreturn (two insns, syscall number is loaded into r7) */
38 #define THUMB_SIGRETURN (0xdf00UL << 16 | 0x2700 | ARM_NR_sigreturn)
39 #define THUMB_RT_SIGRETURN (0xdf00UL << 16 | 0x2700 | ARM_NR_rt_sigreturn)
40
41 /* Thumb2 sigreturn (mov.w r7, $SYS_ify(rt_sigreturn/sigreturn)) */
42 #define THUMB2_SIGRETURN (((0x0700 | ARM_NR_sigreturn) << 16) | 0xf04f)
43 #define THUMB2_RT_SIGRETURN (((0x0700 | ARM_NR_rt_sigreturn) << 16) | 0xf04f)
44
45 namespace OHOS {
46 namespace HiviewDFX {
SetFromUcontext(const ucontext_t & context)47 void DfxRegsArm::SetFromUcontext(const ucontext_t& context)
48 {
49 if (regsData_.size() < REG_LAST) {
50 return;
51 }
52 regsData_[REG_ARM_R0] = static_cast<uintptr_t>(context.uc_mcontext.arm_r0);
53 regsData_[REG_ARM_R1] = static_cast<uintptr_t>(context.uc_mcontext.arm_r1);
54 regsData_[REG_ARM_R2] = static_cast<uintptr_t>(context.uc_mcontext.arm_r2);
55 regsData_[REG_ARM_R3] = static_cast<uintptr_t>(context.uc_mcontext.arm_r3);
56 regsData_[REG_ARM_R4] = static_cast<uintptr_t>(context.uc_mcontext.arm_r4);
57 regsData_[REG_ARM_R5] = static_cast<uintptr_t>(context.uc_mcontext.arm_r5);
58 regsData_[REG_ARM_R6] = static_cast<uintptr_t>(context.uc_mcontext.arm_r6);
59 regsData_[REG_ARM_R7] = static_cast<uintptr_t>(context.uc_mcontext.arm_r7);
60 regsData_[REG_ARM_R8] = static_cast<uintptr_t>(context.uc_mcontext.arm_r8);
61 regsData_[REG_ARM_R9] = static_cast<uintptr_t>(context.uc_mcontext.arm_r9);
62 regsData_[REG_ARM_R10] = static_cast<uintptr_t>(context.uc_mcontext.arm_r10);
63 regsData_[REG_ARM_R11] = static_cast<uintptr_t>(context.uc_mcontext.arm_fp);
64 regsData_[REG_ARM_R12] = static_cast<uintptr_t>(context.uc_mcontext.arm_ip);
65 regsData_[REG_ARM_R13] = static_cast<uintptr_t>(context.uc_mcontext.arm_sp);
66 regsData_[REG_ARM_R14] = static_cast<uintptr_t>(context.uc_mcontext.arm_lr);
67 regsData_[REG_ARM_R15] = static_cast<uintptr_t>(context.uc_mcontext.arm_pc);
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 std::string regString = StringPrintf("Registers:\n%s", buf);
123 return regString;
124 }
125
StepIfSignalFrame(uintptr_t pc,std::shared_ptr<DfxMemory> memory)126 bool DfxRegsArm::StepIfSignalFrame(uintptr_t pc, std::shared_ptr<DfxMemory> memory)
127 {
128 // The least bit denotes thumb/arm mode. Do not read there.
129 pc = pc & ~0x1;
130
131 uint32_t data;
132 if (!memory->ReadU32(pc, &data, false)) {
133 return false;
134 }
135 LOGU("data: %x", data);
136
137 uintptr_t scAddr = 0;
138 if (data == MOV_R7_SIGRETURN || data == ARM_SIGRETURN
139 || data == THUMB_SIGRETURN || data == THUMB2_SIGRETURN) {
140 uintptr_t spAddr = regsData_[REG_SP];
141 // non-RT sigreturn call.
142 // __restore:
143 //
144 // Form 1 (arm):
145 // 0x77 0x70 mov r7, #0x77
146 // 0xa0 0xe3 svc 0x00000000
147 //
148 // Form 2 (arm):
149 // 0x77 0x00 0x90 0xef svc 0x00900077
150 //
151 // Form 3 (thumb):
152 // 0x77 0x27 movs r7, #77
153 // 0x00 0xdf svc 0
154 if (!memory->ReadU32(spAddr, &data, false)) {
155 return false;
156 }
157 if (data == 0x5ac3c35a) {
158 // SP + uc_mcontext offset + r0 offset.
159 scAddr = spAddr + 0x14 + 0xc;
160 } else {
161 // SP + r0 offset
162 scAddr = spAddr + 0xc;
163 }
164 } else if (data == MOV_R7_RT_SIGRETURN || data == ARM_RT_SIGRETURN
165 || data == THUMB_RT_SIGRETURN || data == THUMB2_RT_SIGRETURN) {
166 uintptr_t spAddr = regsData_[REG_SP];
167 // RT sigreturn call.
168 // __restore_rt:
169 //
170 // Form 1 (arm):
171 // 0xad 0x70 mov r7, #0xad
172 // 0xa0 0xe3 svc 0x00000000
173 //
174 // Form 2 (arm):
175 // 0xad 0x00 0x90 0xef svc 0x009000ad
176 //
177 // Form 3 (thumb):
178 // 0xad 0x27 movs r7, #ad
179 // 0x00 0xdf svc 0
180 if (!memory->ReadU32(spAddr, &data, false)) {
181 return false;
182 }
183 if (data == spAddr + 8) { // 8 : eight bytes offset
184 // SP + 8 + sizeof(siginfo_t) + uc_mcontext_offset + r0 offset
185 scAddr = spAddr + 8 + sizeof(siginfo_t) + 0x14 + 0xc; // 8 : eight bytes offset
186 } else {
187 // SP + sizeof(siginfo_t) + uc_mcontext_offset + r0 offset
188 scAddr = spAddr + sizeof(siginfo_t) + 0x14 + 0xc;
189 }
190 }
191 if (scAddr == 0) {
192 return false;
193 }
194 LOGU("scAddr: %x", scAddr);
195 memory->Read(scAddr, regsData_.data(), sizeof(uint32_t) * REG_LAST, false);
196 return true;
197 }
198 } // namespace HiviewDFX
199 } // namespace OHOS
200 #endif
201