Implement new DEX PC lookup scheme.

GDB wasn't handling the old one gracefully.

- Create a RegsInfo structure that can be used to properly eval expression
  data.
- Remove the versions on Dwarf ops. It doesn't work the in the real world
  and doesn't add useful information.
- Fix dex pc frame number bug.

Test: testrunner.py -j40 --host --cdex-fast -t 137
Test: libunwindstack_test
Test: All unit tests pass.
Change-Id: Iac4fea651b81cb6087fd237a9a5027a352a49245
This commit is contained in:
Christopher Ferris 2018-02-12 20:18:03 -08:00
parent 71fa8125b9
commit 559c7f2092
8 changed files with 486 additions and 573 deletions

View file

@ -36,13 +36,45 @@ template <typename AddressType>
constexpr typename DwarfOp<AddressType>::OpCallback DwarfOp<AddressType>::kCallbackTable[256];
template <typename AddressType>
bool DwarfOp<AddressType>::Eval(uint64_t start, uint64_t end, uint8_t dwarf_version) {
uint32_t iterations = 0;
bool DwarfOp<AddressType>::Eval(uint64_t start, uint64_t end) {
is_register_ = false;
stack_.clear();
memory_->set_cur_offset(start);
dex_pc_set_ = false;
// Unroll the first Decode calls to be able to check for a special
// sequence of ops and values that indicate this is the dex pc.
// The pattern is:
// OP_const4u (0x0c) 'D' 'E' 'X' '1'
// OP_drop (0x13)
if (memory_->cur_offset() < end) {
if (!Decode()) {
return false;
}
} else {
return true;
}
bool check_for_drop;
if (cur_op_ == 0x0c && operands_.back() == 0x31584544) {
check_for_drop = true;
} else {
check_for_drop = false;
}
if (memory_->cur_offset() < end) {
if (!Decode()) {
return false;
}
} else {
return true;
}
if (check_for_drop && cur_op_ == 0x13) {
dex_pc_set_ = true;
}
uint32_t iterations = 2;
while (memory_->cur_offset() < end) {
if (!Decode(dwarf_version)) {
if (!Decode()) {
return false;
}
// To protect against a branch that creates an infinite loop,
@ -56,7 +88,7 @@ bool DwarfOp<AddressType>::Eval(uint64_t start, uint64_t end, uint8_t dwarf_vers
}
template <typename AddressType>
bool DwarfOp<AddressType>::Decode(uint8_t dwarf_version) {
bool DwarfOp<AddressType>::Decode() {
last_error_.code = DWARF_ERROR_NONE;
if (!memory_->ReadBytes(&cur_op_, 1)) {
last_error_.code = DWARF_ERROR_MEMORY_INVALID;
@ -71,12 +103,6 @@ bool DwarfOp<AddressType>::Decode(uint8_t dwarf_version) {
return false;
}
// Check for an unsupported opcode.
if (dwarf_version < op->supported_version) {
last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
return false;
}
// Make sure that the required number of stack elements is available.
if (stack_.size() < op->num_required_stack_values) {
last_error_.code = DWARF_ERROR_STACK_INDEX_NOT_VALID;
@ -434,22 +460,22 @@ bool DwarfOp<AddressType>::op_regx() {
template <typename AddressType>
bool DwarfOp<AddressType>::op_breg() {
uint16_t reg = cur_op() - 0x70;
if (reg >= regs_->total_regs()) {
if (reg >= regs_info_->Total()) {
last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
return false;
}
stack_.push_front((*regs_)[reg] + OperandAt(0));
stack_.push_front(regs_info_->Get(reg) + OperandAt(0));
return true;
}
template <typename AddressType>
bool DwarfOp<AddressType>::op_bregx() {
AddressType reg = OperandAt(0);
if (reg >= regs_->total_regs()) {
if (reg >= regs_info_->Total()) {
last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
return false;
}
stack_.push_front((*regs_)[reg] + OperandAt(1));
stack_.push_front(regs_info_->Get(reg) + OperandAt(1));
return true;
}

File diff suppressed because it is too large Load diff

View file

@ -26,16 +26,14 @@
#include <unwindstack/Regs.h>
#include "DwarfCfa.h"
#include "DwarfEncoding.h"
#include "DwarfOp.h"
#include "DwarfDebugFrame.h"
#include "DwarfEhFrame.h"
#include "DwarfEncoding.h"
#include "DwarfOp.h"
#include "RegsInfo.h"
namespace unwindstack {
constexpr uint64_t DEX_PC_REG = 0x20444558;
DwarfSection::DwarfSection(Memory* memory) : memory_(memory) {}
const DwarfFde* DwarfSection::GetFdeFromPc(uint64_t pc) {
@ -75,14 +73,17 @@ bool DwarfSection::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* f
}
template <typename AddressType>
bool DwarfSectionImpl<AddressType>::EvalExpression(const DwarfLocation& loc, uint8_t version,
Memory* regular_memory, AddressType* value) {
bool DwarfSectionImpl<AddressType>::EvalExpression(const DwarfLocation& loc, Memory* regular_memory,
AddressType* value,
RegsInfo<AddressType>* regs_info,
bool* is_dex_pc) {
DwarfOp<AddressType> op(&memory_, regular_memory);
op.set_regs_info(regs_info);
// Need to evaluate the op data.
uint64_t start = loc.values[1];
uint64_t end = start + loc.values[0];
if (!op.Eval(start, end, version)) {
uint64_t end = loc.values[1];
uint64_t start = end - loc.values[0];
if (!op.Eval(start, end)) {
last_error_ = op.last_error();
return false;
}
@ -96,6 +97,9 @@ bool DwarfSectionImpl<AddressType>::EvalExpression(const DwarfLocation& loc, uin
return false;
}
*value = op.StackAt(0);
if (is_dex_pc != nullptr && op.dex_pc_set()) {
*is_dex_pc = true;
}
return true;
}
@ -103,12 +107,10 @@ template <typename AddressType>
struct EvalInfo {
const dwarf_loc_regs_t* loc_regs;
const DwarfCie* cie;
RegsImpl<AddressType>* cur_regs;
Memory* regular_memory;
AddressType cfa;
bool return_address_undefined = false;
uint64_t reg_map = 0;
AddressType reg_values[64];
RegsInfo<AddressType> regs_info;
};
template <typename AddressType>
@ -129,32 +131,18 @@ bool DwarfSectionImpl<AddressType>::EvalRegister(const DwarfLocation* loc, uint3
break;
case DWARF_LOCATION_REGISTER: {
uint32_t cur_reg = loc->values[0];
if (cur_reg >= eval_info->cur_regs->total_regs()) {
if (cur_reg >= eval_info->regs_info.Total()) {
last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
return false;
}
AddressType* cur_reg_ptr = &(*eval_info->cur_regs)[cur_reg];
const auto& entry = eval_info->loc_regs->find(cur_reg);
if (entry != eval_info->loc_regs->end()) {
if (!(eval_info->reg_map & (1 << cur_reg))) {
eval_info->reg_map |= 1 << cur_reg;
eval_info->reg_values[cur_reg] = *cur_reg_ptr;
if (!EvalRegister(&entry->second, cur_reg, cur_reg_ptr, eval_info)) {
return false;
}
}
// Use the register value from before any evaluations.
*reg_ptr = eval_info->reg_values[cur_reg] + loc->values[1];
} else {
*reg_ptr = *cur_reg_ptr + loc->values[1];
}
*reg_ptr = eval_info->regs_info.Get(cur_reg) + loc->values[1];
break;
}
case DWARF_LOCATION_EXPRESSION:
case DWARF_LOCATION_VAL_EXPRESSION: {
AddressType value;
if (!EvalExpression(*loc, eval_info->cie->version, regular_memory, &value)) {
bool is_dex_pc = false;
if (!EvalExpression(*loc, regular_memory, &value, &eval_info->regs_info, &is_dex_pc)) {
return false;
}
if (loc->type == DWARF_LOCATION_EXPRESSION) {
@ -165,6 +153,9 @@ bool DwarfSectionImpl<AddressType>::EvalRegister(const DwarfLocation* loc, uint3
}
} else {
*reg_ptr = value;
if (is_dex_pc) {
eval_info->regs_info.regs->set_dex_pc(value);
}
}
break;
}
@ -201,8 +192,10 @@ bool DwarfSectionImpl<AddressType>::Eval(const DwarfCie* cie, Memory* regular_me
AddressType prev_cfa = regs->sp();
EvalInfo<AddressType> eval_info{
.loc_regs = &loc_regs, .cie = cie, .regular_memory = regular_memory, .cur_regs = cur_regs};
EvalInfo<AddressType> eval_info{.loc_regs = &loc_regs,
.cie = cie,
.regular_memory = regular_memory,
.regs_info = RegsInfo<AddressType>(cur_regs)};
const DwarfLocation* loc = &cfa_entry->second;
// Only a few location types are valid for the cfa.
switch (loc->type) {
@ -224,7 +217,7 @@ bool DwarfSectionImpl<AddressType>::Eval(const DwarfCie* cie, Memory* regular_me
case DWARF_LOCATION_EXPRESSION:
case DWARF_LOCATION_VAL_EXPRESSION: {
AddressType value;
if (!EvalExpression(*loc, cie->version, regular_memory, &value)) {
if (!EvalExpression(*loc, regular_memory, &value, &eval_info.regs_info, nullptr)) {
return false;
}
if (loc->type == DWARF_LOCATION_EXPRESSION) {
@ -249,28 +242,15 @@ bool DwarfSectionImpl<AddressType>::Eval(const DwarfCie* cie, Memory* regular_me
if (reg == CFA_REG) continue;
AddressType* reg_ptr;
AddressType dex_pc = 0;
if (reg == DEX_PC_REG) {
// Special register that indicates this is a dex pc.
dex_pc = 0;
reg_ptr = &dex_pc;
} else if (reg >= cur_regs->total_regs() || eval_info.reg_map & (1 << reg)) {
// Skip this unknown register, or a register that has already been
// processed.
if (reg >= cur_regs->total_regs()) {
// Skip this unknown register.
continue;
} else {
reg_ptr = &(*cur_regs)[reg];
eval_info.reg_map |= 1 << reg;
eval_info.reg_values[reg] = *reg_ptr;
}
reg_ptr = eval_info.regs_info.Save(reg);
if (!EvalRegister(&entry.second, reg, reg_ptr, &eval_info)) {
return false;
}
if (reg == DEX_PC_REG) {
cur_regs->set_dex_pc(dex_pc);
}
}
// Find the return address location.

66
libunwindstack/RegsInfo.h Normal file
View file

@ -0,0 +1,66 @@
/*
* Copyright (C) 2018 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_REGS_INFO_H
#define _LIBUNWINDSTACK_REGS_INFO_H
#include <stdint.h>
#include <unwindstack/Regs.h>
namespace unwindstack {
template <typename AddressType>
struct RegsInfo {
RegsInfo(RegsImpl<AddressType>* regs) : regs(regs) {}
RegsImpl<AddressType>* regs = nullptr;
uint64_t saved_reg_map = 0;
AddressType saved_regs[64];
inline AddressType Get(uint32_t reg) {
if (IsSaved(reg)) {
return saved_regs[reg];
}
return (*regs)[reg];
}
inline AddressType* Save(uint32_t reg) {
if (reg > sizeof(saved_regs) / sizeof(AddressType)) {
// This should never happen as since all currently supported
// architectures have the total number of registers < 64.
abort();
}
saved_reg_map |= 1 << reg;
saved_regs[reg] = (*regs)[reg];
return &(*regs)[reg];
}
inline bool IsSaved(uint32_t reg) {
if (reg > sizeof(saved_regs) / sizeof(AddressType)) {
// This should never happen as since all currently supported
// architectures have the total number of registers < 64.
abort();
}
return saved_reg_map & (1 << reg);
}
inline uint16_t Total() { return regs->total_regs(); }
};
} // namespace unwindstack
#endif // _LIBUNWINDSTACK_REGS_INFO_H

View file

@ -48,6 +48,7 @@ void Unwinder::FillInDexFrame() {
size_t frame_num = frames_.size();
frames_.resize(frame_num + 1);
FrameData* frame = &frames_.at(frame_num);
frame->num = frame_num;
uint64_t dex_pc = regs_->dex_pc();
frame->pc = dex_pc;

View file

@ -32,6 +32,8 @@ namespace unwindstack {
// Forward declarations.
class Memory;
class Regs;
template <typename AddressType>
struct RegsInfo;
class DwarfSection {
public:
@ -149,8 +151,8 @@ class DwarfSectionImpl : public DwarfSection {
bool Log(uint8_t indent, uint64_t pc, uint64_t load_bias, const DwarfFde* fde) override;
protected:
bool EvalExpression(const DwarfLocation& loc, uint8_t version, Memory* regular_memory,
AddressType* value);
bool EvalExpression(const DwarfLocation& loc, Memory* regular_memory, AddressType* value,
RegsInfo<AddressType>* regs_info, bool* is_dex_pc);
bool GetCieInfo(uint8_t* segment_size, uint8_t* encoding);

File diff suppressed because it is too large Load diff

View file

@ -99,7 +99,7 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr_eval_fail) {
regs.set_sp(0x2000);
regs[5] = 0x20;
regs[9] = 0x3000;
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x2, 0x5000}};
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x2, 0x5002}};
bool finished;
ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
@ -116,7 +116,7 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr_no_stack) {
regs[5] = 0x20;
regs[9] = 0x3000;
this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x96, 0x96, 0x96});
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x2, 0x5000}};
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x2, 0x5002}};
bool finished;
ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
EXPECT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->section_->LastErrorCode());
@ -134,7 +134,7 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr) {
this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x0c, 0x00, 0x00, 0x00, 0x80});
TypeParam cfa_value = 0x12345;
this->memory_.SetMemory(0x80000000, &cfa_value, sizeof(cfa_value));
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x4, 0x5000}};
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x4, 0x5004}};
bool finished;
ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
EXPECT_FALSE(finished);
@ -152,7 +152,7 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_val_expr) {
regs[5] = 0x20;
regs[9] = 0x3000;
this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x0c, 0x00, 0x00, 0x00, 0x80});
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_VAL_EXPRESSION, {0x4, 0x5000}};
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_VAL_EXPRESSION, {0x4, 0x5004}};
bool finished;
ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
ASSERT_FALSE(finished);
@ -170,7 +170,7 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr_is_register) {
regs[5] = 0x20;
regs[9] = 0x3000;
this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x50, 0x96, 0x96});
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x2, 0x5000}};
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x2, 0x5002}};
bool finished;
ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
EXPECT_EQ(DWARF_ERROR_NOT_IMPLEMENTED, this->section_->LastErrorCode());
@ -322,7 +322,8 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_dex_pc) {
regs[0] = 0x10;
regs[8] = 0x20;
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
loc_regs[0x20444558] = DwarfLocation{DWARF_LOCATION_REGISTER, {0, 1}};
loc_regs[1] = DwarfLocation{DWARF_LOCATION_VAL_EXPRESSION, {0x8, 0x5008}};
this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x0c, 'D', 'E', 'X', '1', 0x13, 0x08, 0x11});
bool finished;
ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
EXPECT_EQ(0x10U, regs[0]);
@ -462,7 +463,7 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_reg_expr) {
TypeParam cfa_value = 0x12345;
this->memory_.SetMemory(0x80000000, &cfa_value, sizeof(cfa_value));
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
loc_regs[5] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x4, 0x5000}};
loc_regs[5] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x4, 0x5004}};
bool finished;
ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
EXPECT_FALSE(finished);
@ -480,7 +481,7 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_reg_val_expr) {
regs[8] = 0x3000;
this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x0c, 0x00, 0x00, 0x00, 0x80});
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
loc_regs[5] = DwarfLocation{DWARF_LOCATION_VAL_EXPRESSION, {0x4, 0x5000}};
loc_regs[5] = DwarfLocation{DWARF_LOCATION_VAL_EXPRESSION, {0x4, 0x5004}};
bool finished;
ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
EXPECT_FALSE(finished);