123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862 |
- /*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #include <stdint.h>
- #include <deque>
- #include <string>
- #include <android-base/stringprintf.h>
- #include <unwindstack/Log.h>
- #include <unwindstack/MachineArm.h>
- #include <unwindstack/Memory.h>
- #include <unwindstack/RegsArm.h>
- #include "ArmExidx.h"
- #include "Check.h"
- namespace unwindstack {
- static constexpr uint8_t LOG_CFA_REG = 64;
- void ArmExidx::LogRawData() {
- std::string log_str("Raw Data:");
- for (const uint8_t data : data_) {
- log_str += android::base::StringPrintf(" 0x%02x", data);
- }
- log(log_indent_, log_str.c_str());
- }
- bool ArmExidx::ExtractEntryData(uint32_t entry_offset) {
- data_.clear();
- status_ = ARM_STATUS_NONE;
- if (entry_offset & 1) {
- // The offset needs to be at least two byte aligned.
- status_ = ARM_STATUS_INVALID_ALIGNMENT;
- return false;
- }
- // Each entry is a 32 bit prel31 offset followed by 32 bits
- // of unwind information. If bit 31 of the unwind data is zero,
- // then this is a prel31 offset to the start of the unwind data.
- // If the unwind data is 1, then this is a cant unwind entry.
- // Otherwise, this data is the compact form of the unwind information.
- uint32_t data;
- if (!elf_memory_->Read32(entry_offset + 4, &data)) {
- status_ = ARM_STATUS_READ_FAILED;
- status_address_ = entry_offset + 4;
- return false;
- }
- if (data == 1) {
- // This is a CANT UNWIND entry.
- status_ = ARM_STATUS_NO_UNWIND;
- if (log_type_ != ARM_LOG_NONE) {
- if (log_type_ == ARM_LOG_FULL) {
- log(log_indent_, "Raw Data: 0x00 0x00 0x00 0x01");
- }
- log(log_indent_, "[cantunwind]");
- }
- return false;
- }
- if (data & (1UL << 31)) {
- // This is a compact table entry.
- if ((data >> 24) & 0xf) {
- // This is a non-zero index, this code doesn't support
- // other formats.
- status_ = ARM_STATUS_INVALID_PERSONALITY;
- return false;
- }
- data_.push_back((data >> 16) & 0xff);
- data_.push_back((data >> 8) & 0xff);
- uint8_t last_op = data & 0xff;
- data_.push_back(last_op);
- if (last_op != ARM_OP_FINISH) {
- // If this didn't end with a finish op, add one.
- data_.push_back(ARM_OP_FINISH);
- }
- if (log_type_ == ARM_LOG_FULL) {
- LogRawData();
- }
- return true;
- }
- // Get the address of the ops.
- // Sign extend the data value if necessary.
- int32_t signed_data = static_cast<int32_t>(data << 1) >> 1;
- uint32_t addr = (entry_offset + 4) + signed_data;
- if (!elf_memory_->Read32(addr, &data)) {
- status_ = ARM_STATUS_READ_FAILED;
- status_address_ = addr;
- return false;
- }
- size_t num_table_words;
- if (data & (1UL << 31)) {
- // Compact model.
- switch ((data >> 24) & 0xf) {
- case 0:
- num_table_words = 0;
- data_.push_back((data >> 16) & 0xff);
- break;
- case 1:
- case 2:
- num_table_words = (data >> 16) & 0xff;
- addr += 4;
- break;
- default:
- // Only a personality of 0, 1, 2 is valid.
- status_ = ARM_STATUS_INVALID_PERSONALITY;
- return false;
- }
- data_.push_back((data >> 8) & 0xff);
- data_.push_back(data & 0xff);
- } else {
- // Generic model.
- // Skip the personality routine data, it doesn't contain any data
- // needed to decode the unwind information.
- addr += 4;
- if (!elf_memory_->Read32(addr, &data)) {
- status_ = ARM_STATUS_READ_FAILED;
- status_address_ = addr;
- return false;
- }
- num_table_words = (data >> 24) & 0xff;
- data_.push_back((data >> 16) & 0xff);
- data_.push_back((data >> 8) & 0xff);
- data_.push_back(data & 0xff);
- addr += 4;
- }
- if (num_table_words > 5) {
- status_ = ARM_STATUS_MALFORMED;
- return false;
- }
- for (size_t i = 0; i < num_table_words; i++) {
- if (!elf_memory_->Read32(addr, &data)) {
- status_ = ARM_STATUS_READ_FAILED;
- status_address_ = addr;
- return false;
- }
- data_.push_back((data >> 24) & 0xff);
- data_.push_back((data >> 16) & 0xff);
- data_.push_back((data >> 8) & 0xff);
- data_.push_back(data & 0xff);
- addr += 4;
- }
- if (data_.back() != ARM_OP_FINISH) {
- // If this didn't end with a finish op, add one.
- data_.push_back(ARM_OP_FINISH);
- }
- if (log_type_ == ARM_LOG_FULL) {
- LogRawData();
- }
- return true;
- }
- inline bool ArmExidx::GetByte(uint8_t* byte) {
- if (data_.empty()) {
- status_ = ARM_STATUS_TRUNCATED;
- return false;
- }
- *byte = data_.front();
- data_.pop_front();
- return true;
- }
- inline bool ArmExidx::DecodePrefix_10_00(uint8_t byte) {
- CHECK((byte >> 4) == 0x8);
- uint16_t registers = (byte & 0xf) << 8;
- if (!GetByte(&byte)) {
- return false;
- }
- registers |= byte;
- if (registers == 0) {
- // 10000000 00000000: Refuse to unwind
- if (log_type_ != ARM_LOG_NONE) {
- log(log_indent_, "Refuse to unwind");
- }
- status_ = ARM_STATUS_NO_UNWIND;
- return false;
- }
- // 1000iiii iiiiiiii: Pop up to 12 integer registers under masks {r15-r12}, {r11-r4}
- registers <<= 4;
- if (log_type_ != ARM_LOG_NONE) {
- if (log_type_ == ARM_LOG_FULL) {
- bool add_comma = false;
- std::string msg = "pop {";
- for (size_t reg = 4; reg < 16; reg++) {
- if (registers & (1 << reg)) {
- if (add_comma) {
- msg += ", ";
- }
- msg += android::base::StringPrintf("r%zu", reg);
- add_comma = true;
- }
- }
- log(log_indent_, "%s}", msg.c_str());
- } else {
- uint32_t cfa_offset = __builtin_popcount(registers) * 4;
- log_cfa_offset_ += cfa_offset;
- for (size_t reg = 4; reg < 16; reg++) {
- if (registers & (1 << reg)) {
- log_regs_[reg] = cfa_offset;
- cfa_offset -= 4;
- }
- }
- }
- if (log_skip_execution_) {
- return true;
- }
- }
- for (size_t reg = 4; reg < 16; reg++) {
- if (registers & (1 << reg)) {
- if (!process_memory_->Read32(cfa_, &(*regs_)[reg])) {
- status_ = ARM_STATUS_READ_FAILED;
- status_address_ = cfa_;
- return false;
- }
- cfa_ += 4;
- }
- }
- // If the sp register is modified, change the cfa value.
- if (registers & (1 << ARM_REG_SP)) {
- cfa_ = (*regs_)[ARM_REG_SP];
- }
- // Indicate if the pc register was set.
- if (registers & (1 << ARM_REG_PC)) {
- pc_set_ = true;
- }
- return true;
- }
- inline bool ArmExidx::DecodePrefix_10_01(uint8_t byte) {
- CHECK((byte >> 4) == 0x9);
- uint8_t bits = byte & 0xf;
- if (bits == 13 || bits == 15) {
- // 10011101: Reserved as prefix for ARM register to register moves
- // 10011111: Reserved as prefix for Intel Wireless MMX register to register moves
- if (log_type_ != ARM_LOG_NONE) {
- log(log_indent_, "[Reserved]");
- }
- status_ = ARM_STATUS_RESERVED;
- return false;
- }
- // 1001nnnn: Set vsp = r[nnnn] (nnnn != 13, 15)
- if (log_type_ != ARM_LOG_NONE) {
- if (log_type_ == ARM_LOG_FULL) {
- log(log_indent_, "vsp = r%d", bits);
- } else {
- log_regs_[LOG_CFA_REG] = bits;
- }
- if (log_skip_execution_) {
- return true;
- }
- }
- // It is impossible for bits to be larger than the total number of
- // arm registers, so don't bother checking if bits is a valid register.
- cfa_ = (*regs_)[bits];
- return true;
- }
- inline bool ArmExidx::DecodePrefix_10_10(uint8_t byte) {
- CHECK((byte >> 4) == 0xa);
- // 10100nnn: Pop r4-r[4+nnn]
- // 10101nnn: Pop r4-r[4+nnn], r14
- if (log_type_ != ARM_LOG_NONE) {
- uint8_t end_reg = byte & 0x7;
- if (log_type_ == ARM_LOG_FULL) {
- std::string msg = "pop {r4";
- if (end_reg) {
- msg += android::base::StringPrintf("-r%d", 4 + end_reg);
- }
- if (byte & 0x8) {
- log(log_indent_, "%s, r14}", msg.c_str());
- } else {
- log(log_indent_, "%s}", msg.c_str());
- }
- } else {
- end_reg += 4;
- uint32_t cfa_offset = (end_reg - 3) * 4;
- if (byte & 0x8) {
- cfa_offset += 4;
- }
- log_cfa_offset_ += cfa_offset;
- for (uint8_t reg = 4; reg <= end_reg; reg++) {
- log_regs_[reg] = cfa_offset;
- cfa_offset -= 4;
- }
- if (byte & 0x8) {
- log_regs_[14] = cfa_offset;
- }
- }
- if (log_skip_execution_) {
- return true;
- }
- }
- for (size_t i = 4; i <= 4 + (byte & 0x7); i++) {
- if (!process_memory_->Read32(cfa_, &(*regs_)[i])) {
- status_ = ARM_STATUS_READ_FAILED;
- status_address_ = cfa_;
- return false;
- }
- cfa_ += 4;
- }
- if (byte & 0x8) {
- if (!process_memory_->Read32(cfa_, &(*regs_)[ARM_REG_R14])) {
- status_ = ARM_STATUS_READ_FAILED;
- status_address_ = cfa_;
- return false;
- }
- cfa_ += 4;
- }
- return true;
- }
- inline bool ArmExidx::DecodePrefix_10_11_0000() {
- // 10110000: Finish
- if (log_type_ != ARM_LOG_NONE) {
- if (log_type_ == ARM_LOG_FULL) {
- log(log_indent_, "finish");
- }
- if (log_skip_execution_) {
- status_ = ARM_STATUS_FINISH;
- return false;
- }
- }
- status_ = ARM_STATUS_FINISH;
- return false;
- }
- inline bool ArmExidx::DecodePrefix_10_11_0001() {
- uint8_t byte;
- if (!GetByte(&byte)) {
- return false;
- }
- if (byte == 0) {
- // 10110001 00000000: Spare
- if (log_type_ != ARM_LOG_NONE) {
- log(log_indent_, "Spare");
- }
- status_ = ARM_STATUS_SPARE;
- return false;
- }
- if (byte >> 4) {
- // 10110001 xxxxyyyy: Spare (xxxx != 0000)
- if (log_type_ != ARM_LOG_NONE) {
- log(log_indent_, "Spare");
- }
- status_ = ARM_STATUS_SPARE;
- return false;
- }
- // 10110001 0000iiii: Pop integer registers under mask {r3, r2, r1, r0}
- if (log_type_ != ARM_LOG_NONE) {
- if (log_type_ == ARM_LOG_FULL) {
- bool add_comma = false;
- std::string msg = "pop {";
- for (size_t i = 0; i < 4; i++) {
- if (byte & (1 << i)) {
- if (add_comma) {
- msg += ", ";
- }
- msg += android::base::StringPrintf("r%zu", i);
- add_comma = true;
- }
- }
- log(log_indent_, "%s}", msg.c_str());
- } else {
- byte &= 0xf;
- uint32_t cfa_offset = __builtin_popcount(byte) * 4;
- log_cfa_offset_ += cfa_offset;
- for (size_t reg = 0; reg < 4; reg++) {
- if (byte & (1 << reg)) {
- log_regs_[reg] = cfa_offset;
- cfa_offset -= 4;
- }
- }
- }
- if (log_skip_execution_) {
- return true;
- }
- }
- for (size_t reg = 0; reg < 4; reg++) {
- if (byte & (1 << reg)) {
- if (!process_memory_->Read32(cfa_, &(*regs_)[reg])) {
- status_ = ARM_STATUS_READ_FAILED;
- status_address_ = cfa_;
- return false;
- }
- cfa_ += 4;
- }
- }
- return true;
- }
- inline void ArmExidx::AdjustRegisters(int32_t offset) {
- for (auto& entry : log_regs_) {
- if (entry.first >= LOG_CFA_REG) {
- break;
- }
- entry.second += offset;
- }
- }
- inline bool ArmExidx::DecodePrefix_10_11_0010() {
- // 10110010 uleb128: vsp = vsp + 0x204 + (uleb128 << 2)
- uint32_t result = 0;
- uint32_t shift = 0;
- uint8_t byte;
- do {
- if (!GetByte(&byte)) {
- return false;
- }
- result |= (byte & 0x7f) << shift;
- shift += 7;
- } while (byte & 0x80);
- result <<= 2;
- if (log_type_ != ARM_LOG_NONE) {
- int32_t cfa_offset = 0x204 + result;
- if (log_type_ == ARM_LOG_FULL) {
- log(log_indent_, "vsp = vsp + %d", cfa_offset);
- } else {
- log_cfa_offset_ += cfa_offset;
- }
- AdjustRegisters(cfa_offset);
- if (log_skip_execution_) {
- return true;
- }
- }
- cfa_ += 0x204 + result;
- return true;
- }
- inline bool ArmExidx::DecodePrefix_10_11_0011() {
- // 10110011 sssscccc: Pop VFP double precision registers D[ssss]-D[ssss+cccc] by FSTMFDX
- uint8_t byte;
- if (!GetByte(&byte)) {
- return false;
- }
- if (log_type_ != ARM_LOG_NONE) {
- uint8_t start_reg = byte >> 4;
- uint8_t end_reg = start_reg + (byte & 0xf);
- if (log_type_ == ARM_LOG_FULL) {
- std::string msg = android::base::StringPrintf("pop {d%d", start_reg);
- if (end_reg) {
- msg += android::base::StringPrintf("-d%d", end_reg);
- }
- log(log_indent_, "%s}", msg.c_str());
- } else {
- log(log_indent_, "Unsupported DX register display");
- }
- if (log_skip_execution_) {
- return true;
- }
- }
- cfa_ += (byte & 0xf) * 8 + 12;
- return true;
- }
- inline bool ArmExidx::DecodePrefix_10_11_01nn() {
- // 101101nn: Spare
- if (log_type_ != ARM_LOG_NONE) {
- log(log_indent_, "Spare");
- }
- status_ = ARM_STATUS_SPARE;
- return false;
- }
- inline bool ArmExidx::DecodePrefix_10_11_1nnn(uint8_t byte) {
- CHECK((byte & ~0x07) == 0xb8);
- // 10111nnn: Pop VFP double-precision registers D[8]-D[8+nnn] by FSTMFDX
- if (log_type_ != ARM_LOG_NONE) {
- if (log_type_ == ARM_LOG_FULL) {
- uint8_t last_reg = (byte & 0x7);
- std::string msg = "pop {d8";
- if (last_reg) {
- msg += android::base::StringPrintf("-d%d", last_reg + 8);
- }
- log(log_indent_, "%s}", msg.c_str());
- } else {
- log(log_indent_, "Unsupported DX register display");
- }
- if (log_skip_execution_) {
- return true;
- }
- }
- // Only update the cfa.
- cfa_ += (byte & 0x7) * 8 + 12;
- return true;
- }
- inline bool ArmExidx::DecodePrefix_10(uint8_t byte) {
- CHECK((byte >> 6) == 0x2);
- switch ((byte >> 4) & 0x3) {
- case 0:
- return DecodePrefix_10_00(byte);
- case 1:
- return DecodePrefix_10_01(byte);
- case 2:
- return DecodePrefix_10_10(byte);
- default:
- switch (byte & 0xf) {
- case 0:
- return DecodePrefix_10_11_0000();
- case 1:
- return DecodePrefix_10_11_0001();
- case 2:
- return DecodePrefix_10_11_0010();
- case 3:
- return DecodePrefix_10_11_0011();
- default:
- if (byte & 0x8) {
- return DecodePrefix_10_11_1nnn(byte);
- } else {
- return DecodePrefix_10_11_01nn();
- }
- }
- }
- }
- inline bool ArmExidx::DecodePrefix_11_000(uint8_t byte) {
- CHECK((byte & ~0x07) == 0xc0);
- uint8_t bits = byte & 0x7;
- if (bits == 6) {
- if (!GetByte(&byte)) {
- return false;
- }
- // 11000110 sssscccc: Intel Wireless MMX pop wR[ssss]-wR[ssss+cccc]
- if (log_type_ != ARM_LOG_NONE) {
- if (log_type_ == ARM_LOG_FULL) {
- uint8_t start_reg = byte >> 4;
- std::string msg = android::base::StringPrintf("pop {wR%d", start_reg);
- uint8_t end_reg = byte & 0xf;
- if (end_reg) {
- msg += android::base::StringPrintf("-wR%d", start_reg + end_reg);
- }
- log(log_indent_, "%s}", msg.c_str());
- } else {
- log(log_indent_, "Unsupported wRX register display");
- }
- if (log_skip_execution_) {
- return true;
- }
- }
- // Only update the cfa.
- cfa_ += (byte & 0xf) * 8 + 8;
- } else if (bits == 7) {
- if (!GetByte(&byte)) {
- return false;
- }
- if (byte == 0) {
- // 11000111 00000000: Spare
- if (log_type_ != ARM_LOG_NONE) {
- log(log_indent_, "Spare");
- }
- status_ = ARM_STATUS_SPARE;
- return false;
- } else if ((byte >> 4) == 0) {
- // 11000111 0000iiii: Intel Wireless MMX pop wCGR registers {wCGR0,1,2,3}
- if (log_type_ != ARM_LOG_NONE) {
- if (log_type_ == ARM_LOG_FULL) {
- bool add_comma = false;
- std::string msg = "pop {";
- for (size_t i = 0; i < 4; i++) {
- if (byte & (1 << i)) {
- if (add_comma) {
- msg += ", ";
- }
- msg += android::base::StringPrintf("wCGR%zu", i);
- add_comma = true;
- }
- }
- log(log_indent_, "%s}", msg.c_str());
- } else {
- log(log_indent_, "Unsupported wCGR register display");
- }
- if (log_skip_execution_) {
- return true;
- }
- }
- // Only update the cfa.
- cfa_ += __builtin_popcount(byte) * 4;
- } else {
- // 11000111 xxxxyyyy: Spare (xxxx != 0000)
- if (log_type_ != ARM_LOG_NONE) {
- log(log_indent_, "Spare");
- }
- status_ = ARM_STATUS_SPARE;
- return false;
- }
- } else {
- // 11000nnn: Intel Wireless MMX pop wR[10]-wR[10+nnn] (nnn != 6, 7)
- if (log_type_ != ARM_LOG_NONE) {
- if (log_type_ == ARM_LOG_FULL) {
- std::string msg = "pop {wR10";
- uint8_t nnn = byte & 0x7;
- if (nnn) {
- msg += android::base::StringPrintf("-wR%d", 10 + nnn);
- }
- log(log_indent_, "%s}", msg.c_str());
- } else {
- log(log_indent_, "Unsupported wRX register display");
- }
- if (log_skip_execution_) {
- return true;
- }
- }
- // Only update the cfa.
- cfa_ += (byte & 0x7) * 8 + 8;
- }
- return true;
- }
- inline bool ArmExidx::DecodePrefix_11_001(uint8_t byte) {
- CHECK((byte & ~0x07) == 0xc8);
- uint8_t bits = byte & 0x7;
- if (bits == 0) {
- // 11001000 sssscccc: Pop VFP double precision registers D[16+ssss]-D[16+ssss+cccc] by VPUSH
- if (!GetByte(&byte)) {
- return false;
- }
- if (log_type_ != ARM_LOG_NONE) {
- if (log_type_ == ARM_LOG_FULL) {
- uint8_t start_reg = byte >> 4;
- std::string msg = android::base::StringPrintf("pop {d%d", 16 + start_reg);
- uint8_t end_reg = byte & 0xf;
- if (end_reg) {
- msg += android::base::StringPrintf("-d%d", 16 + start_reg + end_reg);
- }
- log(log_indent_, "%s}", msg.c_str());
- } else {
- log(log_indent_, "Unsupported DX register display");
- }
- if (log_skip_execution_) {
- return true;
- }
- }
- // Only update the cfa.
- cfa_ += (byte & 0xf) * 8 + 8;
- } else if (bits == 1) {
- // 11001001 sssscccc: Pop VFP double precision registers D[ssss]-D[ssss+cccc] by VPUSH
- if (!GetByte(&byte)) {
- return false;
- }
- if (log_type_ != ARM_LOG_NONE) {
- if (log_type_ == ARM_LOG_FULL) {
- uint8_t start_reg = byte >> 4;
- std::string msg = android::base::StringPrintf("pop {d%d", start_reg);
- uint8_t end_reg = byte & 0xf;
- if (end_reg) {
- msg += android::base::StringPrintf("-d%d", start_reg + end_reg);
- }
- log(log_indent_, "%s}", msg.c_str());
- } else {
- log(log_indent_, "Unsupported DX register display");
- }
- if (log_skip_execution_) {
- return true;
- }
- }
- // Only update the cfa.
- cfa_ += (byte & 0xf) * 8 + 8;
- } else {
- // 11001yyy: Spare (yyy != 000, 001)
- if (log_type_ != ARM_LOG_NONE) {
- log(log_indent_, "Spare");
- }
- status_ = ARM_STATUS_SPARE;
- return false;
- }
- return true;
- }
- inline bool ArmExidx::DecodePrefix_11_010(uint8_t byte) {
- CHECK((byte & ~0x07) == 0xd0);
- // 11010nnn: Pop VFP double precision registers D[8]-D[8+nnn] by VPUSH
- if (log_type_ != ARM_LOG_NONE) {
- if (log_type_ == ARM_LOG_FULL) {
- std::string msg = "pop {d8";
- uint8_t end_reg = byte & 0x7;
- if (end_reg) {
- msg += android::base::StringPrintf("-d%d", 8 + end_reg);
- }
- log(log_indent_, "%s}", msg.c_str());
- } else {
- log(log_indent_, "Unsupported DX register display");
- }
- if (log_skip_execution_) {
- return true;
- }
- }
- cfa_ += (byte & 0x7) * 8 + 8;
- return true;
- }
- inline bool ArmExidx::DecodePrefix_11(uint8_t byte) {
- CHECK((byte >> 6) == 0x3);
- switch ((byte >> 3) & 0x7) {
- case 0:
- return DecodePrefix_11_000(byte);
- case 1:
- return DecodePrefix_11_001(byte);
- case 2:
- return DecodePrefix_11_010(byte);
- default:
- // 11xxxyyy: Spare (xxx != 000, 001, 010)
- if (log_type_ != ARM_LOG_NONE) {
- log(log_indent_, "Spare");
- }
- status_ = ARM_STATUS_SPARE;
- return false;
- }
- }
- bool ArmExidx::Decode() {
- status_ = ARM_STATUS_NONE;
- uint8_t byte;
- if (!GetByte(&byte)) {
- return false;
- }
- switch (byte >> 6) {
- case 0:
- // 00xxxxxx: vsp = vsp + (xxxxxxx << 2) + 4
- if (log_type_ != ARM_LOG_NONE) {
- int32_t cfa_offset = ((byte & 0x3f) << 2) + 4;
- if (log_type_ == ARM_LOG_FULL) {
- log(log_indent_, "vsp = vsp + %d", cfa_offset);
- } else {
- log_cfa_offset_ += cfa_offset;
- }
- AdjustRegisters(cfa_offset);
- if (log_skip_execution_) {
- break;
- }
- }
- cfa_ += ((byte & 0x3f) << 2) + 4;
- break;
- case 1:
- // 01xxxxxx: vsp = vsp - (xxxxxxx << 2) + 4
- if (log_type_ != ARM_LOG_NONE) {
- uint32_t cfa_offset = ((byte & 0x3f) << 2) + 4;
- if (log_type_ == ARM_LOG_FULL) {
- log(log_indent_, "vsp = vsp - %d", cfa_offset);
- } else {
- log_cfa_offset_ -= cfa_offset;
- }
- AdjustRegisters(-cfa_offset);
- if (log_skip_execution_) {
- break;
- }
- }
- cfa_ -= ((byte & 0x3f) << 2) + 4;
- break;
- case 2:
- return DecodePrefix_10(byte);
- default:
- return DecodePrefix_11(byte);
- }
- return true;
- }
- bool ArmExidx::Eval() {
- pc_set_ = false;
- while (Decode());
- return status_ == ARM_STATUS_FINISH;
- }
- void ArmExidx::LogByReg() {
- if (log_type_ != ARM_LOG_BY_REG) {
- return;
- }
- uint8_t cfa_reg;
- if (log_regs_.count(LOG_CFA_REG) == 0) {
- cfa_reg = 13;
- } else {
- cfa_reg = log_regs_[LOG_CFA_REG];
- }
- if (log_cfa_offset_ != 0) {
- char sign = (log_cfa_offset_ > 0) ? '+' : '-';
- log(log_indent_, "cfa = r%zu %c %d", cfa_reg, sign, abs(log_cfa_offset_));
- } else {
- log(log_indent_, "cfa = r%zu", cfa_reg);
- }
- for (const auto& entry : log_regs_) {
- if (entry.first >= LOG_CFA_REG) {
- break;
- }
- if (entry.second == 0) {
- log(log_indent_, "r%zu = [cfa]", entry.first);
- } else {
- char sign = (entry.second > 0) ? '-' : '+';
- log(log_indent_, "r%zu = [cfa %c %d]", entry.first, sign, abs(entry.second));
- }
- }
- }
- } // namespace unwindstack
|