Merge "Add DwarfOp support."

This commit is contained in:
Christopher Ferris 2017-04-04 20:53:43 +00:00 committed by Gerrit Code Review
commit 3f220aaa63
6 changed files with 3794 additions and 0 deletions

View file

@ -48,6 +48,7 @@ cc_defaults {
srcs: [
"ArmExidx.cpp",
"DwarfMemory.cpp",
"DwarfOp.cpp",
"Elf.cpp",
"ElfInterface.cpp",
"ElfInterfaceArm.cpp",
@ -89,6 +90,8 @@ cc_defaults {
"tests/ArmExidxDecodeTest.cpp",
"tests/ArmExidxExtractTest.cpp",
"tests/DwarfMemoryTest.cpp",
"tests/DwarfOpLogTest.cpp",
"tests/DwarfOpTest.cpp",
"tests/ElfInterfaceArmTest.cpp",
"tests/ElfInterfaceTest.cpp",
"tests/ElfTest.cpp",

View file

@ -0,0 +1,32 @@
/*
* 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.
*/
#ifndef _LIBUNWINDSTACK_DWARF_ERROR_H
#define _LIBUNWINDSTACK_DWARF_ERROR_H
#include <stdint.h>
enum DwarfError : uint8_t {
DWARF_ERROR_NONE,
DWARF_ERROR_MEMORY_INVALID,
DWARF_ERROR_ILLEGAL_VALUE,
DWARF_ERROR_ILLEGAL_STATE,
DWARF_ERROR_STACK_INDEX_NOT_VALID,
DWARF_ERROR_NOT_IMPLEMENTED,
DWARF_ERROR_TOO_MANY_ITERATIONS,
};
#endif // _LIBUNWINDSTACK_DWARF_ERROR_H

462
libunwindstack/DwarfOp.cpp Normal file
View file

@ -0,0 +1,462 @@
/*
* 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 "DwarfError.h"
#include "DwarfMemory.h"
#include "DwarfOp.h"
#include "Log.h"
#include "Memory.h"
#include "Regs.h"
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>;

1636
libunwindstack/DwarfOp.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,68 @@
/*
* 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 <ios>
#include <vector>
#include <gtest/gtest.h>
#include "DwarfError.h"
#include "DwarfMemory.h"
#include "DwarfOp.h"
#include "Log.h"
#include "Regs.h"
#include "MemoryFake.h"
template <typename TypeParam>
class DwarfOpLogTest : public ::testing::Test {
protected:
void SetUp() override {
op_memory_.Clear();
regular_memory_.Clear();
mem_.reset(new DwarfMemory(&op_memory_));
op_.reset(new DwarfOp<TypeParam>(mem_.get(), &regular_memory_));
}
MemoryFake op_memory_;
MemoryFake regular_memory_;
std::unique_ptr<DwarfMemory> mem_;
std::unique_ptr<DwarfOp<TypeParam>> op_;
};
TYPED_TEST_CASE_P(DwarfOpLogTest);
TYPED_TEST_P(DwarfOpLogTest, multiple_ops) {
// Multi operation opcodes.
std::vector<uint8_t> opcode_buffer = {
0x0a, 0x20, 0x10, 0x08, 0x03, 0x12, 0x27,
};
this->op_memory_.SetMemory(0, opcode_buffer);
std::vector<std::string> lines;
this->op_->GetLogInfo(0, opcode_buffer.size(), &lines);
std::vector<std::string> expected{
"DW_OP_const2u 4128", "Raw Data: 0x0a 0x20 0x10", "DW_OP_const1u 3", "Raw Data: 0x08 0x03",
"DW_OP_dup", "Raw Data: 0x12", "DW_OP_xor", "Raw Data: 0x27"};
ASSERT_EQ(expected, lines);
}
REGISTER_TYPED_TEST_CASE_P(DwarfOpLogTest, multiple_ops);
typedef ::testing::Types<uint32_t, uint64_t> DwarfOpLogTestTypes;
INSTANTIATE_TYPED_TEST_CASE_P(, DwarfOpLogTest, DwarfOpLogTestTypes);

File diff suppressed because it is too large Load diff