|  | /* | 
|  | * Copyright (C) 2017 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 <vector> | 
|  |  | 
|  | #include <android-base/stringprintf.h> | 
|  |  | 
|  | #include <unwindstack/DwarfMemory.h> | 
|  | #include <unwindstack/Log.h> | 
|  | #include <unwindstack/Memory.h> | 
|  | #include <unwindstack/Regs.h> | 
|  |  | 
|  | #include "DwarfError.h" | 
|  | #include "DwarfOp.h" | 
|  |  | 
|  | namespace unwindstack { | 
|  |  | 
|  | template <typename AddressType> | 
|  | constexpr typename DwarfOp<AddressType>::OpCallback DwarfOp<AddressType>::kCallbackTable[256]; | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::Eval(uint64_t start, uint64_t end, uint8_t dwarf_version) { | 
|  | uint32_t iterations = 0; | 
|  | is_register_ = false; | 
|  | stack_.clear(); | 
|  | memory_->set_cur_offset(start); | 
|  | while (memory_->cur_offset() < end) { | 
|  | if (!Decode(dwarf_version)) { | 
|  | return false; | 
|  | } | 
|  | // To protect against a branch that creates an infinite loop, | 
|  | // terminate if the number of iterations gets too high. | 
|  | if (iterations++ == 1000) { | 
|  | last_error_ = DWARF_ERROR_TOO_MANY_ITERATIONS; | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::Decode(uint8_t dwarf_version) { | 
|  | last_error_ = DWARF_ERROR_NONE; | 
|  | if (!memory_->ReadBytes(&cur_op_, 1)) { | 
|  | last_error_ = DWARF_ERROR_MEMORY_INVALID; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | const auto* op = &kCallbackTable[cur_op_]; | 
|  | const auto handle_func = op->handle_func; | 
|  | if (handle_func == nullptr) { | 
|  | last_error_ = DWARF_ERROR_ILLEGAL_VALUE; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Check for an unsupported opcode. | 
|  | if (dwarf_version < op->supported_version) { | 
|  | last_error_ = DWARF_ERROR_ILLEGAL_VALUE; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Make sure that the required number of stack elements is available. | 
|  | if (stack_.size() < op->num_required_stack_values) { | 
|  | last_error_ = DWARF_ERROR_STACK_INDEX_NOT_VALID; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | operands_.clear(); | 
|  | for (size_t i = 0; i < op->num_operands; i++) { | 
|  | uint64_t value; | 
|  | if (!memory_->ReadEncodedValue<AddressType>(op->operands[i], &value)) { | 
|  | last_error_ = DWARF_ERROR_MEMORY_INVALID; | 
|  | return false; | 
|  | } | 
|  | operands_.push_back(value); | 
|  | } | 
|  | return (this->*handle_func)(); | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | void DwarfOp<AddressType>::GetLogInfo(uint64_t start, uint64_t end, | 
|  | std::vector<std::string>* lines) { | 
|  | memory_->set_cur_offset(start); | 
|  | while (memory_->cur_offset() < end) { | 
|  | uint8_t cur_op; | 
|  | if (!memory_->ReadBytes(&cur_op, 1)) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | std::string raw_string(android::base::StringPrintf("Raw Data: 0x%02x", cur_op)); | 
|  | std::string log_string; | 
|  | const auto* op = &kCallbackTable[cur_op]; | 
|  | if (op->handle_func == nullptr) { | 
|  | log_string = "Illegal"; | 
|  | } else { | 
|  | log_string = op->name; | 
|  | uint64_t start_offset = memory_->cur_offset(); | 
|  | for (size_t i = 0; i < op->num_operands; i++) { | 
|  | uint64_t value; | 
|  | if (!memory_->ReadEncodedValue<AddressType>(op->operands[i], &value)) { | 
|  | return; | 
|  | } | 
|  | log_string += ' ' + std::to_string(value); | 
|  | } | 
|  | uint64_t end_offset = memory_->cur_offset(); | 
|  |  | 
|  | memory_->set_cur_offset(start_offset); | 
|  | for (size_t i = start_offset; i < end_offset; i++) { | 
|  | uint8_t byte; | 
|  | if (!memory_->ReadBytes(&byte, 1)) { | 
|  | return; | 
|  | } | 
|  | raw_string += android::base::StringPrintf(" 0x%02x", byte); | 
|  | } | 
|  | memory_->set_cur_offset(end_offset); | 
|  | } | 
|  | lines->push_back(std::move(log_string)); | 
|  | lines->push_back(std::move(raw_string)); | 
|  | } | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_deref() { | 
|  | // Read the address and dereference it. | 
|  | AddressType addr = StackPop(); | 
|  | AddressType value; | 
|  | if (!regular_memory()->Read(addr, &value, sizeof(value))) { | 
|  | last_error_ = DWARF_ERROR_MEMORY_INVALID; | 
|  | return false; | 
|  | } | 
|  | stack_.push_front(value); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_deref_size() { | 
|  | AddressType bytes_to_read = OperandAt(0); | 
|  | if (bytes_to_read > sizeof(AddressType) || bytes_to_read == 0) { | 
|  | last_error_ = DWARF_ERROR_ILLEGAL_VALUE; | 
|  | return false; | 
|  | } | 
|  | // Read the address and dereference it. | 
|  | AddressType addr = StackPop(); | 
|  | AddressType value = 0; | 
|  | if (!regular_memory()->Read(addr, &value, bytes_to_read)) { | 
|  | last_error_ = DWARF_ERROR_MEMORY_INVALID; | 
|  | return false; | 
|  | } | 
|  | stack_.push_front(value); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_push() { | 
|  | // Push all of the operands. | 
|  | for (auto operand : operands_) { | 
|  | stack_.push_front(operand); | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_dup() { | 
|  | stack_.push_front(StackAt(0)); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_drop() { | 
|  | StackPop(); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_over() { | 
|  | stack_.push_front(StackAt(1)); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_pick() { | 
|  | AddressType index = OperandAt(0); | 
|  | if (index > StackSize()) { | 
|  | last_error_ = DWARF_ERROR_STACK_INDEX_NOT_VALID; | 
|  | return false; | 
|  | } | 
|  | stack_.push_front(StackAt(index)); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_swap() { | 
|  | AddressType old_value = stack_[0]; | 
|  | stack_[0] = stack_[1]; | 
|  | stack_[1] = old_value; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_rot() { | 
|  | AddressType top = stack_[0]; | 
|  | stack_[0] = stack_[1]; | 
|  | stack_[1] = stack_[2]; | 
|  | stack_[2] = top; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_abs() { | 
|  | SignedType signed_value = static_cast<SignedType>(stack_[0]); | 
|  | if (signed_value < 0) { | 
|  | signed_value = -signed_value; | 
|  | } | 
|  | stack_[0] = static_cast<AddressType>(signed_value); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_and() { | 
|  | AddressType top = StackPop(); | 
|  | stack_[0] &= top; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_div() { | 
|  | AddressType top = StackPop(); | 
|  | if (top == 0) { | 
|  | last_error_ = DWARF_ERROR_ILLEGAL_VALUE; | 
|  | return false; | 
|  | } | 
|  | SignedType signed_divisor = static_cast<SignedType>(top); | 
|  | SignedType signed_dividend = static_cast<SignedType>(stack_[0]); | 
|  | stack_[0] = static_cast<AddressType>(signed_dividend / signed_divisor); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_minus() { | 
|  | AddressType top = StackPop(); | 
|  | stack_[0] -= top; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_mod() { | 
|  | AddressType top = StackPop(); | 
|  | if (top == 0) { | 
|  | last_error_ = DWARF_ERROR_ILLEGAL_VALUE; | 
|  | return false; | 
|  | } | 
|  | stack_[0] %= top; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_mul() { | 
|  | AddressType top = StackPop(); | 
|  | stack_[0] *= top; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_neg() { | 
|  | SignedType signed_value = static_cast<SignedType>(stack_[0]); | 
|  | stack_[0] = static_cast<AddressType>(-signed_value); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_not() { | 
|  | stack_[0] = ~stack_[0]; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_or() { | 
|  | AddressType top = StackPop(); | 
|  | stack_[0] |= top; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_plus() { | 
|  | AddressType top = StackPop(); | 
|  | stack_[0] += top; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_plus_uconst() { | 
|  | stack_[0] += OperandAt(0); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_shl() { | 
|  | AddressType top = StackPop(); | 
|  | stack_[0] <<= top; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_shr() { | 
|  | AddressType top = StackPop(); | 
|  | stack_[0] >>= top; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_shra() { | 
|  | AddressType top = StackPop(); | 
|  | SignedType signed_value = static_cast<SignedType>(stack_[0]) >> top; | 
|  | stack_[0] = static_cast<AddressType>(signed_value); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_xor() { | 
|  | AddressType top = StackPop(); | 
|  | stack_[0] ^= top; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_bra() { | 
|  | // Requires one stack element. | 
|  | AddressType top = StackPop(); | 
|  | int16_t offset = static_cast<int16_t>(OperandAt(0)); | 
|  | uint64_t cur_offset; | 
|  | if (top != 0) { | 
|  | cur_offset = memory_->cur_offset() + offset; | 
|  | } else { | 
|  | cur_offset = memory_->cur_offset() - offset; | 
|  | } | 
|  | memory_->set_cur_offset(cur_offset); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_eq() { | 
|  | AddressType top = StackPop(); | 
|  | stack_[0] = bool_to_dwarf_bool(stack_[0] == top); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_ge() { | 
|  | AddressType top = StackPop(); | 
|  | stack_[0] = bool_to_dwarf_bool(stack_[0] >= top); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_gt() { | 
|  | AddressType top = StackPop(); | 
|  | stack_[0] = bool_to_dwarf_bool(stack_[0] > top); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_le() { | 
|  | AddressType top = StackPop(); | 
|  | stack_[0] = bool_to_dwarf_bool(stack_[0] <= top); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_lt() { | 
|  | AddressType top = StackPop(); | 
|  | stack_[0] = bool_to_dwarf_bool(stack_[0] < top); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_ne() { | 
|  | AddressType top = StackPop(); | 
|  | stack_[0] = bool_to_dwarf_bool(stack_[0] != top); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_skip() { | 
|  | int16_t offset = static_cast<int16_t>(OperandAt(0)); | 
|  | uint64_t cur_offset = memory_->cur_offset() + offset; | 
|  | memory_->set_cur_offset(cur_offset); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_lit() { | 
|  | stack_.push_front(cur_op() - 0x30); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_reg() { | 
|  | is_register_ = true; | 
|  | stack_.push_front(cur_op() - 0x50); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_regx() { | 
|  | is_register_ = true; | 
|  | stack_.push_front(OperandAt(0)); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // It's not clear for breg/bregx, if this op should read the current | 
|  | // value of the register, or where we think that register is located. | 
|  | // For simplicity, the code will read the value before doing the unwind. | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_breg() { | 
|  | uint16_t reg = cur_op() - 0x70; | 
|  | if (reg >= regs_->total_regs()) { | 
|  | last_error_ = DWARF_ERROR_ILLEGAL_VALUE; | 
|  | return false; | 
|  | } | 
|  | stack_.push_front((*regs_)[reg] + OperandAt(0)); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_bregx() { | 
|  | AddressType reg = OperandAt(0); | 
|  | if (reg >= regs_->total_regs()) { | 
|  | last_error_ = DWARF_ERROR_ILLEGAL_VALUE; | 
|  | return false; | 
|  | } | 
|  | stack_.push_front((*regs_)[reg] + OperandAt(1)); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_nop() { | 
|  | return true; | 
|  | } | 
|  |  | 
|  | template <typename AddressType> | 
|  | bool DwarfOp<AddressType>::op_not_implemented() { | 
|  | last_error_ = DWARF_ERROR_NOT_IMPLEMENTED; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Explicitly instantiate DwarfOp. | 
|  | template class DwarfOp<uint32_t>; | 
|  | template class DwarfOp<uint64_t>; | 
|  |  | 
|  | }  // namespace unwindstack |