summaryrefslogtreecommitdiff
path: root/libunwindstack
diff options
context:
space:
mode:
authorChristopher Ferris <cferris@google.com>2017-10-23 13:51:54 -0700
committerChristopher Ferris <cferris@google.com>2017-10-23 14:55:16 -0700
commit23728b7f2d360a30aa5f3749d1b7fe07956f1cac (patch)
treea1356d4d04967408e74a34cc1bfafe5122880c70 /libunwindstack
parent3b8d15ce9c2f0ab4fd9a6e487b58173d2644e9be (diff)
downloadunwinding-23728b7f2d360a30aa5f3749d1b7fe07956f1cac.tar.gz
If the pc is set to zero, the unwind is done.
Bug: 68047085 Test: Ran new unit tests, verified new unwinder does not show an Test: extra pc zero frame for arm 32 bit processes. Change-Id: Ic6532e56fbb786a8b7d41638abae777c2d0f1d59
Diffstat (limited to 'libunwindstack')
-rw-r--r--libunwindstack/DwarfSection.cpp6
-rw-r--r--libunwindstack/ElfInterfaceArm.cpp4
-rw-r--r--libunwindstack/tests/DwarfSectionImplTest.cpp19
-rw-r--r--libunwindstack/tests/ElfInterfaceArmTest.cpp36
4 files changed, 61 insertions, 4 deletions
diff --git a/libunwindstack/DwarfSection.cpp b/libunwindstack/DwarfSection.cpp
index 8b30b76..b8164c5 100644
--- a/libunwindstack/DwarfSection.cpp
+++ b/libunwindstack/DwarfSection.cpp
@@ -225,11 +225,13 @@ bool DwarfSectionImpl<AddressType>::Eval(const DwarfCie* cie, Memory* regular_me
// Find the return address location.
if (return_address_undefined) {
cur_regs->set_pc(0);
- *finished = true;
} else {
cur_regs->set_pc((*cur_regs)[cie->return_address_register]);
- *finished = false;
}
+
+ // If the pc was set to zero, consider this the final frame.
+ *finished = (cur_regs->pc() == 0) ? true : false;
+
cur_regs->set_sp(cfa);
// Return false if the unwind is not finished or the cfa and pc didn't change.
return *finished || prev_cfa != cfa || prev_pc != cur_regs->pc();
diff --git a/libunwindstack/ElfInterfaceArm.cpp b/libunwindstack/ElfInterfaceArm.cpp
index 30a1532..170a5cd 100644
--- a/libunwindstack/ElfInterfaceArm.cpp
+++ b/libunwindstack/ElfInterfaceArm.cpp
@@ -121,8 +121,10 @@ bool ElfInterfaceArm::StepExidx(uint64_t pc, Regs* regs, Memory* process_memory,
}
regs_arm->set_sp(arm.cfa());
(*regs_arm)[ARM_REG_SP] = regs_arm->sp();
- *finished = false;
return_value = true;
+
+ // If the pc was set to zero, consider this the final frame.
+ *finished = (regs_arm->pc() == 0) ? true : false;
}
if (arm.status() == ARM_STATUS_NO_UNWIND) {
diff --git a/libunwindstack/tests/DwarfSectionImplTest.cpp b/libunwindstack/tests/DwarfSectionImplTest.cpp
index c701a29..7e85bbb 100644
--- a/libunwindstack/tests/DwarfSectionImplTest.cpp
+++ b/libunwindstack/tests/DwarfSectionImplTest.cpp
@@ -340,6 +340,23 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_return_address_undefined) {
EXPECT_EQ(0x10U, regs.sp());
}
+TYPED_TEST_P(DwarfSectionImplTest, Eval_pc_zero) {
+ DwarfCie cie{.return_address_register = 5};
+ RegsImplFake<TypeParam> regs(10, 9);
+ dwarf_loc_regs_t loc_regs;
+
+ regs.set_pc(0x100);
+ regs.set_sp(0x2000);
+ regs[5] = 0;
+ regs[8] = 0x10;
+ loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
+ bool finished;
+ ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
+ EXPECT_TRUE(finished);
+ EXPECT_EQ(0U, regs.pc());
+ EXPECT_EQ(0x10U, regs.sp());
+}
+
TYPED_TEST_P(DwarfSectionImplTest, Eval_return_address) {
DwarfCie cie{.return_address_register = 5};
RegsImplFake<TypeParam> regs(10, 9);
@@ -854,7 +871,7 @@ REGISTER_TYPED_TEST_CASE_P(
Eval_cfa_expr_is_register, Eval_cfa_expr, Eval_cfa_val_expr, Eval_bad_regs, Eval_no_cfa,
Eval_cfa_bad, Eval_cfa_register_prev, Eval_cfa_register_from_value, Eval_double_indirection,
Eval_invalid_register, Eval_different_reg_locations, Eval_return_address_undefined,
- Eval_return_address, Eval_ignore_large_reg_loc, Eval_reg_expr, Eval_reg_val_expr,
+ Eval_pc_zero, Eval_return_address, Eval_ignore_large_reg_loc, Eval_reg_expr, Eval_reg_val_expr,
Eval_same_cfa_same_pc, GetCie_fail_should_not_cache, GetCie_32_version_check,
GetCie_negative_data_alignment_factor, GetCie_64_no_augment, GetCie_augment, GetCie_version_3,
GetCie_version_4, GetFdeFromOffset_fail_should_not_cache, GetFdeFromOffset_32_no_augment,
diff --git a/libunwindstack/tests/ElfInterfaceArmTest.cpp b/libunwindstack/tests/ElfInterfaceArmTest.cpp
index feb24ce..4b621c9 100644
--- a/libunwindstack/tests/ElfInterfaceArmTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceArmTest.cpp
@@ -401,4 +401,40 @@ TEST_F(ElfInterfaceArmTest, StepExidx_refuse_unwind) {
ASSERT_EQ(0x1234U, regs.pc());
}
+TEST_F(ElfInterfaceArmTest, StepExidx_pc_zero) {
+ ElfInterfaceArmFake interface(&memory_);
+
+ interface.FakeSetStartOffset(0x1000);
+ interface.FakeSetTotalEntries(1);
+ memory_.SetData32(0x1000, 0x6000);
+ // Set the pc using a pop r15 command.
+ memory_.SetData32(0x1004, 0x808800b0);
+
+ // pc value of zero.
+ process_memory_.SetData32(0x10000, 0);
+
+ RegsArm regs;
+ regs[ARM_REG_SP] = 0x10000;
+ regs[ARM_REG_LR] = 0x20000;
+ regs.set_sp(regs[ARM_REG_SP]);
+ regs.set_pc(0x1234);
+
+ bool finished;
+ ASSERT_TRUE(interface.StepExidx(0x7000, &regs, &process_memory_, &finished));
+ ASSERT_TRUE(finished);
+ ASSERT_EQ(0U, regs.pc());
+
+ // Now set the pc from the lr register (pop r14).
+ memory_.SetData32(0x1004, 0x808400b0);
+
+ regs[ARM_REG_SP] = 0x10000;
+ regs[ARM_REG_LR] = 0x20000;
+ regs.set_sp(regs[ARM_REG_SP]);
+ regs.set_pc(0x1234);
+
+ ASSERT_TRUE(interface.StepExidx(0x7000, &regs, &process_memory_, &finished));
+ ASSERT_TRUE(finished);
+ ASSERT_EQ(0U, regs.pc());
+}
+
} // namespace unwindstack