1800b99b8Sopenharmony_ci/* 2800b99b8Sopenharmony_ci * Copyright (c) 2021-2023 Huawei Device Co., Ltd. 3800b99b8Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4800b99b8Sopenharmony_ci * you may not use this file except in compliance with the License. 5800b99b8Sopenharmony_ci * You may obtain a copy of the License at 6800b99b8Sopenharmony_ci * 7800b99b8Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8800b99b8Sopenharmony_ci * 9800b99b8Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10800b99b8Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11800b99b8Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12800b99b8Sopenharmony_ci * See the License for the specific language governing permissions and 13800b99b8Sopenharmony_ci * limitations under the License. 14800b99b8Sopenharmony_ci */ 15800b99b8Sopenharmony_ci 16800b99b8Sopenharmony_ci#if defined(__arm__) 17800b99b8Sopenharmony_ci#include "dfx_regs.h" 18800b99b8Sopenharmony_ci 19800b99b8Sopenharmony_ci#include <securec.h> 20800b99b8Sopenharmony_ci#include "dfx_define.h" 21800b99b8Sopenharmony_ci#include "dfx_log.h" 22800b99b8Sopenharmony_ci#include "dfx_elf.h" 23800b99b8Sopenharmony_ci#include "string_printf.h" 24800b99b8Sopenharmony_ci 25800b99b8Sopenharmony_ci#define ARM_NR_sigreturn 119 26800b99b8Sopenharmony_ci#define ARM_NR_rt_sigreturn 173 27800b99b8Sopenharmony_ci#define ARM_NR_OABI_SYSCALL_BASE 0x900000 28800b99b8Sopenharmony_ci 29800b99b8Sopenharmony_ci/* ARM EABI sigreturn (the syscall number is loaded into r7) */ 30800b99b8Sopenharmony_ci#define MOV_R7_SIGRETURN (0xe3a07000UL | ARM_NR_sigreturn) 31800b99b8Sopenharmony_ci#define MOV_R7_RT_SIGRETURN (0xe3a07000UL | ARM_NR_rt_sigreturn) 32800b99b8Sopenharmony_ci 33800b99b8Sopenharmony_ci/* ARM OABI sigreturn (using SWI) */ 34800b99b8Sopenharmony_ci#define ARM_SIGRETURN (0xef000000UL | ARM_NR_sigreturn | ARM_NR_OABI_SYSCALL_BASE) 35800b99b8Sopenharmony_ci#define ARM_RT_SIGRETURN (0xef000000UL | ARM_NR_rt_sigreturn | ARM_NR_OABI_SYSCALL_BASE) 36800b99b8Sopenharmony_ci 37800b99b8Sopenharmony_ci/* Thumb sigreturn (two insns, syscall number is loaded into r7) */ 38800b99b8Sopenharmony_ci#define THUMB_SIGRETURN (0xdf00UL << 16 | 0x2700 | ARM_NR_sigreturn) 39800b99b8Sopenharmony_ci#define THUMB_RT_SIGRETURN (0xdf00UL << 16 | 0x2700 | ARM_NR_rt_sigreturn) 40800b99b8Sopenharmony_ci 41800b99b8Sopenharmony_ci/* Thumb2 sigreturn (mov.w r7, $SYS_ify(rt_sigreturn/sigreturn)) */ 42800b99b8Sopenharmony_ci#define THUMB2_SIGRETURN (((0x0700 | ARM_NR_sigreturn) << 16) | 0xf04f) 43800b99b8Sopenharmony_ci#define THUMB2_RT_SIGRETURN (((0x0700 | ARM_NR_rt_sigreturn) << 16) | 0xf04f) 44800b99b8Sopenharmony_ci 45800b99b8Sopenharmony_cinamespace OHOS { 46800b99b8Sopenharmony_cinamespace HiviewDFX { 47800b99b8Sopenharmony_civoid DfxRegsArm::SetFromUcontext(const ucontext_t& context) 48800b99b8Sopenharmony_ci{ 49800b99b8Sopenharmony_ci if (regsData_.size() < REG_LAST) { 50800b99b8Sopenharmony_ci return; 51800b99b8Sopenharmony_ci } 52800b99b8Sopenharmony_ci regsData_[REG_ARM_R0] = static_cast<uintptr_t>(context.uc_mcontext.arm_r0); 53800b99b8Sopenharmony_ci regsData_[REG_ARM_R1] = static_cast<uintptr_t>(context.uc_mcontext.arm_r1); 54800b99b8Sopenharmony_ci regsData_[REG_ARM_R2] = static_cast<uintptr_t>(context.uc_mcontext.arm_r2); 55800b99b8Sopenharmony_ci regsData_[REG_ARM_R3] = static_cast<uintptr_t>(context.uc_mcontext.arm_r3); 56800b99b8Sopenharmony_ci regsData_[REG_ARM_R4] = static_cast<uintptr_t>(context.uc_mcontext.arm_r4); 57800b99b8Sopenharmony_ci regsData_[REG_ARM_R5] = static_cast<uintptr_t>(context.uc_mcontext.arm_r5); 58800b99b8Sopenharmony_ci regsData_[REG_ARM_R6] = static_cast<uintptr_t>(context.uc_mcontext.arm_r6); 59800b99b8Sopenharmony_ci regsData_[REG_ARM_R7] = static_cast<uintptr_t>(context.uc_mcontext.arm_r7); 60800b99b8Sopenharmony_ci regsData_[REG_ARM_R8] = static_cast<uintptr_t>(context.uc_mcontext.arm_r8); 61800b99b8Sopenharmony_ci regsData_[REG_ARM_R9] = static_cast<uintptr_t>(context.uc_mcontext.arm_r9); 62800b99b8Sopenharmony_ci regsData_[REG_ARM_R10] = static_cast<uintptr_t>(context.uc_mcontext.arm_r10); 63800b99b8Sopenharmony_ci regsData_[REG_ARM_R11] = static_cast<uintptr_t>(context.uc_mcontext.arm_fp); 64800b99b8Sopenharmony_ci regsData_[REG_ARM_R12] = static_cast<uintptr_t>(context.uc_mcontext.arm_ip); 65800b99b8Sopenharmony_ci regsData_[REG_ARM_R13] = static_cast<uintptr_t>(context.uc_mcontext.arm_sp); 66800b99b8Sopenharmony_ci regsData_[REG_ARM_R14] = static_cast<uintptr_t>(context.uc_mcontext.arm_lr); 67800b99b8Sopenharmony_ci regsData_[REG_ARM_R15] = static_cast<uintptr_t>(context.uc_mcontext.arm_pc); 68800b99b8Sopenharmony_ci} 69800b99b8Sopenharmony_ci 70800b99b8Sopenharmony_civoid DfxRegsArm::SetFromFpMiniRegs(const uintptr_t* regs, const size_t size) 71800b99b8Sopenharmony_ci{ 72800b99b8Sopenharmony_ci if (size < FP_MINI_REGS_SIZE) { 73800b99b8Sopenharmony_ci return; 74800b99b8Sopenharmony_ci } 75800b99b8Sopenharmony_ci regsData_[REG_ARM_R7] = regs[0]; // 0: R7 offset 76800b99b8Sopenharmony_ci regsData_[REG_ARM_R11] = regs[1]; // 1: R11 offset 77800b99b8Sopenharmony_ci regsData_[REG_SP] = regs[2]; // 2 : sp offset 78800b99b8Sopenharmony_ci regsData_[REG_PC] = regs[3]; // 3 : pc offset 79800b99b8Sopenharmony_ci} 80800b99b8Sopenharmony_ci 81800b99b8Sopenharmony_civoid DfxRegsArm::SetFromQutMiniRegs(const uintptr_t* regs, const size_t size) 82800b99b8Sopenharmony_ci{ 83800b99b8Sopenharmony_ci if (size < QUT_MINI_REGS_SIZE) { 84800b99b8Sopenharmony_ci return; 85800b99b8Sopenharmony_ci } 86800b99b8Sopenharmony_ci regsData_[REG_ARM_R4] = regs[0]; // 0 : r4 offset 87800b99b8Sopenharmony_ci regsData_[REG_ARM_R7] = regs[1]; // 1 : r7 offset 88800b99b8Sopenharmony_ci regsData_[REG_ARM_R10] = regs[2]; // 2 : r10 offset 89800b99b8Sopenharmony_ci regsData_[REG_ARM_R11] = regs[3]; // 3 : r11 offset 90800b99b8Sopenharmony_ci regsData_[REG_SP] = regs[4]; // 4 : sp offset 91800b99b8Sopenharmony_ci regsData_[REG_PC] = regs[5]; // 5 : pc offset 92800b99b8Sopenharmony_ci regsData_[REG_LR] = regs[6]; // 6 : lr offset 93800b99b8Sopenharmony_ci} 94800b99b8Sopenharmony_ci 95800b99b8Sopenharmony_cibool DfxRegsArm::SetPcFromReturnAddress(MAYBE_UNUSED std::shared_ptr<DfxMemory> memory) 96800b99b8Sopenharmony_ci{ 97800b99b8Sopenharmony_ci uintptr_t lr = regsData_[REG_LR]; 98800b99b8Sopenharmony_ci if (regsData_[REG_PC] == lr) { 99800b99b8Sopenharmony_ci return false; 100800b99b8Sopenharmony_ci } 101800b99b8Sopenharmony_ci regsData_[REG_PC] = lr; 102800b99b8Sopenharmony_ci return true; 103800b99b8Sopenharmony_ci} 104800b99b8Sopenharmony_ci 105800b99b8Sopenharmony_cistd::string DfxRegsArm::PrintRegs() const 106800b99b8Sopenharmony_ci{ 107800b99b8Sopenharmony_ci char buf[REGS_PRINT_LEN] = {0}; 108800b99b8Sopenharmony_ci auto regs = GetRegsData(); 109800b99b8Sopenharmony_ci 110800b99b8Sopenharmony_ci BufferPrintf(buf, sizeof(buf), "r0:%08x r1:%08x r2:%08x r3:%08x\n", \ 111800b99b8Sopenharmony_ci regs[REG_ARM_R0], regs[REG_ARM_R1], regs[REG_ARM_R2], regs[REG_ARM_R3]); 112800b99b8Sopenharmony_ci 113800b99b8Sopenharmony_ci BufferPrintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "r4:%08x r5:%08x r6:%08x r7:%08x\n", \ 114800b99b8Sopenharmony_ci regs[REG_ARM_R4], regs[REG_ARM_R5], regs[REG_ARM_R6], regs[REG_ARM_R7]); 115800b99b8Sopenharmony_ci 116800b99b8Sopenharmony_ci BufferPrintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "r8:%08x r9:%08x r10:%08x\n", \ 117800b99b8Sopenharmony_ci regs[REG_ARM_R8], regs[REG_ARM_R9], regs[REG_ARM_R10]); 118800b99b8Sopenharmony_ci 119800b99b8Sopenharmony_ci BufferPrintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "fp:%08x ip:%08x sp:%08x lr:%08x pc:%08x\n", \ 120800b99b8Sopenharmony_ci regs[REG_ARM_R11], regs[REG_ARM_R12], regs[REG_ARM_R13], regs[REG_ARM_R14], regs[REG_ARM_R15]); 121800b99b8Sopenharmony_ci 122800b99b8Sopenharmony_ci std::string regString = StringPrintf("Registers:\n%s", buf); 123800b99b8Sopenharmony_ci return regString; 124800b99b8Sopenharmony_ci} 125800b99b8Sopenharmony_ci 126800b99b8Sopenharmony_cibool DfxRegsArm::StepIfSignalFrame(uintptr_t pc, std::shared_ptr<DfxMemory> memory) 127800b99b8Sopenharmony_ci{ 128800b99b8Sopenharmony_ci // The least bit denotes thumb/arm mode. Do not read there. 129800b99b8Sopenharmony_ci pc = pc & ~0x1; 130800b99b8Sopenharmony_ci 131800b99b8Sopenharmony_ci uint32_t data; 132800b99b8Sopenharmony_ci if (!memory->ReadU32(pc, &data, false)) { 133800b99b8Sopenharmony_ci return false; 134800b99b8Sopenharmony_ci } 135800b99b8Sopenharmony_ci DFXLOGU("data: %{public}x", data); 136800b99b8Sopenharmony_ci 137800b99b8Sopenharmony_ci uintptr_t scAddr = 0; 138800b99b8Sopenharmony_ci if (data == MOV_R7_SIGRETURN || data == ARM_SIGRETURN 139800b99b8Sopenharmony_ci || data == THUMB_SIGRETURN || data == THUMB2_SIGRETURN) { 140800b99b8Sopenharmony_ci uintptr_t spAddr = regsData_[REG_SP]; 141800b99b8Sopenharmony_ci // non-RT sigreturn call. 142800b99b8Sopenharmony_ci // __restore: 143800b99b8Sopenharmony_ci // 144800b99b8Sopenharmony_ci // Form 1 (arm): 145800b99b8Sopenharmony_ci // 0x77 0x70 mov r7, #0x77 146800b99b8Sopenharmony_ci // 0xa0 0xe3 svc 0x00000000 147800b99b8Sopenharmony_ci // 148800b99b8Sopenharmony_ci // Form 2 (arm): 149800b99b8Sopenharmony_ci // 0x77 0x00 0x90 0xef svc 0x00900077 150800b99b8Sopenharmony_ci // 151800b99b8Sopenharmony_ci // Form 3 (thumb): 152800b99b8Sopenharmony_ci // 0x77 0x27 movs r7, #77 153800b99b8Sopenharmony_ci // 0x00 0xdf svc 0 154800b99b8Sopenharmony_ci if (!memory->ReadU32(spAddr, &data, false)) { 155800b99b8Sopenharmony_ci return false; 156800b99b8Sopenharmony_ci } 157800b99b8Sopenharmony_ci if (data == 0x5ac3c35a) { 158800b99b8Sopenharmony_ci // SP + uc_mcontext offset + r0 offset. 159800b99b8Sopenharmony_ci scAddr = spAddr + 0x14 + 0xc; 160800b99b8Sopenharmony_ci } else { 161800b99b8Sopenharmony_ci // SP + r0 offset 162800b99b8Sopenharmony_ci scAddr = spAddr + 0xc; 163800b99b8Sopenharmony_ci } 164800b99b8Sopenharmony_ci } else if (data == MOV_R7_RT_SIGRETURN || data == ARM_RT_SIGRETURN 165800b99b8Sopenharmony_ci || data == THUMB_RT_SIGRETURN || data == THUMB2_RT_SIGRETURN) { 166800b99b8Sopenharmony_ci uintptr_t spAddr = regsData_[REG_SP]; 167800b99b8Sopenharmony_ci // RT sigreturn call. 168800b99b8Sopenharmony_ci // __restore_rt: 169800b99b8Sopenharmony_ci // 170800b99b8Sopenharmony_ci // Form 1 (arm): 171800b99b8Sopenharmony_ci // 0xad 0x70 mov r7, #0xad 172800b99b8Sopenharmony_ci // 0xa0 0xe3 svc 0x00000000 173800b99b8Sopenharmony_ci // 174800b99b8Sopenharmony_ci // Form 2 (arm): 175800b99b8Sopenharmony_ci // 0xad 0x00 0x90 0xef svc 0x009000ad 176800b99b8Sopenharmony_ci // 177800b99b8Sopenharmony_ci // Form 3 (thumb): 178800b99b8Sopenharmony_ci // 0xad 0x27 movs r7, #ad 179800b99b8Sopenharmony_ci // 0x00 0xdf svc 0 180800b99b8Sopenharmony_ci if (!memory->ReadU32(spAddr, &data, false)) { 181800b99b8Sopenharmony_ci return false; 182800b99b8Sopenharmony_ci } 183800b99b8Sopenharmony_ci if (data == spAddr + 8) { // 8 : eight bytes offset 184800b99b8Sopenharmony_ci // SP + 8 + sizeof(siginfo_t) + uc_mcontext_offset + r0 offset 185800b99b8Sopenharmony_ci scAddr = spAddr + 8 + sizeof(siginfo_t) + 0x14 + 0xc; // 8 : eight bytes offset 186800b99b8Sopenharmony_ci } else { 187800b99b8Sopenharmony_ci // SP + sizeof(siginfo_t) + uc_mcontext_offset + r0 offset 188800b99b8Sopenharmony_ci scAddr = spAddr + sizeof(siginfo_t) + 0x14 + 0xc; 189800b99b8Sopenharmony_ci } 190800b99b8Sopenharmony_ci } 191800b99b8Sopenharmony_ci if (scAddr == 0) { 192800b99b8Sopenharmony_ci return false; 193800b99b8Sopenharmony_ci } 194800b99b8Sopenharmony_ci DFXLOGU("scAddr: %{public}x", scAddr); 195800b99b8Sopenharmony_ci memory->Read(scAddr, regsData_.data(), sizeof(uint32_t) * REG_LAST, false); 196800b99b8Sopenharmony_ci return true; 197800b99b8Sopenharmony_ci} 198800b99b8Sopenharmony_ci} // namespace HiviewDFX 199800b99b8Sopenharmony_ci} // namespace OHOS 200800b99b8Sopenharmony_ci#endif 201