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 45namespace OHOS { 46namespace HiviewDFX { 47void 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 70void 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 81void 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 95bool 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 105std::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 126bool 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 DFXLOGU("data: %{public}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 DFXLOGU("scAddr: %{public}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