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:
parent
71fa8125b9
commit
559c7f2092
8 changed files with 486 additions and 573 deletions
|
@ -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
|
@ -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
66
libunwindstack/RegsInfo.h
Normal 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
|
|
@ -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;
|
||||
|
|
|
@ -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
|
@ -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, ®s, &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, ®s, &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, ®s, &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, ®s, &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, ®s, &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, ®s, &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, ®s, &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, ®s, &finished));
|
||||
EXPECT_FALSE(finished);
|
||||
|
|
Loading…
Reference in a new issue