Files
clang-p2996/lldb/unittests/UnwindAssembly/PPC64/TestPPC64InstEmulation.cpp
Jason Molenda 3336d73126 [lldb][NFC] New names for the two RegisterLocation classes (#109611)
lldb has two RegisterLocation classes that do slightly different things.

UnwindPlan::Row::RegisterLocation (new: AbstractRegisterLocation) has a
description of how to find a register's value or location, not specific
to a particular stopping point. It may say that at a given offset into a
function, the caller's register has been spilled to stack memory at CFA
minus an offset. Or it may say that the caller's register is at a DWARF
exprssion.

UnwindLLDB::RegisterLocation (new: ConcreteRegisterLocation) is a
specific address where the register is currently stored, or the register
it has been copied into, or its value at this point in the current
function execution.

When lldb stops in a function, it interprets the
AbstractRegisterLocation's instructions using the register context and
stack memory, to create the ConcreteRegisterLocation at this point in
time for this stack frame.

I'm not thrilled with AbstractRegisterLocation and
ConcreteRegisterLocation, but it's better than the same name and it will
be easier to update them if someone suggests a better pair.
2024-09-23 10:29:21 -07:00

259 lines
9.5 KiB
C++

//===-- TestPPC64InstEmulation.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 "gtest/gtest.h"
#include <vector>
#include "Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h"
#include "lldb/Core/Address.h"
#include "lldb/Core/AddressRange.h"
#include "lldb/Symbol/UnwindPlan.h"
#include "lldb/Target/UnwindAssembly.h"
#include "lldb/Utility/ArchSpec.h"
#include "Plugins/Disassembler/LLVMC/DisassemblerLLVMC.h"
#include "Plugins/Instruction/PPC64/EmulateInstructionPPC64.h"
#include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h"
#include "llvm/Support/TargetSelect.h"
using namespace lldb;
using namespace lldb_private;
class TestPPC64InstEmulation : public testing::Test {
public:
static void SetUpTestCase();
static void TearDownTestCase();
// virtual void SetUp() override { }
// virtual void TearDown() override { }
protected:
};
void TestPPC64InstEmulation::SetUpTestCase() {
llvm::InitializeAllTargets();
llvm::InitializeAllAsmPrinters();
llvm::InitializeAllTargetMCs();
llvm::InitializeAllDisassemblers();
DisassemblerLLVMC::Initialize();
EmulateInstructionPPC64::Initialize();
}
void TestPPC64InstEmulation::TearDownTestCase() {
DisassemblerLLVMC::Terminate();
EmulateInstructionPPC64::Terminate();
}
TEST_F(TestPPC64InstEmulation, TestSimpleFunction) {
ArchSpec arch("powerpc64le-linux-gnu");
std::unique_ptr<UnwindAssemblyInstEmulation> engine(
static_cast<UnwindAssemblyInstEmulation *>(
UnwindAssemblyInstEmulation::CreateInstance(arch)));
ASSERT_NE(nullptr, engine);
UnwindPlan::RowSP row_sp;
AddressRange sample_range;
UnwindPlan unwind_plan(eRegisterKindLLDB);
UnwindPlan::Row::AbstractRegisterLocation regloc;
// prologue and epilogue of:
// int main() {
// int i = test();
// return i;
// }
//
// compiled with clang -O0 -g
uint8_t data[] = {
// prologue
0x02, 0x10, 0x40, 0x3c, // 0: lis r2, 4098
0x00, 0x7f, 0x42, 0x38, // 4: addi r2, r2, 32512
0xa6, 0x02, 0x08, 0x7c, // 8: mflr r0
0xf8, 0xff, 0xe1, 0xfb, // 12: std r31, -8(r1)
0x10, 0x00, 0x01, 0xf8, // 16: std r0, 16(r1)
0x91, 0xff, 0x21, 0xf8, // 20: stdu r1, -112(r1)
0x78, 0x0b, 0x3f, 0x7c, // 24: mr r31, r1
0x00, 0x00, 0x60, 0x38, // 28: li r3, 0
0x64, 0x00, 0x7f, 0x90, // 32: stw r3, 100(r31)
// epilogue
0x70, 0x00, 0x21, 0x38, // 36: addi r1, r1, 112
0x10, 0x00, 0x01, 0xe8, // 40: ld r0, 16(r1)
0xf8, 0xff, 0xe1, 0xeb, // 44: ld r31, -8(r1)
0xa6, 0x03, 0x08, 0x7c, // 48: mtlr r0
0x20, 0x00, 0x80, 0x4e // 52: blr
};
sample_range = AddressRange(0x1000, sizeof(data));
EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
sample_range, data, sizeof(data), unwind_plan));
// 0: CFA=sp+0
row_sp = unwind_plan.GetRowForFunctionOffset(0);
EXPECT_EQ(0ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
// 1: CFA=sp+0 => fp=[CFA-8]
row_sp = unwind_plan.GetRowForFunctionOffset(16);
EXPECT_EQ(16ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_r31_ppc64le, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-8, regloc.GetOffset());
// 2: CFA=sp+0 => fp=[CFA-8] lr=[CFA+16]
row_sp = unwind_plan.GetRowForFunctionOffset(20);
EXPECT_EQ(20ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_ppc64le, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(16, regloc.GetOffset());
// 3: CFA=sp+112 => fp=[CFA-8] lr=[CFA+16]
row_sp = unwind_plan.GetRowForFunctionOffset(24);
EXPECT_EQ(24ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(112, row_sp->GetCFAValue().GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_r31_ppc64le, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-8, regloc.GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_ppc64le, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(16, regloc.GetOffset());
// 4: CFA=r31+112 => fp=[CFA-8] lr=[CFA+16]
row_sp = unwind_plan.GetRowForFunctionOffset(28);
EXPECT_EQ(28ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r31_ppc64le);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(112, row_sp->GetCFAValue().GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_r31_ppc64le, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-8, regloc.GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_ppc64le, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(16, regloc.GetOffset());
// 5: CFA=sp+0 => fp=[CFA-8] lr=[CFA+16]
row_sp = unwind_plan.GetRowForFunctionOffset(40);
EXPECT_EQ(40ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_r31_ppc64le, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-8, regloc.GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_ppc64le, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(16, regloc.GetOffset());
}
TEST_F(TestPPC64InstEmulation, TestMediumFunction) {
ArchSpec arch("powerpc64le-linux-gnu");
std::unique_ptr<UnwindAssemblyInstEmulation> engine(
static_cast<UnwindAssemblyInstEmulation *>(
UnwindAssemblyInstEmulation::CreateInstance(arch)));
ASSERT_NE(nullptr, engine);
UnwindPlan::RowSP row_sp;
AddressRange sample_range;
UnwindPlan unwind_plan(eRegisterKindLLDB);
UnwindPlan::Row::AbstractRegisterLocation regloc;
// prologue and epilogue of main() (call-func.c),
// with several calls and stack variables.
//
// compiled with clang -O0 -g
uint8_t data[] = {
// prologue
0xa6, 0x02, 0x08, 0x7c, // 0: mflr r0
0xf8, 0xff, 0xe1, 0xfb, // 4: std r31, -8(r1)
0x10, 0x00, 0x01, 0xf8, // 8: std r0, 16(r1)
0x78, 0x0b, 0x3e, 0x7c, // 12: mr r30, r1
0xe0, 0x06, 0x20, 0x78, // 16: clrldi r0, r1, 59
0xa0, 0xfa, 0x00, 0x20, // 20: subfic r0, r0, -1376
0x6a, 0x01, 0x21, 0x7c, // 24: stdux r1, r1, r0
0x78, 0x0b, 0x3f, 0x7c, // 28: mr r31, r1
// epilogue
0x00, 0x00, 0x21, 0xe8, // 32: ld r1, 0(r1)
0x20, 0x00, 0x80, 0x4e // 36: blr
};
sample_range = AddressRange(0x1000, sizeof(data));
EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
sample_range, data, sizeof(data), unwind_plan));
// 0: CFA=sp+0
row_sp = unwind_plan.GetRowForFunctionOffset(0);
EXPECT_EQ(0ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
// 1: CFA=sp+0 => fp=[CFA-8]
row_sp = unwind_plan.GetRowForFunctionOffset(8);
EXPECT_EQ(8ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_r31_ppc64le, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-8, regloc.GetOffset());
// 2: CFA=sp+0 => fp=[CFA-8] lr=[CFA+16]
row_sp = unwind_plan.GetRowForFunctionOffset(12);
EXPECT_EQ(12ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_ppc64le, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(16, regloc.GetOffset());
// 3: CFA=r30
row_sp = unwind_plan.GetRowForFunctionOffset(16);
EXPECT_EQ(16ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r30_ppc64le);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
row_sp = unwind_plan.GetRowForFunctionOffset(32);
EXPECT_EQ(16ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r30_ppc64le);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
// 4: CFA=sp+0
row_sp = unwind_plan.GetRowForFunctionOffset(36);
EXPECT_EQ(36ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
}