1800b99b8Sopenharmony_ci/*
2800b99b8Sopenharmony_ci * Copyright (c) 2023-2024 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#include "arm_exidx.h"
17800b99b8Sopenharmony_ci#include <securec.h>
18800b99b8Sopenharmony_ci
19800b99b8Sopenharmony_ci#include "dfx_define.h"
20800b99b8Sopenharmony_ci#include "dfx_regs.h"
21800b99b8Sopenharmony_ci#include "dfx_regs_qut.h"
22800b99b8Sopenharmony_ci#include "dfx_log.h"
23800b99b8Sopenharmony_ci#include "dfx_instr_statistic.h"
24800b99b8Sopenharmony_ci#include "dfx_util.h"
25800b99b8Sopenharmony_ci#include "string_printf.h"
26800b99b8Sopenharmony_ci
27800b99b8Sopenharmony_ci#if defined(__arm__)
28800b99b8Sopenharmony_ci
29800b99b8Sopenharmony_cinamespace OHOS {
30800b99b8Sopenharmony_cinamespace HiviewDFX {
31800b99b8Sopenharmony_cinamespace {
32800b99b8Sopenharmony_ci#undef LOG_DOMAIN
33800b99b8Sopenharmony_ci#undef LOG_TAG
34800b99b8Sopenharmony_ci#define LOG_DOMAIN 0xD002D11
35800b99b8Sopenharmony_ci#define LOG_TAG "DfxArmExidx"
36800b99b8Sopenharmony_ci
37800b99b8Sopenharmony_ci#define ARM_EXIDX_CANT_UNWIND   0x00000001
38800b99b8Sopenharmony_ci#define ARM_EXIDX_COMPACT       0x80000000
39800b99b8Sopenharmony_ci#define ARM_EXTBL_OP_FINISH     0xb0
40800b99b8Sopenharmony_ci
41800b99b8Sopenharmony_cistatic const uintptr_t FOUR_BYTE_OFFSET = 4;
42800b99b8Sopenharmony_cistatic const int TWO_BIT_OFFSET = 2;
43800b99b8Sopenharmony_cistatic const int FOUR_BIT_OFFSET = 4;
44800b99b8Sopenharmony_cistatic const int SEVEN_BIT_OFFSET = 7;
45800b99b8Sopenharmony_cistatic const int EIGHT_BIT_OFFSET = 8;
46800b99b8Sopenharmony_cistatic const int SIXTEEN_BIT_OFFSET = 16;
47800b99b8Sopenharmony_cistatic const int TWENTY_FOUR_BIT_OFFSET = 24;
48800b99b8Sopenharmony_cistatic const int TWENTY_EIGHT_BIT_OFFSET = 28;
49800b99b8Sopenharmony_ci}
50800b99b8Sopenharmony_ci
51800b99b8Sopenharmony_civoid ExidxContext::Reset(size_t size)
52800b99b8Sopenharmony_ci{
53800b99b8Sopenharmony_ci    vsp = 0;
54800b99b8Sopenharmony_ci    transformedBits = 0;
55800b99b8Sopenharmony_ci    if (size != 0) {
56800b99b8Sopenharmony_ci        regs.resize(size);
57800b99b8Sopenharmony_ci    }
58800b99b8Sopenharmony_ci    for (size_t i = 0; i < regs.size(); ++i) {
59800b99b8Sopenharmony_ci        regs[i] = 0;
60800b99b8Sopenharmony_ci    }
61800b99b8Sopenharmony_ci}
62800b99b8Sopenharmony_ci
63800b99b8Sopenharmony_civoid ExidxContext::Transform(uint32_t reg)
64800b99b8Sopenharmony_ci{
65800b99b8Sopenharmony_ci    DFXLOGU("Transform reg: %{public}d", reg);
66800b99b8Sopenharmony_ci    transformedBits = transformedBits | (1 << reg);
67800b99b8Sopenharmony_ci}
68800b99b8Sopenharmony_ci
69800b99b8Sopenharmony_cibool ExidxContext::IsTransformed(uint32_t reg)
70800b99b8Sopenharmony_ci{
71800b99b8Sopenharmony_ci    if (transformedBits & (1 << reg)) {
72800b99b8Sopenharmony_ci        return true;
73800b99b8Sopenharmony_ci    }
74800b99b8Sopenharmony_ci    return false;
75800b99b8Sopenharmony_ci}
76800b99b8Sopenharmony_ci
77800b99b8Sopenharmony_civoid ExidxContext::AddUpVsp(int32_t imm)
78800b99b8Sopenharmony_ci{
79800b99b8Sopenharmony_ci    DFXLOGU("AddUpVsp imm: %{public}d", imm);
80800b99b8Sopenharmony_ci    vsp += imm;
81800b99b8Sopenharmony_ci
82800b99b8Sopenharmony_ci    auto qutRegs = DfxRegsQut::GetQutRegs();
83800b99b8Sopenharmony_ci    for (size_t i = 0; i < qutRegs.size(); i++) {
84800b99b8Sopenharmony_ci        uint32_t reg = static_cast<uint32_t>(qutRegs[i]);
85800b99b8Sopenharmony_ci        if (IsTransformed(reg)) {
86800b99b8Sopenharmony_ci            regs[i] += imm;
87800b99b8Sopenharmony_ci        }
88800b99b8Sopenharmony_ci    }
89800b99b8Sopenharmony_ci}
90800b99b8Sopenharmony_ci
91800b99b8Sopenharmony_ciArmExidx::ArmExidx(std::shared_ptr<DfxMemory> memory) : memory_(memory)
92800b99b8Sopenharmony_ci{
93800b99b8Sopenharmony_ci    (void)memset_s(&lastErrorData_, sizeof(UnwindErrorData), 0, sizeof(UnwindErrorData));
94800b99b8Sopenharmony_ci    context_.Reset(DfxRegsQut::GetQutRegsSize());
95800b99b8Sopenharmony_ci}
96800b99b8Sopenharmony_ci
97800b99b8Sopenharmony_ciinline void ArmExidx::FlushInstr()
98800b99b8Sopenharmony_ci{
99800b99b8Sopenharmony_ci    if (rsState_->cfaReg == 0) {
100800b99b8Sopenharmony_ci        rsState_->cfaReg = REG_SP;
101800b99b8Sopenharmony_ci    }
102800b99b8Sopenharmony_ci    rsState_->cfaRegOffset = 0;
103800b99b8Sopenharmony_ci    if (context_.vsp != 0) {
104800b99b8Sopenharmony_ci        if (__builtin_expect(!((context_.vsp & 0x3) == 0), false)) {
105800b99b8Sopenharmony_ci            DFXLOGE("Check failed: context_.vsp & 0x3) == 0");
106800b99b8Sopenharmony_ci        }
107800b99b8Sopenharmony_ci        rsState_->cfaRegOffset = context_.vsp;
108800b99b8Sopenharmony_ci    }
109800b99b8Sopenharmony_ci    DFXLOGU("rsState cfaReg: %{public}d, cfaRegOffset: %{public}d", rsState_->cfaReg, rsState_->cfaRegOffset);
110800b99b8Sopenharmony_ci
111800b99b8Sopenharmony_ci    auto qutRegs = DfxRegsQut::GetQutRegs();
112800b99b8Sopenharmony_ci    for (size_t i = 0; i < qutRegs.size(); i++) {
113800b99b8Sopenharmony_ci        uint32_t reg = static_cast<uint32_t>(qutRegs[i]);
114800b99b8Sopenharmony_ci        if (context_.IsTransformed(reg)) {
115800b99b8Sopenharmony_ci            if (__builtin_expect(!((context_.regs[i] & 0x3) == 0), false)) {
116800b99b8Sopenharmony_ci                DFXLOGE("Check failed: context_.regs[%{public}zu] & 0x3) == 0", i);
117800b99b8Sopenharmony_ci            }
118800b99b8Sopenharmony_ci            rsState_->locs[i].type = REG_LOC_MEM_OFFSET;
119800b99b8Sopenharmony_ci            rsState_->locs[i].val = -context_.regs[i];
120800b99b8Sopenharmony_ci            DFXLOGU("rsState reg: %{public}d, locs[%{public}d].val: %{public}d", reg, i, rsState_->locs[i].val);
121800b99b8Sopenharmony_ci        }
122800b99b8Sopenharmony_ci    }
123800b99b8Sopenharmony_ci
124800b99b8Sopenharmony_ci    if (!isPcSet_) {
125800b99b8Sopenharmony_ci        rsState_->returnAddressRegister = REG_LR;
126800b99b8Sopenharmony_ci    } else {
127800b99b8Sopenharmony_ci        rsState_->returnAddressRegister = REG_PC;
128800b99b8Sopenharmony_ci    }
129800b99b8Sopenharmony_ci
130800b99b8Sopenharmony_ci    context_.Reset();
131800b99b8Sopenharmony_ci}
132800b99b8Sopenharmony_ci
133800b99b8Sopenharmony_ciinline void ArmExidx::LogRawData()
134800b99b8Sopenharmony_ci{
135800b99b8Sopenharmony_ci    std::string logStr("Raw Data:");
136800b99b8Sopenharmony_ci    for (const uint8_t data : ops_) {
137800b99b8Sopenharmony_ci        logStr += StringPrintf(" 0x%02x", data);
138800b99b8Sopenharmony_ci    }
139800b99b8Sopenharmony_ci    DFXLOGU("%{public}s", logStr.c_str());
140800b99b8Sopenharmony_ci}
141800b99b8Sopenharmony_ci
142800b99b8Sopenharmony_cibool ArmExidx::SearchEntry(uintptr_t pc, struct UnwindTableInfo uti, struct UnwindEntryInfo& uei)
143800b99b8Sopenharmony_ci{
144800b99b8Sopenharmony_ci    uintptr_t tableLen = uti.tableLen / ARM_EXIDX_TABLE_SIZE;
145800b99b8Sopenharmony_ci    uintptr_t tableData = uti.tableData;
146800b99b8Sopenharmony_ci    DFXLOGU("SearchEntry pc: %{public}p tableData: %{public}p, tableLen: %{public}u",
147800b99b8Sopenharmony_ci        (void*)pc, (void*)tableData, (uint32_t)tableLen);
148800b99b8Sopenharmony_ci    if (tableLen == 0) {
149800b99b8Sopenharmony_ci        lastErrorData_.SetCode(UNW_ERROR_NO_UNWIND_INFO);
150800b99b8Sopenharmony_ci        return false;
151800b99b8Sopenharmony_ci    }
152800b99b8Sopenharmony_ci
153800b99b8Sopenharmony_ci    // do binary search
154800b99b8Sopenharmony_ci    uintptr_t entry = 0;
155800b99b8Sopenharmony_ci    uintptr_t low = 0;
156800b99b8Sopenharmony_ci    uintptr_t high = tableLen;
157800b99b8Sopenharmony_ci    while (low < high) {
158800b99b8Sopenharmony_ci        uintptr_t cur = (low + high) / 2; // 2 : binary search divided parameter
159800b99b8Sopenharmony_ci        uintptr_t ptr = tableData + cur * ARM_EXIDX_TABLE_SIZE;
160800b99b8Sopenharmony_ci        uintptr_t addr = 0;
161800b99b8Sopenharmony_ci        if (!memory_->ReadPrel31(ptr, &addr)) {
162800b99b8Sopenharmony_ci            lastErrorData_.SetAddrAndCode(ptr, UNW_ERROR_ILLEGAL_VALUE);
163800b99b8Sopenharmony_ci            return false;
164800b99b8Sopenharmony_ci        }
165800b99b8Sopenharmony_ci
166800b99b8Sopenharmony_ci        if (pc == addr) {
167800b99b8Sopenharmony_ci            entry = ptr;
168800b99b8Sopenharmony_ci            break;
169800b99b8Sopenharmony_ci        }
170800b99b8Sopenharmony_ci        if (pc < addr) {
171800b99b8Sopenharmony_ci            high = cur;
172800b99b8Sopenharmony_ci        } else {
173800b99b8Sopenharmony_ci            low = cur + 1;
174800b99b8Sopenharmony_ci        }
175800b99b8Sopenharmony_ci    }
176800b99b8Sopenharmony_ci    if (entry == 0) {
177800b99b8Sopenharmony_ci        if (high != 0) {
178800b99b8Sopenharmony_ci            entry = tableData + (high - 1) * ARM_EXIDX_TABLE_SIZE;
179800b99b8Sopenharmony_ci        } else {
180800b99b8Sopenharmony_ci            lastErrorData_.SetCode(UNW_ERROR_NO_UNWIND_INFO);
181800b99b8Sopenharmony_ci            return false;
182800b99b8Sopenharmony_ci        }
183800b99b8Sopenharmony_ci    }
184800b99b8Sopenharmony_ci
185800b99b8Sopenharmony_ci    uei.unwindInfoSize = ARM_EXIDX_TABLE_SIZE;
186800b99b8Sopenharmony_ci    uei.unwindInfo = (void *) entry;
187800b99b8Sopenharmony_ci    uei.format = UNW_INFO_FORMAT_ARM_EXIDX;
188800b99b8Sopenharmony_ci    return true;
189800b99b8Sopenharmony_ci}
190800b99b8Sopenharmony_ci
191800b99b8Sopenharmony_cibool ArmExidx::ExtractEntryData(uintptr_t entryOffset)
192800b99b8Sopenharmony_ci{
193800b99b8Sopenharmony_ci    DFXLOGU("Exidx entryOffset: %{public}llx", (uint64_t)entryOffset);
194800b99b8Sopenharmony_ci    ops_.clear();
195800b99b8Sopenharmony_ci    uint32_t data = 0;
196800b99b8Sopenharmony_ci    if (entryOffset & 1) {
197800b99b8Sopenharmony_ci        DFXLOGE("[%{public}d]: entryOffset: %{public}llx error.", __LINE__, (uint64_t)entryOffset);
198800b99b8Sopenharmony_ci        lastErrorData_.SetAddrAndCode(entryOffset, UNW_ERROR_INVALID_ALIGNMENT);
199800b99b8Sopenharmony_ci        return false;
200800b99b8Sopenharmony_ci    }
201800b99b8Sopenharmony_ci
202800b99b8Sopenharmony_ci    entryOffset += FOUR_BYTE_OFFSET;
203800b99b8Sopenharmony_ci    if (!memory_->ReadU32(entryOffset, &data, false)) {
204800b99b8Sopenharmony_ci        DFXLOGE("[%{public}d]: entryOffset: %{public}llx error.", __LINE__, (uint64_t)entryOffset);
205800b99b8Sopenharmony_ci        lastErrorData_.SetAddrAndCode(entryOffset, UNW_ERROR_ILLEGAL_VALUE);
206800b99b8Sopenharmony_ci        return false;
207800b99b8Sopenharmony_ci    }
208800b99b8Sopenharmony_ci
209800b99b8Sopenharmony_ci    if (data == ARM_EXIDX_CANT_UNWIND) {
210800b99b8Sopenharmony_ci        DFXLOGU("This is a CANT UNWIND entry, data: %{public}x.", data);
211800b99b8Sopenharmony_ci        lastErrorData_.SetAddrAndCode(entryOffset, UNW_ERROR_CANT_UNWIND);
212800b99b8Sopenharmony_ci        return false;
213800b99b8Sopenharmony_ci    } else if ((data & ARM_EXIDX_COMPACT) != 0) {
214800b99b8Sopenharmony_ci        if (((data >> TWENTY_FOUR_BIT_OFFSET) & 0x7f) != 0) {
215800b99b8Sopenharmony_ci            DFXLOGE("This is a non-zero index, this code doesn't support other formats.");
216800b99b8Sopenharmony_ci            lastErrorData_.SetCode(UNW_ERROR_INVALID_PERSONALITY);
217800b99b8Sopenharmony_ci            return false;
218800b99b8Sopenharmony_ci        }
219800b99b8Sopenharmony_ci        DFXLOGU("This is a compact table entry, data: %{public}x.", data);
220800b99b8Sopenharmony_ci        ops_.push_back((data >> SIXTEEN_BIT_OFFSET) & 0xff);
221800b99b8Sopenharmony_ci        ops_.push_back((data >> EIGHT_BIT_OFFSET) & 0xff);
222800b99b8Sopenharmony_ci        uint8_t lastOp = data & 0xff;
223800b99b8Sopenharmony_ci        ops_.push_back(lastOp);
224800b99b8Sopenharmony_ci        if (lastOp != ARM_EXTBL_OP_FINISH) {
225800b99b8Sopenharmony_ci            ops_.push_back(ARM_EXTBL_OP_FINISH);
226800b99b8Sopenharmony_ci        }
227800b99b8Sopenharmony_ci        LogRawData();
228800b99b8Sopenharmony_ci        return true;
229800b99b8Sopenharmony_ci    }
230800b99b8Sopenharmony_ci
231800b99b8Sopenharmony_ci    uintptr_t extabAddr = 0;
232800b99b8Sopenharmony_ci    // prel31 decode point to .ARM.extab
233800b99b8Sopenharmony_ci#ifndef TEST_ARM_EXIDX
234800b99b8Sopenharmony_ci    if (!memory_->ReadPrel31(entryOffset, &extabAddr)) {
235800b99b8Sopenharmony_ci        lastErrorData_.SetAddrAndCode(entryOffset, UNW_ERROR_INVALID_MEMORY);
236800b99b8Sopenharmony_ci        return false;
237800b99b8Sopenharmony_ci    }
238800b99b8Sopenharmony_ci#else
239800b99b8Sopenharmony_ci    extabAddr = entryOffset + FOUR_BYTE_OFFSET;
240800b99b8Sopenharmony_ci#endif
241800b99b8Sopenharmony_ci    return ExtractEntryTab(extabAddr);
242800b99b8Sopenharmony_ci}
243800b99b8Sopenharmony_ci
244800b99b8Sopenharmony_cibool ArmExidx::ExtractEntryTab(uintptr_t tabOffset)
245800b99b8Sopenharmony_ci{
246800b99b8Sopenharmony_ci    uint32_t data = 0;
247800b99b8Sopenharmony_ci    DFXLOGU("Exidx tabOffset: %{public}llx", (uint64_t)tabOffset);
248800b99b8Sopenharmony_ci    if (!memory_->ReadU32(tabOffset, &data, false)) {
249800b99b8Sopenharmony_ci        lastErrorData_.SetAddrAndCode(tabOffset, UNW_ERROR_INVALID_MEMORY);
250800b99b8Sopenharmony_ci        return false;
251800b99b8Sopenharmony_ci    }
252800b99b8Sopenharmony_ci
253800b99b8Sopenharmony_ci    uint8_t tableCount = 0;
254800b99b8Sopenharmony_ci    if ((data & ARM_EXIDX_COMPACT) == 0) {
255800b99b8Sopenharmony_ci        DFXLOGU("Arm generic personality, data: %{public}x.", data);
256800b99b8Sopenharmony_ci#ifndef TEST_ARM_EXIDX
257800b99b8Sopenharmony_ci        uintptr_t perRoutine;
258800b99b8Sopenharmony_ci        if (!memory_->ReadPrel31(tabOffset, &perRoutine)) {
259800b99b8Sopenharmony_ci            DFXLOGE("Arm Personality routine error");
260800b99b8Sopenharmony_ci            lastErrorData_.SetAddrAndCode(tabOffset, UNW_ERROR_INVALID_MEMORY);
261800b99b8Sopenharmony_ci            return false;
262800b99b8Sopenharmony_ci        }
263800b99b8Sopenharmony_ci#endif
264800b99b8Sopenharmony_ci
265800b99b8Sopenharmony_ci        tabOffset += FOUR_BYTE_OFFSET;
266800b99b8Sopenharmony_ci        // Skip four bytes, because dont have unwind data to read
267800b99b8Sopenharmony_ci        if (!memory_->ReadU32(tabOffset, &data, false)) {
268800b99b8Sopenharmony_ci            lastErrorData_.SetAddrAndCode(tabOffset, UNW_ERROR_INVALID_MEMORY);
269800b99b8Sopenharmony_ci            return false;
270800b99b8Sopenharmony_ci        }
271800b99b8Sopenharmony_ci        tableCount = (data >> TWENTY_FOUR_BIT_OFFSET) & 0xff;
272800b99b8Sopenharmony_ci        ops_.push_back((data >> SIXTEEN_BIT_OFFSET) & 0xff);
273800b99b8Sopenharmony_ci        ops_.push_back((data >> EIGHT_BIT_OFFSET) & 0xff);
274800b99b8Sopenharmony_ci        ops_.push_back(data & 0xff);
275800b99b8Sopenharmony_ci        tabOffset += FOUR_BYTE_OFFSET;
276800b99b8Sopenharmony_ci    } else {
277800b99b8Sopenharmony_ci        DFXLOGU("Arm compact personality, data: %{public}x.", data);
278800b99b8Sopenharmony_ci        if ((data >> TWENTY_EIGHT_BIT_OFFSET) != 0x8) {
279800b99b8Sopenharmony_ci            DFXLOGE("incorrect Arm compact model, [31:28]bit must be 0x8(%{public}x)",
280800b99b8Sopenharmony_ci                data >> TWENTY_EIGHT_BIT_OFFSET);
281800b99b8Sopenharmony_ci            lastErrorData_.SetCode(UNW_ERROR_INVALID_PERSONALITY);
282800b99b8Sopenharmony_ci            return false;
283800b99b8Sopenharmony_ci        }
284800b99b8Sopenharmony_ci        uint8_t personality = (data >> TWENTY_FOUR_BIT_OFFSET) & 0x3;
285800b99b8Sopenharmony_ci        if (personality > 2) { // 2 : personality must be 0 1 2
286800b99b8Sopenharmony_ci            DFXLOGE("incorrect Arm compact personality(%{public}u)", personality);
287800b99b8Sopenharmony_ci            lastErrorData_.SetCode(UNW_ERROR_INVALID_PERSONALITY);
288800b99b8Sopenharmony_ci            return false;
289800b99b8Sopenharmony_ci        }
290800b99b8Sopenharmony_ci        // inline compact model, when personality is 0
291800b99b8Sopenharmony_ci        if (personality == 0) {
292800b99b8Sopenharmony_ci            ops_.push_back((data >> SIXTEEN_BIT_OFFSET) & 0xff);
293800b99b8Sopenharmony_ci        } else if (personality == 1 || personality == 2) { // 2 : personality equal to 2
294800b99b8Sopenharmony_ci            tableCount = (data >> SIXTEEN_BIT_OFFSET) & 0xff;
295800b99b8Sopenharmony_ci            tabOffset += FOUR_BYTE_OFFSET;
296800b99b8Sopenharmony_ci        }
297800b99b8Sopenharmony_ci        ops_.push_back((data >> EIGHT_BIT_OFFSET) & 0xff);
298800b99b8Sopenharmony_ci        ops_.push_back(data & 0xff);
299800b99b8Sopenharmony_ci    }
300800b99b8Sopenharmony_ci    if (tableCount > 5) { // 5 : 5 operators
301800b99b8Sopenharmony_ci        lastErrorData_.SetCode(UNW_ERROR_NOT_SUPPORT);
302800b99b8Sopenharmony_ci        return false;
303800b99b8Sopenharmony_ci    }
304800b99b8Sopenharmony_ci
305800b99b8Sopenharmony_ci    for (size_t i = 0; i < tableCount; i++) {
306800b99b8Sopenharmony_ci        if (!memory_->ReadU32(tabOffset, &data, false)) {
307800b99b8Sopenharmony_ci            return false;
308800b99b8Sopenharmony_ci        }
309800b99b8Sopenharmony_ci        tabOffset += FOUR_BYTE_OFFSET;
310800b99b8Sopenharmony_ci        ops_.push_back((data >> TWENTY_FOUR_BIT_OFFSET) & 0xff);
311800b99b8Sopenharmony_ci        ops_.push_back((data >> SIXTEEN_BIT_OFFSET) & 0xff);
312800b99b8Sopenharmony_ci        ops_.push_back((data >> EIGHT_BIT_OFFSET) & 0xff);
313800b99b8Sopenharmony_ci        ops_.push_back(data & 0xff);
314800b99b8Sopenharmony_ci    }
315800b99b8Sopenharmony_ci
316800b99b8Sopenharmony_ci    if (!ops_.empty() && ops_.back() != ARM_EXTBL_OP_FINISH) {
317800b99b8Sopenharmony_ci        ops_.push_back(ARM_EXTBL_OP_FINISH);
318800b99b8Sopenharmony_ci    }
319800b99b8Sopenharmony_ci    LogRawData();
320800b99b8Sopenharmony_ci    return true;
321800b99b8Sopenharmony_ci}
322800b99b8Sopenharmony_ci
323800b99b8Sopenharmony_ciinline bool ArmExidx::GetOpCode()
324800b99b8Sopenharmony_ci{
325800b99b8Sopenharmony_ci    if (ops_.empty()) {
326800b99b8Sopenharmony_ci        return false;
327800b99b8Sopenharmony_ci    }
328800b99b8Sopenharmony_ci    curOp_ = ops_.front();
329800b99b8Sopenharmony_ci    ops_.pop_front();
330800b99b8Sopenharmony_ci    DFXLOGU("curOp: %{public}llx", (uint64_t)curOp_);
331800b99b8Sopenharmony_ci    return true;
332800b99b8Sopenharmony_ci}
333800b99b8Sopenharmony_ci
334800b99b8Sopenharmony_cibool ArmExidx::Eval(uintptr_t entryOffset)
335800b99b8Sopenharmony_ci{
336800b99b8Sopenharmony_ci    if (!ExtractEntryData(entryOffset)) {
337800b99b8Sopenharmony_ci        return false;
338800b99b8Sopenharmony_ci    }
339800b99b8Sopenharmony_ci
340800b99b8Sopenharmony_ci    DecodeTable decodeTable[] = {
341800b99b8Sopenharmony_ci        {0xc0, 0x00, &ArmExidx::Decode00xxxxxx},
342800b99b8Sopenharmony_ci        {0xc0, 0x40, &ArmExidx::Decode01xxxxxx},
343800b99b8Sopenharmony_ci        {0xf0, 0x80, &ArmExidx::Decode1000iiiiiiiiiiii},
344800b99b8Sopenharmony_ci        {0xf0, 0x90, &ArmExidx::Decode1001nnnn},
345800b99b8Sopenharmony_ci        {0xf0, 0xa0, &ArmExidx::Decode1010nnnn},
346800b99b8Sopenharmony_ci        {0xff, 0xb0, &ArmExidx::Decode10110000},
347800b99b8Sopenharmony_ci        {0xff, 0xb1, &ArmExidx::Decode101100010000iiii},
348800b99b8Sopenharmony_ci        {0xff, 0xb2, &ArmExidx::Decode10110010uleb128},
349800b99b8Sopenharmony_ci        {0xff, 0xb3, &ArmExidx::Decode10110011sssscccc},
350800b99b8Sopenharmony_ci        {0xfc, 0xb4, &ArmExidx::Decode101101nn},
351800b99b8Sopenharmony_ci        {0xf8, 0xb8, &ArmExidx::Decode10111nnn},
352800b99b8Sopenharmony_ci        {0xff, 0xc6, &ArmExidx::Decode11000110sssscccc},
353800b99b8Sopenharmony_ci        {0xff, 0xc7, &ArmExidx::Decode110001110000iiii},
354800b99b8Sopenharmony_ci        {0xfe, 0xc8, &ArmExidx::Decode1100100nsssscccc},
355800b99b8Sopenharmony_ci        {0xc8, 0xc8, &ArmExidx::Decode11001yyy},
356800b99b8Sopenharmony_ci        {0xf8, 0xc0, &ArmExidx::Decode11000nnn},
357800b99b8Sopenharmony_ci        {0xf8, 0xd0, &ArmExidx::Decode11010nnn},
358800b99b8Sopenharmony_ci        {0xc0, 0xc0, &ArmExidx::Decode11xxxyyy}
359800b99b8Sopenharmony_ci    };
360800b99b8Sopenharmony_ci    context_.Reset();
361800b99b8Sopenharmony_ci    while (Decode(decodeTable, sizeof(decodeTable) / sizeof(decodeTable[0])));
362800b99b8Sopenharmony_ci    return true;
363800b99b8Sopenharmony_ci}
364800b99b8Sopenharmony_ci
365800b99b8Sopenharmony_cibool ArmExidx::Step(uintptr_t entryOffset, std::shared_ptr<RegLocState> rs)
366800b99b8Sopenharmony_ci{
367800b99b8Sopenharmony_ci    if (rs == nullptr) {
368800b99b8Sopenharmony_ci        return false;
369800b99b8Sopenharmony_ci    }
370800b99b8Sopenharmony_ci    rsState_ = rs;
371800b99b8Sopenharmony_ci
372800b99b8Sopenharmony_ci    if (!Eval(entryOffset)) {
373800b99b8Sopenharmony_ci        return false;
374800b99b8Sopenharmony_ci    }
375800b99b8Sopenharmony_ci
376800b99b8Sopenharmony_ci    FlushInstr();
377800b99b8Sopenharmony_ci    return true;
378800b99b8Sopenharmony_ci}
379800b99b8Sopenharmony_ci
380800b99b8Sopenharmony_ciinline bool ArmExidx::DecodeSpare()
381800b99b8Sopenharmony_ci{
382800b99b8Sopenharmony_ci    DFXLOGU("Exidx Decode Spare");
383800b99b8Sopenharmony_ci    lastErrorData_.SetCode(UNW_ERROR_ARM_EXIDX_SPARE);
384800b99b8Sopenharmony_ci    return false;
385800b99b8Sopenharmony_ci}
386800b99b8Sopenharmony_ci
387800b99b8Sopenharmony_ciinline bool ArmExidx::Decode(DecodeTable decodeTable[], size_t size)
388800b99b8Sopenharmony_ci{
389800b99b8Sopenharmony_ci    if (!GetOpCode()) {
390800b99b8Sopenharmony_ci        return false;
391800b99b8Sopenharmony_ci    }
392800b99b8Sopenharmony_ci
393800b99b8Sopenharmony_ci    bool ret = false;
394800b99b8Sopenharmony_ci    for (size_t i = 0; i < size; ++i) {
395800b99b8Sopenharmony_ci        if ((curOp_ & decodeTable[i].mask) == decodeTable[i].result) {
396800b99b8Sopenharmony_ci            if (decodeTable[i].decoder != nullptr) {
397800b99b8Sopenharmony_ci                DFXLOGU("decodeTable[%{public}d].mask: %{public}02x", i, decodeTable[i].mask);
398800b99b8Sopenharmony_ci                ret = (this->*(decodeTable[i].decoder))();
399800b99b8Sopenharmony_ci                break;
400800b99b8Sopenharmony_ci            }
401800b99b8Sopenharmony_ci        }
402800b99b8Sopenharmony_ci    }
403800b99b8Sopenharmony_ci    return ret;
404800b99b8Sopenharmony_ci}
405800b99b8Sopenharmony_ci
406800b99b8Sopenharmony_ciinline bool ArmExidx::Decode00xxxxxx()
407800b99b8Sopenharmony_ci{
408800b99b8Sopenharmony_ci    // 00xxxxxx: vsp = vsp + (xxxxxx << 2) + 4. Covers range 0x04-0x100 inclusive
409800b99b8Sopenharmony_ci    context_.AddUpVsp(((curOp_ & 0x3f) << 2) + 4);
410800b99b8Sopenharmony_ci    return true;
411800b99b8Sopenharmony_ci}
412800b99b8Sopenharmony_ci
413800b99b8Sopenharmony_ciinline bool ArmExidx::Decode01xxxxxx()
414800b99b8Sopenharmony_ci{
415800b99b8Sopenharmony_ci    // 01xxxxxx: vsp = vsp - (xxxxxx << 2) + 4. Covers range 0x04-0x100 inclusive
416800b99b8Sopenharmony_ci    context_.AddUpVsp(-(((curOp_ & 0x3f) << 2) + 4));
417800b99b8Sopenharmony_ci    return true;
418800b99b8Sopenharmony_ci}
419800b99b8Sopenharmony_ci
420800b99b8Sopenharmony_ciinline bool ArmExidx::Decode1000iiiiiiiiiiii()
421800b99b8Sopenharmony_ci{
422800b99b8Sopenharmony_ci    uint16_t registers = ((curOp_ & 0x0f) << 8);
423800b99b8Sopenharmony_ci    if (!GetOpCode()) {
424800b99b8Sopenharmony_ci        return false;
425800b99b8Sopenharmony_ci    }
426800b99b8Sopenharmony_ci    registers |= curOp_;
427800b99b8Sopenharmony_ci    if (registers == 0x0) {
428800b99b8Sopenharmony_ci        DFXLOGE("10000000 00000000: Refuse to unwind!");
429800b99b8Sopenharmony_ci        lastErrorData_.SetCode(UNW_ERROR_CANT_UNWIND);
430800b99b8Sopenharmony_ci        return false;
431800b99b8Sopenharmony_ci    }
432800b99b8Sopenharmony_ci
433800b99b8Sopenharmony_ci    registers <<= FOUR_BIT_OFFSET;
434800b99b8Sopenharmony_ci    DFXLOGU("1000iiii iiiiiiii: registers: %{public}02x)", registers);
435800b99b8Sopenharmony_ci    for (size_t reg = REG_ARM_R4; reg < REG_ARM_LAST; reg++) {
436800b99b8Sopenharmony_ci        if ((registers & (1 << reg))) {
437800b99b8Sopenharmony_ci            if (REG_PC == reg) {
438800b99b8Sopenharmony_ci                isPcSet_ = true;
439800b99b8Sopenharmony_ci            }
440800b99b8Sopenharmony_ci            context_.Transform(reg);
441800b99b8Sopenharmony_ci            context_.AddUpVsp(FOUR_BYTE_OFFSET);
442800b99b8Sopenharmony_ci        }
443800b99b8Sopenharmony_ci    }
444800b99b8Sopenharmony_ci    return true;
445800b99b8Sopenharmony_ci}
446800b99b8Sopenharmony_ci
447800b99b8Sopenharmony_ciinline bool ArmExidx::Decode1001nnnn()
448800b99b8Sopenharmony_ci{
449800b99b8Sopenharmony_ci    uint8_t bits = curOp_ & 0xf;
450800b99b8Sopenharmony_ci    if (bits == REG_ARM_R13 || bits == REG_ARM_R15) {
451800b99b8Sopenharmony_ci        DFXLOGU("10011101 or 10011111: Reserved");
452800b99b8Sopenharmony_ci        lastErrorData_.SetCode(UNW_ERROR_RESERVED_VALUE);
453800b99b8Sopenharmony_ci        return false;
454800b99b8Sopenharmony_ci    }
455800b99b8Sopenharmony_ci    // 1001nnnn: Set vsp = r[nnnn]
456800b99b8Sopenharmony_ci    if ((bits == REG_ARM_R7) || (bits == REG_ARM_R11)) {
457800b99b8Sopenharmony_ci        DFXLOGU("1001nnnn: Set vsp = R%{public}d", bits);
458800b99b8Sopenharmony_ci        if (context_.transformedBits == 0) {
459800b99b8Sopenharmony_ci            // No register transformed, ignore vsp offset.
460800b99b8Sopenharmony_ci            context_.Reset();
461800b99b8Sopenharmony_ci        }
462800b99b8Sopenharmony_ci    } else {
463800b99b8Sopenharmony_ci        INSTR_STATISTIC(UnsupportedArmExidx, bits, curOp_);
464800b99b8Sopenharmony_ci        return false;
465800b99b8Sopenharmony_ci    }
466800b99b8Sopenharmony_ci    rsState_->cfaReg = bits;
467800b99b8Sopenharmony_ci    rsState_->cfaRegOffset = 0;
468800b99b8Sopenharmony_ci    return true;
469800b99b8Sopenharmony_ci}
470800b99b8Sopenharmony_ci
471800b99b8Sopenharmony_ciinline bool ArmExidx::Decode1010nnnn()
472800b99b8Sopenharmony_ci{
473800b99b8Sopenharmony_ci    // 10100nnn: Pop r4-r[4+nnn]
474800b99b8Sopenharmony_ci    // 10101nnn: Pop r4-r[4+nnn], r14
475800b99b8Sopenharmony_ci    size_t startReg = REG_ARM_R4;
476800b99b8Sopenharmony_ci    size_t endReg = REG_ARM_R4 + (curOp_ & 0x7);
477800b99b8Sopenharmony_ci    std::string msg = "Pop r" + std::to_string(startReg);
478800b99b8Sopenharmony_ci    if (endReg > startReg) {
479800b99b8Sopenharmony_ci        msg += "-r" + std::to_string(endReg);
480800b99b8Sopenharmony_ci    }
481800b99b8Sopenharmony_ci    if (curOp_ & 0x8) {
482800b99b8Sopenharmony_ci        msg += ", r14";
483800b99b8Sopenharmony_ci    }
484800b99b8Sopenharmony_ci    DFXLOGU("%{public}s", msg.c_str());
485800b99b8Sopenharmony_ci
486800b99b8Sopenharmony_ci    for (size_t reg = startReg; reg <= endReg; reg++) {
487800b99b8Sopenharmony_ci        context_.Transform(reg);
488800b99b8Sopenharmony_ci        context_.AddUpVsp(FOUR_BYTE_OFFSET);
489800b99b8Sopenharmony_ci    }
490800b99b8Sopenharmony_ci
491800b99b8Sopenharmony_ci    if (curOp_ & 0x8) {
492800b99b8Sopenharmony_ci        context_.Transform(REG_LR);
493800b99b8Sopenharmony_ci        context_.AddUpVsp(FOUR_BYTE_OFFSET);
494800b99b8Sopenharmony_ci    }
495800b99b8Sopenharmony_ci    return true;
496800b99b8Sopenharmony_ci}
497800b99b8Sopenharmony_ci
498800b99b8Sopenharmony_ciinline bool ArmExidx::Decode10110000()
499800b99b8Sopenharmony_ci{
500800b99b8Sopenharmony_ci    DFXLOGU("10110000: Finish");
501800b99b8Sopenharmony_ci    lastErrorData_.SetCode(UNW_ERROR_ARM_EXIDX_FINISH);
502800b99b8Sopenharmony_ci    return true;
503800b99b8Sopenharmony_ci}
504800b99b8Sopenharmony_ci
505800b99b8Sopenharmony_ciinline bool ArmExidx::Decode101100010000iiii()
506800b99b8Sopenharmony_ci{
507800b99b8Sopenharmony_ci    if (!GetOpCode()) {
508800b99b8Sopenharmony_ci        return false;
509800b99b8Sopenharmony_ci    }
510800b99b8Sopenharmony_ci    // 10110001 00000000: spare
511800b99b8Sopenharmony_ci    // 10110001 xxxxyyyy: spare (xxxx != 0000)
512800b99b8Sopenharmony_ci    if (curOp_ == 0x00 || (curOp_ & 0xf0) != 0) {
513800b99b8Sopenharmony_ci        return DecodeSpare();
514800b99b8Sopenharmony_ci    }
515800b99b8Sopenharmony_ci
516800b99b8Sopenharmony_ci    // 10110001 0000iiii(i not all 0) Pop integer registers under mask{r3, r2, r1, r0}
517800b99b8Sopenharmony_ci    uint8_t registers = curOp_ & 0x0f;
518800b99b8Sopenharmony_ci    DFXLOGU("10110001 0000iiii, registers: %{public}02x", registers);
519800b99b8Sopenharmony_ci    for (size_t reg = 0; reg < 4; reg++) { // 4 : four registers {r3, r2, r1, r0}
520800b99b8Sopenharmony_ci        if ((registers & (1 << reg))) {
521800b99b8Sopenharmony_ci            context_.AddUpVsp(FOUR_BYTE_OFFSET);
522800b99b8Sopenharmony_ci        }
523800b99b8Sopenharmony_ci    }
524800b99b8Sopenharmony_ci    return true;
525800b99b8Sopenharmony_ci}
526800b99b8Sopenharmony_ci
527800b99b8Sopenharmony_ciinline bool ArmExidx::Decode10110010uleb128()
528800b99b8Sopenharmony_ci{
529800b99b8Sopenharmony_ci    // 10110010 uleb128 vsp = vsp + 0x204 + (uleb128 << 2)
530800b99b8Sopenharmony_ci    uint8_t shift = 0;
531800b99b8Sopenharmony_ci    uint32_t uleb128 = 0;
532800b99b8Sopenharmony_ci    do {
533800b99b8Sopenharmony_ci        if (!GetOpCode()) {
534800b99b8Sopenharmony_ci            return false;
535800b99b8Sopenharmony_ci        }
536800b99b8Sopenharmony_ci        uleb128 |= (curOp_ & 0x7f) << shift;
537800b99b8Sopenharmony_ci        shift += SEVEN_BIT_OFFSET;
538800b99b8Sopenharmony_ci    } while ((curOp_ & 0x80) != 0);
539800b99b8Sopenharmony_ci    uint32_t offset = 0x204 + (uleb128 << TWO_BIT_OFFSET);
540800b99b8Sopenharmony_ci    DFXLOGU("vsp = vsp + %{public}d", offset);
541800b99b8Sopenharmony_ci    context_.AddUpVsp(offset);
542800b99b8Sopenharmony_ci    return true;
543800b99b8Sopenharmony_ci}
544800b99b8Sopenharmony_ci
545800b99b8Sopenharmony_ciinline bool ArmExidx::Decode10110011sssscccc()
546800b99b8Sopenharmony_ci{
547800b99b8Sopenharmony_ci    // Pop VFP double precision registers D[ssss]-D[ssss+cccc] by FSTMFDX
548800b99b8Sopenharmony_ci    if (!GetOpCode()) {
549800b99b8Sopenharmony_ci        return false;
550800b99b8Sopenharmony_ci    }
551800b99b8Sopenharmony_ci    uint8_t popRegCount = (curOp_ & 0x0f) + 1;
552800b99b8Sopenharmony_ci    uint32_t offset = popRegCount * 8 + 4;
553800b99b8Sopenharmony_ci    context_.AddUpVsp(offset);
554800b99b8Sopenharmony_ci    return true;
555800b99b8Sopenharmony_ci}
556800b99b8Sopenharmony_ci
557800b99b8Sopenharmony_ciinline bool ArmExidx::Decode101101nn()
558800b99b8Sopenharmony_ci{
559800b99b8Sopenharmony_ci    return DecodeSpare();
560800b99b8Sopenharmony_ci}
561800b99b8Sopenharmony_ci
562800b99b8Sopenharmony_ciinline bool ArmExidx::Decode10111nnn()
563800b99b8Sopenharmony_ci{
564800b99b8Sopenharmony_ci    // 10111nnn: Pop VFP double-precision registers D[8]-D[8+nnn] by FSTMFDX
565800b99b8Sopenharmony_ci    uint8_t popRegCount = (curOp_ & 0x07) + 1;
566800b99b8Sopenharmony_ci    uint32_t offset = popRegCount * 8 + 4;
567800b99b8Sopenharmony_ci    context_.AddUpVsp(offset);
568800b99b8Sopenharmony_ci    return true;
569800b99b8Sopenharmony_ci}
570800b99b8Sopenharmony_ci
571800b99b8Sopenharmony_ciinline bool ArmExidx::Decode11000110sssscccc()
572800b99b8Sopenharmony_ci{
573800b99b8Sopenharmony_ci    // 11000110 sssscccc: Intel Wireless MMX pop wR[ssss]-wR[ssss+cccc] (see remark e)
574800b99b8Sopenharmony_ci    if (!GetOpCode()) {
575800b99b8Sopenharmony_ci        return false;
576800b99b8Sopenharmony_ci    }
577800b99b8Sopenharmony_ci    return Decode11000nnn();
578800b99b8Sopenharmony_ci}
579800b99b8Sopenharmony_ci
580800b99b8Sopenharmony_ciinline bool ArmExidx::Decode110001110000iiii()
581800b99b8Sopenharmony_ci{
582800b99b8Sopenharmony_ci    // Intel Wireless MMX pop wCGR registers under mask {wCGR3,2,1,0}
583800b99b8Sopenharmony_ci    if (!GetOpCode()) {
584800b99b8Sopenharmony_ci        return false;
585800b99b8Sopenharmony_ci    }
586800b99b8Sopenharmony_ci    // 11000111 00000000: Spare
587800b99b8Sopenharmony_ci    // 11000111 xxxxyyyy: Spare (xxxx != 0000)
588800b99b8Sopenharmony_ci    if ((curOp_ & 0xf0) != 0 || curOp_ == 0) {
589800b99b8Sopenharmony_ci        return DecodeSpare();
590800b99b8Sopenharmony_ci    }
591800b99b8Sopenharmony_ci
592800b99b8Sopenharmony_ci    // 11000111 0000iiii: Intel Wireless MMX pop wCGR registers {wCGR0,1,2,3}
593800b99b8Sopenharmony_ci    for (size_t i = 0; i < 4; i++) { // 4 : four registers
594800b99b8Sopenharmony_ci        if (curOp_ & (1 << i)) {
595800b99b8Sopenharmony_ci            context_.AddUpVsp(FOUR_BYTE_OFFSET);
596800b99b8Sopenharmony_ci        }
597800b99b8Sopenharmony_ci    }
598800b99b8Sopenharmony_ci    return true;
599800b99b8Sopenharmony_ci}
600800b99b8Sopenharmony_ci
601800b99b8Sopenharmony_ciinline bool ArmExidx::Decode1100100nsssscccc()
602800b99b8Sopenharmony_ci{
603800b99b8Sopenharmony_ci    // 11001000 sssscccc: Pop VFP double precision registers D[16+ssss]-D[16+ssss+cccc] by VPUSH
604800b99b8Sopenharmony_ci    // 11001001 sssscccc: Pop VFP double precision registers D[ssss]-D[ssss+cccc] by VPUSH
605800b99b8Sopenharmony_ci    if (!GetOpCode()) {
606800b99b8Sopenharmony_ci        return false;
607800b99b8Sopenharmony_ci    }
608800b99b8Sopenharmony_ci    uint8_t popRegCount = (curOp_ & 0x0f) + 1;
609800b99b8Sopenharmony_ci    uint32_t offset = popRegCount * 8;
610800b99b8Sopenharmony_ci    context_.AddUpVsp(offset);
611800b99b8Sopenharmony_ci    return true;
612800b99b8Sopenharmony_ci}
613800b99b8Sopenharmony_ci
614800b99b8Sopenharmony_ciinline bool ArmExidx::Decode11001yyy()
615800b99b8Sopenharmony_ci{
616800b99b8Sopenharmony_ci    // 11001yyy: Spare (yyy != 000, 001)
617800b99b8Sopenharmony_ci    return DecodeSpare();
618800b99b8Sopenharmony_ci}
619800b99b8Sopenharmony_ci
620800b99b8Sopenharmony_ciinline bool ArmExidx::Decode11000nnn()
621800b99b8Sopenharmony_ci{
622800b99b8Sopenharmony_ci    // Intel Wireless MMX pop wR[10]-wR[10+nnn]
623800b99b8Sopenharmony_ci    uint8_t popRegCount = (curOp_ & 0x0f) + 1;
624800b99b8Sopenharmony_ci    uint32_t offset = popRegCount * 8;
625800b99b8Sopenharmony_ci    context_.AddUpVsp(offset);
626800b99b8Sopenharmony_ci    return true;
627800b99b8Sopenharmony_ci}
628800b99b8Sopenharmony_ci
629800b99b8Sopenharmony_ciinline bool ArmExidx::Decode11010nnn()
630800b99b8Sopenharmony_ci{
631800b99b8Sopenharmony_ci    // Pop VFP double-precision registers D[8]-D[8+nnn] saved (as if) by VPUSH (seeremark d)
632800b99b8Sopenharmony_ci    uint8_t popRegCount = (curOp_ & 0x0f) + 1;
633800b99b8Sopenharmony_ci    uint32_t offset = popRegCount * 8;
634800b99b8Sopenharmony_ci    context_.AddUpVsp(offset);
635800b99b8Sopenharmony_ci    return true;
636800b99b8Sopenharmony_ci}
637800b99b8Sopenharmony_ci
638800b99b8Sopenharmony_ciinline bool ArmExidx::Decode11xxxyyy()
639800b99b8Sopenharmony_ci{
640800b99b8Sopenharmony_ci    // 11xxxyyy: Spare (xxx != 000, 001, 010)
641800b99b8Sopenharmony_ci    return DecodeSpare();
642800b99b8Sopenharmony_ci}
643800b99b8Sopenharmony_ci} // namespace HiviewDFX
644800b99b8Sopenharmony_ci} // namespace OHOS
645800b99b8Sopenharmony_ci#endif