Skip to content

[lldb] Support negative function offsets in UnwindPlans #134662

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
merged 2 commits into from
Apr 10, 2025
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
10 changes: 5 additions & 5 deletions lldb/include/lldb/Symbol/UnwindPlan.h
Original file line number Diff line number Diff line change
Expand Up @@ -356,11 +356,11 @@ class UnwindPlan {

void RemoveRegisterInfo(uint32_t reg_num);

lldb::addr_t GetOffset() const { return m_offset; }
int64_t GetOffset() const { return m_offset; }

void SetOffset(lldb::addr_t offset) { m_offset = offset; }
void SetOffset(int64_t offset) { m_offset = offset; }

void SlideOffset(lldb::addr_t offset) { m_offset += offset; }
void SlideOffset(int64_t offset) { m_offset += offset; }

const FAValue &GetCFAValue() const { return m_cfa_value; }
FAValue &GetCFAValue() { return m_cfa_value; }
Expand Down Expand Up @@ -420,7 +420,7 @@ class UnwindPlan {

protected:
typedef std::map<uint32_t, AbstractRegisterLocation> collection;
lldb::addr_t m_offset = 0; // Offset into the function for this row
int64_t m_offset = 0; // Offset into the function for this row

FAValue m_cfa_value;
FAValue m_afa_value;
Expand Down Expand Up @@ -455,7 +455,7 @@ class UnwindPlan {
// practice, the UnwindPlan for a function with no known start address will be
// the architectural default UnwindPlan which will only have one row.
const UnwindPlan::Row *
GetRowForFunctionOffset(std::optional<int> offset) const;
GetRowForFunctionOffset(std::optional<int64_t> offset) const;

lldb::RegisterKind GetRegisterKind() const { return m_register_kind; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1390,11 +1390,12 @@ bool x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite(

// If we already have one row for this instruction, we can continue.
while (row_id < unwind_plan.GetRowCount() &&
unwind_plan.GetRowAtIndex(row_id)->GetOffset() <= offset) {
unwind_plan.GetRowAtIndex(row_id)->GetOffset() <=
static_cast<int64_t>(offset)) {
row_id++;
}
const UnwindPlan::Row *original_row = unwind_plan.GetRowAtIndex(row_id - 1);
if (original_row->GetOffset() == offset) {
if (original_row->GetOffset() == static_cast<int64_t>(offset)) {
row = *original_row;
continue;
}
Expand Down
2 changes: 1 addition & 1 deletion lldb/source/Symbol/DWARFCallFrameInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -765,7 +765,7 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset,
__FUNCTION__, dwarf_offset, startaddr.GetFileAddress());
break;
}
lldb::addr_t offset = row.GetOffset();
int64_t offset = row.GetOffset();
row = std::move(stack.back());
stack.pop_back();
row.SetOffset(offset);
Expand Down
6 changes: 3 additions & 3 deletions lldb/source/Symbol/UnwindPlan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -398,10 +398,10 @@ void UnwindPlan::AppendRow(Row row) {
}

struct RowLess {
bool operator()(addr_t a, const UnwindPlan::Row &b) const {
bool operator()(int64_t a, const UnwindPlan::Row &b) const {
return a < b.GetOffset();
}
bool operator()(const UnwindPlan::Row &a, addr_t b) const {
bool operator()(const UnwindPlan::Row &a, int64_t b) const {
return a.GetOffset() < b;
}
};
Expand All @@ -418,7 +418,7 @@ void UnwindPlan::InsertRow(Row row, bool replace_existing) {
}

const UnwindPlan::Row *
UnwindPlan::GetRowForFunctionOffset(std::optional<int> offset) const {
UnwindPlan::GetRowForFunctionOffset(std::optional<int64_t> offset) const {
auto it = offset ? llvm::upper_bound(m_row_list, *offset, RowLess())
: m_row_list.end();
if (it == m_row_list.begin())
Expand Down
5 changes: 5 additions & 0 deletions lldb/unittests/Symbol/UnwindPlanTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ static UnwindPlan::Row make_simple_row(addr_t offset, uint64_t cfa_value) {
TEST(UnwindPlan, InsertRow) {
UnwindPlan::Row row1 = make_simple_row(0, 42);
UnwindPlan::Row row2 = make_simple_row(0, 47);
UnwindPlan::Row row3 = make_simple_row(-1, 4242);

UnwindPlan plan(eRegisterKindGeneric);
plan.InsertRow(row1);
Expand All @@ -34,6 +35,10 @@ TEST(UnwindPlan, InsertRow) {

plan.InsertRow(row2, /*replace_existing=*/true);
EXPECT_THAT(plan.GetRowForFunctionOffset(0), testing::Pointee(row2));

EXPECT_THAT(plan.GetRowForFunctionOffset(-1), nullptr);
plan.InsertRow(row3);
EXPECT_THAT(plan.GetRowForFunctionOffset(-1), testing::Pointee(row3));
}

TEST(UnwindPlan, GetRowForFunctionOffset) {
Expand Down
50 changes: 25 additions & 25 deletions lldb/unittests/UnwindAssembly/ARM64/TestArm64InstEmulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ TEST_F(TestArm64InstEmulation, TestSimpleDarwinFunction) {

// CFA=sp +0 => fp= <same> lr= <same>
row = unwind_plan.GetRowForFunctionOffset(0);
EXPECT_EQ(0ull, row->GetOffset());
EXPECT_EQ(0, row->GetOffset());
EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(0, row->GetCFAValue().GetOffset());
Expand All @@ -103,7 +103,7 @@ TEST_F(TestArm64InstEmulation, TestSimpleDarwinFunction) {

// CFA=sp+16 => fp=[CFA-16] lr=[CFA-8]
row = unwind_plan.GetRowForFunctionOffset(4);
EXPECT_EQ(4ull, row->GetOffset());
EXPECT_EQ(4, row->GetOffset());
EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(16, row->GetCFAValue().GetOffset());
Expand All @@ -118,7 +118,7 @@ TEST_F(TestArm64InstEmulation, TestSimpleDarwinFunction) {

// CFA=fp+16 => fp=[CFA-16] lr=[CFA-8]
row = unwind_plan.GetRowForFunctionOffset(8);
EXPECT_EQ(8ull, row->GetOffset());
EXPECT_EQ(8, row->GetOffset());
EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(16, row->GetCFAValue().GetOffset());
Expand All @@ -133,7 +133,7 @@ TEST_F(TestArm64InstEmulation, TestSimpleDarwinFunction) {

// CFA=sp+16 => fp=[CFA-16] lr=[CFA-8]
row = unwind_plan.GetRowForFunctionOffset(16);
EXPECT_EQ(16ull, row->GetOffset());
EXPECT_EQ(16, row->GetOffset());
EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(16, row->GetCFAValue().GetOffset());
Expand All @@ -148,7 +148,7 @@ TEST_F(TestArm64InstEmulation, TestSimpleDarwinFunction) {

// CFA=sp +0 => fp= <same> lr= <same>
row = unwind_plan.GetRowForFunctionOffset(20);
EXPECT_EQ(20ull, row->GetOffset());
EXPECT_EQ(20, row->GetOffset());
EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(0, row->GetCFAValue().GetOffset());
Expand Down Expand Up @@ -219,14 +219,14 @@ TEST_F(TestArm64InstEmulation, TestMediumDarwinFunction) {

// 0: CFA=sp +0 =>
row = unwind_plan.GetRowForFunctionOffset(0);
EXPECT_EQ(0ull, row->GetOffset());
EXPECT_EQ(0, row->GetOffset());
EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(0, row->GetCFAValue().GetOffset());

// 4: CFA=sp+48 => x21=[CFA-40] x22=[CFA-48]
row = unwind_plan.GetRowForFunctionOffset(4);
EXPECT_EQ(4ull, row->GetOffset());
EXPECT_EQ(4, row->GetOffset());
EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_EQ(48, row->GetCFAValue().GetOffset());

Expand All @@ -240,7 +240,7 @@ TEST_F(TestArm64InstEmulation, TestMediumDarwinFunction) {

// 8: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
row = unwind_plan.GetRowForFunctionOffset(8);
EXPECT_EQ(8ull, row->GetOffset());
EXPECT_EQ(8, row->GetOffset());
EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_EQ(48, row->GetCFAValue().GetOffset());

Expand All @@ -255,7 +255,7 @@ TEST_F(TestArm64InstEmulation, TestMediumDarwinFunction) {
// 12: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
// fp=[CFA-16] lr=[CFA-8]
row = unwind_plan.GetRowForFunctionOffset(12);
EXPECT_EQ(12ull, row->GetOffset());
EXPECT_EQ(12, row->GetOffset());
EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_EQ(48, row->GetCFAValue().GetOffset());

Expand All @@ -270,23 +270,23 @@ TEST_F(TestArm64InstEmulation, TestMediumDarwinFunction) {
// 16: CFA=fp+16 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
// fp=[CFA-16] lr=[CFA-8]
row = unwind_plan.GetRowForFunctionOffset(16);
EXPECT_EQ(16ull, row->GetOffset());
EXPECT_EQ(16, row->GetOffset());
EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(16, row->GetCFAValue().GetOffset());

// 28: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
// fp=[CFA-16] lr=[CFA-8]
row = unwind_plan.GetRowForFunctionOffset(28);
EXPECT_EQ(28ull, row->GetOffset());
EXPECT_EQ(28, row->GetOffset());
EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(48, row->GetCFAValue().GetOffset());

// 32: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48] fp=
// <same> lr= <same>
row = unwind_plan.GetRowForFunctionOffset(32);
EXPECT_EQ(32ull, row->GetOffset());
EXPECT_EQ(32, row->GetOffset());

// I'd prefer if these restored registers were cleared entirely instead of set
// to IsSame...
Expand All @@ -299,7 +299,7 @@ TEST_F(TestArm64InstEmulation, TestMediumDarwinFunction) {
// 36: CFA=sp+48 => x19= <same> x20= <same> x21=[CFA-40] x22=[CFA-48] fp=
// <same> lr= <same>
row = unwind_plan.GetRowForFunctionOffset(36);
EXPECT_EQ(36ull, row->GetOffset());
EXPECT_EQ(36, row->GetOffset());

EXPECT_TRUE(row->GetRegisterInfo(gpr_x19_arm64, regloc));
EXPECT_TRUE(regloc.IsSame());
Expand All @@ -310,7 +310,7 @@ TEST_F(TestArm64InstEmulation, TestMediumDarwinFunction) {
// 40: CFA=sp +0 => x19= <same> x20= <same> x21= <same> x22= <same> fp= <same>
// lr= <same>
row = unwind_plan.GetRowForFunctionOffset(40);
EXPECT_EQ(40ull, row->GetOffset());
EXPECT_EQ(40, row->GetOffset());
EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(0, row->GetCFAValue().GetOffset());
Expand Down Expand Up @@ -373,7 +373,7 @@ TEST_F(TestArm64InstEmulation, TestFramelessThreeEpilogueFunction) {

// 0: CFA=sp +0 =>
row = unwind_plan.GetRowForFunctionOffset(0);
EXPECT_EQ(0ull, row->GetOffset());
EXPECT_EQ(0, row->GetOffset());
EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(0, row->GetCFAValue().GetOffset());
Expand Down Expand Up @@ -503,7 +503,7 @@ TEST_F(TestArm64InstEmulation, TestRegisterSavedTwice) {
sample_range, data, sizeof(data), unwind_plan));

row = unwind_plan.GetRowForFunctionOffset(36);
EXPECT_EQ(28ull, row->GetOffset());
EXPECT_EQ(28, row->GetOffset());
EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(16, row->GetCFAValue().GetOffset());
Expand All @@ -513,7 +513,7 @@ TEST_F(TestArm64InstEmulation, TestRegisterSavedTwice) {
EXPECT_EQ(-32, regloc.GetOffset());

row = unwind_plan.GetRowForFunctionOffset(40);
EXPECT_EQ(28ull, row->GetOffset());
EXPECT_EQ(28, row->GetOffset());
EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(16, row->GetCFAValue().GetOffset());
Expand Down Expand Up @@ -619,7 +619,7 @@ TEST_F(TestArm64InstEmulation, TestRegisterDoubleSpills) {
// d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64] d12=[CFA-72]
// d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]
row = unwind_plan.GetRowForFunctionOffset(28);
EXPECT_EQ(28ull, row->GetOffset());
EXPECT_EQ(28, row->GetOffset());
EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(16, row->GetCFAValue().GetOffset());
Expand Down Expand Up @@ -658,7 +658,7 @@ TEST_F(TestArm64InstEmulation, TestRegisterDoubleSpills) {

// 60: CFA=sp +0 =>
row = unwind_plan.GetRowForFunctionOffset(60);
EXPECT_EQ(60ull, row->GetOffset());
EXPECT_EQ(60, row->GetOffset());
EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(0, row->GetCFAValue().GetOffset());
Expand Down Expand Up @@ -765,30 +765,30 @@ TEST_F(TestArm64InstEmulation, TestCFARegisterTrackedAcrossJumps) {

// Confirm CFA at mid-func epilogue 'ret' is $sp+0
row = unwind_plan.GetRowForFunctionOffset(40);
EXPECT_EQ(40ull, row->GetOffset());
EXPECT_EQ(40, row->GetOffset());
EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(0, row->GetCFAValue().GetOffset());

// After the 'ret', confirm we're back to the correct CFA of $fp+16
row = unwind_plan.GetRowForFunctionOffset(44);
EXPECT_EQ(44ull, row->GetOffset());
EXPECT_EQ(44, row->GetOffset());
EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(16, row->GetCFAValue().GetOffset());

// Confirm that we have no additional UnwindPlan rows before the
// real epilogue -- we still get the Row at offset 44.
row = unwind_plan.GetRowForFunctionOffset(60);
EXPECT_EQ(44ull, row->GetOffset());
EXPECT_EQ(44, row->GetOffset());
EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(16, row->GetCFAValue().GetOffset());

// And in the epilogue, confirm that we start by switching back to
// defining the CFA in terms of $sp.
row = unwind_plan.GetRowForFunctionOffset(64);
EXPECT_EQ(64ull, row->GetOffset());
EXPECT_EQ(64, row->GetOffset());
EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(32, row->GetCFAValue().GetOffset());
Expand Down Expand Up @@ -845,14 +845,14 @@ TEST_F(TestArm64InstEmulation, TestCFAResetToSP) {

// Confirm CFA before epilogue instructions is in terms of $fp
row = unwind_plan.GetRowForFunctionOffset(12);
EXPECT_EQ(12ull, row->GetOffset());
EXPECT_EQ(12, row->GetOffset());
EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);

// Confirm that after restoring $fp to caller's value, CFA is now in
// terms of $sp
row = unwind_plan.GetRowForFunctionOffset(16);
EXPECT_EQ(16ull, row->GetOffset());
EXPECT_EQ(16, row->GetOffset());
EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
}
Loading