Add a new unwind method on error.
If a function crashes by jumping into unexecutable code, the old method
could not unwind through that. Add a fallback method to set the pc from
the default return address location.
In addition, add a new finished check for steps. This will provide a method
to indicate that this step is the last step. This prevents cases where
the fallback method might be triggered incorrectly.
Update the libbacktrace code to unwind using the new methodology.
Update the unwind tool to use the new unwind methodology.
Add a new option to crasher that calls through a null function.
Create a new object, Unwinder, that encapsulates the a basic unwind. For now,
libbacktrace will still use the custom code.
Added new unit tests to cover the new cases. Also add a test that
crashes calling a nullptr as a function, and then has call frames in
the signal stack.
Bug: 65842173
Test: Pass all unit tests, verify crasher dumps properly.
Change-Id: Ia18430ab107e9f7bdf0e14a9b74710b1280bd7f4
diff --git a/libunwindstack/tests/DwarfSectionImplTest.cpp b/libunwindstack/tests/DwarfSectionImplTest.cpp
index b871539..2939126 100644
--- a/libunwindstack/tests/DwarfSectionImplTest.cpp
+++ b/libunwindstack/tests/DwarfSectionImplTest.cpp
@@ -98,7 +98,8 @@
regs[5] = 0x20;
regs[9] = 0x3000;
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x2, 0x5000}};
- ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s));
+ bool finished;
+ ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->last_error());
}
@@ -113,7 +114,8 @@
regs[9] = 0x3000;
this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x96, 0x96, 0x96});
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x2, 0x5000}};
- ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s));
+ bool finished;
+ ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
EXPECT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->section_->last_error());
}
@@ -130,7 +132,9 @@
TypeParam cfa_value = 0x12345;
this->memory_.SetMemory(0x80000000, &cfa_value, sizeof(cfa_value));
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x4, 0x5000}};
- ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s));
+ bool finished;
+ ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
+ EXPECT_FALSE(finished);
EXPECT_EQ(0x12345U, regs.sp());
EXPECT_EQ(0x20U, regs.pc());
}
@@ -146,7 +150,9 @@
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}};
- ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s));
+ bool finished;
+ ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
+ ASSERT_FALSE(finished);
EXPECT_EQ(0x80000000U, regs.sp());
EXPECT_EQ(0x20U, regs.pc());
}
@@ -162,7 +168,8 @@
regs[9] = 0x3000;
this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x50, 0x96, 0x96});
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x2, 0x5000}};
- ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s));
+ bool finished;
+ ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
EXPECT_EQ(DWARF_ERROR_NOT_IMPLEMENTED, this->section_->last_error());
}
@@ -171,7 +178,8 @@
RegsFake<TypeParam> regs(10, 9);
dwarf_loc_regs_t loc_regs;
- ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s));
+ bool finished;
+ ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error());
}
@@ -180,7 +188,8 @@
RegsFake<TypeParam> regs(10, 9);
dwarf_loc_regs_t loc_regs;
- ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s));
+ bool finished;
+ ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
EXPECT_EQ(DWARF_ERROR_CFA_NOT_DEFINED, this->section_->last_error());
}
@@ -190,25 +199,26 @@
dwarf_loc_regs_t loc_regs;
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {20, 0}};
- ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s));
+ bool finished;
+ ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error());
this->section_->TestClearError();
loc_regs.erase(CFA_REG);
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_INVALID, {0, 0}};
- ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s));
+ ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error());
this->section_->TestClearError();
loc_regs.erase(CFA_REG);
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_OFFSET, {0, 0}};
- ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s));
+ ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error());
this->section_->TestClearError();
loc_regs.erase(CFA_REG);
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_VAL_OFFSET, {0, 0}};
- ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s));
+ ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error());
}
@@ -222,7 +232,9 @@
regs[5] = 0x20;
regs[9] = 0x3000;
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {9, 0}};
- ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s));
+ bool finished;
+ ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
+ EXPECT_FALSE(finished);
EXPECT_EQ(0x20U, regs.pc());
EXPECT_EQ(0x2000U, regs.sp());
}
@@ -238,7 +250,9 @@
regs[6] = 0x4000;
regs[9] = 0x3000;
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {6, 0}};
- ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s));
+ bool finished;
+ ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
+ EXPECT_FALSE(finished);
EXPECT_EQ(0x20U, regs.pc());
EXPECT_EQ(0x4000U, regs.sp());
}
@@ -254,7 +268,8 @@
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
loc_regs[1] = DwarfLocation{DWARF_LOCATION_REGISTER, {3, 0}};
loc_regs[9] = DwarfLocation{DWARF_LOCATION_REGISTER, {1, 0}};
- ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s));
+ bool finished;
+ ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
EXPECT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->section_->last_error());
}
@@ -268,7 +283,8 @@
regs[8] = 0x10;
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
loc_regs[1] = DwarfLocation{DWARF_LOCATION_REGISTER, {10, 0}};
- ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s));
+ bool finished;
+ ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error());
}
@@ -292,7 +308,9 @@
loc_regs[1] = DwarfLocation{DWARF_LOCATION_VAL_OFFSET, {0x100, 0}};
loc_regs[2] = DwarfLocation{DWARF_LOCATION_OFFSET, {0x50, 0}};
loc_regs[3] = DwarfLocation{DWARF_LOCATION_UNDEFINED, {0, 0}};
- ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s));
+ bool finished;
+ ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
+ EXPECT_FALSE(finished);
EXPECT_EQ(0x10U, regs.pc());
EXPECT_EQ(0x2100U, regs.sp());
EXPECT_EQ(0x2200U, regs[1]);
@@ -315,7 +333,9 @@
regs[8] = 0x10;
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
loc_regs[5] = DwarfLocation{DWARF_LOCATION_UNDEFINED, {0, 0}};
- ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s));
+ bool finished;
+ ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
+ EXPECT_TRUE(finished);
EXPECT_EQ(0U, regs.pc());
EXPECT_EQ(0x10U, regs.sp());
}
@@ -330,7 +350,9 @@
regs[5] = 0x20;
regs[8] = 0x10;
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
- ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s));
+ bool finished;
+ ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
+ EXPECT_FALSE(finished);
EXPECT_EQ(0x20U, regs.pc());
EXPECT_EQ(0x10U, regs.sp());
}
@@ -347,7 +369,9 @@
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
// This should not result in any errors.
loc_regs[20] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
- ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s));
+ bool finished;
+ ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
+ EXPECT_FALSE(finished);
EXPECT_EQ(0x20U, regs.pc());
EXPECT_EQ(0x10U, regs.sp());
}
@@ -365,7 +389,9 @@
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}};
- ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s));
+ bool finished;
+ ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
+ EXPECT_FALSE(finished);
EXPECT_EQ(0x3000U, regs.sp());
EXPECT_EQ(0x12345U, regs.pc());
}
@@ -381,7 +407,9 @@
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}};
- ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s));
+ bool finished;
+ ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
+ EXPECT_FALSE(finished);
EXPECT_EQ(0x3000U, regs.sp());
EXPECT_EQ(0x80000000U, regs.pc());
}
@@ -396,7 +424,8 @@
regs[5] = 0x100;
regs[8] = 0x2000;
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
- ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s));
+ bool finished;
+ ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
EXPECT_EQ(0x2000U, regs.sp());
EXPECT_EQ(0x100U, regs.pc());
}
diff --git a/libunwindstack/tests/DwarfSectionTest.cpp b/libunwindstack/tests/DwarfSectionTest.cpp
index fc67063..3fcd2b6 100644
--- a/libunwindstack/tests/DwarfSectionTest.cpp
+++ b/libunwindstack/tests/DwarfSectionTest.cpp
@@ -32,7 +32,7 @@
MOCK_METHOD4(Log, bool(uint8_t, uint64_t, uint64_t, const DwarfFde*));
- MOCK_METHOD4(Eval, bool(const DwarfCie*, Memory*, const dwarf_loc_regs_t&, Regs*));
+ MOCK_METHOD5(Eval, bool(const DwarfCie*, Memory*, const dwarf_loc_regs_t&, Regs*, bool*));
MOCK_METHOD3(GetCfaLocationInfo, bool(uint64_t, const DwarfFde*, dwarf_loc_regs_t*));
@@ -104,7 +104,8 @@
EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
.WillOnce(::testing::Return(false));
- ASSERT_FALSE(mock_section.Step(0x1000, nullptr, nullptr));
+ bool finished;
+ ASSERT_FALSE(mock_section.Step(0x1000, nullptr, nullptr, &finished));
}
TEST_F(DwarfSectionTest, Step_fail_cie_null) {
@@ -118,7 +119,8 @@
.WillOnce(::testing::Return(true));
EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde));
- ASSERT_FALSE(mock_section.Step(0x1000, nullptr, nullptr));
+ bool finished;
+ ASSERT_FALSE(mock_section.Step(0x1000, nullptr, nullptr, &finished));
}
TEST_F(DwarfSectionTest, Step_fail_cfa_location) {
@@ -136,7 +138,8 @@
EXPECT_CALL(mock_section, GetCfaLocationInfo(0x1000, &fde, ::testing::_))
.WillOnce(::testing::Return(false));
- ASSERT_FALSE(mock_section.Step(0x1000, nullptr, nullptr));
+ bool finished;
+ ASSERT_FALSE(mock_section.Step(0x1000, nullptr, nullptr, &finished));
}
TEST_F(DwarfSectionTest, Step_pass) {
@@ -155,10 +158,11 @@
.WillOnce(::testing::Return(true));
MemoryFake process;
- EXPECT_CALL(mock_section, Eval(&cie, &process, ::testing::_, nullptr))
+ EXPECT_CALL(mock_section, Eval(&cie, &process, ::testing::_, nullptr, ::testing::_))
.WillOnce(::testing::Return(true));
- ASSERT_TRUE(mock_section.Step(0x1000, nullptr, &process));
+ bool finished;
+ ASSERT_TRUE(mock_section.Step(0x1000, nullptr, &process, &finished));
}
} // namespace unwindstack
diff --git a/libunwindstack/tests/ElfInterfaceArmTest.cpp b/libunwindstack/tests/ElfInterfaceArmTest.cpp
index c7ef4a1..4df7e1c 100644
--- a/libunwindstack/tests/ElfInterfaceArmTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceArmTest.cpp
@@ -322,7 +322,8 @@
ElfInterfaceArm interface(&memory_);
// FindEntry fails.
- ASSERT_FALSE(interface.StepExidx(0x7000, nullptr, nullptr));
+ bool finished;
+ ASSERT_FALSE(interface.StepExidx(0x7000, nullptr, nullptr, &finished));
// ExtractEntry should fail.
interface.set_start_offset(0x1000);
@@ -335,15 +336,16 @@
regs[ARM_REG_LR] = 0x20000;
regs.set_sp(regs[ARM_REG_SP]);
regs.set_pc(0x1234);
- ASSERT_FALSE(interface.StepExidx(0x7000, ®s, &process_memory_));
+ ASSERT_FALSE(interface.StepExidx(0x7000, ®s, &process_memory_, &finished));
// Eval should fail.
memory_.SetData32(0x1004, 0x81000000);
- ASSERT_FALSE(interface.StepExidx(0x7000, ®s, &process_memory_));
+ ASSERT_FALSE(interface.StepExidx(0x7000, ®s, &process_memory_, &finished));
// Everything should pass.
memory_.SetData32(0x1004, 0x80b0b0b0);
- ASSERT_TRUE(interface.StepExidx(0x7000, ®s, &process_memory_));
+ ASSERT_TRUE(interface.StepExidx(0x7000, ®s, &process_memory_, &finished));
+ ASSERT_FALSE(finished);
ASSERT_EQ(0x1000U, regs.sp());
ASSERT_EQ(0x1000U, regs[ARM_REG_SP]);
ASSERT_EQ(0x20000U, regs.pc());
@@ -367,11 +369,57 @@
regs.set_pc(0x1234);
// Everything should pass.
- ASSERT_TRUE(interface.StepExidx(0x7000, ®s, &process_memory_));
+ bool finished;
+ ASSERT_TRUE(interface.StepExidx(0x7000, ®s, &process_memory_, &finished));
+ ASSERT_FALSE(finished);
ASSERT_EQ(0x10004U, regs.sp());
ASSERT_EQ(0x10004U, regs[ARM_REG_SP]);
ASSERT_EQ(0x10U, regs.pc());
ASSERT_EQ(0x10U, regs[ARM_REG_PC]);
}
+TEST_F(ElfInterfaceArmTest, StepExidx_cant_unwind) {
+ ElfInterfaceArm interface(&memory_);
+
+ interface.set_start_offset(0x1000);
+ interface.set_total_entries(1);
+ memory_.SetData32(0x1000, 0x6000);
+ memory_.SetData32(0x1004, 1);
+
+ 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, ®s, &process_memory_, &finished));
+ ASSERT_TRUE(finished);
+ ASSERT_EQ(0x10000U, regs.sp());
+ ASSERT_EQ(0x10000U, regs[ARM_REG_SP]);
+ ASSERT_EQ(0x1234U, regs.pc());
+}
+
+TEST_F(ElfInterfaceArmTest, StepExidx_refuse_unwind) {
+ ElfInterfaceArm interface(&memory_);
+
+ interface.set_start_offset(0x1000);
+ interface.set_total_entries(1);
+ memory_.SetData32(0x1000, 0x6000);
+ memory_.SetData32(0x1004, 0x808000b0);
+
+ 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, ®s, &process_memory_, &finished));
+ ASSERT_TRUE(finished);
+ ASSERT_EQ(0x10000U, regs.sp());
+ ASSERT_EQ(0x10000U, regs[ARM_REG_SP]);
+ ASSERT_EQ(0x1234U, regs.pc());
+}
+
} // namespace unwindstack
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp
index ed1be3b..42a0246 100644
--- a/libunwindstack/tests/ElfTest.cpp
+++ b/libunwindstack/tests/ElfTest.cpp
@@ -129,7 +129,8 @@
uint64_t func_offset;
ASSERT_FALSE(elf.GetFunctionName(0, &name, &func_offset));
- ASSERT_FALSE(elf.Step(0, nullptr, nullptr));
+ bool finished;
+ ASSERT_FALSE(elf.Step(0, nullptr, nullptr, &finished));
}
TEST_F(ElfTest, elf32_invalid_machine) {
diff --git a/libunwindstack/tests/RegsFake.h b/libunwindstack/tests/RegsFake.h
index c76ecaa..b667ec1 100644
--- a/libunwindstack/tests/RegsFake.h
+++ b/libunwindstack/tests/RegsFake.h
@@ -35,6 +35,7 @@
uint64_t GetAdjustedPc(uint64_t, Elf*) override { return 0; }
void SetFromRaw() override {}
+ bool SetPcFromReturnAddress(Memory*) override { return false; }
bool StepIfSignalHandler(uint64_t, Elf*, Memory*) override { return false; }
bool GetReturnAddressFromDefault(Memory*, uint64_t*) { return false; }
};
diff --git a/libunwindstack/tests/RegsTest.cpp b/libunwindstack/tests/RegsTest.cpp
index f549a50..3912e17 100644
--- a/libunwindstack/tests/RegsTest.cpp
+++ b/libunwindstack/tests/RegsTest.cpp
@@ -46,7 +46,7 @@
void InitHeaders() override {}
bool GetSoname(std::string*) override { return false; }
bool GetFunctionName(uint64_t, std::string*, uint64_t*) override { return false; }
- bool Step(uint64_t, Regs*, Memory*) override { return false; }
+ bool Step(uint64_t, Regs*, Memory*, bool*) override { return false; }
};
template <typename TypeParam>
@@ -62,6 +62,7 @@
uint64_t GetAdjustedPc(uint64_t, Elf*) override { return 0; }
void SetFromRaw() override {}
+ bool SetPcFromReturnAddress(Memory*) override { return false; }
bool StepIfSignalHandler(uint64_t, Elf*, Memory*) override { return false; }
};
diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp
index a4f920a..9f9ca8b 100644
--- a/libunwindstack/tests/UnwindTest.cpp
+++ b/libunwindstack/tests/UnwindTest.cpp
@@ -31,12 +31,13 @@
#include <thread>
#include <vector>
-#include <unwindstack/Elf.h>
-#include <unwindstack/MapInfo.h>
+#include <android-base/stringprintf.h>
+
#include <unwindstack/Maps.h>
#include <unwindstack/Memory.h>
#include <unwindstack/Regs.h>
#include <unwindstack/RegsGetLocal.h>
+#include <unwindstack/Unwinder.h>
#include "TestUtils.h"
@@ -56,11 +57,11 @@
g_ucontext = 0;
}
-static std::vector<const char*> kFunctionOrder{"InnerFunction", "MiddleFunction", "OuterFunction"};
+static std::vector<const char*> kFunctionOrder{"OuterFunction", "MiddleFunction", "InnerFunction"};
-static std::vector<const char*> kFunctionSignalOrder{"SignalInnerFunction", "SignalMiddleFunction",
- "SignalOuterFunction", "InnerFunction",
- "MiddleFunction", "OuterFunction"};
+static std::vector<const char*> kFunctionSignalOrder{"OuterFunction", "MiddleFunction",
+ "InnerFunction", "SignalOuterFunction",
+ "SignalMiddleFunction", "SignalInnerFunction"};
static void SignalHandler(int, siginfo_t*, void* sigcontext) {
g_ucontext = reinterpret_cast<uintptr_t>(sigcontext);
@@ -86,62 +87,44 @@
SignalOuterFunction();
}
-static std::string ErrorMsg(const std::vector<const char*>& function_names, size_t index,
- std::stringstream& unwind_stream) {
+static std::string ErrorMsg(const std::vector<const char*>& function_names, Unwinder& unwinder) {
+ std::string unwind;
+ for (size_t i = 0; i < unwinder.NumFrames(); i++) {
+ unwind += unwinder.FormatFrame(i) + '\n';
+ }
+
return std::string(
"Unwind completed without finding all frames\n"
" Looking for function: ") +
- function_names[index] + "\n" + "Unwind data:\n" + unwind_stream.str();
+ function_names.front() + "\n" + "Unwind data:\n" + unwind;
}
static void VerifyUnwind(pid_t pid, Maps* maps, Regs* regs,
- std::vector<const char*>& function_names) {
- size_t function_name_index = 0;
+ std::vector<const char*> expected_function_names) {
+ auto process_memory(Memory::CreateProcessMemory(pid));
- auto process_memory = Memory::CreateProcessMemory(pid);
- std::stringstream unwind_stream;
- unwind_stream << std::hex;
- for (size_t frame_num = 0; frame_num < 64; frame_num++) {
- ASSERT_NE(0U, regs->pc()) << ErrorMsg(function_names, function_name_index, unwind_stream);
- MapInfo* map_info = maps->Find(regs->pc());
- ASSERT_TRUE(map_info != nullptr) << ErrorMsg(function_names, function_name_index, unwind_stream);
+ Unwinder unwinder(512, maps, regs, process_memory);
+ unwinder.Unwind();
- Elf* elf = map_info->GetElf(process_memory, true);
- uint64_t rel_pc = elf->GetRelPc(regs->pc(), map_info);
- uint64_t adjusted_rel_pc = rel_pc;
- if (frame_num != 0) {
- adjusted_rel_pc = regs->GetAdjustedPc(rel_pc, elf);
- }
- unwind_stream << " PC: 0x" << regs->pc() << " Rel: 0x" << adjusted_rel_pc;
- unwind_stream << " Map: ";
- if (!map_info->name.empty()) {
- unwind_stream << map_info->name;
- } else {
- unwind_stream << " anonymous";
- }
- unwind_stream << "<" << map_info->start << "-" << map_info->end << ">";
-
- std::string name;
- uint64_t func_offset;
- if (elf->GetFunctionName(adjusted_rel_pc, &name, &func_offset)) {
- if (name == function_names[function_name_index]) {
- if (++function_name_index == function_names.size()) {
- return;
- }
+ std::string expected_function = expected_function_names.back();
+ expected_function_names.pop_back();
+ for (auto& frame : unwinder.frames()) {
+ if (frame.function_name == expected_function) {
+ if (expected_function_names.empty()) {
+ break;
}
- unwind_stream << " " << name;
+ expected_function = expected_function_names.back();
+ expected_function_names.pop_back();
}
- unwind_stream << "\n";
- ASSERT_TRUE(elf->Step(rel_pc + map_info->elf_offset, regs, process_memory.get()))
- << ErrorMsg(function_names, function_name_index, unwind_stream);
}
- ASSERT_TRUE(false) << ErrorMsg(function_names, function_name_index, unwind_stream);
+
+ ASSERT_TRUE(expected_function_names.empty()) << ErrorMsg(expected_function_names, unwinder);
}
// This test assumes that this code is compiled with optimizations turned
// off. If this doesn't happen, then all of the calls will be optimized
// away.
-extern "C" void InnerFunction(bool local) {
+extern "C" void InnerFunction(bool local, bool trigger_invalid_call) {
if (local) {
LocalMaps maps;
ASSERT_TRUE(maps.Parse());
@@ -152,17 +135,21 @@
} else {
g_ready_for_remote = true;
g_ready = true;
+ if (trigger_invalid_call) {
+ void (*crash_func)() = nullptr;
+ crash_func();
+ }
while (!g_finish.load()) {
}
}
}
-extern "C" void MiddleFunction(bool local) {
- InnerFunction(local);
+extern "C" void MiddleFunction(bool local, bool trigger_invalid_call) {
+ InnerFunction(local, trigger_invalid_call);
}
-extern "C" void OuterFunction(bool local) {
- MiddleFunction(local);
+extern "C" void OuterFunction(bool local, bool trigger_invalid_call) {
+ MiddleFunction(local, trigger_invalid_call);
}
class UnwindTest : public ::testing::Test {
@@ -171,7 +158,7 @@
};
TEST_F(UnwindTest, local) {
- OuterFunction(true);
+ OuterFunction(true, false);
}
void WaitForRemote(pid_t pid, uint64_t addr, bool leave_attached, bool* completed) {
@@ -206,7 +193,7 @@
TEST_F(UnwindTest, remote) {
pid_t pid;
if ((pid = fork()) == 0) {
- OuterFunction(false);
+ OuterFunction(false, false);
exit(0);
}
ASSERT_NE(-1, pid);
@@ -231,7 +218,7 @@
std::atomic_int tid(0);
std::thread thread([&]() {
tid = syscall(__NR_gettid);
- OuterFunction(false);
+ OuterFunction(false, false);
});
struct sigaction act, oldact;
@@ -273,25 +260,27 @@
thread.join();
}
-static void RemoteThroughSignal(unsigned int sa_flags) {
+static void RemoteThroughSignal(int signal, unsigned int sa_flags) {
pid_t pid;
if ((pid = fork()) == 0) {
struct sigaction act, oldact;
memset(&act, 0, sizeof(act));
act.sa_sigaction = SignalCallerHandler;
act.sa_flags = SA_RESTART | SA_ONSTACK | sa_flags;
- ASSERT_EQ(0, sigaction(SIGUSR1, &act, &oldact));
+ ASSERT_EQ(0, sigaction(signal, &act, &oldact));
- OuterFunction(false);
+ OuterFunction(false, signal == SIGSEGV);
exit(0);
}
ASSERT_NE(-1, pid);
TestScopedPidReaper reap(pid);
bool completed;
- WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_ready_for_remote), false, &completed);
- ASSERT_TRUE(completed) << "Timed out waiting for remote process to be ready.";
- ASSERT_EQ(0, kill(pid, SIGUSR1));
+ if (signal != SIGSEGV) {
+ WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_ready_for_remote), false, &completed);
+ ASSERT_TRUE(completed) << "Timed out waiting for remote process to be ready.";
+ ASSERT_EQ(0, kill(pid, SIGUSR1));
+ }
WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_signal_ready_for_remote), true, &completed);
ASSERT_TRUE(completed) << "Timed out waiting for remote process to be in signal handler.";
@@ -307,11 +296,19 @@
}
TEST_F(UnwindTest, remote_through_signal) {
- RemoteThroughSignal(0);
+ RemoteThroughSignal(SIGUSR1, 0);
}
TEST_F(UnwindTest, remote_through_signal_sa_siginfo) {
- RemoteThroughSignal(SA_SIGINFO);
+ RemoteThroughSignal(SIGUSR1, SA_SIGINFO);
+}
+
+TEST_F(UnwindTest, remote_through_signal_with_invalid_func) {
+ RemoteThroughSignal(SIGSEGV, 0);
+}
+
+TEST_F(UnwindTest, remote_through_signal_sa_siginfo_with_invalid_func) {
+ RemoteThroughSignal(SIGSEGV, SA_SIGINFO);
}
} // namespace unwindstack