diff --git a/libunwindstack/DwarfSection.cpp b/libunwindstack/DwarfSection.cpp index 9e2a3cda7..bf86e6e66 100644 --- a/libunwindstack/DwarfSection.cpp +++ b/libunwindstack/DwarfSection.cpp @@ -465,13 +465,9 @@ bool DwarfSectionImpl::EvalRegister(const DwarfLocation* loc, uint3 eval_info->return_address_undefined = true; } break; - case DWARF_LOCATION_PSEUDO_REGISTER: { - if (!eval_info->regs_info.regs->SetPseudoRegister(reg, loc->values[0])) { - last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; - return false; - } - break; - } + case DWARF_LOCATION_PSEUDO_REGISTER: + last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; + return false; default: break; } @@ -543,11 +539,15 @@ bool DwarfSectionImpl::Eval(const DwarfCie* cie, Memory* regular_me // Skip this unknown register. continue; } - } - - reg_ptr = eval_info.regs_info.Save(reg); - if (!EvalRegister(&entry.second, reg, reg_ptr, &eval_info)) { - return false; + if (!eval_info.regs_info.regs->SetPseudoRegister(reg, entry.second.values[0])) { + last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; + return false; + } + } else { + reg_ptr = eval_info.regs_info.Save(reg); + if (!EvalRegister(&entry.second, reg, reg_ptr, &eval_info)) { + return false; + } } } diff --git a/libunwindstack/tests/DwarfSectionImplTest.cpp b/libunwindstack/tests/DwarfSectionImplTest.cpp index d57cd339d..a08a8d070 100644 --- a/libunwindstack/tests/DwarfSectionImplTest.cpp +++ b/libunwindstack/tests/DwarfSectionImplTest.cpp @@ -492,6 +492,40 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_reg_val_expr) { EXPECT_EQ(0x80000000U, regs.pc()); } +TYPED_TEST_P(DwarfSectionImplTest, Eval_pseudo_register_invalid) { + DwarfCie cie{.return_address_register = 5}; + RegsImplFake regs(10); + regs.set_pseudo_reg(11); + dwarf_loc_regs_t loc_regs; + + loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}}; + loc_regs[1] = DwarfLocation{DWARF_LOCATION_PSEUDO_REGISTER, {20, 0}}; + bool finished; + ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished)); + EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode()); + + loc_regs.clear(); + loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}}; + loc_regs[12] = DwarfLocation{DWARF_LOCATION_PSEUDO_REGISTER, {20, 0}}; + ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished)); + EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode()); +} + +TYPED_TEST_P(DwarfSectionImplTest, Eval_pseudo_register) { + DwarfCie cie{.return_address_register = 5}; + RegsImplFake regs(10); + regs.set_pseudo_reg(11); + dwarf_loc_regs_t loc_regs; + + loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}}; + loc_regs[11] = DwarfLocation{DWARF_LOCATION_PSEUDO_REGISTER, {20, 0}}; + bool finished; + ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished)); + uint64_t pseudo_value = 0; + ASSERT_TRUE(regs.GetPseudoRegister(11, &pseudo_value)); + EXPECT_EQ(20U, pseudo_value); +} + TYPED_TEST_P(DwarfSectionImplTest, GetCfaLocationInfo_cie_not_cached) { DwarfCie cie{}; cie.cfa_instructions_offset = 0x3000; @@ -581,6 +615,7 @@ REGISTER_TYPED_TEST_SUITE_P(DwarfSectionImplTest, GetCieFromOffset_fail_should_n Eval_invalid_register, Eval_different_reg_locations, Eval_return_address_undefined, Eval_pc_zero, Eval_return_address, Eval_ignore_large_reg_loc, Eval_reg_expr, Eval_reg_val_expr, + Eval_pseudo_register_invalid, Eval_pseudo_register, GetCfaLocationInfo_cie_not_cached, GetCfaLocationInfo_cie_cached, Log); typedef ::testing::Types DwarfSectionImplTestTypes; diff --git a/libunwindstack/tests/RegsFake.h b/libunwindstack/tests/RegsFake.h index 75fc9d02d..f67d7dc61 100644 --- a/libunwindstack/tests/RegsFake.h +++ b/libunwindstack/tests/RegsFake.h @@ -83,15 +83,33 @@ class RegsImplFake : public RegsImpl { uint64_t sp() override { return fake_sp_; } void set_pc(uint64_t pc) override { fake_pc_ = pc; } void set_sp(uint64_t sp) override { fake_sp_ = sp; } + void set_pseudo_reg(uint64_t reg) { fake_pseudo_reg_ = reg; } bool SetPcFromReturnAddress(Memory*) override { return false; } bool StepIfSignalHandler(uint64_t, Elf*, Memory*) override { return false; } + bool SetPseudoRegister(uint16_t reg, uint64_t value) override { + if (fake_pseudo_reg_ != reg) { + return false; + } + fake_pseudo_reg_value_ = value; + return true; + } + bool GetPseudoRegister(uint16_t reg, uint64_t* value) override { + if (fake_pseudo_reg_ != reg) { + return false; + } + *value = fake_pseudo_reg_value_; + return true; + } + Regs* Clone() override { return nullptr; } private: uint64_t fake_pc_ = 0; uint64_t fake_sp_ = 0; + uint16_t fake_pseudo_reg_ = 0; + uint64_t fake_pseudo_reg_value_ = 0; }; } // namespace unwindstack