1 //===-- TestArm64InstEmulation.cpp ------------------------------------*- C++ 2 //-*-===// 3 4 // 5 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 6 // See https://llvm.org/LICENSE.txt for license information. 7 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 8 // 9 //===----------------------------------------------------------------------===// 10 11 #include "gtest/gtest.h" 12 13 #include <vector> 14 15 #include "Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h" 16 17 #include "lldb/Core/Address.h" 18 #include "lldb/Core/AddressRange.h" 19 #include "lldb/Symbol/UnwindPlan.h" 20 #include "lldb/Target/UnwindAssembly.h" 21 #include "lldb/Utility/ArchSpec.h" 22 23 #include "Plugins/Disassembler/llvm/DisassemblerLLVMC.h" 24 #include "Plugins/Instruction/ARM64/EmulateInstructionARM64.h" 25 #include "Plugins/Process/Utility/lldb-arm64-register-enums.h" 26 #include "llvm/Support/TargetSelect.h" 27 28 using namespace lldb; 29 using namespace lldb_private; 30 31 class TestArm64InstEmulation : public testing::Test { 32 public: 33 static void SetUpTestCase(); 34 static void TearDownTestCase(); 35 36 // virtual void SetUp() override { } 37 // virtual void TearDown() override { } 38 39 protected: 40 }; 41 42 void TestArm64InstEmulation::SetUpTestCase() { 43 llvm::InitializeAllTargets(); 44 llvm::InitializeAllAsmPrinters(); 45 llvm::InitializeAllTargetMCs(); 46 llvm::InitializeAllDisassemblers(); 47 DisassemblerLLVMC::Initialize(); 48 EmulateInstructionARM64::Initialize(); 49 } 50 51 void TestArm64InstEmulation::TearDownTestCase() { 52 DisassemblerLLVMC::Terminate(); 53 EmulateInstructionARM64::Terminate(); 54 } 55 56 TEST_F(TestArm64InstEmulation, TestSimpleDarwinFunction) { 57 ArchSpec arch("arm64-apple-ios10"); 58 std::unique_ptr<UnwindAssemblyInstEmulation> engine( 59 static_cast<UnwindAssemblyInstEmulation *>( 60 UnwindAssemblyInstEmulation::CreateInstance(arch))); 61 ASSERT_NE(nullptr, engine); 62 63 UnwindPlan::RowSP row_sp; 64 AddressRange sample_range; 65 UnwindPlan unwind_plan(eRegisterKindLLDB); 66 UnwindPlan::Row::RegisterLocation regloc; 67 68 // 'int main() { }' compiled for arm64-apple-ios with clang 69 uint8_t data[] = { 70 0xfd, 0x7b, 0xbf, 0xa9, // 0xa9bf7bfd : stp x29, x30, [sp, #-0x10]! 71 0xfd, 0x03, 0x00, 0x91, // 0x910003fd : mov x29, sp 72 0xff, 0x43, 0x00, 0xd1, // 0xd10043ff : sub sp, sp, #0x10 73 74 0xbf, 0x03, 0x00, 0x91, // 0x910003bf : mov sp, x29 75 0xfd, 0x7b, 0xc1, 0xa8, // 0xa8c17bfd : ldp x29, x30, [sp], #16 76 0xc0, 0x03, 0x5f, 0xd6, // 0xd65f03c0 : ret 77 }; 78 79 // UnwindPlan we expect: 80 81 // row[0]: 0: CFA=sp +0 => 82 // row[1]: 4: CFA=sp+16 => fp=[CFA-16] lr=[CFA-8] 83 // row[2]: 8: CFA=fp+16 => fp=[CFA-16] lr=[CFA-8] 84 // row[2]: 16: CFA=sp+16 => fp=[CFA-16] lr=[CFA-8] 85 // row[3]: 20: CFA=sp +0 => fp= <same> lr= <same> 86 87 sample_range = AddressRange(0x1000, sizeof(data)); 88 89 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 90 sample_range, data, sizeof(data), unwind_plan)); 91 92 // CFA=sp +0 93 row_sp = unwind_plan.GetRowForFunctionOffset(0); 94 EXPECT_EQ(0ull, row_sp->GetOffset()); 95 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64); 96 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 97 EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset()); 98 99 // CFA=sp+16 => fp=[CFA-16] lr=[CFA-8] 100 row_sp = unwind_plan.GetRowForFunctionOffset(4); 101 EXPECT_EQ(4ull, row_sp->GetOffset()); 102 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64); 103 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 104 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); 105 106 EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc)); 107 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 108 EXPECT_EQ(-16, regloc.GetOffset()); 109 110 EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc)); 111 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 112 EXPECT_EQ(-8, regloc.GetOffset()); 113 114 // CFA=fp+16 => fp=[CFA-16] lr=[CFA-8] 115 row_sp = unwind_plan.GetRowForFunctionOffset(8); 116 EXPECT_EQ(8ull, row_sp->GetOffset()); 117 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64); 118 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 119 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); 120 121 EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc)); 122 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 123 EXPECT_EQ(-16, regloc.GetOffset()); 124 125 EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc)); 126 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 127 EXPECT_EQ(-8, regloc.GetOffset()); 128 129 // CFA=sp+16 => fp=[CFA-16] lr=[CFA-8] 130 row_sp = unwind_plan.GetRowForFunctionOffset(16); 131 EXPECT_EQ(16ull, row_sp->GetOffset()); 132 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64); 133 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 134 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); 135 136 EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc)); 137 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 138 EXPECT_EQ(-16, regloc.GetOffset()); 139 140 EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc)); 141 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 142 EXPECT_EQ(-8, regloc.GetOffset()); 143 144 // CFA=sp +0 => fp= <same> lr= <same> 145 row_sp = unwind_plan.GetRowForFunctionOffset(20); 146 EXPECT_EQ(20ull, row_sp->GetOffset()); 147 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64); 148 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 149 EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset()); 150 } 151 152 TEST_F(TestArm64InstEmulation, TestMediumDarwinFunction) { 153 ArchSpec arch("arm64-apple-ios10"); 154 std::unique_ptr<UnwindAssemblyInstEmulation> engine( 155 static_cast<UnwindAssemblyInstEmulation *>( 156 UnwindAssemblyInstEmulation::CreateInstance(arch))); 157 ASSERT_NE(nullptr, engine); 158 159 UnwindPlan::RowSP row_sp; 160 AddressRange sample_range; 161 UnwindPlan unwind_plan(eRegisterKindLLDB); 162 UnwindPlan::Row::RegisterLocation regloc; 163 164 // disassembly of -[NSPlaceholderString initWithBytes:length:encoding:] 165 // from Foundation for iOS. 166 uint8_t data[] = { 167 0xf6, 0x57, 0xbd, 0xa9, // 0: 0xa9bd57f6 stp x22, x21, [sp, #-48]! 168 0xf4, 0x4f, 0x01, 0xa9, // 4: 0xa9014ff4 stp x20, x19, [sp, #16] 169 0xfd, 0x7b, 0x02, 0xa9, // 8: 0xa9027bfd stp x29, x30, [sp, #32] 170 0xfd, 0x83, 0x00, 0x91, // 12: 0x910083fd add x29, sp, #32 171 0xff, 0x43, 0x00, 0xd1, // 16: 0xd10043ff sub sp, sp, #16 172 173 // [... function body ...] 174 0x1f, 0x20, 0x03, 0xd5, // 20: 0xd503201f nop 175 176 0xbf, 0x83, 0x00, 0xd1, // 24: 0xd10083bf sub sp, x29, #32 177 0xfd, 0x7b, 0x42, 0xa9, // 28: 0xa9427bfd ldp x29, x30, [sp, #32] 178 0xf4, 0x4f, 0x41, 0xa9, // 32: 0xa9414ff4 ldp x20, x19, [sp, #16] 179 0xf6, 0x57, 0xc3, 0xa8, // 36: 0xa8c357f6 ldp x22, x21, [sp], #48 180 0x01, 0x16, 0x09, 0x14, // 40: 0x14091601 b 0x18f640524 ; symbol stub 181 // for: CFStringCreateWithBytes 182 }; 183 184 // UnwindPlan we expect: 185 // 0: CFA=sp +0 => 186 // 4: CFA=sp+48 => x21=[CFA-40] x22=[CFA-48] 187 // 8: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48] 188 // 12: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48] 189 // fp=[CFA-16] lr=[CFA-8] 190 // 16: CFA=fp+16 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48] 191 // fp=[CFA-16] lr=[CFA-8] 192 193 // [... function body ...] 194 195 // 28: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48] 196 // fp=[CFA-16] lr=[CFA-8] 197 // 32: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48] fp= 198 // <same> lr= <same> 199 // 36: CFA=sp+48 => x19= <same> x20= <same> x21=[CFA-40] x22=[CFA-48] fp= 200 // <same> lr= <same> 201 // 40: CFA=sp +0 => x19= <same> x20= <same> x21= <same> x22= <same> fp= <same> 202 // lr= <same> 203 204 sample_range = AddressRange(0x1000, sizeof(data)); 205 206 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 207 sample_range, data, sizeof(data), unwind_plan)); 208 209 // 0: CFA=sp +0 => 210 row_sp = unwind_plan.GetRowForFunctionOffset(0); 211 EXPECT_EQ(0ull, row_sp->GetOffset()); 212 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64); 213 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 214 EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset()); 215 216 // 4: CFA=sp+48 => x21=[CFA-40] x22=[CFA-48] 217 row_sp = unwind_plan.GetRowForFunctionOffset(4); 218 EXPECT_EQ(4ull, row_sp->GetOffset()); 219 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64); 220 EXPECT_EQ(48, row_sp->GetCFAValue().GetOffset()); 221 222 EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x21_arm64, regloc)); 223 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 224 EXPECT_EQ(-40, regloc.GetOffset()); 225 226 EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x22_arm64, regloc)); 227 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 228 EXPECT_EQ(-48, regloc.GetOffset()); 229 230 // 8: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48] 231 row_sp = unwind_plan.GetRowForFunctionOffset(8); 232 EXPECT_EQ(8ull, row_sp->GetOffset()); 233 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64); 234 EXPECT_EQ(48, row_sp->GetCFAValue().GetOffset()); 235 236 EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x19_arm64, regloc)); 237 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 238 EXPECT_EQ(-24, regloc.GetOffset()); 239 240 EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x20_arm64, regloc)); 241 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 242 EXPECT_EQ(-32, regloc.GetOffset()); 243 244 // 12: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48] 245 // fp=[CFA-16] lr=[CFA-8] 246 row_sp = unwind_plan.GetRowForFunctionOffset(12); 247 EXPECT_EQ(12ull, row_sp->GetOffset()); 248 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64); 249 EXPECT_EQ(48, row_sp->GetCFAValue().GetOffset()); 250 251 EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc)); 252 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 253 EXPECT_EQ(-16, regloc.GetOffset()); 254 255 EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc)); 256 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 257 EXPECT_EQ(-8, regloc.GetOffset()); 258 259 // 16: CFA=fp+16 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48] 260 // fp=[CFA-16] lr=[CFA-8] 261 row_sp = unwind_plan.GetRowForFunctionOffset(16); 262 EXPECT_EQ(16ull, row_sp->GetOffset()); 263 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64); 264 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 265 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); 266 267 // 28: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48] 268 // fp=[CFA-16] lr=[CFA-8] 269 row_sp = unwind_plan.GetRowForFunctionOffset(28); 270 EXPECT_EQ(28ull, row_sp->GetOffset()); 271 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64); 272 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 273 EXPECT_EQ(48, row_sp->GetCFAValue().GetOffset()); 274 275 // 32: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48] fp= 276 // <same> lr= <same> 277 row_sp = unwind_plan.GetRowForFunctionOffset(32); 278 EXPECT_EQ(32ull, row_sp->GetOffset()); 279 280 // I'd prefer if these restored registers were cleared entirely instead of set 281 // to IsSame... 282 EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc)); 283 EXPECT_TRUE(regloc.IsSame()); 284 285 EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc)); 286 EXPECT_TRUE(regloc.IsSame()); 287 288 // 36: CFA=sp+48 => x19= <same> x20= <same> x21=[CFA-40] x22=[CFA-48] fp= 289 // <same> lr= <same> 290 row_sp = unwind_plan.GetRowForFunctionOffset(36); 291 EXPECT_EQ(36ull, row_sp->GetOffset()); 292 293 EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x19_arm64, regloc)); 294 EXPECT_TRUE(regloc.IsSame()); 295 296 EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x20_arm64, regloc)); 297 EXPECT_TRUE(regloc.IsSame()); 298 299 // 40: CFA=sp +0 => x19= <same> x20= <same> x21= <same> x22= <same> fp= <same> 300 // lr= <same> 301 row_sp = unwind_plan.GetRowForFunctionOffset(40); 302 EXPECT_EQ(40ull, row_sp->GetOffset()); 303 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64); 304 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 305 EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset()); 306 307 EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x21_arm64, regloc)); 308 EXPECT_TRUE(regloc.IsSame()); 309 310 EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x22_arm64, regloc)); 311 EXPECT_TRUE(regloc.IsSame()); 312 } 313 314 TEST_F(TestArm64InstEmulation, TestFramelessThreeEpilogueFunction) { 315 ArchSpec arch("arm64-apple-ios10"); 316 std::unique_ptr<UnwindAssemblyInstEmulation> engine( 317 static_cast<UnwindAssemblyInstEmulation *>( 318 UnwindAssemblyInstEmulation::CreateInstance(arch))); 319 ASSERT_NE(nullptr, engine); 320 321 UnwindPlan::RowSP row_sp; 322 AddressRange sample_range; 323 UnwindPlan unwind_plan(eRegisterKindLLDB); 324 UnwindPlan::Row::RegisterLocation regloc; 325 326 // disassembly of JSC::ARM64LogicalImmediate::findBitRange<16u> 327 // from JavaScriptcore for iOS. 328 uint8_t data[] = { 329 0x08, 0x3c, 0x0f, 0x53, // 0: 0x530f3c08 ubfx w8, w0, #15, #1 330 0x68, 0x00, 0x00, 0x39, // 4: 0x39000068 strb w8, [x3] 331 0x08, 0x3c, 0x40, 0xd2, // 8: 0xd2403c08 eor x8, x0, #0xffff 332 0x1f, 0x00, 0x71, 0xf2, // 12: 0xf271001f tst x0, #0x8000 333 334 // [...] 335 336 0x3f, 0x01, 0x0c, 0xeb, // 16: 0xeb0c013f cmp x9, x12 337 0x81, 0x00, 0x00, 0x54, // 20: 0x54000081 b.ne +34 338 0x5f, 0x00, 0x00, 0xb9, // 24: 0xb900005f str wzr, [x2] 339 0xe0, 0x03, 0x00, 0x32, // 28: 0x320003e0 orr w0, wzr, #0x1 340 0xc0, 0x03, 0x5f, 0xd6, // 32: 0xd65f03c0 ret 341 0x89, 0x01, 0x09, 0xca, // 36: 0xca090189 eor x9, x12, x9 342 343 // [...] 344 345 0x08, 0x05, 0x00, 0x11, // 40: 0x11000508 add w8, w8, #0x1 346 0x48, 0x00, 0x00, 0xb9, // 44: 0xb9000048 str w8, [x2] 347 0xe0, 0x03, 0x00, 0x32, // 48: 0x320003e0 orr w0, wzr, #0x1 348 0xc0, 0x03, 0x5f, 0xd6, // 52: 0xd65f03c0 ret 349 0x00, 0x00, 0x80, 0x52, // 56: 0x52800000 mov w0, #0x0 350 0xc0, 0x03, 0x5f, 0xd6, // 60: 0xd65f03c0 ret 351 352 }; 353 354 // UnwindPlan we expect: 355 // 0: CFA=sp +0 => 356 // (possibly with additional rows at offsets 36 and 56 saying the same thing) 357 358 sample_range = AddressRange(0x1000, sizeof(data)); 359 360 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 361 sample_range, data, sizeof(data), unwind_plan)); 362 363 // 0: CFA=sp +0 => 364 row_sp = unwind_plan.GetRowForFunctionOffset(0); 365 EXPECT_EQ(0ull, row_sp->GetOffset()); 366 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64); 367 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 368 EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset()); 369 370 row_sp = unwind_plan.GetRowForFunctionOffset(32); 371 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64); 372 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 373 EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset()); 374 375 EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x19_arm64, regloc)); 376 EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x20_arm64, regloc)); 377 EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x21_arm64, regloc)); 378 EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x22_arm64, regloc)); 379 EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x23_arm64, regloc)); 380 EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x24_arm64, regloc)); 381 EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x25_arm64, regloc)); 382 EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x26_arm64, regloc)); 383 EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x27_arm64, regloc)); 384 EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x28_arm64, regloc)); 385 EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc)); 386 EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc)); 387 388 row_sp = unwind_plan.GetRowForFunctionOffset(36); 389 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64); 390 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 391 EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset()); 392 393 row_sp = unwind_plan.GetRowForFunctionOffset(52); 394 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64); 395 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 396 EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset()); 397 398 row_sp = unwind_plan.GetRowForFunctionOffset(56); 399 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64); 400 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 401 EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset()); 402 403 row_sp = unwind_plan.GetRowForFunctionOffset(60); 404 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64); 405 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 406 EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset()); 407 } 408 409 TEST_F(TestArm64InstEmulation, TestRegisterSavedTwice) { 410 ArchSpec arch("arm64-apple-ios10"); 411 std::unique_ptr<UnwindAssemblyInstEmulation> engine( 412 static_cast<UnwindAssemblyInstEmulation *>( 413 UnwindAssemblyInstEmulation::CreateInstance(arch))); 414 ASSERT_NE(nullptr, engine); 415 416 UnwindPlan::RowSP row_sp; 417 AddressRange sample_range; 418 UnwindPlan unwind_plan(eRegisterKindLLDB); 419 UnwindPlan::Row::RegisterLocation regloc; 420 421 // disassembly of mach_msg_sever_once from libsystem_kernel.dylib for iOS. 422 uint8_t data[] = { 423 424 0xfc, 0x6f, 0xba, 0xa9, // 0: 0xa9ba6ffc stp x28, x27, [sp, #-0x60]! 425 0xfa, 0x67, 0x01, 0xa9, // 4: 0xa90167fa stp x26, x25, [sp, #0x10] 426 0xf8, 0x5f, 0x02, 0xa9, // 8: 0xa9025ff8 stp x24, x23, [sp, #0x20] 427 0xf6, 0x57, 0x03, 0xa9, // 12: 0xa90357f6 stp x22, x21, [sp, #0x30] 428 0xf4, 0x4f, 0x04, 0xa9, // 16: 0xa9044ff4 stp x20, x19, [sp, #0x40] 429 0xfd, 0x7b, 0x05, 0xa9, // 20: 0xa9057bfd stp x29, x30, [sp, #0x50] 430 0xfd, 0x43, 0x01, 0x91, // 24: 0x910143fd add x29, sp, #0x50 431 0xff, 0xc3, 0x00, 0xd1, // 28: 0xd100c3ff sub sp, sp, #0x30 432 433 // mid-function, store x20 & x24 on the stack at a different location. 434 // this should not show up in the unwind plan; caller's values are not 435 // being saved to stack. 436 0xf8, 0x53, 0x01, 0xa9, // 32: 0xa90153f8 stp x24, x20, [sp, #0x10] 437 438 // mid-function, copy x20 and x19 off of the stack -- but not from 439 // their original locations. unwind plan should ignore this. 440 0xf4, 0x4f, 0x41, 0xa9, // 36: 0xa9414ff4 ldp x20, x19, [sp, #0x10] 441 442 // epilogue 443 0xbf, 0x43, 0x01, 0xd1, // 40: 0xd10143bf sub sp, x29, #0x50 444 0xfd, 0x7b, 0x45, 0xa9, // 44: 0xa9457bfd ldp x29, x30, [sp, #0x50] 445 0xf4, 0x4f, 0x44, 0xa9, // 48: 0xa9444ff4 ldp x20, x19, [sp, #0x40] 446 0xf6, 0x57, 0x43, 0xa9, // 52: 0xa94357f6 ldp x22, x21, [sp, #0x30] 447 0xf8, 0x5f, 0x42, 0xa9, // 56: 0xa9425ff8 ldp x24, x23, [sp, #0x20] 448 0xfa, 0x67, 0x41, 0xa9, // 60: 0xa94167fa ldp x26, x25, [sp, #0x10] 449 0xfc, 0x6f, 0xc6, 0xa8, // 64: 0xa8c66ffc ldp x28, x27, [sp], #0x60 450 0xc0, 0x03, 0x5f, 0xd6, // 68: 0xd65f03c0 ret 451 }; 452 453 // UnwindPlan we expect: 454 // 0: CFA=sp +0 => 455 // 4: CFA=sp+96 => x27=[CFA-88] x28=[CFA-96] 456 // 8: CFA=sp+96 => x25=[CFA-72] x26=[CFA-80] x27=[CFA-88] x28=[CFA-96] 457 // 12: CFA=sp+96 => x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80] 458 // x27=[CFA-88] x28=[CFA-96] 459 // 16: CFA=sp+96 => x21=[CFA-40] x22=[CFA-48] x23=[CFA-56] x24=[CFA-64] 460 // x25=[CFA-72] x26=[CFA-80] x27=[CFA-88] x28=[CFA-96] 461 // 20: CFA=sp+96 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48] 462 // x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80] x27=[CFA-88] 463 // x28=[CFA-96] 464 // 24: CFA=sp+96 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48] 465 // x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80] x27=[CFA-88] 466 // x28=[CFA-96] fp=[CFA-16] lr=[CFA-8] 467 // 28: CFA=fp+16 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48] 468 // x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80] x27=[CFA-88] 469 // x28=[CFA-96] fp=[CFA-16] lr=[CFA-8] 470 471 // 44: CFA=sp+96 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48] 472 // x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80] x27=[CFA-88] 473 // x28=[CFA-96] fp=[CFA-16] lr=[CFA-8] 474 // 48: CFA=sp+96 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48] 475 // x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80] x27=[CFA-88] 476 // x28=[CFA-96] 477 // 52: CFA=sp+96 => x21=[CFA-40] x22=[CFA-48] x23=[CFA-56] x24=[CFA-64] 478 // x25=[CFA-72] x26=[CFA-80] x27=[CFA-88] x28=[CFA-96] 479 // 56: CFA=sp+96 => x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80] 480 // x27=[CFA-88] x28=[CFA-96] 481 // 60: CFA=sp+96 => x25=[CFA-72] x26=[CFA-80] x27=[CFA-88] x28=[CFA-96] 482 // 64: CFA=sp+96 => x27=[CFA-88] x28=[CFA-96] 483 // 68: CFA=sp +0 => 484 485 sample_range = AddressRange(0x1000, sizeof(data)); 486 487 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 488 sample_range, data, sizeof(data), unwind_plan)); 489 490 row_sp = unwind_plan.GetRowForFunctionOffset(36); 491 EXPECT_EQ(28ull, row_sp->GetOffset()); 492 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64); 493 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 494 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); 495 496 EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x20_arm64, regloc)); 497 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 498 EXPECT_EQ(-32, regloc.GetOffset()); 499 500 row_sp = unwind_plan.GetRowForFunctionOffset(40); 501 EXPECT_EQ(28ull, row_sp->GetOffset()); 502 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64); 503 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 504 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); 505 506 EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x20_arm64, regloc)); 507 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 508 EXPECT_EQ(-32, regloc.GetOffset()); 509 } 510 511 TEST_F(TestArm64InstEmulation, TestRegisterDoubleSpills) { 512 ArchSpec arch("arm64-apple-ios10"); 513 std::unique_ptr<UnwindAssemblyInstEmulation> engine( 514 static_cast<UnwindAssemblyInstEmulation *>( 515 UnwindAssemblyInstEmulation::CreateInstance(arch))); 516 ASSERT_NE(nullptr, engine); 517 518 UnwindPlan::RowSP row_sp; 519 AddressRange sample_range; 520 UnwindPlan unwind_plan(eRegisterKindLLDB); 521 UnwindPlan::Row::RegisterLocation regloc; 522 523 // this file built with clang for iOS arch arm64 optimization -Os 524 // #include <stdio.h> 525 // double foo(double in) { 526 // double arr[32]; 527 // for (int i = 0; i < 32; i++) 528 // arr[i] = in + i; 529 // for (int i = 2; i < 30; i++) 530 // arr[i] = ((((arr[i - 1] * arr[i - 2] * 0.2) + (0.7 * arr[i])) / 531 // ((((arr[i] * 0.73) + 0.65) * (arr[i - 1] + 0.2)) - ((arr[i + 1] + (arr[i] 532 // * 0.32) + 0.52) / 0.3) + (0.531 * arr[i - 2]))) + ((arr[i - 1] + 5) / 533 // ((arr[i + 2] + 0.4) / arr[i])) + (arr[5] * (0.17 + arr[7] * arr[i])) + 534 // ((i > 5 ? (arr[i - 3]) : arr[i - 1]) * 0.263) + (((arr[i - 2] + arr[i - 535 // 1]) * 0.3252) + 3.56) - (arr[i + 1] * 0.852311)) * ((arr[i] * 85234.1345) 536 // + (77342.451324 / (arr[i - 2] + arr[i - 1] - 73425341.33455))) + (arr[i] 537 // * 875712013.55) - (arr[i - 1] * 0.5555) - ((arr[i] * (arr[i + 1] + 538 // 17342834.44) / 8688200123.555)) + (arr[i - 2] + 8888.888); 539 // return arr[16]; 540 //} 541 // int main(int argc, char **argv) { printf("%g\n", foo(argc)); } 542 543 // so function foo() uses enough registers that it spills the callee-saved 544 // floating point registers. 545 uint8_t data[] = { 546 // prologue 547 0xef, 0x3b, 0xba, 0x6d, // 0: 0x6dba3bef stp d15, d14, [sp, #-0x60]! 548 0xed, 0x33, 0x01, 0x6d, // 4: 0x6d0133ed stp d13, d12, [sp, #0x10] 549 0xeb, 0x2b, 0x02, 0x6d, // 8: 0x6d022beb stp d11, d10, [sp, #0x20] 550 0xe9, 0x23, 0x03, 0x6d, // 12: 0x6d0323e9 stp d9, d8, [sp, #0x30] 551 0xfc, 0x6f, 0x04, 0xa9, // 16: 0xa9046ffc stp x28, x27, [sp, #0x40] 552 0xfd, 0x7b, 0x05, 0xa9, // 20: 0xa9057bfd stp x29, x30, [sp, #0x50] 553 0xfd, 0x43, 0x01, 0x91, // 24: 0x910143fd add x29, sp, #0x50 554 0xff, 0x43, 0x04, 0xd1, // 28: 0xd10443ff sub sp, sp, #0x110 555 556 // epilogue 557 0xbf, 0x43, 0x01, 0xd1, // 32: 0xd10143bf sub sp, x29, #0x50 558 0xfd, 0x7b, 0x45, 0xa9, // 36: 0xa9457bfd ldp x29, x30, [sp, #0x50] 559 0xfc, 0x6f, 0x44, 0xa9, // 40: 0xa9446ffc ldp x28, x27, [sp, #0x40] 560 0xe9, 0x23, 0x43, 0x6d, // 44: 0x6d4323e9 ldp d9, d8, [sp, #0x30] 561 0xeb, 0x2b, 0x42, 0x6d, // 48: 0x6d422beb ldp d11, d10, [sp, #0x20] 562 0xed, 0x33, 0x41, 0x6d, // 52: 0x6d4133ed ldp d13, d12, [sp, #0x10] 563 0xef, 0x3b, 0xc6, 0x6c, // 56: 0x6cc63bef ldp d15, d14, [sp], #0x60 564 0xc0, 0x03, 0x5f, 0xd6, // 60: 0xd65f03c0 ret 565 }; 566 567 // UnwindPlan we expect: 568 // 0: CFA=sp +0 => 569 // 4: CFA=sp+96 => d14=[CFA-88] d15=[CFA-96] 570 // 8: CFA=sp+96 => d12=[CFA-72] d13=[CFA-80] d14=[CFA-88] d15=[CFA-96] 571 // 12: CFA=sp+96 => d10=[CFA-56] d11=[CFA-64] d12=[CFA-72] d13=[CFA-80] 572 // d14=[CFA-88] d15=[CFA-96] 573 // 16: CFA=sp+96 => d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64] 574 // d12=[CFA-72] d13=[CFA-80] d14=[CFA-88] d15=[CFA-96] 575 // 20: CFA=sp+96 => x27=[CFA-24] x28=[CFA-32] d8=[CFA-40] d9=[CFA-48] 576 // d10=[CFA-56] d11=[CFA-64] d12=[CFA-72] d13=[CFA-80] d14=[CFA-88] 577 // d15=[CFA-96] 578 // 24: CFA=sp+96 => x27=[CFA-24] x28=[CFA-32] fp=[CFA-16] lr=[CFA-8] 579 // d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64] d12=[CFA-72] 580 // d13=[CFA-80] d14=[CFA-88] d15=[CFA-96] 581 // 28: CFA=fp+16 => x27=[CFA-24] x28=[CFA-32] fp=[CFA-16] lr=[CFA-8] 582 // d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64] d12=[CFA-72] 583 // d13=[CFA-80] d14=[CFA-88] d15=[CFA-96] 584 // 36: CFA=sp+96 => x27=[CFA-24] x28=[CFA-32] fp=[CFA-16] lr=[CFA-8] 585 // d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64] d12=[CFA-72] 586 // d13=[CFA-80] d14=[CFA-88] d15=[CFA-96] 587 // 40: CFA=sp+96 => x27=[CFA-24] x28=[CFA-32] d8=[CFA-40] d9=[CFA-48] 588 // d10=[CFA-56] d11=[CFA-64] d12=[CFA-72] d13=[CFA-80] d14=[CFA-88] 589 // d15=[CFA-96] 590 // 44: CFA=sp+96 => d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64] 591 // d12=[CFA-72] d13=[CFA-80] d14=[CFA-88] d15=[CFA-96] 592 // 48: CFA=sp+96 => d10=[CFA-56] d11=[CFA-64] d12=[CFA-72] d13=[CFA-80] 593 // d14=[CFA-88] d15=[CFA-96] 594 // 52: CFA=sp+96 => d12=[CFA-72] d13=[CFA-80] d14=[CFA-88] d15=[CFA-96] 595 // 56: CFA=sp+96 => d14=[CFA-88] d15=[CFA-96] 596 // 60: CFA=sp +0 => 597 598 sample_range = AddressRange(0x1000, sizeof(data)); 599 600 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 601 sample_range, data, sizeof(data), unwind_plan)); 602 603 // 28: CFA=fp+16 => x27=[CFA-24] x28=[CFA-32] fp=[CFA-16] lr=[CFA-8] 604 // d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64] d12=[CFA-72] 605 // d13=[CFA-80] d14=[CFA-88] d15=[CFA-96] 606 row_sp = unwind_plan.GetRowForFunctionOffset(28); 607 EXPECT_EQ(28ull, row_sp->GetOffset()); 608 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64); 609 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 610 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); 611 612 EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d15_arm64, regloc)); 613 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 614 EXPECT_EQ(-96, regloc.GetOffset()); 615 616 EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d14_arm64, regloc)); 617 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 618 EXPECT_EQ(-88, regloc.GetOffset()); 619 620 EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d13_arm64, regloc)); 621 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 622 EXPECT_EQ(-80, regloc.GetOffset()); 623 624 EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d12_arm64, regloc)); 625 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 626 EXPECT_EQ(-72, regloc.GetOffset()); 627 628 EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d11_arm64, regloc)); 629 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 630 EXPECT_EQ(-64, regloc.GetOffset()); 631 632 EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d10_arm64, regloc)); 633 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 634 EXPECT_EQ(-56, regloc.GetOffset()); 635 636 EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d9_arm64, regloc)); 637 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 638 EXPECT_EQ(-48, regloc.GetOffset()); 639 640 EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d8_arm64, regloc)); 641 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 642 EXPECT_EQ(-40, regloc.GetOffset()); 643 644 // 60: CFA=sp +0 => 645 row_sp = unwind_plan.GetRowForFunctionOffset(60); 646 EXPECT_EQ(60ull, row_sp->GetOffset()); 647 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64); 648 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 649 EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset()); 650 651 if (row_sp->GetRegisterInfo(fpu_d8_arm64, regloc)) { 652 EXPECT_TRUE(regloc.IsSame()); 653 } 654 if (row_sp->GetRegisterInfo(fpu_d9_arm64, regloc)) { 655 EXPECT_TRUE(regloc.IsSame()); 656 } 657 if (row_sp->GetRegisterInfo(fpu_d10_arm64, regloc)) { 658 EXPECT_TRUE(regloc.IsSame()); 659 } 660 if (row_sp->GetRegisterInfo(fpu_d11_arm64, regloc)) { 661 EXPECT_TRUE(regloc.IsSame()); 662 } 663 if (row_sp->GetRegisterInfo(fpu_d12_arm64, regloc)) { 664 EXPECT_TRUE(regloc.IsSame()); 665 } 666 if (row_sp->GetRegisterInfo(fpu_d13_arm64, regloc)) { 667 EXPECT_TRUE(regloc.IsSame()); 668 } 669 if (row_sp->GetRegisterInfo(fpu_d14_arm64, regloc)) { 670 EXPECT_TRUE(regloc.IsSame()); 671 } 672 if (row_sp->GetRegisterInfo(fpu_d15_arm64, regloc)) { 673 EXPECT_TRUE(regloc.IsSame()); 674 } 675 if (row_sp->GetRegisterInfo(gpr_x27_arm64, regloc)) { 676 EXPECT_TRUE(regloc.IsSame()); 677 } 678 if (row_sp->GetRegisterInfo(gpr_x28_arm64, regloc)) { 679 EXPECT_TRUE(regloc.IsSame()); 680 } 681 } 682