Merge "Don't hide error by INVALID_MAP in speculative frame."
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 0536f6d..2312652 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -150,7 +150,11 @@
if (map_info == nullptr) {
step_pc = regs_->pc();
rel_pc = step_pc;
- last_error_.code = ERROR_INVALID_MAP;
+ // If we get invalid map via return_address_attempt, don't hide error for the previous frame.
+ if (!return_address_attempt || last_error_.code == ERROR_NONE) {
+ last_error_.code = ERROR_INVALID_MAP;
+ last_error_.address = step_pc;
+ }
elf = nullptr;
} else {
if (ShouldStop(map_suffixes_to_ignore, map_info->name())) {
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index b37f9d1..8e43fe4 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -887,6 +887,32 @@
ASSERT_EQ(0U, unwinder.NumFrames());
}
+// Verify that a speculative frame mapping to invalid map doesn't hide error
+// for the previous frame.
+TEST_F(UnwinderTest, speculative_frame_to_invalid_map_not_hide_prev_error) {
+ regs_.set_pc(0x100000);
+ regs_.set_sp(0x10000);
+ regs_.FakeSetReturnAddress(0x4);
+ regs_.FakeSetReturnAddressValid(true);
+
+ Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
+ unwinder.Unwind();
+ EXPECT_EQ(ERROR_INVALID_ELF, unwinder.LastErrorCode());
+ EXPECT_EQ(WARNING_NONE, unwinder.warnings());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
+
+ ASSERT_EQ(1U, unwinder.NumFrames());
+
+ auto* frame = &unwinder.frames()[0];
+ EXPECT_EQ(0U, frame->num);
+ EXPECT_EQ(0x300U, frame->rel_pc);
+ EXPECT_EQ(0x100000U, frame->pc);
+ EXPECT_EQ(0x10000U, frame->sp);
+ EXPECT_EQ("", frame->function_name);
+ EXPECT_EQ(0U, frame->function_offset);
+ ASSERT_TRUE(frame->map_info != nullptr);
+}
+
// Verify that an unwind stops when a frame is in given suffix.
TEST_F(UnwinderTest, map_ignore_suffixes) {
ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));