1 //===-- TestPPC64InstEmulation.cpp ----------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "gtest/gtest.h" 10 11 #include <vector> 12 13 #include "Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h" 14 15 #include "lldb/Core/Address.h" 16 #include "lldb/Core/AddressRange.h" 17 #include "lldb/Symbol/UnwindPlan.h" 18 #include "lldb/Target/UnwindAssembly.h" 19 #include "lldb/Utility/ArchSpec.h" 20 21 #include "Plugins/Disassembler/LLVMC/DisassemblerLLVMC.h" 22 #include "Plugins/Instruction/PPC64/EmulateInstructionPPC64.h" 23 #include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h" 24 #include "llvm/Support/TargetSelect.h" 25 26 using namespace lldb; 27 using namespace lldb_private; 28 29 class TestPPC64InstEmulation : public testing::Test { 30 public: 31 static void SetUpTestCase(); 32 static void TearDownTestCase(); 33 34 // virtual void SetUp() override { } 35 // virtual void TearDown() override { } 36 37 protected: 38 }; 39 40 void TestPPC64InstEmulation::SetUpTestCase() { 41 llvm::InitializeAllTargets(); 42 llvm::InitializeAllAsmPrinters(); 43 llvm::InitializeAllTargetMCs(); 44 llvm::InitializeAllDisassemblers(); 45 DisassemblerLLVMC::Initialize(); 46 EmulateInstructionPPC64::Initialize(); 47 } 48 49 void TestPPC64InstEmulation::TearDownTestCase() { 50 DisassemblerLLVMC::Terminate(); 51 EmulateInstructionPPC64::Terminate(); 52 } 53 54 TEST_F(TestPPC64InstEmulation, TestSimpleFunction) { 55 ArchSpec arch("powerpc64le-linux-gnu"); 56 std::unique_ptr<UnwindAssemblyInstEmulation> engine( 57 static_cast<UnwindAssemblyInstEmulation *>( 58 UnwindAssemblyInstEmulation::CreateInstance(arch))); 59 ASSERT_NE(nullptr, engine); 60 61 UnwindPlan::RowSP row_sp; 62 AddressRange sample_range; 63 UnwindPlan unwind_plan(eRegisterKindLLDB); 64 UnwindPlan::Row::AbstractRegisterLocation regloc; 65 66 // prologue and epilogue of: 67 // int main() { 68 // int i = test(); 69 // return i; 70 // } 71 // 72 // compiled with clang -O0 -g 73 uint8_t data[] = { 74 // prologue 75 0x02, 0x10, 0x40, 0x3c, // 0: lis r2, 4098 76 0x00, 0x7f, 0x42, 0x38, // 4: addi r2, r2, 32512 77 0xa6, 0x02, 0x08, 0x7c, // 8: mflr r0 78 0xf8, 0xff, 0xe1, 0xfb, // 12: std r31, -8(r1) 79 0x10, 0x00, 0x01, 0xf8, // 16: std r0, 16(r1) 80 0x91, 0xff, 0x21, 0xf8, // 20: stdu r1, -112(r1) 81 0x78, 0x0b, 0x3f, 0x7c, // 24: mr r31, r1 82 0x00, 0x00, 0x60, 0x38, // 28: li r3, 0 83 0x64, 0x00, 0x7f, 0x90, // 32: stw r3, 100(r31) 84 85 // epilogue 86 0x70, 0x00, 0x21, 0x38, // 36: addi r1, r1, 112 87 0x10, 0x00, 0x01, 0xe8, // 40: ld r0, 16(r1) 88 0xf8, 0xff, 0xe1, 0xeb, // 44: ld r31, -8(r1) 89 0xa6, 0x03, 0x08, 0x7c, // 48: mtlr r0 90 0x20, 0x00, 0x80, 0x4e // 52: blr 91 }; 92 93 sample_range = AddressRange(0x1000, sizeof(data)); 94 95 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 96 sample_range, data, sizeof(data), unwind_plan)); 97 98 // 0: CFA=sp+0 99 row_sp = unwind_plan.GetRowForFunctionOffset(0); 100 EXPECT_EQ(0ull, row_sp->GetOffset()); 101 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le); 102 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 103 EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset()); 104 105 // 1: CFA=sp+0 => fp=[CFA-8] 106 row_sp = unwind_plan.GetRowForFunctionOffset(16); 107 EXPECT_EQ(16ull, row_sp->GetOffset()); 108 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le); 109 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 110 EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset()); 111 112 EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_r31_ppc64le, regloc)); 113 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 114 EXPECT_EQ(-8, regloc.GetOffset()); 115 116 // 2: CFA=sp+0 => fp=[CFA-8] lr=[CFA+16] 117 row_sp = unwind_plan.GetRowForFunctionOffset(20); 118 EXPECT_EQ(20ull, row_sp->GetOffset()); 119 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le); 120 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 121 EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset()); 122 123 EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_ppc64le, regloc)); 124 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 125 EXPECT_EQ(16, regloc.GetOffset()); 126 127 // 3: CFA=sp+112 => fp=[CFA-8] lr=[CFA+16] 128 row_sp = unwind_plan.GetRowForFunctionOffset(24); 129 EXPECT_EQ(24ull, row_sp->GetOffset()); 130 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le); 131 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 132 EXPECT_EQ(112, row_sp->GetCFAValue().GetOffset()); 133 134 EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_r31_ppc64le, regloc)); 135 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 136 EXPECT_EQ(-8, regloc.GetOffset()); 137 138 EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_ppc64le, regloc)); 139 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 140 EXPECT_EQ(16, regloc.GetOffset()); 141 142 // 4: CFA=r31+112 => fp=[CFA-8] lr=[CFA+16] 143 row_sp = unwind_plan.GetRowForFunctionOffset(28); 144 EXPECT_EQ(28ull, row_sp->GetOffset()); 145 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r31_ppc64le); 146 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 147 EXPECT_EQ(112, row_sp->GetCFAValue().GetOffset()); 148 149 EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_r31_ppc64le, regloc)); 150 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 151 EXPECT_EQ(-8, regloc.GetOffset()); 152 153 EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_ppc64le, regloc)); 154 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 155 EXPECT_EQ(16, regloc.GetOffset()); 156 157 // 5: CFA=sp+0 => fp=[CFA-8] lr=[CFA+16] 158 row_sp = unwind_plan.GetRowForFunctionOffset(40); 159 EXPECT_EQ(40ull, row_sp->GetOffset()); 160 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le); 161 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 162 EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset()); 163 164 EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_r31_ppc64le, regloc)); 165 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 166 EXPECT_EQ(-8, regloc.GetOffset()); 167 168 EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_ppc64le, regloc)); 169 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 170 EXPECT_EQ(16, regloc.GetOffset()); 171 } 172 173 TEST_F(TestPPC64InstEmulation, TestMediumFunction) { 174 ArchSpec arch("powerpc64le-linux-gnu"); 175 std::unique_ptr<UnwindAssemblyInstEmulation> engine( 176 static_cast<UnwindAssemblyInstEmulation *>( 177 UnwindAssemblyInstEmulation::CreateInstance(arch))); 178 ASSERT_NE(nullptr, engine); 179 180 UnwindPlan::RowSP row_sp; 181 AddressRange sample_range; 182 UnwindPlan unwind_plan(eRegisterKindLLDB); 183 UnwindPlan::Row::AbstractRegisterLocation regloc; 184 185 // prologue and epilogue of main() (call-func.c), 186 // with several calls and stack variables. 187 // 188 // compiled with clang -O0 -g 189 uint8_t data[] = { 190 // prologue 191 0xa6, 0x02, 0x08, 0x7c, // 0: mflr r0 192 0xf8, 0xff, 0xe1, 0xfb, // 4: std r31, -8(r1) 193 0x10, 0x00, 0x01, 0xf8, // 8: std r0, 16(r1) 194 0x78, 0x0b, 0x3e, 0x7c, // 12: mr r30, r1 195 0xe0, 0x06, 0x20, 0x78, // 16: clrldi r0, r1, 59 196 0xa0, 0xfa, 0x00, 0x20, // 20: subfic r0, r0, -1376 197 0x6a, 0x01, 0x21, 0x7c, // 24: stdux r1, r1, r0 198 0x78, 0x0b, 0x3f, 0x7c, // 28: mr r31, r1 199 200 // epilogue 201 0x00, 0x00, 0x21, 0xe8, // 32: ld r1, 0(r1) 202 0x20, 0x00, 0x80, 0x4e // 36: blr 203 }; 204 205 sample_range = AddressRange(0x1000, sizeof(data)); 206 207 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 208 sample_range, data, sizeof(data), unwind_plan)); 209 210 // 0: CFA=sp+0 211 row_sp = unwind_plan.GetRowForFunctionOffset(0); 212 EXPECT_EQ(0ull, row_sp->GetOffset()); 213 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le); 214 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 215 EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset()); 216 217 // 1: CFA=sp+0 => fp=[CFA-8] 218 row_sp = unwind_plan.GetRowForFunctionOffset(8); 219 EXPECT_EQ(8ull, row_sp->GetOffset()); 220 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le); 221 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 222 EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset()); 223 224 EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_r31_ppc64le, regloc)); 225 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 226 EXPECT_EQ(-8, regloc.GetOffset()); 227 228 // 2: CFA=sp+0 => fp=[CFA-8] lr=[CFA+16] 229 row_sp = unwind_plan.GetRowForFunctionOffset(12); 230 EXPECT_EQ(12ull, row_sp->GetOffset()); 231 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le); 232 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 233 EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset()); 234 235 EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_ppc64le, regloc)); 236 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 237 EXPECT_EQ(16, regloc.GetOffset()); 238 239 // 3: CFA=r30 240 row_sp = unwind_plan.GetRowForFunctionOffset(16); 241 EXPECT_EQ(16ull, row_sp->GetOffset()); 242 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r30_ppc64le); 243 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 244 EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset()); 245 246 row_sp = unwind_plan.GetRowForFunctionOffset(32); 247 EXPECT_EQ(16ull, row_sp->GetOffset()); 248 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r30_ppc64le); 249 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 250 EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset()); 251 252 // 4: CFA=sp+0 253 row_sp = unwind_plan.GetRowForFunctionOffset(36); 254 EXPECT_EQ(36ull, row_sp->GetOffset()); 255 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le); 256 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 257 EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset()); 258 } 259