This is mainly useful for discontinuous functions because individual parts of the function will have separate FDE entries, which can begin many megabytes from the start of the function. However, I'm separating it out, because it turns out we already have a test case for the situation where the FDE does not begin exactly at the function boundary. The test works mostly by accident because the FDE starts only one byte after the beginning of the function so it doesn't really matter whether one looks up the unwind row using the function or fde offset. In this patch, I beef up the test to catch this problem more reliably. To make this work I've also needed to change a couple of places which that an unwind plan always has a row at offset zero.
87 lines
3.1 KiB
C++
87 lines
3.1 KiB
C++
//===-- UnwindPlanTest.cpp ------------------------------------------------===//
|
|
//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "lldb/Symbol/UnwindPlan.h"
|
|
#include "gmock/gmock.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
using namespace lldb_private;
|
|
using namespace lldb;
|
|
|
|
static UnwindPlan::Row make_simple_row(addr_t offset, uint64_t cfa_value) {
|
|
UnwindPlan::Row row;
|
|
row.SetOffset(offset);
|
|
row.GetCFAValue().SetIsConstant(cfa_value);
|
|
return row;
|
|
}
|
|
|
|
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);
|
|
EXPECT_THAT(plan.GetRowForFunctionOffset(0), testing::Pointee(row1));
|
|
|
|
plan.InsertRow(row2, /*replace_existing=*/false);
|
|
EXPECT_THAT(plan.GetRowForFunctionOffset(0), testing::Pointee(row1));
|
|
|
|
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) {
|
|
UnwindPlan::Row row1 = make_simple_row(10, 42);
|
|
UnwindPlan::Row row2 = make_simple_row(20, 47);
|
|
|
|
UnwindPlan plan(eRegisterKindGeneric);
|
|
plan.InsertRow(row1);
|
|
plan.InsertRow(row2);
|
|
|
|
EXPECT_THAT(plan.GetRowForFunctionOffset(0), nullptr);
|
|
EXPECT_THAT(plan.GetRowForFunctionOffset(9), nullptr);
|
|
EXPECT_THAT(plan.GetRowForFunctionOffset(10), testing::Pointee(row1));
|
|
EXPECT_THAT(plan.GetRowForFunctionOffset(19), testing::Pointee(row1));
|
|
EXPECT_THAT(plan.GetRowForFunctionOffset(20), testing::Pointee(row2));
|
|
EXPECT_THAT(plan.GetRowForFunctionOffset(99), testing::Pointee(row2));
|
|
}
|
|
|
|
TEST(UnwindPlan, PlanValidAtAddress) {
|
|
UnwindPlan::Row row1 = make_simple_row(0, 42);
|
|
UnwindPlan::Row row2 = make_simple_row(10, 47);
|
|
|
|
UnwindPlan plan(eRegisterKindGeneric);
|
|
// When valid address range is not set, plans are valid as long as they have a
|
|
// row that sets the CFA.
|
|
EXPECT_FALSE(plan.PlanValidAtAddress(Address(0)));
|
|
EXPECT_FALSE(plan.PlanValidAtAddress(Address(10)));
|
|
|
|
plan.InsertRow(row2);
|
|
EXPECT_TRUE(plan.PlanValidAtAddress(Address(0)));
|
|
EXPECT_TRUE(plan.PlanValidAtAddress(Address(10)));
|
|
|
|
plan.InsertRow(row1);
|
|
EXPECT_TRUE(plan.PlanValidAtAddress(Address(0)));
|
|
EXPECT_TRUE(plan.PlanValidAtAddress(Address(10)));
|
|
|
|
// With an address range, they're only valid within that range.
|
|
plan.SetPlanValidAddressRanges({AddressRange(0, 5), AddressRange(15, 5)});
|
|
EXPECT_TRUE(plan.PlanValidAtAddress(Address(0)));
|
|
EXPECT_FALSE(plan.PlanValidAtAddress(Address(5)));
|
|
EXPECT_FALSE(plan.PlanValidAtAddress(Address(10)));
|
|
EXPECT_TRUE(plan.PlanValidAtAddress(Address(15)));
|
|
EXPECT_FALSE(plan.PlanValidAtAddress(Address(20)));
|
|
EXPECT_FALSE(plan.PlanValidAtAddress(Address(25)));
|
|
}
|