Index: lldb/trunk/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h =================================================================== --- lldb/trunk/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h +++ lldb/trunk/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h @@ -102,6 +102,7 @@ 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 ®no); bool pop_reg_p(int ®no); bool pop_rbp_pattern_p(); Index: lldb/trunk/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp =================================================================== --- lldb/trunk/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp +++ lldb/trunk/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp @@ -452,6 +452,33 @@ 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 ®no) { @@ -843,6 +870,12 @@ 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 Index: lldb/trunk/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp =================================================================== --- lldb/trunk/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp +++ lldb/trunk/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 @@ 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 engine = Getx86_64Inspector(); @@ -2337,3 +2347,71 @@ EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc)); } + +TEST_F(Testx86AssemblyInspectionEngine, TestStackRealign8BitDisp_i386) { + std::unique_ptr 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 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()); +}