• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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