Add the Dwarf CFA handling.
Bug: 23762183 Test: Ran new unit tests. Change-Id: I31abac1238cc671b78a505da655fb6298be072b4
This commit is contained in:
parent
39aee46352
commit
8642fcbad2
7 changed files with 2837 additions and 0 deletions
|
|
@ -47,6 +47,7 @@ cc_defaults {
|
|||
|
||||
srcs: [
|
||||
"ArmExidx.cpp",
|
||||
"DwarfCfa.cpp",
|
||||
"DwarfMemory.cpp",
|
||||
"DwarfOp.cpp",
|
||||
"Elf.cpp",
|
||||
|
|
@ -92,6 +93,8 @@ cc_defaults {
|
|||
srcs: [
|
||||
"tests/ArmExidxDecodeTest.cpp",
|
||||
"tests/ArmExidxExtractTest.cpp",
|
||||
"tests/DwarfCfaLogTest.cpp",
|
||||
"tests/DwarfCfaTest.cpp",
|
||||
"tests/DwarfMemoryTest.cpp",
|
||||
"tests/DwarfOpLogTest.cpp",
|
||||
"tests/DwarfOpTest.cpp",
|
||||
|
|
|
|||
713
libunwindstack/DwarfCfa.cpp
Normal file
713
libunwindstack/DwarfCfa.cpp
Normal file
|
|
@ -0,0 +1,713 @@
|
|||
/*
|
||||
* 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 <inttypes.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include <android-base/stringprintf.h>
|
||||
|
||||
#include "DwarfCfa.h"
|
||||
#include "DwarfEncoding.h"
|
||||
#include "DwarfMemory.h"
|
||||
#include "DwarfOp.h"
|
||||
#include "DwarfStructs.h"
|
||||
#include "Log.h"
|
||||
|
||||
template <typename AddressType>
|
||||
constexpr typename DwarfCfa<AddressType>::process_func DwarfCfa<AddressType>::kCallbackTable[64];
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfCfa<AddressType>::GetLocationInfo(uint64_t pc, uint64_t start_offset, uint64_t end_offset,
|
||||
dwarf_loc_regs_t* loc_regs) {
|
||||
if (cie_loc_regs_ != nullptr) {
|
||||
for (const auto& entry : *cie_loc_regs_) {
|
||||
(*loc_regs)[entry.first] = entry.second;
|
||||
}
|
||||
}
|
||||
last_error_ = DWARF_ERROR_NONE;
|
||||
|
||||
memory_->set_cur_offset(start_offset);
|
||||
uint64_t cfa_offset;
|
||||
cur_pc_ = fde_->pc_start;
|
||||
while ((cfa_offset = memory_->cur_offset()) < end_offset && cur_pc_ <= pc) {
|
||||
operands_.clear();
|
||||
// Read the cfa information.
|
||||
uint8_t cfa_value;
|
||||
if (!memory_->ReadBytes(&cfa_value, 1)) {
|
||||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
uint8_t cfa_low = cfa_value & 0x3f;
|
||||
// Check the 2 high bits.
|
||||
switch (cfa_value >> 6) {
|
||||
case 1:
|
||||
cur_pc_ += cfa_low * fde_->cie->code_alignment_factor;
|
||||
break;
|
||||
case 2: {
|
||||
uint64_t offset;
|
||||
if (!memory_->ReadULEB128(&offset)) {
|
||||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
SignedType signed_offset =
|
||||
static_cast<SignedType>(offset) * fde_->cie->data_alignment_factor;
|
||||
(*loc_regs)[cfa_low] = {.type = DWARF_LOCATION_OFFSET,
|
||||
.values = {static_cast<uint64_t>(signed_offset)}};
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
if (cie_loc_regs_ == nullptr) {
|
||||
log(0, "restore while processing cie");
|
||||
last_error_ = DWARF_ERROR_ILLEGAL_STATE;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto reg_entry = cie_loc_regs_->find(cfa_low);
|
||||
if (reg_entry == cie_loc_regs_->end()) {
|
||||
loc_regs->erase(cfa_low);
|
||||
} else {
|
||||
(*loc_regs)[cfa_low] = reg_entry->second;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0: {
|
||||
const auto handle_func = DwarfCfa<AddressType>::kCallbackTable[cfa_low];
|
||||
if (handle_func == nullptr) {
|
||||
last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto cfa = &DwarfCfaInfo::kTable[cfa_low];
|
||||
for (size_t i = 0; i < cfa->num_operands; i++) {
|
||||
if (cfa->operands[i] == DW_EH_PE_block) {
|
||||
uint64_t block_length;
|
||||
if (!memory_->ReadULEB128(&block_length)) {
|
||||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
operands_.push_back(block_length);
|
||||
memory_->set_cur_offset(memory_->cur_offset() + block_length);
|
||||
continue;
|
||||
}
|
||||
uint64_t value;
|
||||
if (!memory_->ReadEncodedValue<AddressType>(cfa->operands[i], &value)) {
|
||||
last_error_ = DWARF_ERROR_MEMORY_INVALID;
|
||||
return false;
|
||||
}
|
||||
operands_.push_back(value);
|
||||
}
|
||||
|
||||
if (!(this->*handle_func)(loc_regs)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
std::string DwarfCfa<AddressType>::GetOperandString(uint8_t operand, uint64_t value,
|
||||
uint64_t* cur_pc) {
|
||||
std::string string;
|
||||
switch (operand) {
|
||||
case DwarfCfaInfo::DWARF_DISPLAY_REGISTER:
|
||||
string = " register(" + std::to_string(value) + ")";
|
||||
break;
|
||||
case DwarfCfaInfo::DWARF_DISPLAY_SIGNED_NUMBER:
|
||||
string += " " + std::to_string(static_cast<SignedType>(value));
|
||||
break;
|
||||
case DwarfCfaInfo::DWARF_DISPLAY_ADVANCE_LOC:
|
||||
*cur_pc += value;
|
||||
// Fall through to log the value.
|
||||
case DwarfCfaInfo::DWARF_DISPLAY_NUMBER:
|
||||
string += " " + std::to_string(value);
|
||||
break;
|
||||
case DwarfCfaInfo::DWARF_DISPLAY_SET_LOC:
|
||||
*cur_pc = value;
|
||||
// Fall through to log the value.
|
||||
case DwarfCfaInfo::DWARF_DISPLAY_ADDRESS:
|
||||
if (std::is_same<AddressType, uint32_t>::value) {
|
||||
string += android::base::StringPrintf(" 0x%" PRIx32, static_cast<uint32_t>(value));
|
||||
} else {
|
||||
string += android::base::StringPrintf(" 0x%" PRIx64, static_cast<uint64_t>(value));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
string = " unknown";
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfCfa<AddressType>::LogOffsetRegisterString(uint32_t indent, uint64_t cfa_offset,
|
||||
uint8_t reg) {
|
||||
uint64_t offset;
|
||||
if (!memory_->ReadULEB128(&offset)) {
|
||||
return false;
|
||||
}
|
||||
uint64_t end_offset = memory_->cur_offset();
|
||||
memory_->set_cur_offset(cfa_offset);
|
||||
|
||||
std::string raw_data = "Raw Data:";
|
||||
for (uint64_t i = cfa_offset; i < end_offset; i++) {
|
||||
uint8_t value;
|
||||
if (!memory_->ReadBytes(&value, 1)) {
|
||||
return false;
|
||||
}
|
||||
raw_data += android::base::StringPrintf(" 0x%02x", value);
|
||||
}
|
||||
log(indent, "DW_CFA_offset register(%d) %" PRId64, reg, offset);
|
||||
log(indent, "%s", raw_data.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfCfa<AddressType>::LogInstruction(uint32_t indent, uint64_t cfa_offset, uint8_t op,
|
||||
uint64_t* cur_pc) {
|
||||
const auto* cfa = &DwarfCfaInfo::kTable[op];
|
||||
if (cfa->name == nullptr) {
|
||||
log(indent, "Illegal");
|
||||
log(indent, "Raw Data: 0x%02x", op);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string log_string(cfa->name);
|
||||
std::vector<std::string> expression_lines;
|
||||
for (size_t i = 0; i < cfa->num_operands; i++) {
|
||||
if (cfa->operands[i] == DW_EH_PE_block) {
|
||||
// This is a Dwarf Expression.
|
||||
uint64_t end_offset;
|
||||
if (!memory_->ReadULEB128(&end_offset)) {
|
||||
return false;
|
||||
}
|
||||
log_string += " " + std::to_string(end_offset);
|
||||
end_offset += memory_->cur_offset();
|
||||
|
||||
DwarfOp<AddressType> op(memory_, nullptr);
|
||||
op.GetLogInfo(memory_->cur_offset(), end_offset, &expression_lines);
|
||||
memory_->set_cur_offset(end_offset);
|
||||
} else {
|
||||
uint64_t value;
|
||||
if (!memory_->ReadEncodedValue<AddressType>(cfa->operands[i], &value)) {
|
||||
return false;
|
||||
}
|
||||
log_string += GetOperandString(cfa->display_operands[i], value, cur_pc);
|
||||
}
|
||||
}
|
||||
log(indent, "%s", log_string.c_str());
|
||||
|
||||
// Get the raw bytes of the data.
|
||||
uint64_t end_offset = memory_->cur_offset();
|
||||
memory_->set_cur_offset(cfa_offset);
|
||||
std::string raw_data("Raw Data:");
|
||||
for (uint64_t i = 0; i < end_offset - cfa_offset; i++) {
|
||||
uint8_t value;
|
||||
if (!memory_->ReadBytes(&value, 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only show 10 raw bytes per line.
|
||||
if ((i % 10) == 0 && i != 0) {
|
||||
log(indent, "%s", raw_data.c_str());
|
||||
raw_data.clear();
|
||||
}
|
||||
if (raw_data.empty()) {
|
||||
raw_data = "Raw Data:";
|
||||
}
|
||||
raw_data += android::base::StringPrintf(" 0x%02x", value);
|
||||
}
|
||||
if (!raw_data.empty()) {
|
||||
log(indent, "%s", raw_data.c_str());
|
||||
}
|
||||
|
||||
// Log any of the expression data.
|
||||
for (const auto line : expression_lines) {
|
||||
log(indent + 1, "%s", line.c_str());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfCfa<AddressType>::Log(uint32_t indent, uint64_t pc, uint64_t load_bias,
|
||||
uint64_t start_offset, uint64_t end_offset) {
|
||||
memory_->set_cur_offset(start_offset);
|
||||
uint64_t cfa_offset;
|
||||
uint64_t cur_pc = fde_->pc_start;
|
||||
uint64_t old_pc = cur_pc;
|
||||
while ((cfa_offset = memory_->cur_offset()) < end_offset && cur_pc <= pc) {
|
||||
// Read the cfa information.
|
||||
uint8_t cfa_value;
|
||||
if (!memory_->ReadBytes(&cfa_value, 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check the 2 high bits.
|
||||
uint8_t cfa_low = cfa_value & 0x3f;
|
||||
switch (cfa_value >> 6) {
|
||||
case 0:
|
||||
if (!LogInstruction(indent, cfa_offset, cfa_low, &cur_pc)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
log(indent, "DW_CFA_advance_loc %d", cfa_low);
|
||||
log(indent, "Raw Data: 0x%02x", cfa_value);
|
||||
cur_pc += cfa_low * fde_->cie->code_alignment_factor;
|
||||
break;
|
||||
case 2:
|
||||
if (!LogOffsetRegisterString(indent, cfa_offset, cfa_low)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
log(indent, "DW_CFA_restore register(%d)", cfa_low);
|
||||
log(indent, "Raw Data: 0x%02x", cfa_value);
|
||||
break;
|
||||
}
|
||||
if (cur_pc != old_pc) {
|
||||
log(indent, "");
|
||||
log(indent, "PC 0x%" PRIx64, cur_pc + load_bias);
|
||||
}
|
||||
old_pc = cur_pc;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Static data.
|
||||
template <typename AddressType>
|
||||
bool DwarfCfa<AddressType>::cfa_nop(dwarf_loc_regs_t*) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfCfa<AddressType>::cfa_set_loc(dwarf_loc_regs_t*) {
|
||||
AddressType cur_pc = cur_pc_;
|
||||
AddressType new_pc = operands_[0];
|
||||
if (new_pc < cur_pc) {
|
||||
if (std::is_same<AddressType, uint32_t>::value) {
|
||||
log(0, "Warning: PC is moving backwards: old 0x%" PRIx32 " new 0x%" PRIx32, cur_pc, new_pc);
|
||||
} else {
|
||||
log(0, "Warning: PC is moving backwards: old 0x%" PRIx64 " new 0x%" PRIx64, cur_pc, new_pc);
|
||||
}
|
||||
}
|
||||
cur_pc_ = new_pc;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfCfa<AddressType>::cfa_advance_loc(dwarf_loc_regs_t*) {
|
||||
cur_pc_ += operands_[0] * fde_->cie->code_alignment_factor;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfCfa<AddressType>::cfa_offset(dwarf_loc_regs_t* loc_regs) {
|
||||
AddressType reg = operands_[0];
|
||||
(*loc_regs)[reg] = {.type = DWARF_LOCATION_OFFSET, .values = {operands_[1]}};
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfCfa<AddressType>::cfa_restore(dwarf_loc_regs_t* loc_regs) {
|
||||
AddressType reg = operands_[0];
|
||||
if (cie_loc_regs_ == nullptr) {
|
||||
log(0, "restore while processing cie");
|
||||
last_error_ = DWARF_ERROR_ILLEGAL_STATE;
|
||||
return false;
|
||||
}
|
||||
auto reg_entry = cie_loc_regs_->find(reg);
|
||||
if (reg_entry == cie_loc_regs_->end()) {
|
||||
loc_regs->erase(reg);
|
||||
} else {
|
||||
(*loc_regs)[reg] = reg_entry->second;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfCfa<AddressType>::cfa_undefined(dwarf_loc_regs_t* loc_regs) {
|
||||
AddressType reg = operands_[0];
|
||||
(*loc_regs)[reg] = {.type = DWARF_LOCATION_UNDEFINED};
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfCfa<AddressType>::cfa_same_value(dwarf_loc_regs_t* loc_regs) {
|
||||
AddressType reg = operands_[0];
|
||||
loc_regs->erase(reg);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfCfa<AddressType>::cfa_register(dwarf_loc_regs_t* loc_regs) {
|
||||
AddressType reg = operands_[0];
|
||||
AddressType reg_dst = operands_[1];
|
||||
(*loc_regs)[reg] = {.type = DWARF_LOCATION_REGISTER, .values = {reg_dst}};
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfCfa<AddressType>::cfa_remember_state(dwarf_loc_regs_t* loc_regs) {
|
||||
loc_reg_state_.push(*loc_regs);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfCfa<AddressType>::cfa_restore_state(dwarf_loc_regs_t* loc_regs) {
|
||||
if (loc_reg_state_.size() == 0) {
|
||||
log(0, "Warning: Attempt to restore without remember.");
|
||||
return true;
|
||||
}
|
||||
*loc_regs = loc_reg_state_.top();
|
||||
loc_reg_state_.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfCfa<AddressType>::cfa_def_cfa(dwarf_loc_regs_t* loc_regs) {
|
||||
(*loc_regs)[CFA_REG] = {.type = DWARF_LOCATION_REGISTER, .values = {operands_[0], operands_[1]}};
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfCfa<AddressType>::cfa_def_cfa_register(dwarf_loc_regs_t* loc_regs) {
|
||||
auto cfa_location = loc_regs->find(CFA_REG);
|
||||
if (cfa_location == loc_regs->end() || cfa_location->second.type != DWARF_LOCATION_REGISTER) {
|
||||
log(0, "Attempt to set new register, but cfa is not already set to a register.");
|
||||
last_error_ = DWARF_ERROR_ILLEGAL_STATE;
|
||||
return false;
|
||||
}
|
||||
|
||||
cfa_location->second.values[0] = operands_[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfCfa<AddressType>::cfa_def_cfa_offset(dwarf_loc_regs_t* loc_regs) {
|
||||
// Changing the offset if this is not a register is illegal.
|
||||
auto cfa_location = loc_regs->find(CFA_REG);
|
||||
if (cfa_location == loc_regs->end() || cfa_location->second.type != DWARF_LOCATION_REGISTER) {
|
||||
log(0, "Attempt to set offset, but cfa is not set to a register.");
|
||||
last_error_ = DWARF_ERROR_ILLEGAL_STATE;
|
||||
return false;
|
||||
}
|
||||
cfa_location->second.values[1] = operands_[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfCfa<AddressType>::cfa_def_cfa_expression(dwarf_loc_regs_t* loc_regs) {
|
||||
(*loc_regs)[CFA_REG] = {.type = DWARF_LOCATION_EXPRESSION,
|
||||
.values = {operands_[0], memory_->cur_offset()}};
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfCfa<AddressType>::cfa_expression(dwarf_loc_regs_t* loc_regs) {
|
||||
AddressType reg = operands_[0];
|
||||
(*loc_regs)[reg] = {.type = DWARF_LOCATION_EXPRESSION,
|
||||
.values = {operands_[1], memory_->cur_offset()}};
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfCfa<AddressType>::cfa_offset_extended_sf(dwarf_loc_regs_t* loc_regs) {
|
||||
AddressType reg = operands_[0];
|
||||
SignedType value = static_cast<SignedType>(operands_[1]) * fde_->cie->data_alignment_factor;
|
||||
(*loc_regs)[reg] = {.type = DWARF_LOCATION_OFFSET, .values = {static_cast<uint64_t>(value)}};
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfCfa<AddressType>::cfa_def_cfa_sf(dwarf_loc_regs_t* loc_regs) {
|
||||
SignedType offset = static_cast<SignedType>(operands_[1]) * fde_->cie->data_alignment_factor;
|
||||
(*loc_regs)[CFA_REG] = {.type = DWARF_LOCATION_REGISTER,
|
||||
.values = {operands_[0], static_cast<uint64_t>(offset)}};
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfCfa<AddressType>::cfa_def_cfa_offset_sf(dwarf_loc_regs_t* loc_regs) {
|
||||
// Changing the offset if this is not a register is illegal.
|
||||
auto cfa_location = loc_regs->find(CFA_REG);
|
||||
if (cfa_location == loc_regs->end() || cfa_location->second.type != DWARF_LOCATION_REGISTER) {
|
||||
log(0, "Attempt to set offset, but cfa is not set to a register.");
|
||||
last_error_ = DWARF_ERROR_ILLEGAL_STATE;
|
||||
return false;
|
||||
}
|
||||
SignedType offset = static_cast<SignedType>(operands_[0]) * fde_->cie->data_alignment_factor;
|
||||
cfa_location->second.values[1] = static_cast<uint64_t>(offset);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfCfa<AddressType>::cfa_val_offset(dwarf_loc_regs_t* loc_regs) {
|
||||
AddressType reg = operands_[0];
|
||||
SignedType offset = static_cast<SignedType>(operands_[1]) * fde_->cie->data_alignment_factor;
|
||||
(*loc_regs)[reg] = {.type = DWARF_LOCATION_VAL_OFFSET, .values = {static_cast<uint64_t>(offset)}};
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfCfa<AddressType>::cfa_val_offset_sf(dwarf_loc_regs_t* loc_regs) {
|
||||
AddressType reg = operands_[0];
|
||||
SignedType offset = static_cast<SignedType>(operands_[1]) * fde_->cie->data_alignment_factor;
|
||||
(*loc_regs)[reg] = {.type = DWARF_LOCATION_VAL_OFFSET, .values = {static_cast<uint64_t>(offset)}};
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfCfa<AddressType>::cfa_val_expression(dwarf_loc_regs_t* loc_regs) {
|
||||
AddressType reg = operands_[0];
|
||||
(*loc_regs)[reg] = {.type = DWARF_LOCATION_VAL_EXPRESSION,
|
||||
.values = {operands_[1], memory_->cur_offset()}};
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
bool DwarfCfa<AddressType>::cfa_gnu_negative_offset_extended(dwarf_loc_regs_t* loc_regs) {
|
||||
AddressType reg = operands_[0];
|
||||
SignedType offset = -static_cast<SignedType>(operands_[1]);
|
||||
(*loc_regs)[reg] = {.type = DWARF_LOCATION_OFFSET, .values = {static_cast<uint64_t>(offset)}};
|
||||
return true;
|
||||
}
|
||||
|
||||
const DwarfCfaInfo::Info DwarfCfaInfo::kTable[64] = {
|
||||
{
|
||||
// 0x00 DW_CFA_nop
|
||||
"DW_CFA_nop",
|
||||
2,
|
||||
0,
|
||||
{},
|
||||
{},
|
||||
},
|
||||
{
|
||||
"DW_CFA_set_loc", // 0x01 DW_CFA_set_loc
|
||||
2,
|
||||
1,
|
||||
{DW_EH_PE_absptr},
|
||||
{DWARF_DISPLAY_SET_LOC},
|
||||
},
|
||||
{
|
||||
"DW_CFA_advance_loc1", // 0x02 DW_CFA_advance_loc1
|
||||
2,
|
||||
1,
|
||||
{DW_EH_PE_udata1},
|
||||
{DWARF_DISPLAY_ADVANCE_LOC},
|
||||
},
|
||||
{
|
||||
"DW_CFA_advance_loc2", // 0x03 DW_CFA_advance_loc2
|
||||
2,
|
||||
1,
|
||||
{DW_EH_PE_udata2},
|
||||
{DWARF_DISPLAY_ADVANCE_LOC},
|
||||
},
|
||||
{
|
||||
"DW_CFA_advance_loc4", // 0x04 DW_CFA_advance_loc4
|
||||
2,
|
||||
1,
|
||||
{DW_EH_PE_udata4},
|
||||
{DWARF_DISPLAY_ADVANCE_LOC},
|
||||
},
|
||||
{
|
||||
"DW_CFA_offset_extended", // 0x05 DW_CFA_offset_extended
|
||||
2,
|
||||
2,
|
||||
{DW_EH_PE_uleb128, DW_EH_PE_uleb128},
|
||||
{DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_NUMBER},
|
||||
},
|
||||
{
|
||||
"DW_CFA_restore_extended", // 0x06 DW_CFA_restore_extended
|
||||
2,
|
||||
1,
|
||||
{DW_EH_PE_uleb128},
|
||||
{DWARF_DISPLAY_REGISTER},
|
||||
},
|
||||
{
|
||||
"DW_CFA_undefined", // 0x07 DW_CFA_undefined
|
||||
2,
|
||||
1,
|
||||
{DW_EH_PE_uleb128},
|
||||
{DWARF_DISPLAY_REGISTER},
|
||||
},
|
||||
{
|
||||
"DW_CFA_same_value", // 0x08 DW_CFA_same_value
|
||||
2,
|
||||
1,
|
||||
{DW_EH_PE_uleb128},
|
||||
{DWARF_DISPLAY_REGISTER},
|
||||
},
|
||||
{
|
||||
"DW_CFA_register", // 0x09 DW_CFA_register
|
||||
2,
|
||||
2,
|
||||
{DW_EH_PE_uleb128, DW_EH_PE_uleb128},
|
||||
{DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_REGISTER},
|
||||
},
|
||||
{
|
||||
"DW_CFA_remember_state", // 0x0a DW_CFA_remember_state
|
||||
2,
|
||||
0,
|
||||
{},
|
||||
{},
|
||||
},
|
||||
{
|
||||
"DW_CFA_restore_state", // 0x0b DW_CFA_restore_state
|
||||
2,
|
||||
0,
|
||||
{},
|
||||
{},
|
||||
},
|
||||
{
|
||||
"DW_CFA_def_cfa", // 0x0c DW_CFA_def_cfa
|
||||
2,
|
||||
2,
|
||||
{DW_EH_PE_uleb128, DW_EH_PE_uleb128},
|
||||
{DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_NUMBER},
|
||||
},
|
||||
{
|
||||
"DW_CFA_def_cfa_register", // 0x0d DW_CFA_def_cfa_register
|
||||
2,
|
||||
1,
|
||||
{DW_EH_PE_uleb128},
|
||||
{DWARF_DISPLAY_REGISTER},
|
||||
},
|
||||
{
|
||||
"DW_CFA_def_cfa_offset", // 0x0e DW_CFA_def_cfa_offset
|
||||
2,
|
||||
1,
|
||||
{DW_EH_PE_uleb128},
|
||||
{DWARF_DISPLAY_NUMBER},
|
||||
},
|
||||
{
|
||||
"DW_CFA_def_cfa_expression", // 0x0f DW_CFA_def_cfa_expression
|
||||
2,
|
||||
1,
|
||||
{DW_EH_PE_block},
|
||||
{DWARF_DISPLAY_EVAL_BLOCK},
|
||||
},
|
||||
{
|
||||
"DW_CFA_expression", // 0x10 DW_CFA_expression
|
||||
2,
|
||||
2,
|
||||
{DW_EH_PE_uleb128, DW_EH_PE_block},
|
||||
{DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_EVAL_BLOCK},
|
||||
},
|
||||
{
|
||||
"DW_CFA_offset_extended_sf", // 0x11 DW_CFA_offset_extend_sf
|
||||
2,
|
||||
2,
|
||||
{DW_EH_PE_uleb128, DW_EH_PE_sleb128},
|
||||
{DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_SIGNED_NUMBER},
|
||||
},
|
||||
{
|
||||
"DW_CFA_def_cfa_sf", // 0x12 DW_CFA_def_cfa_sf
|
||||
2,
|
||||
2,
|
||||
{DW_EH_PE_uleb128, DW_EH_PE_sleb128},
|
||||
{DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_SIGNED_NUMBER},
|
||||
},
|
||||
{
|
||||
"DW_CFA_def_cfa_offset_sf", // 0x13 DW_CFA_def_cfa_offset_sf
|
||||
2,
|
||||
1,
|
||||
{DW_EH_PE_sleb128},
|
||||
{DWARF_DISPLAY_SIGNED_NUMBER},
|
||||
},
|
||||
{
|
||||
"DW_CFA_val_offset", // 0x14 DW_CFA_val_offset
|
||||
2,
|
||||
2,
|
||||
{DW_EH_PE_uleb128, DW_EH_PE_uleb128},
|
||||
{DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_NUMBER},
|
||||
},
|
||||
{
|
||||
"DW_CFA_val_offset_sf", // 0x15 DW_CFA_val_offset_sf
|
||||
2,
|
||||
2,
|
||||
{DW_EH_PE_uleb128, DW_EH_PE_sleb128},
|
||||
{DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_SIGNED_NUMBER},
|
||||
},
|
||||
{
|
||||
"DW_CFA_val_expression", // 0x16 DW_CFA_val_expression
|
||||
2,
|
||||
2,
|
||||
{DW_EH_PE_uleb128, DW_EH_PE_block},
|
||||
{DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_EVAL_BLOCK},
|
||||
},
|
||||
{nullptr, 0, 0, {}, {}}, // 0x17 illegal cfa
|
||||
{nullptr, 0, 0, {}, {}}, // 0x18 illegal cfa
|
||||
{nullptr, 0, 0, {}, {}}, // 0x19 illegal cfa
|
||||
{nullptr, 0, 0, {}, {}}, // 0x1a illegal cfa
|
||||
{nullptr, 0, 0, {}, {}}, // 0x1b illegal cfa
|
||||
{nullptr, 0, 0, {}, {}}, // 0x1c DW_CFA_lo_user (Treat as illegal)
|
||||
{nullptr, 0, 0, {}, {}}, // 0x1d illegal cfa
|
||||
{nullptr, 0, 0, {}, {}}, // 0x1e illegal cfa
|
||||
{nullptr, 0, 0, {}, {}}, // 0x1f illegal cfa
|
||||
{nullptr, 0, 0, {}, {}}, // 0x20 illegal cfa
|
||||
{nullptr, 0, 0, {}, {}}, // 0x21 illegal cfa
|
||||
{nullptr, 0, 0, {}, {}}, // 0x22 illegal cfa
|
||||
{nullptr, 0, 0, {}, {}}, // 0x23 illegal cfa
|
||||
{nullptr, 0, 0, {}, {}}, // 0x24 illegal cfa
|
||||
{nullptr, 0, 0, {}, {}}, // 0x25 illegal cfa
|
||||
{nullptr, 0, 0, {}, {}}, // 0x26 illegal cfa
|
||||
{nullptr, 0, 0, {}, {}}, // 0x27 illegal cfa
|
||||
{nullptr, 0, 0, {}, {}}, // 0x28 illegal cfa
|
||||
{nullptr, 0, 0, {}, {}}, // 0x29 illegal cfa
|
||||
{nullptr, 0, 0, {}, {}}, // 0x2a illegal cfa
|
||||
{nullptr, 0, 0, {}, {}}, // 0x2b illegal cfa
|
||||
{nullptr, 0, 0, {}, {}}, // 0x2c illegal cfa
|
||||
{nullptr, 0, 0, {}, {}}, // 0x2d DW_CFA_GNU_window_save (Treat as illegal)
|
||||
{
|
||||
"DW_CFA_GNU_args_size", // 0x2e DW_CFA_GNU_args_size
|
||||
2,
|
||||
1,
|
||||
{DW_EH_PE_uleb128},
|
||||
{DWARF_DISPLAY_NUMBER},
|
||||
},
|
||||
{
|
||||
"DW_CFA_GNU_negative_offset_extended", // 0x2f DW_CFA_GNU_negative_offset_extended
|
||||
2,
|
||||
2,
|
||||
{DW_EH_PE_uleb128, DW_EH_PE_uleb128},
|
||||
{DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_NUMBER},
|
||||
},
|
||||
{nullptr, 0, 0, {}, {}}, // 0x31 illegal cfa
|
||||
{nullptr, 0, 0, {}, {}}, // 0x32 illegal cfa
|
||||
{nullptr, 0, 0, {}, {}}, // 0x33 illegal cfa
|
||||
{nullptr, 0, 0, {}, {}}, // 0x34 illegal cfa
|
||||
{nullptr, 0, 0, {}, {}}, // 0x35 illegal cfa
|
||||
{nullptr, 0, 0, {}, {}}, // 0x36 illegal cfa
|
||||
{nullptr, 0, 0, {}, {}}, // 0x37 illegal cfa
|
||||
{nullptr, 0, 0, {}, {}}, // 0x38 illegal cfa
|
||||
{nullptr, 0, 0, {}, {}}, // 0x39 illegal cfa
|
||||
{nullptr, 0, 0, {}, {}}, // 0x3a illegal cfa
|
||||
{nullptr, 0, 0, {}, {}}, // 0x3b illegal cfa
|
||||
{nullptr, 0, 0, {}, {}}, // 0x3c illegal cfa
|
||||
{nullptr, 0, 0, {}, {}}, // 0x3d illegal cfa
|
||||
{nullptr, 0, 0, {}, {}}, // 0x3e illegal cfa
|
||||
{nullptr, 0, 0, {}, {}}, // 0x3f DW_CFA_hi_user (Treat as illegal)
|
||||
};
|
||||
|
||||
// Explicitly instantiate DwarfCfa.
|
||||
template class DwarfCfa<uint32_t>;
|
||||
template class DwarfCfa<uint64_t>;
|
||||
255
libunwindstack/DwarfCfa.h
Normal file
255
libunwindstack/DwarfCfa.h
Normal file
|
|
@ -0,0 +1,255 @@
|
|||
/*
|
||||
* 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_CFA_H
|
||||
#define _LIBUNWINDSTACK_DWARF_CFA_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <stack>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "DwarfError.h"
|
||||
#include "DwarfLocation.h"
|
||||
#include "DwarfMemory.h"
|
||||
#include "DwarfStructs.h"
|
||||
|
||||
// DWARF Standard home: http://dwarfstd.org/
|
||||
// This code is based on DWARF 4: http://http://dwarfstd.org/doc/DWARF4.pdf
|
||||
// See section 6.4.2.1 for a description of the DW_CFA_xxx values.
|
||||
|
||||
class DwarfCfaInfo {
|
||||
public:
|
||||
enum DisplayType : uint8_t {
|
||||
DWARF_DISPLAY_NONE = 0,
|
||||
DWARF_DISPLAY_REGISTER,
|
||||
DWARF_DISPLAY_NUMBER,
|
||||
DWARF_DISPLAY_SIGNED_NUMBER,
|
||||
DWARF_DISPLAY_EVAL_BLOCK,
|
||||
DWARF_DISPLAY_ADDRESS,
|
||||
DWARF_DISPLAY_SET_LOC,
|
||||
DWARF_DISPLAY_ADVANCE_LOC,
|
||||
};
|
||||
|
||||
struct Info {
|
||||
const char* name;
|
||||
uint8_t supported_version;
|
||||
uint8_t num_operands;
|
||||
uint8_t operands[2];
|
||||
uint8_t display_operands[2];
|
||||
};
|
||||
|
||||
const static Info kTable[64];
|
||||
};
|
||||
|
||||
template <typename AddressType>
|
||||
class DwarfCfa {
|
||||
// Signed version of AddressType
|
||||
typedef typename std::make_signed<AddressType>::type SignedType;
|
||||
|
||||
public:
|
||||
DwarfCfa(DwarfMemory* memory, const DwarfFDE* fde) : memory_(memory), fde_(fde) {}
|
||||
virtual ~DwarfCfa() = default;
|
||||
|
||||
bool GetLocationInfo(uint64_t pc, uint64_t start_offset, uint64_t end_offset,
|
||||
dwarf_loc_regs_t* loc_regs);
|
||||
|
||||
bool Log(uint32_t indent, uint64_t pc, uint64_t load_bias, uint64_t start_offset,
|
||||
uint64_t end_offset);
|
||||
|
||||
DwarfError last_error() { return last_error_; }
|
||||
|
||||
AddressType cur_pc() { return cur_pc_; }
|
||||
|
||||
void set_cie_loc_regs(const dwarf_loc_regs_t* cie_loc_regs) { cie_loc_regs_ = cie_loc_regs; }
|
||||
|
||||
protected:
|
||||
std::string GetOperandString(uint8_t operand, uint64_t value, uint64_t* cur_pc);
|
||||
|
||||
bool LogOffsetRegisterString(uint32_t indent, uint64_t cfa_offset, uint8_t reg);
|
||||
|
||||
bool LogInstruction(uint32_t indent, uint64_t cfa_offset, uint8_t op, uint64_t* cur_pc);
|
||||
|
||||
private:
|
||||
DwarfError last_error_;
|
||||
DwarfMemory* memory_;
|
||||
const DwarfFDE* fde_;
|
||||
|
||||
AddressType cur_pc_;
|
||||
const dwarf_loc_regs_t* cie_loc_regs_ = nullptr;
|
||||
std::vector<AddressType> operands_;
|
||||
std::stack<dwarf_loc_regs_t> loc_reg_state_;
|
||||
|
||||
// CFA processing functions.
|
||||
bool cfa_nop(dwarf_loc_regs_t*);
|
||||
bool cfa_set_loc(dwarf_loc_regs_t*);
|
||||
bool cfa_advance_loc(dwarf_loc_regs_t*);
|
||||
bool cfa_offset(dwarf_loc_regs_t*);
|
||||
bool cfa_restore(dwarf_loc_regs_t*);
|
||||
bool cfa_undefined(dwarf_loc_regs_t*);
|
||||
bool cfa_same_value(dwarf_loc_regs_t*);
|
||||
bool cfa_register(dwarf_loc_regs_t*);
|
||||
bool cfa_remember_state(dwarf_loc_regs_t*);
|
||||
bool cfa_restore_state(dwarf_loc_regs_t*);
|
||||
bool cfa_def_cfa(dwarf_loc_regs_t*);
|
||||
bool cfa_def_cfa_register(dwarf_loc_regs_t*);
|
||||
bool cfa_def_cfa_offset(dwarf_loc_regs_t*);
|
||||
bool cfa_def_cfa_expression(dwarf_loc_regs_t*);
|
||||
bool cfa_expression(dwarf_loc_regs_t*);
|
||||
bool cfa_offset_extended_sf(dwarf_loc_regs_t*);
|
||||
bool cfa_def_cfa_sf(dwarf_loc_regs_t*);
|
||||
bool cfa_def_cfa_offset_sf(dwarf_loc_regs_t*);
|
||||
bool cfa_val_offset(dwarf_loc_regs_t*);
|
||||
bool cfa_val_offset_sf(dwarf_loc_regs_t*);
|
||||
bool cfa_val_expression(dwarf_loc_regs_t*);
|
||||
bool cfa_gnu_negative_offset_extended(dwarf_loc_regs_t*);
|
||||
|
||||
using process_func = bool (DwarfCfa::*)(dwarf_loc_regs_t*);
|
||||
constexpr static process_func kCallbackTable[64] = {
|
||||
// 0x00 DW_CFA_nop
|
||||
&DwarfCfa::cfa_nop,
|
||||
// 0x01 DW_CFA_set_loc
|
||||
&DwarfCfa::cfa_set_loc,
|
||||
// 0x02 DW_CFA_advance_loc1
|
||||
&DwarfCfa::cfa_advance_loc,
|
||||
// 0x03 DW_CFA_advance_loc2
|
||||
&DwarfCfa::cfa_advance_loc,
|
||||
// 0x04 DW_CFA_advance_loc4
|
||||
&DwarfCfa::cfa_advance_loc,
|
||||
// 0x05 DW_CFA_offset_extended
|
||||
&DwarfCfa::cfa_offset,
|
||||
// 0x06 DW_CFA_restore_extended
|
||||
&DwarfCfa::cfa_restore,
|
||||
// 0x07 DW_CFA_undefined
|
||||
&DwarfCfa::cfa_undefined,
|
||||
// 0x08 DW_CFA_same_value
|
||||
&DwarfCfa::cfa_same_value,
|
||||
// 0x09 DW_CFA_register
|
||||
&DwarfCfa::cfa_register,
|
||||
// 0x0a DW_CFA_remember_state
|
||||
&DwarfCfa::cfa_remember_state,
|
||||
// 0x0b DW_CFA_restore_state
|
||||
&DwarfCfa::cfa_restore_state,
|
||||
// 0x0c DW_CFA_def_cfa
|
||||
&DwarfCfa::cfa_def_cfa,
|
||||
// 0x0d DW_CFA_def_cfa_register
|
||||
&DwarfCfa::cfa_def_cfa_register,
|
||||
// 0x0e DW_CFA_def_cfa_offset
|
||||
&DwarfCfa::cfa_def_cfa_offset,
|
||||
// 0x0f DW_CFA_def_cfa_expression
|
||||
&DwarfCfa::cfa_def_cfa_expression,
|
||||
// 0x10 DW_CFA_expression
|
||||
&DwarfCfa::cfa_expression,
|
||||
// 0x11 DW_CFA_offset_extended_sf
|
||||
&DwarfCfa::cfa_offset_extended_sf,
|
||||
// 0x12 DW_CFA_def_cfa_sf
|
||||
&DwarfCfa::cfa_def_cfa_sf,
|
||||
// 0x13 DW_CFA_def_cfa_offset_sf
|
||||
&DwarfCfa::cfa_def_cfa_offset_sf,
|
||||
// 0x14 DW_CFA_val_offset
|
||||
&DwarfCfa::cfa_val_offset,
|
||||
// 0x15 DW_CFA_val_offset_sf
|
||||
&DwarfCfa::cfa_val_offset_sf,
|
||||
// 0x16 DW_CFA_val_expression
|
||||
&DwarfCfa::cfa_val_expression,
|
||||
// 0x17 illegal cfa
|
||||
nullptr,
|
||||
// 0x18 illegal cfa
|
||||
nullptr,
|
||||
// 0x19 illegal cfa
|
||||
nullptr,
|
||||
// 0x1a illegal cfa
|
||||
nullptr,
|
||||
// 0x1b illegal cfa
|
||||
nullptr,
|
||||
// 0x1c DW_CFA_lo_user (Treat this as illegal)
|
||||
nullptr,
|
||||
// 0x1d illegal cfa
|
||||
nullptr,
|
||||
// 0x1e illegal cfa
|
||||
nullptr,
|
||||
// 0x1f illegal cfa
|
||||
nullptr,
|
||||
// 0x20 illegal cfa
|
||||
nullptr,
|
||||
// 0x21 illegal cfa
|
||||
nullptr,
|
||||
// 0x22 illegal cfa
|
||||
nullptr,
|
||||
// 0x23 illegal cfa
|
||||
nullptr,
|
||||
// 0x24 illegal cfa
|
||||
nullptr,
|
||||
// 0x25 illegal cfa
|
||||
nullptr,
|
||||
// 0x26 illegal cfa
|
||||
nullptr,
|
||||
// 0x27 illegal cfa
|
||||
nullptr,
|
||||
// 0x28 illegal cfa
|
||||
nullptr,
|
||||
// 0x29 illegal cfa
|
||||
nullptr,
|
||||
// 0x2a illegal cfa
|
||||
nullptr,
|
||||
// 0x2b illegal cfa
|
||||
nullptr,
|
||||
// 0x2c illegal cfa
|
||||
nullptr,
|
||||
// 0x2d DW_CFA_GNU_window_save (Treat this as illegal)
|
||||
nullptr,
|
||||
// 0x2e DW_CFA_GNU_args_size
|
||||
&DwarfCfa::cfa_nop,
|
||||
// 0x2f DW_CFA_GNU_negative_offset_extended
|
||||
&DwarfCfa::cfa_gnu_negative_offset_extended,
|
||||
// 0x30 illegal cfa
|
||||
nullptr,
|
||||
// 0x31 illegal cfa
|
||||
nullptr,
|
||||
// 0x32 illegal cfa
|
||||
nullptr,
|
||||
// 0x33 illegal cfa
|
||||
nullptr,
|
||||
// 0x34 illegal cfa
|
||||
nullptr,
|
||||
// 0x35 illegal cfa
|
||||
nullptr,
|
||||
// 0x36 illegal cfa
|
||||
nullptr,
|
||||
// 0x37 illegal cfa
|
||||
nullptr,
|
||||
// 0x38 illegal cfa
|
||||
nullptr,
|
||||
// 0x39 illegal cfa
|
||||
nullptr,
|
||||
// 0x3a illegal cfa
|
||||
nullptr,
|
||||
// 0x3b illegal cfa
|
||||
nullptr,
|
||||
// 0x3c illegal cfa
|
||||
nullptr,
|
||||
// 0x3d illegal cfa
|
||||
nullptr,
|
||||
// 0x3e illegal cfa
|
||||
nullptr,
|
||||
// 0x3f DW_CFA_hi_user (Treat this as illegal)
|
||||
nullptr,
|
||||
};
|
||||
};
|
||||
|
||||
#endif // _LIBUNWINDSTACK_DWARF_CFA_H
|
||||
41
libunwindstack/DwarfLocation.h
Normal file
41
libunwindstack/DwarfLocation.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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_LOCATION_H
|
||||
#define _LIBUNWINDSTACK_DWARF_LOCATION_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
enum DwarfLocationEnum : uint8_t {
|
||||
DWARF_LOCATION_INVALID = 0,
|
||||
DWARF_LOCATION_UNDEFINED,
|
||||
DWARF_LOCATION_OFFSET,
|
||||
DWARF_LOCATION_VAL_OFFSET,
|
||||
DWARF_LOCATION_REGISTER,
|
||||
DWARF_LOCATION_EXPRESSION,
|
||||
DWARF_LOCATION_VAL_EXPRESSION,
|
||||
};
|
||||
|
||||
struct DwarfLocation {
|
||||
DwarfLocationEnum type;
|
||||
uint64_t values[2];
|
||||
};
|
||||
|
||||
typedef std::unordered_map<uint16_t, DwarfLocation> dwarf_loc_regs_t;
|
||||
|
||||
#endif // _LIBUNWINDSTACK_DWARF_LOCATION_H
|
||||
52
libunwindstack/DwarfStructs.h
Normal file
52
libunwindstack/DwarfStructs.h
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* 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_STRUCTS_H
|
||||
#define _LIBUNWINDSTACK_DWARF_STRUCTS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "DwarfEncoding.h"
|
||||
|
||||
struct DwarfCIE {
|
||||
uint8_t version = 0;
|
||||
uint8_t fde_address_encoding = DW_EH_PE_absptr;
|
||||
uint8_t lsda_encoding = DW_EH_PE_omit;
|
||||
uint8_t segment_size = 0;
|
||||
std::vector<char> augmentation_string;
|
||||
uint64_t personality_handler = 0;
|
||||
uint64_t cfa_instructions_offset = 0;
|
||||
uint64_t cfa_instructions_end = 0;
|
||||
uint64_t code_alignment_factor = 0;
|
||||
int64_t data_alignment_factor = 0;
|
||||
uint64_t return_address_register = 0;
|
||||
};
|
||||
|
||||
struct DwarfFDE {
|
||||
uint64_t cie_offset = 0;
|
||||
uint64_t cfa_instructions_offset = 0;
|
||||
uint64_t cfa_instructions_end = 0;
|
||||
uint64_t pc_start = 0;
|
||||
uint64_t pc_end = 0;
|
||||
uint64_t lsda_address = 0;
|
||||
const DwarfCIE* cie = nullptr;
|
||||
};
|
||||
|
||||
constexpr uint16_t CFA_REG = static_cast<uint16_t>(-1);
|
||||
|
||||
#endif // _LIBUNWINDSTACK_DWARF_STRUCTS_H
|
||||
814
libunwindstack/tests/DwarfCfaLogTest.cpp
Normal file
814
libunwindstack/tests/DwarfCfaLogTest.cpp
Normal file
|
|
@ -0,0 +1,814 @@
|
|||
/*
|
||||
* 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 <memory>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "DwarfCfa.h"
|
||||
#include "DwarfLocation.h"
|
||||
#include "DwarfMemory.h"
|
||||
#include "DwarfStructs.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include "LogFake.h"
|
||||
#include "MemoryFake.h"
|
||||
|
||||
template <typename TypeParam>
|
||||
class DwarfCfaLogTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
ResetLogs();
|
||||
memory_.Clear();
|
||||
|
||||
dmem_.reset(new DwarfMemory(&memory_));
|
||||
|
||||
cie_.cfa_instructions_offset = 0x1000;
|
||||
cie_.cfa_instructions_end = 0x1030;
|
||||
// These two values should be different to distinguish between
|
||||
// operations that deal with code versus data.
|
||||
cie_.code_alignment_factor = 4;
|
||||
cie_.data_alignment_factor = 8;
|
||||
|
||||
fde_.cfa_instructions_offset = 0x2000;
|
||||
fde_.cfa_instructions_end = 0x2030;
|
||||
fde_.pc_start = 0x2000;
|
||||
fde_.pc_end = 0x2000;
|
||||
fde_.pc_end = 0x10000;
|
||||
fde_.cie = &cie_;
|
||||
cfa_.reset(new DwarfCfa<TypeParam>(dmem_.get(), &fde_));
|
||||
}
|
||||
|
||||
MemoryFake memory_;
|
||||
std::unique_ptr<DwarfMemory> dmem_;
|
||||
std::unique_ptr<DwarfCfa<TypeParam>> cfa_;
|
||||
DwarfCIE cie_;
|
||||
DwarfFDE fde_;
|
||||
};
|
||||
TYPED_TEST_CASE_P(DwarfCfaLogTest);
|
||||
|
||||
// NOTE: All class variable references have to be prefaced with this->.
|
||||
|
||||
TYPED_TEST_P(DwarfCfaLogTest, cfa_illegal) {
|
||||
for (uint8_t i = 0x17; i < 0x3f; i++) {
|
||||
if (i == 0x2e || i == 0x2f) {
|
||||
// Skip gnu extension ops.
|
||||
continue;
|
||||
}
|
||||
this->memory_.SetMemory(0x2000, std::vector<uint8_t>{i});
|
||||
|
||||
ResetLogs();
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x2000, 0x2001));
|
||||
std::string expected = "4 unwind Illegal\n";
|
||||
expected += android::base::StringPrintf("4 unwind Raw Data: 0x%02x\n", i);
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaLogTest, cfa_nop) {
|
||||
this->memory_.SetMemory(0x2000, std::vector<uint8_t>{0x00});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x2000, 0x2001));
|
||||
std::string expected =
|
||||
"4 unwind DW_CFA_nop\n"
|
||||
"4 unwind Raw Data: 0x00\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaLogTest, cfa_offset) {
|
||||
this->memory_.SetMemory(0x2000, std::vector<uint8_t>{0x83, 0x04});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x2000, 0x2002));
|
||||
std::string expected =
|
||||
"4 unwind DW_CFA_offset register(3) 4\n"
|
||||
"4 unwind Raw Data: 0x83 0x04\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
this->memory_.SetMemory(0x2100, std::vector<uint8_t>{0x83, 0x84, 0x01});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x2100, 0x2103));
|
||||
expected =
|
||||
"4 unwind DW_CFA_offset register(3) 132\n"
|
||||
"4 unwind Raw Data: 0x83 0x84 0x01\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaLogTest, cfa_offset_extended) {
|
||||
this->memory_.SetMemory(0x500, std::vector<uint8_t>{0x05, 0x03, 0x02});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x500, 0x503));
|
||||
std::string expected =
|
||||
"4 unwind DW_CFA_offset_extended register(3) 2\n"
|
||||
"4 unwind Raw Data: 0x05 0x03 0x02\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
this->memory_.SetMemory(0x1500, std::vector<uint8_t>{0x05, 0x81, 0x01, 0x82, 0x12});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x1500, 0x1505));
|
||||
expected =
|
||||
"4 unwind DW_CFA_offset_extended register(129) 2306\n"
|
||||
"4 unwind Raw Data: 0x05 0x81 0x01 0x82 0x12\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaLogTest, cfa_offset_extended_sf) {
|
||||
this->memory_.SetMemory(0x500, std::vector<uint8_t>{0x11, 0x05, 0x10});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x500, 0x503));
|
||||
std::string expected =
|
||||
"4 unwind DW_CFA_offset_extended_sf register(5) 16\n"
|
||||
"4 unwind Raw Data: 0x11 0x05 0x10\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
// Check a negative value for the offset.
|
||||
ResetLogs();
|
||||
this->memory_.SetMemory(0x1500, std::vector<uint8_t>{0x11, 0x86, 0x01, 0xff, 0x7f});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x1500, 0x1505));
|
||||
expected =
|
||||
"4 unwind DW_CFA_offset_extended_sf register(134) -1\n"
|
||||
"4 unwind Raw Data: 0x11 0x86 0x01 0xff 0x7f\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaLogTest, cfa_restore) {
|
||||
this->memory_.SetMemory(0x2000, std::vector<uint8_t>{0xc2});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x2000, 0x2001));
|
||||
std::string expected =
|
||||
"4 unwind DW_CFA_restore register(2)\n"
|
||||
"4 unwind Raw Data: 0xc2\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
this->memory_.SetMemory(0x3000, std::vector<uint8_t>{0x82, 0x04, 0xc2});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x3000, 0x3003));
|
||||
expected =
|
||||
"4 unwind DW_CFA_offset register(2) 4\n"
|
||||
"4 unwind Raw Data: 0x82 0x04\n"
|
||||
"4 unwind DW_CFA_restore register(2)\n"
|
||||
"4 unwind Raw Data: 0xc2\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaLogTest, cfa_restore_extended) {
|
||||
this->memory_.SetMemory(0x4000, std::vector<uint8_t>{0x06, 0x08});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x4000, 0x4002));
|
||||
std::string expected =
|
||||
"4 unwind DW_CFA_restore_extended register(8)\n"
|
||||
"4 unwind Raw Data: 0x06 0x08\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x05, 0x82, 0x02, 0x04, 0x06, 0x82, 0x02});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x5000, 0x5007));
|
||||
expected =
|
||||
"4 unwind DW_CFA_offset_extended register(258) 4\n"
|
||||
"4 unwind Raw Data: 0x05 0x82 0x02 0x04\n"
|
||||
"4 unwind DW_CFA_restore_extended register(258)\n"
|
||||
"4 unwind Raw Data: 0x06 0x82 0x02\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaLogTest, cfa_set_loc) {
|
||||
uint8_t buffer[1 + sizeof(TypeParam)];
|
||||
buffer[0] = 0x1;
|
||||
TypeParam address;
|
||||
std::string raw_data("Raw Data: 0x01 ");
|
||||
std::string address_str;
|
||||
if (std::is_same<TypeParam, uint32_t>::value) {
|
||||
address = 0x81234578U;
|
||||
address_str = "0x81234578";
|
||||
raw_data += "0x78 0x45 0x23 0x81";
|
||||
} else {
|
||||
address = 0x8123456712345678ULL;
|
||||
address_str = "0x8123456712345678";
|
||||
raw_data += "0x78 0x56 0x34 0x12 0x67 0x45 0x23 0x81";
|
||||
}
|
||||
memcpy(&buffer[1], &address, sizeof(address));
|
||||
|
||||
this->memory_.SetMemory(0x50, buffer, sizeof(buffer));
|
||||
ResetLogs();
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x50, 0x51 + sizeof(TypeParam)));
|
||||
std::string expected = "4 unwind DW_CFA_set_loc " + address_str + "\n";
|
||||
expected += "4 unwind " + raw_data + "\n";
|
||||
expected += "4 unwind \n";
|
||||
expected += "4 unwind PC " + address_str + "\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
// Check for a set going back.
|
||||
ResetLogs();
|
||||
this->fde_.pc_start = address + 0x10;
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x50, 0x51 + sizeof(TypeParam)));
|
||||
expected = "4 unwind DW_CFA_set_loc " + address_str + "\n";
|
||||
expected += "4 unwind " + raw_data + "\n";
|
||||
expected += "4 unwind \n";
|
||||
expected += "4 unwind PC " + address_str + "\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaLogTest, cfa_advance_loc) {
|
||||
this->memory_.SetMemory(0x200, std::vector<uint8_t>{0x44});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x200, 0x201));
|
||||
std::string expected =
|
||||
"4 unwind DW_CFA_advance_loc 4\n"
|
||||
"4 unwind Raw Data: 0x44\n"
|
||||
"4 unwind \n"
|
||||
"4 unwind PC 0x2010\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x100, 0x200, 0x201));
|
||||
expected =
|
||||
"4 unwind DW_CFA_advance_loc 4\n"
|
||||
"4 unwind Raw Data: 0x44\n"
|
||||
"4 unwind \n"
|
||||
"4 unwind PC 0x2110\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaLogTest, cfa_advance_loc1) {
|
||||
this->memory_.SetMemory(0x200, std::vector<uint8_t>{0x02, 0x04});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x200, 0x202));
|
||||
std::string expected =
|
||||
"4 unwind DW_CFA_advance_loc1 4\n"
|
||||
"4 unwind Raw Data: 0x02 0x04\n"
|
||||
"4 unwind \n"
|
||||
"4 unwind PC 0x2004\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x10, 0x200, 0x202));
|
||||
expected =
|
||||
"4 unwind DW_CFA_advance_loc1 4\n"
|
||||
"4 unwind Raw Data: 0x02 0x04\n"
|
||||
"4 unwind \n"
|
||||
"4 unwind PC 0x2014\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaLogTest, cfa_advance_loc2) {
|
||||
this->memory_.SetMemory(0x600, std::vector<uint8_t>{0x03, 0x04, 0x03});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x600, 0x603));
|
||||
std::string expected =
|
||||
"4 unwind DW_CFA_advance_loc2 772\n"
|
||||
"4 unwind Raw Data: 0x03 0x04 0x03\n"
|
||||
"4 unwind \n"
|
||||
"4 unwind PC 0x2304\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x1000, 0x600, 0x603));
|
||||
expected =
|
||||
"4 unwind DW_CFA_advance_loc2 772\n"
|
||||
"4 unwind Raw Data: 0x03 0x04 0x03\n"
|
||||
"4 unwind \n"
|
||||
"4 unwind PC 0x3304\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaLogTest, cfa_advance_loc4) {
|
||||
this->memory_.SetMemory(0x500, std::vector<uint8_t>{0x04, 0x04, 0x03, 0x02, 0x01});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x500, 0x505));
|
||||
std::string expected =
|
||||
"4 unwind DW_CFA_advance_loc4 16909060\n"
|
||||
"4 unwind Raw Data: 0x04 0x04 0x03 0x02 0x01\n"
|
||||
"4 unwind \n"
|
||||
"4 unwind PC 0x1022304\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x2000, 0x500, 0x505));
|
||||
expected =
|
||||
"4 unwind DW_CFA_advance_loc4 16909060\n"
|
||||
"4 unwind Raw Data: 0x04 0x04 0x03 0x02 0x01\n"
|
||||
"4 unwind \n"
|
||||
"4 unwind PC 0x1024304\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaLogTest, cfa_undefined) {
|
||||
this->memory_.SetMemory(0xa00, std::vector<uint8_t>{0x07, 0x09});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0xa00, 0xa02));
|
||||
std::string expected =
|
||||
"4 unwind DW_CFA_undefined register(9)\n"
|
||||
"4 unwind Raw Data: 0x07 0x09\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
dwarf_loc_regs_t cie_loc_regs;
|
||||
this->memory_.SetMemory(0x1a00, std::vector<uint8_t>{0x07, 0x81, 0x01});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x1a00, 0x1a03));
|
||||
expected =
|
||||
"4 unwind DW_CFA_undefined register(129)\n"
|
||||
"4 unwind Raw Data: 0x07 0x81 0x01\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaLogTest, cfa_same) {
|
||||
this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x08, 0x7f});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x100, 0x102));
|
||||
std::string expected =
|
||||
"4 unwind DW_CFA_same_value register(127)\n"
|
||||
"4 unwind Raw Data: 0x08 0x7f\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
this->memory_.SetMemory(0x2100, std::vector<uint8_t>{0x08, 0xff, 0x01});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x2100, 0x2103));
|
||||
expected =
|
||||
"4 unwind DW_CFA_same_value register(255)\n"
|
||||
"4 unwind Raw Data: 0x08 0xff 0x01\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaLogTest, cfa_register) {
|
||||
this->memory_.SetMemory(0x300, std::vector<uint8_t>{0x09, 0x02, 0x01});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x300, 0x303));
|
||||
std::string expected =
|
||||
"4 unwind DW_CFA_register register(2) register(1)\n"
|
||||
"4 unwind Raw Data: 0x09 0x02 0x01\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
this->memory_.SetMemory(0x4300, std::vector<uint8_t>{0x09, 0xff, 0x01, 0xff, 0x03});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x4300, 0x4305));
|
||||
expected =
|
||||
"4 unwind DW_CFA_register register(255) register(511)\n"
|
||||
"4 unwind Raw Data: 0x09 0xff 0x01 0xff 0x03\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaLogTest, cfa_state) {
|
||||
this->memory_.SetMemory(0x300, std::vector<uint8_t>{0x0a});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x300, 0x301));
|
||||
|
||||
std::string expected =
|
||||
"4 unwind DW_CFA_remember_state\n"
|
||||
"4 unwind Raw Data: 0x0a\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
this->memory_.SetMemory(0x4300, std::vector<uint8_t>{0x0b});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x4300, 0x4301));
|
||||
|
||||
expected =
|
||||
"4 unwind DW_CFA_restore_state\n"
|
||||
"4 unwind Raw Data: 0x0b\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaLogTest, cfa_state_cfa_offset_restore) {
|
||||
this->memory_.SetMemory(0x3000, std::vector<uint8_t>{0x0a, 0x0e, 0x40, 0x0b});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x3000, 0x3004));
|
||||
|
||||
std::string expected =
|
||||
"4 unwind DW_CFA_remember_state\n"
|
||||
"4 unwind Raw Data: 0x0a\n"
|
||||
"4 unwind DW_CFA_def_cfa_offset 64\n"
|
||||
"4 unwind Raw Data: 0x0e 0x40\n"
|
||||
"4 unwind DW_CFA_restore_state\n"
|
||||
"4 unwind Raw Data: 0x0b\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaLogTest, cfa_def_cfa) {
|
||||
this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x0c, 0x7f, 0x74});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x100, 0x103));
|
||||
|
||||
std::string expected =
|
||||
"4 unwind DW_CFA_def_cfa register(127) 116\n"
|
||||
"4 unwind Raw Data: 0x0c 0x7f 0x74\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
this->memory_.SetMemory(0x200, std::vector<uint8_t>{0x0c, 0xff, 0x02, 0xf4, 0x04});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x200, 0x205));
|
||||
|
||||
expected =
|
||||
"4 unwind DW_CFA_def_cfa register(383) 628\n"
|
||||
"4 unwind Raw Data: 0x0c 0xff 0x02 0xf4 0x04\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaLogTest, cfa_def_cfa_sf) {
|
||||
this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x12, 0x30, 0x25});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x100, 0x103));
|
||||
|
||||
std::string expected =
|
||||
"4 unwind DW_CFA_def_cfa_sf register(48) 37\n"
|
||||
"4 unwind Raw Data: 0x12 0x30 0x25\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
// Test a negative value.
|
||||
ResetLogs();
|
||||
this->memory_.SetMemory(0x200, std::vector<uint8_t>{0x12, 0xa3, 0x01, 0xfa, 0x7f});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x200, 0x205));
|
||||
|
||||
expected =
|
||||
"4 unwind DW_CFA_def_cfa_sf register(163) -6\n"
|
||||
"4 unwind Raw Data: 0x12 0xa3 0x01 0xfa 0x7f\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaLogTest, cfa_def_cfa_register) {
|
||||
this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x0d, 0x72});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x100, 0x102));
|
||||
|
||||
std::string expected =
|
||||
"4 unwind DW_CFA_def_cfa_register register(114)\n"
|
||||
"4 unwind Raw Data: 0x0d 0x72\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
this->memory_.SetMemory(0x200, std::vector<uint8_t>{0x0d, 0xf9, 0x20});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x200, 0x203));
|
||||
|
||||
expected =
|
||||
"4 unwind DW_CFA_def_cfa_register register(4217)\n"
|
||||
"4 unwind Raw Data: 0x0d 0xf9 0x20\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaLogTest, cfa_def_cfa_offset) {
|
||||
this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x0e, 0x59});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x100, 0x102));
|
||||
|
||||
std::string expected =
|
||||
"4 unwind DW_CFA_def_cfa_offset 89\n"
|
||||
"4 unwind Raw Data: 0x0e 0x59\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x100, 0x102));
|
||||
|
||||
expected =
|
||||
"4 unwind DW_CFA_def_cfa_offset 89\n"
|
||||
"4 unwind Raw Data: 0x0e 0x59\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
this->memory_.SetMemory(0x200, std::vector<uint8_t>{0x0e, 0xd4, 0x0a});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x200, 0x203));
|
||||
|
||||
expected =
|
||||
"4 unwind DW_CFA_def_cfa_offset 1364\n"
|
||||
"4 unwind Raw Data: 0x0e 0xd4 0x0a\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaLogTest, cfa_def_cfa_offset_sf) {
|
||||
this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x13, 0x23});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x100, 0x102));
|
||||
|
||||
std::string expected =
|
||||
"4 unwind DW_CFA_def_cfa_offset_sf 35\n"
|
||||
"4 unwind Raw Data: 0x13 0x23\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x100, 0x102));
|
||||
|
||||
expected =
|
||||
"4 unwind DW_CFA_def_cfa_offset_sf 35\n"
|
||||
"4 unwind Raw Data: 0x13 0x23\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
// Negative offset.
|
||||
ResetLogs();
|
||||
this->memory_.SetMemory(0x200, std::vector<uint8_t>{0x13, 0xf6, 0x7f});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x200, 0x203));
|
||||
|
||||
expected =
|
||||
"4 unwind DW_CFA_def_cfa_offset_sf -10\n"
|
||||
"4 unwind Raw Data: 0x13 0xf6 0x7f\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaLogTest, cfa_def_cfa_expression) {
|
||||
this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x0f, 0x04, 0x01, 0x02, 0x04, 0x05});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x100, 0x106));
|
||||
|
||||
std::string expected =
|
||||
"4 unwind DW_CFA_def_cfa_expression 4\n"
|
||||
"4 unwind Raw Data: 0x0f 0x04 0x01 0x02 0x04 0x05\n"
|
||||
"4 unwind Illegal\n"
|
||||
"4 unwind Raw Data: 0x01\n"
|
||||
"4 unwind Illegal\n"
|
||||
"4 unwind Raw Data: 0x02\n"
|
||||
"4 unwind Illegal\n"
|
||||
"4 unwind Raw Data: 0x04\n"
|
||||
"4 unwind Illegal\n"
|
||||
"4 unwind Raw Data: 0x05\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
std::vector<uint8_t> ops{0x0f, 0x81, 0x01};
|
||||
expected = "4 unwind Raw Data: 0x0f 0x81 0x01";
|
||||
std::string op_string;
|
||||
for (uint8_t i = 3; i < 132; i++) {
|
||||
ops.push_back(0x05);
|
||||
op_string +=
|
||||
"4 unwind Illegal\n"
|
||||
"4 unwind Raw Data: 0x05\n";
|
||||
expected += " 0x05";
|
||||
if (((i + 1) % 10) == 0) {
|
||||
expected += "\n4 unwind Raw Data:";
|
||||
}
|
||||
}
|
||||
expected += '\n';
|
||||
this->memory_.SetMemory(0x200, ops);
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x200, 0x284));
|
||||
|
||||
expected = "4 unwind DW_CFA_def_cfa_expression 129\n" + expected;
|
||||
ASSERT_EQ(expected + op_string, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaLogTest, cfa_expression) {
|
||||
this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x10, 0x04, 0x02, 0xc0, 0xc1});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x100, 0x105));
|
||||
|
||||
std::string expected =
|
||||
"4 unwind DW_CFA_expression register(4) 2\n"
|
||||
"4 unwind Raw Data: 0x10 0x04 0x02 0xc0 0xc1\n"
|
||||
"4 unwind Illegal\n"
|
||||
"4 unwind Raw Data: 0xc0\n"
|
||||
"4 unwind Illegal\n"
|
||||
"4 unwind Raw Data: 0xc1\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
std::vector<uint8_t> ops{0x10, 0xff, 0x01, 0x82, 0x01};
|
||||
expected = "4 unwind Raw Data: 0x10 0xff 0x01 0x82 0x01";
|
||||
std::string op_string;
|
||||
for (uint8_t i = 5; i < 135; i++) {
|
||||
ops.push_back(0xa0 + (i - 5) % 96);
|
||||
op_string += "4 unwind Illegal\n";
|
||||
op_string += android::base::StringPrintf("4 unwind Raw Data: 0x%02x\n", ops.back());
|
||||
expected += android::base::StringPrintf(" 0x%02x", ops.back());
|
||||
if (((i + 1) % 10) == 0) {
|
||||
expected += "\n4 unwind Raw Data:";
|
||||
}
|
||||
}
|
||||
expected = "4 unwind DW_CFA_expression register(255) 130\n" + expected + "\n";
|
||||
|
||||
this->memory_.SetMemory(0x200, ops);
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x200, 0x287));
|
||||
|
||||
ASSERT_EQ(expected + op_string, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaLogTest, cfa_val_offset) {
|
||||
this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x14, 0x45, 0x54});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x100, 0x103));
|
||||
|
||||
std::string expected =
|
||||
"4 unwind DW_CFA_val_offset register(69) 84\n"
|
||||
"4 unwind Raw Data: 0x14 0x45 0x54\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
this->memory_.SetMemory(0x400, std::vector<uint8_t>{0x14, 0xa2, 0x02, 0xb4, 0x05});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x400, 0x405));
|
||||
|
||||
expected =
|
||||
"4 unwind DW_CFA_val_offset register(290) 692\n"
|
||||
"4 unwind Raw Data: 0x14 0xa2 0x02 0xb4 0x05\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaLogTest, cfa_val_offset_sf) {
|
||||
this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x15, 0x56, 0x12});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x100, 0x103));
|
||||
|
||||
std::string expected =
|
||||
"4 unwind DW_CFA_val_offset_sf register(86) 18\n"
|
||||
"4 unwind Raw Data: 0x15 0x56 0x12\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
// Negative value.
|
||||
ResetLogs();
|
||||
this->memory_.SetMemory(0xa00, std::vector<uint8_t>{0x15, 0xff, 0x01, 0xc0, 0x7f});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0xa00, 0xa05));
|
||||
|
||||
expected =
|
||||
"4 unwind DW_CFA_val_offset_sf register(255) -64\n"
|
||||
"4 unwind Raw Data: 0x15 0xff 0x01 0xc0 0x7f\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaLogTest, cfa_val_expression) {
|
||||
this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x16, 0x05, 0x02, 0xb0, 0xb1});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x100, 0x105));
|
||||
|
||||
std::string expected =
|
||||
"4 unwind DW_CFA_val_expression register(5) 2\n"
|
||||
"4 unwind Raw Data: 0x16 0x05 0x02 0xb0 0xb1\n"
|
||||
"4 unwind Illegal\n"
|
||||
"4 unwind Raw Data: 0xb0\n"
|
||||
"4 unwind Illegal\n"
|
||||
"4 unwind Raw Data: 0xb1\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
std::vector<uint8_t> ops{0x16, 0x83, 0x10, 0xa8, 0x01};
|
||||
expected = "4 unwind Raw Data: 0x16 0x83 0x10 0xa8 0x01";
|
||||
std::string op_string;
|
||||
for (uint8_t i = 0; i < 168; i++) {
|
||||
ops.push_back(0xa0 + (i % 96));
|
||||
op_string += "4 unwind Illegal\n";
|
||||
op_string += android::base::StringPrintf("4 unwind Raw Data: 0x%02x\n", ops.back());
|
||||
expected += android::base::StringPrintf(" 0x%02x", ops.back());
|
||||
if (((i + 6) % 10) == 0) {
|
||||
expected += "\n4 unwind Raw Data:";
|
||||
}
|
||||
}
|
||||
expected = "4 unwind DW_CFA_val_expression register(2051) 168\n" + expected + "\n";
|
||||
|
||||
this->memory_.SetMemory(0xa00, ops);
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0xa00, 0xaad));
|
||||
|
||||
ASSERT_EQ(expected + op_string, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaLogTest, cfa_gnu_args_size) {
|
||||
this->memory_.SetMemory(0x2000, std::vector<uint8_t>{0x2e, 0x04});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x2000, 0x2002));
|
||||
|
||||
std::string expected =
|
||||
"4 unwind DW_CFA_GNU_args_size 4\n"
|
||||
"4 unwind Raw Data: 0x2e 0x04\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x2e, 0xa4, 0x80, 0x04});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x5000, 0x5004));
|
||||
|
||||
expected =
|
||||
"4 unwind DW_CFA_GNU_args_size 65572\n"
|
||||
"4 unwind Raw Data: 0x2e 0xa4 0x80 0x04\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaLogTest, cfa_gnu_negative_offset_extended) {
|
||||
this->memory_.SetMemory(0x500, std::vector<uint8_t>{0x2f, 0x08, 0x10});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x500, 0x503));
|
||||
|
||||
std::string expected =
|
||||
"4 unwind DW_CFA_GNU_negative_offset_extended register(8) 16\n"
|
||||
"4 unwind Raw Data: 0x2f 0x08 0x10\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
this->memory_.SetMemory(0x1500, std::vector<uint8_t>{0x2f, 0x81, 0x02, 0xff, 0x01});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x1500, 0x1505));
|
||||
|
||||
expected =
|
||||
"4 unwind DW_CFA_GNU_negative_offset_extended register(257) 255\n"
|
||||
"4 unwind Raw Data: 0x2f 0x81 0x02 0xff 0x01\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaLogTest, cfa_register_override) {
|
||||
this->memory_.SetMemory(0x300, std::vector<uint8_t>{0x09, 0x02, 0x01, 0x09, 0x02, 0x04});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0, 0x300, 0x306));
|
||||
|
||||
std::string expected =
|
||||
"4 unwind DW_CFA_register register(2) register(1)\n"
|
||||
"4 unwind Raw Data: 0x09 0x02 0x01\n"
|
||||
"4 unwind DW_CFA_register register(2) register(4)\n"
|
||||
"4 unwind Raw Data: 0x09 0x02 0x04\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
REGISTER_TYPED_TEST_CASE_P(DwarfCfaLogTest, cfa_illegal, cfa_nop, cfa_offset, cfa_offset_extended,
|
||||
cfa_offset_extended_sf, cfa_restore, cfa_restore_extended, cfa_set_loc,
|
||||
cfa_advance_loc, cfa_advance_loc1, cfa_advance_loc2, cfa_advance_loc4,
|
||||
cfa_undefined, cfa_same, cfa_register, cfa_state,
|
||||
cfa_state_cfa_offset_restore, cfa_def_cfa, cfa_def_cfa_sf,
|
||||
cfa_def_cfa_register, cfa_def_cfa_offset, cfa_def_cfa_offset_sf,
|
||||
cfa_def_cfa_expression, cfa_expression, cfa_val_offset,
|
||||
cfa_val_offset_sf, cfa_val_expression, cfa_gnu_args_size,
|
||||
cfa_gnu_negative_offset_extended, cfa_register_override);
|
||||
|
||||
typedef ::testing::Types<uint32_t, uint64_t> DwarfCfaLogTestTypes;
|
||||
INSTANTIATE_TYPED_TEST_CASE_P(, DwarfCfaLogTest, DwarfCfaLogTestTypes);
|
||||
959
libunwindstack/tests/DwarfCfaTest.cpp
Normal file
959
libunwindstack/tests/DwarfCfaTest.cpp
Normal file
|
|
@ -0,0 +1,959 @@
|
|||
/*
|
||||
* 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 <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "DwarfCfa.h"
|
||||
#include "DwarfLocation.h"
|
||||
#include "DwarfMemory.h"
|
||||
#include "DwarfStructs.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include "LogFake.h"
|
||||
#include "MemoryFake.h"
|
||||
|
||||
template <typename TypeParam>
|
||||
class DwarfCfaTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
ResetLogs();
|
||||
memory_.Clear();
|
||||
|
||||
dmem_.reset(new DwarfMemory(&memory_));
|
||||
|
||||
cie_.cfa_instructions_offset = 0x1000;
|
||||
cie_.cfa_instructions_end = 0x1030;
|
||||
// These two values should be different to distinguish between
|
||||
// operations that deal with code versus data.
|
||||
cie_.code_alignment_factor = 4;
|
||||
cie_.data_alignment_factor = 8;
|
||||
|
||||
fde_.cfa_instructions_offset = 0x2000;
|
||||
fde_.cfa_instructions_end = 0x2030;
|
||||
fde_.pc_start = 0x2000;
|
||||
fde_.cie = &cie_;
|
||||
|
||||
cfa_.reset(new DwarfCfa<TypeParam>(dmem_.get(), &fde_));
|
||||
}
|
||||
|
||||
MemoryFake memory_;
|
||||
std::unique_ptr<DwarfMemory> dmem_;
|
||||
std::unique_ptr<DwarfCfa<TypeParam>> cfa_;
|
||||
DwarfCIE cie_;
|
||||
DwarfFDE fde_;
|
||||
};
|
||||
TYPED_TEST_CASE_P(DwarfCfaTest);
|
||||
|
||||
// NOTE: All test class variables need to be referenced as this->.
|
||||
|
||||
TYPED_TEST_P(DwarfCfaTest, cfa_illegal) {
|
||||
for (uint8_t i = 0x17; i < 0x3f; i++) {
|
||||
if (i == 0x2e || i == 0x2f) {
|
||||
// Skip gnu extension ops.
|
||||
continue;
|
||||
}
|
||||
this->memory_.SetMemory(0x2000, std::vector<uint8_t>{i});
|
||||
dwarf_loc_regs_t loc_regs;
|
||||
|
||||
ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2000, 0x2001, &loc_regs));
|
||||
ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->cfa_->last_error());
|
||||
ASSERT_EQ(0x2001U, this->dmem_->cur_offset());
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaTest, cfa_nop) {
|
||||
this->memory_.SetMemory(0x2000, std::vector<uint8_t>{0x00});
|
||||
dwarf_loc_regs_t loc_regs;
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2000, 0x2001, &loc_regs));
|
||||
ASSERT_EQ(0x2001U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(0U, loc_regs.size());
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
// This test needs to be examined.
|
||||
TYPED_TEST_P(DwarfCfaTest, cfa_offset) {
|
||||
this->memory_.SetMemory(0x2000, std::vector<uint8_t>{0x83, 0x04});
|
||||
dwarf_loc_regs_t loc_regs;
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2000, 0x2002, &loc_regs));
|
||||
ASSERT_EQ(0x2002U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
auto location = loc_regs.find(3);
|
||||
ASSERT_NE(loc_regs.end(), location);
|
||||
ASSERT_EQ(DWARF_LOCATION_OFFSET, location->second.type);
|
||||
ASSERT_EQ(32U, location->second.values[0]);
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
this->memory_.SetMemory(0x2100, std::vector<uint8_t>{0x83, 0x84, 0x01});
|
||||
loc_regs.clear();
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2100, 0x2103, &loc_regs));
|
||||
ASSERT_EQ(0x2103U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
location = loc_regs.find(3);
|
||||
ASSERT_NE(loc_regs.end(), location);
|
||||
ASSERT_EQ(DWARF_LOCATION_OFFSET, location->second.type);
|
||||
ASSERT_EQ(1056U, location->second.values[0]);
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaTest, cfa_offset_extended) {
|
||||
this->memory_.SetMemory(0x500, std::vector<uint8_t>{0x05, 0x03, 0x02});
|
||||
dwarf_loc_regs_t loc_regs;
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x500, 0x503, &loc_regs));
|
||||
ASSERT_EQ(0x503U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
auto location = loc_regs.find(3);
|
||||
ASSERT_NE(loc_regs.end(), location);
|
||||
ASSERT_EQ(DWARF_LOCATION_OFFSET, location->second.type);
|
||||
ASSERT_EQ(2U, location->second.values[0]);
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
loc_regs.clear();
|
||||
this->memory_.SetMemory(0x1500, std::vector<uint8_t>{0x05, 0x81, 0x01, 0x82, 0x12});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x1500, 0x1505, &loc_regs));
|
||||
ASSERT_EQ(0x1505U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
location = loc_regs.find(129);
|
||||
ASSERT_NE(loc_regs.end(), location);
|
||||
ASSERT_EQ(DWARF_LOCATION_OFFSET, location->second.type);
|
||||
ASSERT_EQ(2306U, location->second.values[0]);
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaTest, cfa_offset_extended_sf) {
|
||||
this->memory_.SetMemory(0x500, std::vector<uint8_t>{0x11, 0x05, 0x10});
|
||||
dwarf_loc_regs_t loc_regs;
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x500, 0x503, &loc_regs));
|
||||
ASSERT_EQ(0x503U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
auto location = loc_regs.find(5);
|
||||
ASSERT_NE(loc_regs.end(), location);
|
||||
ASSERT_EQ(DWARF_LOCATION_OFFSET, location->second.type);
|
||||
ASSERT_EQ(0x80U, location->second.values[0]);
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
// Check a negative value for the offset.
|
||||
ResetLogs();
|
||||
loc_regs.clear();
|
||||
this->memory_.SetMemory(0x1500, std::vector<uint8_t>{0x11, 0x86, 0x01, 0xff, 0x7f});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x1500, 0x1505, &loc_regs));
|
||||
ASSERT_EQ(0x1505U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
location = loc_regs.find(134);
|
||||
ASSERT_NE(loc_regs.end(), location);
|
||||
ASSERT_EQ(DWARF_LOCATION_OFFSET, location->second.type);
|
||||
ASSERT_EQ(static_cast<uint64_t>(-8), location->second.values[0]);
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaTest, cfa_restore) {
|
||||
this->memory_.SetMemory(0x2000, std::vector<uint8_t>{0xc2});
|
||||
dwarf_loc_regs_t loc_regs;
|
||||
|
||||
ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2000, 0x2001, &loc_regs));
|
||||
ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->last_error());
|
||||
ASSERT_EQ(0x2001U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(0U, loc_regs.size());
|
||||
|
||||
ASSERT_EQ("4 unwind restore while processing cie\n", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
dwarf_loc_regs_t cie_loc_regs;
|
||||
cie_loc_regs[2] = {.type = DWARF_LOCATION_REGISTER, .values = {0, 0}};
|
||||
this->cfa_->set_cie_loc_regs(&cie_loc_regs);
|
||||
this->memory_.SetMemory(0x3000, std::vector<uint8_t>{0x82, 0x04, 0xc2});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x3000, 0x3003, &loc_regs));
|
||||
ASSERT_EQ(0x3003U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
auto location = loc_regs.find(2);
|
||||
ASSERT_NE(loc_regs.end(), location);
|
||||
ASSERT_EQ(DWARF_LOCATION_REGISTER, location->second.type);
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaTest, cfa_restore_extended) {
|
||||
this->memory_.SetMemory(0x4000, std::vector<uint8_t>{0x06, 0x08});
|
||||
dwarf_loc_regs_t loc_regs;
|
||||
|
||||
ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x4000, 0x4002, &loc_regs));
|
||||
ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->last_error());
|
||||
ASSERT_EQ(0x4002U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(0U, loc_regs.size());
|
||||
|
||||
ASSERT_EQ("4 unwind restore while processing cie\n", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
loc_regs.clear();
|
||||
this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x05, 0x82, 0x02, 0x04, 0x06, 0x82, 0x02});
|
||||
dwarf_loc_regs_t cie_loc_regs;
|
||||
cie_loc_regs[258] = {.type = DWARF_LOCATION_REGISTER, .values = {0, 0}};
|
||||
this->cfa_->set_cie_loc_regs(&cie_loc_regs);
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x5000, 0x5007, &loc_regs));
|
||||
ASSERT_EQ(0x5007U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
auto location = loc_regs.find(258);
|
||||
ASSERT_NE(loc_regs.end(), location);
|
||||
ASSERT_EQ(DWARF_LOCATION_REGISTER, location->second.type);
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaTest, cfa_set_loc) {
|
||||
uint8_t buffer[1 + sizeof(TypeParam)];
|
||||
buffer[0] = 0x1;
|
||||
TypeParam address;
|
||||
std::string raw_data("Raw Data: 0x01 ");
|
||||
std::string address_str;
|
||||
if (sizeof(TypeParam) == 4) {
|
||||
address = 0x81234578U;
|
||||
address_str = "0x81234578";
|
||||
raw_data += "0x78 0x45 0x23 0x81";
|
||||
} else {
|
||||
address = 0x8123456712345678ULL;
|
||||
address_str = "0x8123456712345678";
|
||||
raw_data += "0x78 0x56 0x34 0x12 0x67 0x45 0x23 0x81";
|
||||
}
|
||||
memcpy(&buffer[1], &address, sizeof(address));
|
||||
|
||||
this->memory_.SetMemory(0x50, buffer, sizeof(buffer));
|
||||
ResetLogs();
|
||||
dwarf_loc_regs_t loc_regs;
|
||||
ASSERT_TRUE(
|
||||
this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x50, 0x51 + sizeof(TypeParam), &loc_regs));
|
||||
ASSERT_EQ(0x51 + sizeof(TypeParam), this->dmem_->cur_offset());
|
||||
ASSERT_EQ(address, this->cfa_->cur_pc());
|
||||
ASSERT_EQ(0U, loc_regs.size());
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
// Check for a set going back.
|
||||
ResetLogs();
|
||||
loc_regs.clear();
|
||||
this->fde_.pc_start = address + 0x10;
|
||||
ASSERT_TRUE(
|
||||
this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x50, 0x51 + sizeof(TypeParam), &loc_regs));
|
||||
ASSERT_EQ(0x51 + sizeof(TypeParam), this->dmem_->cur_offset());
|
||||
ASSERT_EQ(address, this->cfa_->cur_pc());
|
||||
ASSERT_EQ(0U, loc_regs.size());
|
||||
|
||||
std::string cur_address_str(address_str);
|
||||
cur_address_str[cur_address_str.size() - 2] = '8';
|
||||
std::string expected = "4 unwind Warning: PC is moving backwards: old " + cur_address_str +
|
||||
" new " + address_str + "\n";
|
||||
ASSERT_EQ(expected, GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaTest, cfa_advance_loc1) {
|
||||
this->memory_.SetMemory(0x200, std::vector<uint8_t>{0x02, 0x04});
|
||||
dwarf_loc_regs_t loc_regs;
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x200, 0x202, &loc_regs));
|
||||
ASSERT_EQ(0x202U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(this->fde_.pc_start + 0x10, this->cfa_->cur_pc());
|
||||
ASSERT_EQ(0U, loc_regs.size());
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaTest, cfa_advance_loc2) {
|
||||
this->memory_.SetMemory(0x600, std::vector<uint8_t>{0x03, 0x04, 0x03});
|
||||
dwarf_loc_regs_t loc_regs;
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x600, 0x603, &loc_regs));
|
||||
ASSERT_EQ(0x603U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(this->fde_.pc_start + 0xc10U, this->cfa_->cur_pc());
|
||||
ASSERT_EQ(0U, loc_regs.size());
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaTest, cfa_advance_loc4) {
|
||||
this->memory_.SetMemory(0x500, std::vector<uint8_t>{0x04, 0x04, 0x03, 0x02, 0x01});
|
||||
dwarf_loc_regs_t loc_regs;
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x500, 0x505, &loc_regs));
|
||||
ASSERT_EQ(0x505U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(this->fde_.pc_start + 0x4080c10, this->cfa_->cur_pc());
|
||||
ASSERT_EQ(0U, loc_regs.size());
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaTest, cfa_undefined) {
|
||||
this->memory_.SetMemory(0xa00, std::vector<uint8_t>{0x07, 0x09});
|
||||
dwarf_loc_regs_t loc_regs;
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0xa00, 0xa02, &loc_regs));
|
||||
ASSERT_EQ(0xa02U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
auto location = loc_regs.find(9);
|
||||
ASSERT_NE(loc_regs.end(), location);
|
||||
ASSERT_EQ(DWARF_LOCATION_UNDEFINED, location->second.type);
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
loc_regs.clear();
|
||||
this->memory_.SetMemory(0x1a00, std::vector<uint8_t>{0x07, 0x81, 0x01});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x1a00, 0x1a03, &loc_regs));
|
||||
ASSERT_EQ(0x1a03U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
location = loc_regs.find(129);
|
||||
ASSERT_NE(loc_regs.end(), location);
|
||||
ASSERT_EQ(DWARF_LOCATION_UNDEFINED, location->second.type);
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaTest, cfa_same) {
|
||||
this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x08, 0x7f});
|
||||
dwarf_loc_regs_t loc_regs;
|
||||
|
||||
loc_regs[127] = {.type = DWARF_LOCATION_REGISTER, .values = {0, 0}};
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x102, &loc_regs));
|
||||
ASSERT_EQ(0x102U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(0U, loc_regs.size());
|
||||
ASSERT_EQ(0U, loc_regs.count(127));
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
loc_regs.clear();
|
||||
this->memory_.SetMemory(0x2100, std::vector<uint8_t>{0x08, 0xff, 0x01});
|
||||
|
||||
loc_regs[255] = {.type = DWARF_LOCATION_REGISTER, .values = {0, 0}};
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2100, 0x2103, &loc_regs));
|
||||
ASSERT_EQ(0x2103U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(0U, loc_regs.size());
|
||||
ASSERT_EQ(0U, loc_regs.count(255));
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaTest, cfa_register) {
|
||||
this->memory_.SetMemory(0x300, std::vector<uint8_t>{0x09, 0x02, 0x01});
|
||||
dwarf_loc_regs_t loc_regs;
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x300, 0x303, &loc_regs));
|
||||
ASSERT_EQ(0x303U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
auto location = loc_regs.find(2);
|
||||
ASSERT_NE(loc_regs.end(), location);
|
||||
ASSERT_EQ(DWARF_LOCATION_REGISTER, location->second.type);
|
||||
ASSERT_EQ(1U, location->second.values[0]);
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
loc_regs.clear();
|
||||
this->memory_.SetMemory(0x4300, std::vector<uint8_t>{0x09, 0xff, 0x01, 0xff, 0x03});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x4300, 0x4305, &loc_regs));
|
||||
ASSERT_EQ(0x4305U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
location = loc_regs.find(255);
|
||||
ASSERT_NE(loc_regs.end(), location);
|
||||
ASSERT_EQ(DWARF_LOCATION_REGISTER, location->second.type);
|
||||
ASSERT_EQ(511U, location->second.values[0]);
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaTest, cfa_state) {
|
||||
this->memory_.SetMemory(0x300, std::vector<uint8_t>{0x0a});
|
||||
dwarf_loc_regs_t loc_regs;
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x300, 0x301, &loc_regs));
|
||||
ASSERT_EQ(0x301U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(0U, loc_regs.size());
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
this->memory_.SetMemory(0x4300, std::vector<uint8_t>{0x0b});
|
||||
|
||||
loc_regs.clear();
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x4300, 0x4301, &loc_regs));
|
||||
ASSERT_EQ(0x4301U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(0U, loc_regs.size());
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
this->memory_.SetMemory(0x2000, std::vector<uint8_t>{0x85, 0x02, 0x0a, 0x86, 0x04, 0x0b});
|
||||
|
||||
loc_regs.clear();
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2000, 0x2005, &loc_regs));
|
||||
ASSERT_EQ(0x2005U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(2U, loc_regs.size());
|
||||
ASSERT_NE(loc_regs.end(), loc_regs.find(5));
|
||||
ASSERT_NE(loc_regs.end(), loc_regs.find(6));
|
||||
|
||||
loc_regs.clear();
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2000, 0x2006, &loc_regs));
|
||||
ASSERT_EQ(0x2006U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
ASSERT_NE(loc_regs.end(), loc_regs.find(5));
|
||||
|
||||
ResetLogs();
|
||||
this->memory_.SetMemory(
|
||||
0x6000, std::vector<uint8_t>{0x0a, 0x85, 0x02, 0x0a, 0x86, 0x04, 0x0a, 0x87, 0x01, 0x0a, 0x89,
|
||||
0x05, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b});
|
||||
|
||||
loc_regs.clear();
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x6000, 0x600c, &loc_regs));
|
||||
ASSERT_EQ(0x600cU, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(4U, loc_regs.size());
|
||||
ASSERT_NE(loc_regs.end(), loc_regs.find(5));
|
||||
ASSERT_NE(loc_regs.end(), loc_regs.find(6));
|
||||
ASSERT_NE(loc_regs.end(), loc_regs.find(7));
|
||||
ASSERT_NE(loc_regs.end(), loc_regs.find(9));
|
||||
|
||||
loc_regs.clear();
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x6000, 0x600d, &loc_regs));
|
||||
ASSERT_EQ(0x600dU, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(3U, loc_regs.size());
|
||||
ASSERT_NE(loc_regs.end(), loc_regs.find(5));
|
||||
ASSERT_NE(loc_regs.end(), loc_regs.find(6));
|
||||
ASSERT_NE(loc_regs.end(), loc_regs.find(7));
|
||||
|
||||
loc_regs.clear();
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x6000, 0x600e, &loc_regs));
|
||||
ASSERT_EQ(0x600eU, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(2U, loc_regs.size());
|
||||
ASSERT_NE(loc_regs.end(), loc_regs.find(5));
|
||||
ASSERT_NE(loc_regs.end(), loc_regs.find(6));
|
||||
|
||||
loc_regs.clear();
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x6000, 0x600f, &loc_regs));
|
||||
ASSERT_EQ(0x600fU, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
ASSERT_NE(loc_regs.end(), loc_regs.find(5));
|
||||
|
||||
loc_regs.clear();
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x6000, 0x6010, &loc_regs));
|
||||
ASSERT_EQ(0x6010U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(0U, loc_regs.size());
|
||||
|
||||
loc_regs.clear();
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x6000, 0x6011, &loc_regs));
|
||||
ASSERT_EQ(0x6011U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(0U, loc_regs.size());
|
||||
}
|
||||
|
||||
// This test verifies that the cfa offset is saved and restored properly.
|
||||
// Even though the spec is not clear about whether the offset is also
|
||||
// restored, the gcc unwinder does, and libunwind does too.
|
||||
TYPED_TEST_P(DwarfCfaTest, cfa_state_cfa_offset_restore) {
|
||||
this->memory_.SetMemory(0x3000, std::vector<uint8_t>{0x0a, 0x0e, 0x40, 0x0b});
|
||||
dwarf_loc_regs_t loc_regs;
|
||||
loc_regs[CFA_REG] = {.type = DWARF_LOCATION_REGISTER, .values = {5, 100}};
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x3000, 0x3004, &loc_regs));
|
||||
ASSERT_EQ(0x3004U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
ASSERT_EQ(DWARF_LOCATION_REGISTER, loc_regs[CFA_REG].type);
|
||||
ASSERT_EQ(5U, loc_regs[CFA_REG].values[0]);
|
||||
ASSERT_EQ(100U, loc_regs[CFA_REG].values[1]);
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaTest, cfa_def_cfa) {
|
||||
this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x0c, 0x7f, 0x74});
|
||||
dwarf_loc_regs_t loc_regs;
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x103, &loc_regs));
|
||||
ASSERT_EQ(0x103U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
ASSERT_EQ(DWARF_LOCATION_REGISTER, loc_regs[CFA_REG].type);
|
||||
ASSERT_EQ(0x7fU, loc_regs[CFA_REG].values[0]);
|
||||
ASSERT_EQ(0x74U, loc_regs[CFA_REG].values[1]);
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
loc_regs.clear();
|
||||
this->memory_.SetMemory(0x200, std::vector<uint8_t>{0x0c, 0xff, 0x02, 0xf4, 0x04});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x200, 0x205, &loc_regs));
|
||||
ASSERT_EQ(0x205U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
ASSERT_EQ(DWARF_LOCATION_REGISTER, loc_regs[CFA_REG].type);
|
||||
ASSERT_EQ(0x17fU, loc_regs[CFA_REG].values[0]);
|
||||
ASSERT_EQ(0x274U, loc_regs[CFA_REG].values[1]);
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaTest, cfa_def_cfa_sf) {
|
||||
this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x12, 0x30, 0x25});
|
||||
dwarf_loc_regs_t loc_regs;
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x103, &loc_regs));
|
||||
ASSERT_EQ(0x103U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
ASSERT_EQ(DWARF_LOCATION_REGISTER, loc_regs[CFA_REG].type);
|
||||
ASSERT_EQ(0x30U, loc_regs[CFA_REG].values[0]);
|
||||
ASSERT_EQ(0x128U, loc_regs[CFA_REG].values[1]);
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
// Test a negative value.
|
||||
ResetLogs();
|
||||
loc_regs.clear();
|
||||
this->memory_.SetMemory(0x200, std::vector<uint8_t>{0x12, 0xa3, 0x01, 0xfa, 0x7f});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x200, 0x205, &loc_regs));
|
||||
ASSERT_EQ(0x205U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
ASSERT_EQ(DWARF_LOCATION_REGISTER, loc_regs[CFA_REG].type);
|
||||
ASSERT_EQ(0xa3U, loc_regs[CFA_REG].values[0]);
|
||||
ASSERT_EQ(static_cast<uint64_t>(-48), loc_regs[CFA_REG].values[1]);
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaTest, cfa_def_cfa_register) {
|
||||
this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x0d, 0x72});
|
||||
dwarf_loc_regs_t loc_regs;
|
||||
|
||||
// This fails because the cfa is not defined as a register.
|
||||
ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x102, &loc_regs));
|
||||
ASSERT_EQ(0U, loc_regs.size());
|
||||
ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->last_error());
|
||||
|
||||
ASSERT_EQ("4 unwind Attempt to set new register, but cfa is not already set to a register.\n",
|
||||
GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
loc_regs.clear();
|
||||
loc_regs[CFA_REG] = {.type = DWARF_LOCATION_REGISTER, .values = {3, 20}};
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x102, &loc_regs));
|
||||
ASSERT_EQ(0x102U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
ASSERT_EQ(DWARF_LOCATION_REGISTER, loc_regs[CFA_REG].type);
|
||||
ASSERT_EQ(0x72U, loc_regs[CFA_REG].values[0]);
|
||||
ASSERT_EQ(20U, loc_regs[CFA_REG].values[1]);
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
this->memory_.SetMemory(0x200, std::vector<uint8_t>{0x0d, 0xf9, 0x20});
|
||||
loc_regs.clear();
|
||||
loc_regs[CFA_REG] = {.type = DWARF_LOCATION_REGISTER, .values = {3, 60}};
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x200, 0x203, &loc_regs));
|
||||
ASSERT_EQ(0x203U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
ASSERT_EQ(DWARF_LOCATION_REGISTER, loc_regs[CFA_REG].type);
|
||||
ASSERT_EQ(0x1079U, loc_regs[CFA_REG].values[0]);
|
||||
ASSERT_EQ(60U, loc_regs[CFA_REG].values[1]);
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaTest, cfa_def_cfa_offset) {
|
||||
this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x0e, 0x59});
|
||||
dwarf_loc_regs_t loc_regs;
|
||||
|
||||
// This fails because the cfa is not defined as a register.
|
||||
ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x102, &loc_regs));
|
||||
ASSERT_EQ(0U, loc_regs.size());
|
||||
ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->last_error());
|
||||
|
||||
ASSERT_EQ("4 unwind Attempt to set offset, but cfa is not set to a register.\n",
|
||||
GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
loc_regs.clear();
|
||||
loc_regs[CFA_REG] = {.type = DWARF_LOCATION_REGISTER, .values = {3}};
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x102, &loc_regs));
|
||||
ASSERT_EQ(0x102U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
ASSERT_EQ(DWARF_LOCATION_REGISTER, loc_regs[CFA_REG].type);
|
||||
ASSERT_EQ(3U, loc_regs[CFA_REG].values[0]);
|
||||
ASSERT_EQ(0x59U, loc_regs[CFA_REG].values[1]);
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
this->memory_.SetMemory(0x200, std::vector<uint8_t>{0x0e, 0xd4, 0x0a});
|
||||
loc_regs.clear();
|
||||
loc_regs[CFA_REG] = {.type = DWARF_LOCATION_REGISTER, .values = {3}};
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x200, 0x203, &loc_regs));
|
||||
ASSERT_EQ(0x203U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
ASSERT_EQ(DWARF_LOCATION_REGISTER, loc_regs[CFA_REG].type);
|
||||
ASSERT_EQ(3U, loc_regs[CFA_REG].values[0]);
|
||||
ASSERT_EQ(0x554U, loc_regs[CFA_REG].values[1]);
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaTest, cfa_def_cfa_offset_sf) {
|
||||
this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x13, 0x23});
|
||||
dwarf_loc_regs_t loc_regs;
|
||||
|
||||
// This fails because the cfa is not defined as a register.
|
||||
ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x102, &loc_regs));
|
||||
ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->last_error());
|
||||
|
||||
ASSERT_EQ("4 unwind Attempt to set offset, but cfa is not set to a register.\n",
|
||||
GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
loc_regs.clear();
|
||||
loc_regs[CFA_REG] = {.type = DWARF_LOCATION_REGISTER, .values = {3}};
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x102, &loc_regs));
|
||||
ASSERT_EQ(0x102U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
ASSERT_EQ(DWARF_LOCATION_REGISTER, loc_regs[CFA_REG].type);
|
||||
ASSERT_EQ(3U, loc_regs[CFA_REG].values[0]);
|
||||
ASSERT_EQ(0x118U, loc_regs[CFA_REG].values[1]);
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
// Negative offset.
|
||||
ResetLogs();
|
||||
this->memory_.SetMemory(0x200, std::vector<uint8_t>{0x13, 0xf6, 0x7f});
|
||||
loc_regs.clear();
|
||||
loc_regs[CFA_REG] = {.type = DWARF_LOCATION_REGISTER, .values = {3}};
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x200, 0x203, &loc_regs));
|
||||
ASSERT_EQ(0x203U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
ASSERT_EQ(DWARF_LOCATION_REGISTER, loc_regs[CFA_REG].type);
|
||||
ASSERT_EQ(3U, loc_regs[CFA_REG].values[0]);
|
||||
ASSERT_EQ(static_cast<TypeParam>(-80), static_cast<TypeParam>(loc_regs[CFA_REG].values[1]));
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaTest, cfa_def_cfa_expression) {
|
||||
this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x0f, 0x04, 0x01, 0x02, 0x03, 0x04});
|
||||
dwarf_loc_regs_t loc_regs;
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x106, &loc_regs));
|
||||
ASSERT_EQ(0x106U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
std::vector<uint8_t> ops{0x0f, 0x81, 0x01};
|
||||
for (uint8_t i = 3; i < 132; i++) {
|
||||
ops.push_back(i - 1);
|
||||
}
|
||||
this->memory_.SetMemory(0x200, ops);
|
||||
loc_regs.clear();
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x200, 0x284, &loc_regs));
|
||||
ASSERT_EQ(0x284U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaTest, cfa_expression) {
|
||||
this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x10, 0x04, 0x02, 0x40, 0x20});
|
||||
dwarf_loc_regs_t loc_regs;
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x105, &loc_regs));
|
||||
ASSERT_EQ(0x105U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
auto location = loc_regs.find(4);
|
||||
ASSERT_NE(loc_regs.end(), location);
|
||||
ASSERT_EQ(DWARF_LOCATION_EXPRESSION, location->second.type);
|
||||
ASSERT_EQ(2U, location->second.values[0]);
|
||||
ASSERT_EQ(0x105U, location->second.values[1]);
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
std::vector<uint8_t> ops{0x10, 0xff, 0x01, 0x82, 0x01};
|
||||
for (uint8_t i = 5; i < 135; i++) {
|
||||
ops.push_back(i - 4);
|
||||
}
|
||||
|
||||
this->memory_.SetMemory(0x200, ops);
|
||||
loc_regs.clear();
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x200, 0x287, &loc_regs));
|
||||
ASSERT_EQ(0x287U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
location = loc_regs.find(255);
|
||||
ASSERT_NE(loc_regs.end(), location);
|
||||
ASSERT_EQ(DWARF_LOCATION_EXPRESSION, location->second.type);
|
||||
ASSERT_EQ(130U, location->second.values[0]);
|
||||
ASSERT_EQ(0x287U, location->second.values[1]);
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaTest, cfa_val_offset) {
|
||||
this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x14, 0x45, 0x54});
|
||||
dwarf_loc_regs_t loc_regs;
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x103, &loc_regs));
|
||||
ASSERT_EQ(0x103U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
auto location = loc_regs.find(69);
|
||||
ASSERT_NE(loc_regs.end(), location);
|
||||
ASSERT_EQ(DWARF_LOCATION_VAL_OFFSET, location->second.type);
|
||||
ASSERT_EQ(0x2a0U, location->second.values[0]);
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
loc_regs.clear();
|
||||
this->memory_.SetMemory(0x400, std::vector<uint8_t>{0x14, 0xa2, 0x02, 0xb4, 0x05});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x400, 0x405, &loc_regs));
|
||||
ASSERT_EQ(0x405U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
location = loc_regs.find(290);
|
||||
ASSERT_NE(loc_regs.end(), location);
|
||||
ASSERT_EQ(DWARF_LOCATION_VAL_OFFSET, location->second.type);
|
||||
ASSERT_EQ(0x15a0U, location->second.values[0]);
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaTest, cfa_val_offset_sf) {
|
||||
this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x15, 0x56, 0x12});
|
||||
dwarf_loc_regs_t loc_regs;
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x103, &loc_regs));
|
||||
ASSERT_EQ(0x103U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
auto location = loc_regs.find(86);
|
||||
ASSERT_NE(loc_regs.end(), location);
|
||||
ASSERT_EQ(DWARF_LOCATION_VAL_OFFSET, location->second.type);
|
||||
ASSERT_EQ(0x90U, location->second.values[0]);
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
// Negative value.
|
||||
ResetLogs();
|
||||
loc_regs.clear();
|
||||
this->memory_.SetMemory(0xa00, std::vector<uint8_t>{0x15, 0xff, 0x01, 0xc0, 0x7f});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0xa00, 0xa05, &loc_regs));
|
||||
ASSERT_EQ(0xa05U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
location = loc_regs.find(255);
|
||||
ASSERT_NE(loc_regs.end(), location);
|
||||
ASSERT_EQ(DWARF_LOCATION_VAL_OFFSET, location->second.type);
|
||||
ASSERT_EQ(static_cast<uint64_t>(-512), location->second.values[0]);
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaTest, cfa_val_expression) {
|
||||
this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x16, 0x05, 0x02, 0x10, 0x20});
|
||||
dwarf_loc_regs_t loc_regs;
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x105, &loc_regs));
|
||||
ASSERT_EQ(0x105U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
auto location = loc_regs.find(5);
|
||||
ASSERT_NE(loc_regs.end(), location);
|
||||
ASSERT_EQ(DWARF_LOCATION_VAL_EXPRESSION, location->second.type);
|
||||
ASSERT_EQ(2U, location->second.values[0]);
|
||||
ASSERT_EQ(0x105U, location->second.values[1]);
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
std::vector<uint8_t> ops{0x16, 0x83, 0x10, 0xa8, 0x01};
|
||||
for (uint8_t i = 0; i < 168; i++) {
|
||||
ops.push_back(i);
|
||||
}
|
||||
|
||||
this->memory_.SetMemory(0xa00, ops);
|
||||
loc_regs.clear();
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0xa00, 0xaad, &loc_regs));
|
||||
ASSERT_EQ(0xaadU, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
location = loc_regs.find(2051);
|
||||
ASSERT_NE(loc_regs.end(), location);
|
||||
ASSERT_EQ(DWARF_LOCATION_VAL_EXPRESSION, location->second.type);
|
||||
ASSERT_EQ(168U, location->second.values[0]);
|
||||
ASSERT_EQ(0xaadU, location->second.values[1]);
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaTest, cfa_gnu_args_size) {
|
||||
this->memory_.SetMemory(0x2000, std::vector<uint8_t>{0x2e, 0x04});
|
||||
dwarf_loc_regs_t loc_regs;
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2000, 0x2002, &loc_regs));
|
||||
ASSERT_EQ(0x2002U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(0U, loc_regs.size());
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
loc_regs.clear();
|
||||
this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x2e, 0xa4, 0x80, 0x04});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x5000, 0x5004, &loc_regs));
|
||||
ASSERT_EQ(0x5004U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(0U, loc_regs.size());
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaTest, cfa_gnu_negative_offset_extended) {
|
||||
this->memory_.SetMemory(0x500, std::vector<uint8_t>{0x2f, 0x08, 0x10});
|
||||
dwarf_loc_regs_t loc_regs;
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x500, 0x503, &loc_regs));
|
||||
ASSERT_EQ(0x503U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
auto location = loc_regs.find(8);
|
||||
ASSERT_NE(loc_regs.end(), location);
|
||||
ASSERT_EQ(DWARF_LOCATION_OFFSET, location->second.type);
|
||||
ASSERT_EQ(static_cast<uint64_t>(-16), location->second.values[0]);
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
|
||||
ResetLogs();
|
||||
loc_regs.clear();
|
||||
this->memory_.SetMemory(0x1500, std::vector<uint8_t>{0x2f, 0x81, 0x02, 0xff, 0x01});
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x1500, 0x1505, &loc_regs));
|
||||
ASSERT_EQ(0x1505U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
location = loc_regs.find(257);
|
||||
ASSERT_NE(loc_regs.end(), location);
|
||||
ASSERT_EQ(DWARF_LOCATION_OFFSET, location->second.type);
|
||||
ASSERT_EQ(static_cast<uint64_t>(-255), location->second.values[0]);
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(DwarfCfaTest, cfa_register_override) {
|
||||
this->memory_.SetMemory(0x300, std::vector<uint8_t>{0x09, 0x02, 0x01, 0x09, 0x02, 0x04});
|
||||
dwarf_loc_regs_t loc_regs;
|
||||
|
||||
ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x300, 0x306, &loc_regs));
|
||||
ASSERT_EQ(0x306U, this->dmem_->cur_offset());
|
||||
ASSERT_EQ(1U, loc_regs.size());
|
||||
auto location = loc_regs.find(2);
|
||||
ASSERT_NE(loc_regs.end(), location);
|
||||
ASSERT_EQ(DWARF_LOCATION_REGISTER, location->second.type);
|
||||
ASSERT_EQ(4U, location->second.values[0]);
|
||||
|
||||
ASSERT_EQ("", GetFakeLogPrint());
|
||||
ASSERT_EQ("", GetFakeLogBuf());
|
||||
}
|
||||
|
||||
REGISTER_TYPED_TEST_CASE_P(DwarfCfaTest, cfa_illegal, cfa_nop, cfa_offset, cfa_offset_extended,
|
||||
cfa_offset_extended_sf, cfa_restore, cfa_restore_extended, cfa_set_loc,
|
||||
cfa_advance_loc1, cfa_advance_loc2, cfa_advance_loc4, cfa_undefined,
|
||||
cfa_same, cfa_register, cfa_state, cfa_state_cfa_offset_restore,
|
||||
cfa_def_cfa, cfa_def_cfa_sf, cfa_def_cfa_register, cfa_def_cfa_offset,
|
||||
cfa_def_cfa_offset_sf, cfa_def_cfa_expression, cfa_expression,
|
||||
cfa_val_offset, cfa_val_offset_sf, cfa_val_expression, cfa_gnu_args_size,
|
||||
cfa_gnu_negative_offset_extended, cfa_register_override);
|
||||
|
||||
typedef ::testing::Types<uint32_t, uint64_t> DwarfCfaTestTypes;
|
||||
INSTANTIATE_TYPED_TEST_CASE_P(, DwarfCfaTest, DwarfCfaTestTypes);
|
||||
Loading…
Add table
Reference in a new issue