summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp33
-rw-r--r--lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h1
-rw-r--r--lldb/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp78
3 files changed, 112 insertions, 0 deletions
diff --git a/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp b/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
index 9aad2e1e70e..9d79a411faa 100644
--- a/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
+++ b/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
@@ -452,6 +452,33 @@ bool x86AssemblyInspectionEngine::lea_rsp_pattern_p(int &amount) {
return false;
}
+// lea -0x28(%ebp), %esp
+// (32-bit and 64-bit variants, 8-bit and 32-bit displacement)
+bool x86AssemblyInspectionEngine::lea_rbp_rsp_pattern_p(int &amount) {
+ uint8_t *p = m_cur_insn;
+ if (m_wordsize == 8 && *p == 0x48)
+ p++;
+
+ // Check opcode
+ if (*p != 0x8d)
+ return false;
+ ++p;
+
+ // 8 bit displacement
+ if (*p == 0x65) {
+ amount = (int8_t)p[1];
+ return true;
+ }
+
+ // 32 bit displacement
+ if (*p == 0xa5) {
+ amount = (int32_t)extract_4(p + 1);
+ return true;
+ }
+
+ return false;
+}
+
// popq %rbx
// popl %ebx
bool x86AssemblyInspectionEngine::pop_reg_p(int &regno) {
@@ -843,6 +870,12 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(
in_epilogue = true;
}
+ else if (lea_rbp_rsp_pattern_p(stack_offset) &&
+ row->GetCFAValue().GetRegisterNumber() == m_lldb_fp_regnum) {
+ current_sp_bytes_offset_from_cfa =
+ row->GetCFAValue().GetOffset() - stack_offset;
+ }
+
else if (ret_pattern_p() && prologue_completed_row.get()) {
// Reinstate the saved prologue setup for any instructions
// that come after the ret instruction
diff --git a/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h b/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h
index 1c84c89aee8..2e7875966cb 100644
--- a/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h
+++ b/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h
@@ -102,6 +102,7 @@ private:
bool sub_rsp_pattern_p(int &amount);
bool add_rsp_pattern_p(int &amount);
bool lea_rsp_pattern_p(int &amount);
+ bool lea_rbp_rsp_pattern_p(int &amount);
bool push_reg_p(int &regno);
bool pop_reg_p(int &regno);
bool pop_rbp_pattern_p();
diff --git a/lldb/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp b/lldb/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp
index e216d4be16f..e9776096719 100644
--- a/lldb/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp
+++ b/lldb/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp
@@ -18,6 +18,7 @@
#include "lldb/Core/AddressRange.h"
#include "lldb/Core/ArchSpec.h"
#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Utility/StreamString.h"
#include "llvm/Support/TargetSelect.h"
@@ -130,6 +131,15 @@ std::unique_ptr<x86AssemblyInspectionEngine> Geti386Inspector() {
return engine;
}
+namespace lldb_private {
+static std::ostream &operator<<(std::ostream &OS,
+ const UnwindPlan::Row::CFAValue &CFA) {
+ StreamString S;
+ CFA.Dump(S, nullptr, nullptr);
+ return OS << S.GetData();
+}
+} // namespace lldb_private
+
TEST_F(Testx86AssemblyInspectionEngine, TestSimple64bitFrameFunction) {
std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
@@ -2337,3 +2347,71 @@ TEST_F(Testx86AssemblyInspectionEngine, Test32BitOnlyInstruction) {
EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestStackRealign8BitDisp_i386) {
+ std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
+
+ uint8_t data[] = {
+ 0x55, // pushl %ebp
+ 0x89, 0xe5, // movl %esp, %ebp
+ 0x53, // pushl %ebx
+ 0x83, 0xe4, 0xf0, // andl $-16, %esp
+ 0x83, 0xec, 0x10, // subl $16, %esp
+ 0x8d, 0x65, 0xfc, // leal -4(%ebp), %esp
+ 0x5b, // popl %ebx
+ 0x5d, // popl %ebp
+ 0xc3, // retl
+ };
+
+ AddressRange sample_range(0x1000, sizeof(data));
+ UnwindPlan plan(eRegisterKindLLDB);
+ ASSERT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(data, sizeof(data),
+ sample_range, plan));
+
+ UnwindPlan::Row::CFAValue esp_plus_4, esp_plus_8, ebp_plus_8;
+ esp_plus_4.SetIsRegisterPlusOffset(k_esp, 4);
+ esp_plus_8.SetIsRegisterPlusOffset(k_esp, 8);
+ ebp_plus_8.SetIsRegisterPlusOffset(k_ebp, 8);
+
+ EXPECT_EQ(esp_plus_4, plan.GetRowForFunctionOffset(0)->GetCFAValue());
+ EXPECT_EQ(esp_plus_8, plan.GetRowForFunctionOffset(1)->GetCFAValue());
+ for (size_t i = 3; i < sizeof(data) - 2; ++i)
+ EXPECT_EQ(ebp_plus_8, plan.GetRowForFunctionOffset(i)->GetCFAValue())
+ << "i: " << i;
+ EXPECT_EQ(esp_plus_4,
+ plan.GetRowForFunctionOffset(sizeof(data) - 1)->GetCFAValue());
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestStackRealign32BitDisp_x86_64) {
+ std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
+
+ uint8_t data[] = {
+ 0x55, // pushq %rbp
+ 0x48, 0x89, 0xe5, // movq %rsp, %rbp
+ 0x53, // pushl %rbx
+ 0x48, 0x83, 0xe4, 0xf0, // andq $-16, %rsp
+ 0x48, 0x81, 0xec, 0x00, 0x01, 0x00, 0x00, // subq $256, %rsp
+ 0x48, 0x8d, 0x65, 0xf8, // leaq -8(%rbp), %rsp
+ 0x5b, // popq %rbx
+ 0x5d, // popq %rbp
+ 0xc3, // retq
+ };
+
+ AddressRange sample_range(0x1000, sizeof(data));
+ UnwindPlan plan(eRegisterKindLLDB);
+ ASSERT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(data, sizeof(data),
+ sample_range, plan));
+
+ UnwindPlan::Row::CFAValue rsp_plus_8, rsp_plus_16, rbp_plus_16;
+ rsp_plus_8.SetIsRegisterPlusOffset(k_rsp, 8);
+ rsp_plus_16.SetIsRegisterPlusOffset(k_rsp, 16);
+ rbp_plus_16.SetIsRegisterPlusOffset(k_rbp, 16);
+
+ EXPECT_EQ(rsp_plus_8, plan.GetRowForFunctionOffset(0)->GetCFAValue());
+ EXPECT_EQ(rsp_plus_16, plan.GetRowForFunctionOffset(1)->GetCFAValue());
+ for (size_t i = 4; i < sizeof(data) - 2; ++i)
+ EXPECT_EQ(rbp_plus_16, plan.GetRowForFunctionOffset(i)->GetCFAValue())
+ << "i: " << i;
+ EXPECT_EQ(rsp_plus_8,
+ plan.GetRowForFunctionOffset(sizeof(data) - 1)->GetCFAValue());
+}
OpenPOWER on IntegriCloud