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