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