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