Skip to content

[lldb] Improve mid-function epilogue scanning for x86 #110965

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -809,7 +809,7 @@ bool x86AssemblyInspectionEngine::local_branch_p (
// Branch target is before the start of this function
return false;
}
if (offset + next_pc_value > func_range.GetByteSize()) {
if (offset + next_pc_value >= func_range.GetByteSize()) {
// Branch targets outside this function's bounds
return false;
}
Expand Down Expand Up @@ -967,6 +967,8 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(

bool in_epilogue = false; // we're in the middle of an epilogue sequence
bool row_updated = false; // The UnwindPlan::Row 'row' has been updated
bool current_sp_offset_updated =
false; // current_sp_bytes_offset_from_fa has been updated this insn

m_cur_insn = data + current_func_text_offset;
if (!instruction_length(m_cur_insn, insn_len, size - current_func_text_offset)
Expand Down Expand Up @@ -1013,8 +1015,10 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(
afa_value.SetUnspecified();
row_updated = true;
}
if (fa_value_ptr->GetRegisterNumber() == m_lldb_fp_regnum)
if (fa_value_ptr->GetRegisterNumber() == m_lldb_fp_regnum) {
current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset();
current_sp_offset_updated = true;
}
}

else if (mov_rbx_rsp_pattern_p()) {
Expand All @@ -1025,8 +1029,10 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(
afa_value.SetUnspecified();
row_updated = true;
}
if (fa_value_ptr->GetRegisterNumber() == m_lldb_alt_fp_regnum)
if (fa_value_ptr->GetRegisterNumber() == m_lldb_alt_fp_regnum) {
current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset();
current_sp_offset_updated = true;
}
}

// This is the start() function (or a pthread equivalent), it starts with a
Expand All @@ -1039,6 +1045,7 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(

else if (push_reg_p(machine_regno)) {
current_sp_bytes_offset_from_fa += m_wordsize;
current_sp_offset_updated = true;
// the PUSH instruction has moved the stack pointer - if the FA is set
// in terms of the stack pointer, we need to add a new row of
// instructions.
Expand All @@ -1064,6 +1071,7 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(

else if (pop_reg_p(machine_regno)) {
current_sp_bytes_offset_from_fa -= m_wordsize;
current_sp_offset_updated = true;

if (nonvolatile_reg_p(machine_regno) &&
machine_regno_to_lldb_regno(machine_regno, lldb_regno) &&
Expand Down Expand Up @@ -1091,6 +1099,7 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(

else if (pop_misc_reg_p()) {
current_sp_bytes_offset_from_fa -= m_wordsize;
current_sp_offset_updated = true;
if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
fa_value_ptr->SetIsRegisterPlusOffset(
m_lldb_sp_regnum, current_sp_bytes_offset_from_fa);
Expand Down Expand Up @@ -1126,6 +1135,7 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(
}

current_sp_bytes_offset_from_fa -= m_wordsize;
current_sp_offset_updated = true;

if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
fa_value_ptr->SetIsRegisterPlusOffset(
Expand Down Expand Up @@ -1161,6 +1171,7 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(

else if (sub_rsp_pattern_p(stack_offset)) {
current_sp_bytes_offset_from_fa += stack_offset;
current_sp_offset_updated = true;
if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa);
row_updated = true;
Expand All @@ -1169,6 +1180,7 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(

else if (add_rsp_pattern_p(stack_offset)) {
current_sp_bytes_offset_from_fa -= stack_offset;
current_sp_offset_updated = true;
if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa);
row_updated = true;
Expand All @@ -1179,6 +1191,7 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(
else if (push_extended_pattern_p() || push_imm_pattern_p() ||
push_misc_reg_p()) {
current_sp_bytes_offset_from_fa += m_wordsize;
current_sp_offset_updated = true;
if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa);
row_updated = true;
Expand All @@ -1187,6 +1200,7 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(

else if (lea_rsp_pattern_p(stack_offset)) {
current_sp_bytes_offset_from_fa -= stack_offset;
current_sp_offset_updated = true;
if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa);
row_updated = true;
Expand All @@ -1206,6 +1220,7 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(
if (fa_value_ptr->GetRegisterNumber() == m_lldb_fp_regnum) {
current_sp_bytes_offset_from_fa =
fa_value_ptr->GetOffset() - stack_offset;
current_sp_offset_updated = true;
}
}

Expand All @@ -1219,6 +1234,7 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(
}
if (fa_value_ptr->GetRegisterNumber() == m_lldb_alt_fp_regnum) {
current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset() - stack_offset;
current_sp_offset_updated = true;
}
}

Expand Down Expand Up @@ -1251,6 +1267,7 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(
row.reset(newrow);
current_sp_bytes_offset_from_fa =
prologue_completed_sp_bytes_offset_from_cfa;
current_sp_offset_updated = true;
is_aligned = prologue_completed_is_aligned;

saved_registers.clear();
Expand All @@ -1272,6 +1289,7 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(
// global data
else if (call_next_insn_pattern_p()) {
current_sp_bytes_offset_from_fa += m_wordsize;
current_sp_offset_updated = true;
if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa);
row_updated = true;
Expand Down Expand Up @@ -1304,7 +1322,7 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(

// We may change the sp value without adding a new Row necessarily -- keep
// track of it either way.
if (!in_epilogue) {
if (!in_epilogue && current_sp_offset_updated) {
prologue_completed_sp_bytes_offset_from_cfa =
current_sp_bytes_offset_from_fa;
prologue_completed_is_aligned = is_aligned;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2859,16 +2859,17 @@ TEST_F(Testx86AssemblyInspectionEngine, TestDisassemblyMidFunctionEpilogues) {

0x90, // <+18>: nop // prologue setup back

0x74, 0x7, // <+19>: je 6 <+27>
0x74, 0x8, // <+19>: je 7 <+28>
0x48, 0x83, 0xc4, 0x70, // <+21>: addq $0x70, %rsp
0x5d, // <+25>: popq %rbp
0xc3, // <+26>: retq // epilogue completed
0x90, // <+26>: nop // mid-epilogue non-epilogue
0xc3, // <+27>: retq // epilogue completed

0x90, // <+27>: nop // prologue setup back
0x90, // <+28>: nop // prologue setup back

0x48, 0x83, 0xc4, 0x70, // <+28>: addq $0x70, %rsp
0x5d, // <+32>: popq %rbp
0xc3, // <+33>: retq // epilogue completed
0x48, 0x83, 0xc4, 0x70, // <+29>: addq $0x70, %rsp
0x5d, // <+33>: popq %rbp
0xc3, // <+34>: retq // epilogue completed

};

Expand Down Expand Up @@ -2898,17 +2899,17 @@ TEST_F(Testx86AssemblyInspectionEngine, TestDisassemblyMidFunctionEpilogues) {
// Check that we've reinstated the stack frame setup
// unwind instructions after a mid-function retq
// row: CFA=ebp +8 => esp=CFA+0 eip=[CFA-8]
row_sp = unwind_plan.GetRowForFunctionOffset(27);
EXPECT_EQ(27ull, row_sp->GetOffset());
row_sp = unwind_plan.GetRowForFunctionOffset(28);
EXPECT_EQ(28ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(wordsize * 2, row_sp->GetCFAValue().GetOffset());

// After last instruction in the function, verify that
// the stack frame has been unwound
// row: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
row_sp = unwind_plan.GetRowForFunctionOffset(33);
EXPECT_EQ(33ull, row_sp->GetOffset());
row_sp = unwind_plan.GetRowForFunctionOffset(34);
EXPECT_EQ(34ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(wordsize, row_sp->GetCFAValue().GetOffset());
Expand Down Expand Up @@ -2940,17 +2941,17 @@ TEST_F(Testx86AssemblyInspectionEngine, TestDisassemblyMidFunctionEpilogues) {
// Check that we've reinstated the stack frame setup
// unwind instructions after a mid-function retq
// row: CFA=rbp+16 => rsp=CFA+0 rip=[CFA-16]
row_sp = unwind_plan.GetRowForFunctionOffset(27);
EXPECT_EQ(27ull, row_sp->GetOffset());
row_sp = unwind_plan.GetRowForFunctionOffset(28);
EXPECT_EQ(28ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(wordsize * 2, row_sp->GetCFAValue().GetOffset());

// After last instruction in the function, verify that
// the stack frame has been unwound
// row: CFA=rsp +8 => esp=CFA+0 rip=[CFA-8]
row_sp = unwind_plan.GetRowForFunctionOffset(33);
EXPECT_EQ(33ull, row_sp->GetOffset());
row_sp = unwind_plan.GetRowForFunctionOffset(34);
EXPECT_EQ(34ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(wordsize, row_sp->GetCFAValue().GetOffset());
Expand Down
Loading