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