1 //===-- Testx86AssemblyInspectionEngine.cpp ---------------------------*- C++ 2 //-*-===// 3 4 // 5 // The LLVM Compiler Infrastructure 6 // 7 // This file is distributed under the University of Illinois Open Source 8 // License. See LICENSE.TXT for details. 9 // 10 //===----------------------------------------------------------------------===// 11 12 #include "gtest/gtest.h" 13 14 #include <vector> 15 16 #include "Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h" 17 #include "lldb/Core/Address.h" 18 #include "lldb/Core/AddressRange.h" 19 #include "lldb/Core/ArchSpec.h" 20 #include "lldb/Symbol/UnwindPlan.h" 21 22 #include "llvm/Support/TargetSelect.h" 23 24 using namespace lldb; 25 using namespace lldb_private; 26 27 class Testx86AssemblyInspectionEngine : public testing::Test { 28 public: 29 static void SetUpTestCase(); 30 31 // static void TearDownTestCase() { } 32 33 // virtual void SetUp() override { } 34 35 // virtual void TearDown() override { } 36 37 protected: 38 }; 39 40 void Testx86AssemblyInspectionEngine::SetUpTestCase() { 41 llvm::InitializeAllTargets(); 42 llvm::InitializeAllAsmPrinters(); 43 llvm::InitializeAllTargetMCs(); 44 llvm::InitializeAllDisassemblers(); 45 } 46 47 // only defining the register names / numbers that the unwinder is actually 48 // using today 49 50 // names should match the constants below. These will be the eRegisterKindLLDB 51 // register numbers. 52 53 const char *x86_64_reg_names[] = {"rax", "rbx", "rcx", "rdx", "rsp", "rbp", 54 "rsi", "rdi", "r8", "r9", "r10", "r11", 55 "r12", "r13", "r14", "r15", "rip"}; 56 57 enum x86_64_regs { 58 k_rax = 0, 59 k_rbx = 1, 60 k_rcx = 2, 61 k_rdx = 3, 62 k_rsp = 4, 63 k_rbp = 5, 64 k_rsi = 6, 65 k_rdi = 7, 66 k_r8 = 8, 67 k_r9 = 9, 68 k_r10 = 10, 69 k_r11 = 11, 70 k_r12 = 12, 71 k_r13 = 13, 72 k_r14 = 14, 73 k_r15 = 15, 74 k_rip = 16 75 }; 76 77 // names should match the constants below. These will be the eRegisterKindLLDB 78 // register numbers. 79 80 const char *i386_reg_names[] = {"eax", "ecx", "edx", "ebx", "esp", 81 "ebp", "esi", "edi", "eip"}; 82 83 enum i386_regs { 84 k_eax = 0, 85 k_ecx = 1, 86 k_edx = 2, 87 k_ebx = 3, 88 k_esp = 4, 89 k_ebp = 5, 90 k_esi = 6, 91 k_edi = 7, 92 k_eip = 8 93 }; 94 95 std::unique_ptr<x86AssemblyInspectionEngine> Getx86_64Inspector() { 96 97 ArchSpec arch("x86_64-apple-macosx", nullptr); 98 std::unique_ptr<x86AssemblyInspectionEngine> engine( 99 new x86AssemblyInspectionEngine(arch)); 100 101 std::vector<x86AssemblyInspectionEngine::lldb_reg_info> lldb_regnums; 102 int i = 0; 103 for (const auto &name : x86_64_reg_names) { 104 x86AssemblyInspectionEngine::lldb_reg_info ri; 105 ri.name = name; 106 ri.lldb_regnum = i++; 107 lldb_regnums.push_back(ri); 108 } 109 110 engine->Initialize(lldb_regnums); 111 return engine; 112 } 113 114 std::unique_ptr<x86AssemblyInspectionEngine> Geti386Inspector() { 115 116 ArchSpec arch("i386-apple-macosx", nullptr); 117 std::unique_ptr<x86AssemblyInspectionEngine> engine( 118 new x86AssemblyInspectionEngine(arch)); 119 120 std::vector<x86AssemblyInspectionEngine::lldb_reg_info> lldb_regnums; 121 int i = 0; 122 for (const auto &name : i386_reg_names) { 123 x86AssemblyInspectionEngine::lldb_reg_info ri; 124 ri.name = name; 125 ri.lldb_regnum = i++; 126 lldb_regnums.push_back(ri); 127 } 128 129 engine->Initialize(lldb_regnums); 130 return engine; 131 } 132 133 TEST_F(Testx86AssemblyInspectionEngine, TestSimple64bitFrameFunction) { 134 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector(); 135 136 // 'int main() { }' compiled for x86_64-apple-macosx with clang 137 uint8_t data[] = { 138 0x55, // offset 0 -- pushq %rbp 139 0x48, 0x89, 0xe5, // offset 1 -- movq %rsp, %rbp 140 0x31, 0xc0, // offset 4 -- xorl %eax, %eax 141 0x5d, // offset 6 -- popq %rbp 142 0xc3 // offset 7 -- retq 143 }; 144 145 AddressRange sample_range(0x1000, sizeof(data)); 146 147 UnwindPlan unwind_plan(eRegisterKindLLDB); 148 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 149 data, sizeof(data), sample_range, unwind_plan)); 150 151 // Expect four unwind rows: 152 // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8] 153 // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8] 154 // 4: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8] 155 // 7: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8] 156 157 EXPECT_TRUE(unwind_plan.GetInitialCFARegister() == k_rsp); 158 EXPECT_TRUE(unwind_plan.GetUnwindPlanValidAtAllInstructions() == 159 eLazyBoolYes); 160 EXPECT_TRUE(unwind_plan.GetSourcedFromCompiler() == eLazyBoolNo); 161 162 UnwindPlan::Row::RegisterLocation regloc; 163 164 // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8] 165 UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(0); 166 EXPECT_EQ(0ull, row_sp->GetOffset()); 167 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 168 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 169 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 170 171 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc)); 172 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 173 EXPECT_EQ(-8, regloc.GetOffset()); 174 175 // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8] 176 row_sp = unwind_plan.GetRowForFunctionOffset(1); 177 EXPECT_EQ(1ull, row_sp->GetOffset()); 178 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 179 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 180 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); 181 182 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc)); 183 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 184 EXPECT_EQ(-8, regloc.GetOffset()); 185 186 // 4: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8] 187 row_sp = unwind_plan.GetRowForFunctionOffset(4); 188 EXPECT_EQ(4ull, row_sp->GetOffset()); 189 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp); 190 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 191 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); 192 193 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc)); 194 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 195 EXPECT_EQ(-8, regloc.GetOffset()); 196 197 // 7: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8] 198 row_sp = unwind_plan.GetRowForFunctionOffset(7); 199 EXPECT_EQ(7ull, row_sp->GetOffset()); 200 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 201 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 202 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 203 204 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc)); 205 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 206 EXPECT_EQ(-8, regloc.GetOffset()); 207 } 208 209 TEST_F(Testx86AssemblyInspectionEngine, TestSimple32bitFrameFunction) { 210 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector(); 211 212 // 'int main() { }' compiled for i386-apple-macosx with clang 213 uint8_t data[] = { 214 0x55, // offset 0 -- pushl %ebp 215 0x89, 0xe5, // offset 1 -- movl %esp, %ebp 216 0x31, 0xc0, // offset 3 -- xorl %eax, %eax 217 0x5d, // offset 5 -- popl %ebp 218 0xc3 // offset 6 -- retl 219 }; 220 221 AddressRange sample_range(0x1000, sizeof(data)); 222 223 UnwindPlan unwind_plan(eRegisterKindLLDB); 224 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 225 data, sizeof(data), sample_range, unwind_plan)); 226 227 // Expect four unwind rows: 228 // 0: CFA=esp +4 => esp=CFA+0 eip=[CFA-4] 229 // 1: CFA=esp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4] 230 // 3: CFA=ebp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4] 231 // 6: CFA=esp +4 => esp=CFA+0 eip=[CFA-4] 232 233 EXPECT_TRUE(unwind_plan.GetInitialCFARegister() == k_esp); 234 EXPECT_TRUE(unwind_plan.GetUnwindPlanValidAtAllInstructions() == 235 eLazyBoolYes); 236 EXPECT_TRUE(unwind_plan.GetSourcedFromCompiler() == eLazyBoolNo); 237 238 UnwindPlan::Row::RegisterLocation regloc; 239 240 // offset 0 -- pushl %ebp 241 UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(0); 242 EXPECT_EQ(0ull, row_sp->GetOffset()); 243 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp); 244 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 245 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset()); 246 247 EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc)); 248 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 249 EXPECT_TRUE(regloc.GetOffset() == -4); 250 251 // 1: CFA=esp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4] 252 row_sp = unwind_plan.GetRowForFunctionOffset(1); 253 EXPECT_EQ(1ull, row_sp->GetOffset()); 254 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp); 255 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 256 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 257 258 EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc)); 259 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 260 EXPECT_EQ(-4, regloc.GetOffset()); 261 262 // 3: CFA=ebp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4] 263 row_sp = unwind_plan.GetRowForFunctionOffset(3); 264 EXPECT_EQ(3ull, row_sp->GetOffset()); 265 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp); 266 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 267 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 268 269 EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc)); 270 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 271 EXPECT_EQ(-4, regloc.GetOffset()); 272 273 // 6: CFA=esp +4 => esp=CFA+0 eip=[CFA-4] 274 row_sp = unwind_plan.GetRowForFunctionOffset(6); 275 EXPECT_EQ(6ull, row_sp->GetOffset()); 276 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp); 277 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 278 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset()); 279 280 EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc)); 281 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 282 EXPECT_EQ(-4, regloc.GetOffset()); 283 } 284 285 TEST_F(Testx86AssemblyInspectionEngine, Test64bitFramelessBigStackFrame) { 286 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector(); 287 288 // this source file: 289 // 290 // #include <stdio.h> 291 // int main (int argc, char **argv) 292 // { 293 // 294 // const int arrsize = 60; 295 // int buf[arrsize * arrsize]; 296 // int accum = argc; 297 // for (int i = 0; i < arrsize; i++) 298 // for (int j = 0; j < arrsize; j++) 299 // { 300 // if (i > 0 && j > 0) 301 // { 302 // int n = buf[(i-1) * (j-1)] * 2; 303 // int m = buf[(i-1) * (j-1)] / 2; 304 // int j = buf[(i-1) * (j-1)] + 2; 305 // int k = buf[(i-1) * (j-1)] - 2; 306 // printf ("%d ", n + m + j + k); 307 // buf[(i-1) * (j-1)] += n - m + j - k; 308 // } 309 // buf[i*j] = accum++; 310 // } 311 // 312 // return buf[(arrsize * arrsize) - 2] + printf ("%d\n", buf[(arrsize * 313 // arrsize) - 3]); 314 // } 315 // 316 // compiled 'clang -fomit-frame-pointer -Os' for x86_64-apple-macosx 317 318 uint8_t data[] = { 319 0x55, // offset 0 -- pushq %rbp 320 0x41, 0x57, // offset 1 -- pushq %r15 321 0x41, 0x56, // offset 3 -- pushq %r14 322 0x41, 0x55, // offset 5 -- pushq %r13 323 0x41, 0x54, // offset 7 -- pushq %r12 324 0x53, // offset 9 -- pushq %rbx 325 0x48, 0x81, 0xec, 0x68, 0x38, 0x00, 326 0x00, // offset 10 -- subq $0x3868, %rsp 327 328 // .... 329 330 0x48, 0x81, 0xc4, 0x68, 0x38, 0x00, 331 0x00, // offset 17 -- addq $0x3868, %rsp 332 0x5b, // offset 24 -- popq %rbx 333 0x41, 0x5c, // offset 25 -- popq %r12 334 0x41, 0x5d, // offset 27 -- popq %r13 335 0x41, 0x5e, // offset 29 -- popq %r14 336 0x41, 0x5f, // offset 31 -- popq %r15 337 0x5d, // offset 33 -- popq %rbp 338 0xc3, // offset 34 -- retq 339 0xe8, 0x12, 0x34, 0x56, 0x78 // offset 35 -- callq whatever 340 }; 341 342 AddressRange sample_range(0x1000, sizeof(data)); 343 344 UnwindPlan unwind_plan(eRegisterKindLLDB); 345 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 346 data, sizeof(data), sample_range, unwind_plan)); 347 348 // Unwind rules should look like 349 // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8] 350 // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8] 351 // 3: CFA=rsp+24 => rbp=[CFA-16] rsp=CFA+0 r15=[CFA-24] rip=[CFA-8] 352 // 5: CFA=rsp+32 => rbp=[CFA-16] rsp=CFA+0 r14=[CFA-32] r15=[CFA-24] 353 // rip=[CFA-8 354 // 7: CFA=rsp+40 => rbp=[CFA-16] rsp=CFA+0 r13=[CFA-40] r14=[CFA-32] 355 // r15=[CFA-24] rip=[CFA-8] 356 // 9: CFA=rsp+48 => rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48] r13=[CFA-40] 357 // r14=[CFA-32] r15=[CFA-24] rip=[CFA-8] 358 // 10: CFA=rsp+56 => rbx=[CFA-56] rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48] 359 // r13=[CFA-40] r14=[CFA-32] r15=[CFA-24] rip=[CFA-8] 360 // 17: CFA=rsp+14496 => rbx=[CFA-56] rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48] 361 // r13=[CFA-40] r14=[CFA-32] r15=[CFA-24] rip=[CFA-8] 362 363 // 24: CFA=rsp+56 => rbx=[CFA-56] rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48] 364 // r13=[CFA-40] r14=[CFA-32] r15=[CFA-24] rip=[CFA-8] 365 // 25: CFA=rsp+48 => rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48] r13=[CFA-40] 366 // r14=[CFA-32] r15=[CFA-24] rip=[CFA-8] 367 // 27: CFA=rsp+40 => rbp=[CFA-16] rsp=CFA+0 r13=[CFA-40] r14=[CFA-32] 368 // r15=[CFA-24] rip=[CFA-8] 369 // 29: CFA=rsp+32 => rbp=[CFA-16] rsp=CFA+0 r14=[CFA-32] r15=[CFA-24] 370 // rip=[CFA-8] 371 // 31: CFA=rsp+24 => rbp=[CFA-16] rsp=CFA+0 r15=[CFA-24] rip=[CFA-8] 372 // 33: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8] 373 // 34: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8] 374 375 UnwindPlan::Row::RegisterLocation regloc; 376 377 // grab the Row for when the prologue has finished executing: 378 // 17: CFA=rsp+14496 => rbx=[CFA-56] rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48] 379 // r13=[CFA-40] r14=[CFA-32] r15=[CFA-24] rip=[CFA-8] 380 381 UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(17); 382 383 EXPECT_EQ(17ull, row_sp->GetOffset()); 384 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 385 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 386 EXPECT_EQ(14496, row_sp->GetCFAValue().GetOffset()); 387 388 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc)); 389 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 390 EXPECT_EQ(-8, regloc.GetOffset()); 391 392 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbp, regloc)); 393 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 394 EXPECT_EQ(-16, regloc.GetOffset()); 395 396 EXPECT_TRUE(row_sp->GetRegisterInfo(k_r15, regloc)); 397 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 398 EXPECT_EQ(-24, regloc.GetOffset()); 399 400 EXPECT_TRUE(row_sp->GetRegisterInfo(k_r14, regloc)); 401 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 402 EXPECT_EQ(-32, regloc.GetOffset()); 403 404 EXPECT_TRUE(row_sp->GetRegisterInfo(k_r13, regloc)); 405 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 406 EXPECT_EQ(-40, regloc.GetOffset()); 407 408 EXPECT_TRUE(row_sp->GetRegisterInfo(k_r12, regloc)); 409 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 410 EXPECT_EQ(-48, regloc.GetOffset()); 411 412 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbx, regloc)); 413 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 414 EXPECT_EQ(-56, regloc.GetOffset()); 415 416 // grab the Row for when the epilogue has finished executing: 417 // 34: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8] 418 419 row_sp = unwind_plan.GetRowForFunctionOffset(34); 420 421 EXPECT_EQ(34ull, row_sp->GetOffset()); 422 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 423 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 424 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 425 426 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc)); 427 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 428 EXPECT_EQ(-8, regloc.GetOffset()); 429 430 // these could be set to IsSame and be valid -- meaning that the 431 // register value is the same as the caller's -- but I'd rather 432 // they not be mentioned at all. 433 434 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rax, regloc)); 435 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbx, regloc)); 436 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rcx, regloc)); 437 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rdx, regloc)); 438 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc)); 439 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rsi, regloc)); 440 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rdi, regloc)); 441 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r8, regloc)); 442 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r9, regloc)); 443 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r10, regloc)); 444 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r11, regloc)); 445 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r12, regloc)); 446 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r13, regloc)); 447 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r14, regloc)); 448 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r15, regloc)); 449 } 450 451 TEST_F(Testx86AssemblyInspectionEngine, Test32bitFramelessBigStackFrame) { 452 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector(); 453 454 // this source file: 455 // 456 // #include <stdio.h> 457 // int main (int argc, char **argv) 458 // { 459 // 460 // const int arrsize = 60; 461 // int buf[arrsize * arrsize]; 462 // int accum = argc; 463 // for (int i = 0; i < arrsize; i++) 464 // for (int j = 0; j < arrsize; j++) 465 // { 466 // if (i > 0 && j > 0) 467 // { 468 // int n = buf[(i-1) * (j-1)] * 2; 469 // int m = buf[(i-1) * (j-1)] / 2; 470 // int j = buf[(i-1) * (j-1)] + 2; 471 // int k = buf[(i-1) * (j-1)] - 2; 472 // printf ("%d ", n + m + j + k); 473 // buf[(i-1) * (j-1)] += n - m + j - k; 474 // } 475 // buf[i*j] = accum++; 476 // } 477 // 478 // return buf[(arrsize * arrsize) - 2] + printf ("%d\n", buf[(arrsize * 479 // arrsize) - 3]); 480 // } 481 // 482 // compiled 'clang -arch i386 -fomit-frame-pointer -Os' for i386-apple-macosx 483 484 // simplified assembly version of the above function, which is used as the 485 // input 486 // data: 487 // 488 // .section __TEXT,__text,regular,pure_instructions 489 // .macosx_version_min 10, 12 490 // .globl _main 491 // .align 4, 0x90 492 // _main: ## @main 493 // ## BB#0: 494 // pushl %ebp 495 // pushl %ebx 496 // pushl %edi 497 // pushl %esi 498 // L0$pb: 499 // subl $0x386c, %esp 500 // calll L1 501 // L1: 502 // popl %ecx 503 // movl %ecx, 0x8(%esp) 504 // subl $0x8, %esp 505 // pushl %eax 506 // pushl 0x20(%esp) 507 // calll _puts 508 // addl $0x10, %esp 509 // incl %ebx 510 // addl $0x386c, %esp 511 // popl %esi 512 // popl %edi 513 // popl %ebx 514 // popl %ebp 515 // retl 516 // 517 // .section __TEXT,__cstring,cstring_literals 518 // L_.str: ## @.str 519 // .asciz "HI" 520 // 521 // 522 // .subsections_via_symbols 523 524 uint8_t data[] = { 525 0x55, 526 // offset 0 -- pushl %ebp 527 528 0x53, 529 // offset 1 -- pushl %ebx 530 531 0x57, 532 // offset 2 -- pushl %edi 533 534 0x56, 535 // offset 3 -- pushl %esi 536 537 0x81, 0xec, 0x6c, 0x38, 0x00, 0x00, 538 // offset 4 -- subl $0x386c, %esp 539 540 0xe8, 0x00, 0x00, 0x00, 0x00, 541 // offset 10 -- calll 0 542 // call the next instruction, to put the pc on the stack 543 544 0x59, 545 // offset 15 -- popl %ecx 546 // pop the saved pc address into ecx 547 548 0x89, 0x4c, 0x24, 0x08, 549 // offset 16 -- movl %ecx, 0x8(%esp) 550 551 // .... 552 553 0x83, 0xec, 0x08, 554 // offset 20 -- subl $0x8, %esp 555 556 0x50, 557 // offset 23 -- pushl %eax 558 559 0xff, 0x74, 0x24, 0x20, 560 // offset 24 -- pushl 0x20(%esp) 561 562 0xe8, 0x8c, 0x00, 0x00, 0x00, 563 // offset 28 -- calll puts 564 565 0x83, 0xc4, 0x10, 566 // offset 33 -- addl $0x10, %esp 567 // get esp back to the value it was before the 568 // alignment & argument saves for the puts call 569 570 0x43, 571 // offset 36 -- incl %ebx 572 573 // .... 574 575 0x81, 0xc4, 0x6c, 0x38, 0x00, 0x00, 576 // offset 37 -- addl $0x386c, %esp 577 578 0x5e, 579 // offset 43 -- popl %esi 580 581 0x5f, 582 // offset 44 -- popl %edi 583 584 0x5b, 585 // offset 45 -- popl %ebx 586 587 0x5d, 588 // offset 46 -- popl %ebp 589 590 0xc3, 591 // offset 47 -- retl 592 593 0xe8, 0x12, 0x34, 0x56, 0x78, 594 // offset 48 -- calll __stack_chk_fail 595 }; 596 597 AddressRange sample_range(0x1000, sizeof(data)); 598 599 UnwindPlan unwind_plan(eRegisterKindLLDB); 600 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 601 data, sizeof(data), sample_range, unwind_plan)); 602 603 // Unwind rules should look like 604 // 605 // 0: CFA=esp +4 => esp=CFA+0 eip=[CFA-4] 606 // 1: CFA=esp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4] 607 // 2: CFA=esp+12 => ebx=[CFA-12] ebp=[CFA-8] esp=CFA+0 eip=[CFA-4] 608 // 3: CFA=esp+16 => ebx=[CFA-12] edi=[CFA-16] ebp=[CFA-8] esp=CFA+0 609 // eip=[CFA-4] 610 // 4: CFA=esp+20 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8] 611 // esp=CFA+0 eip=[CFA-4] 612 // 10: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8] 613 // esp=CFA+0 eip=[CFA-4] 614 // 15: CFA=esp+14468 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8] 615 // esp=CFA+0 eip=[CFA-4] 616 // 16: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8] 617 // esp=CFA+0 eip=[CFA-4] 618 // 619 // .... 620 // 621 // 23: CFA=esp+14472 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8] 622 // esp=CFA+0 eip=[CFA-4] 623 // 24: CFA=esp+14476 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8] 624 // esp=CFA+0 eip=[CFA-4] 625 // 28: CFA=esp+14480 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8] 626 // esp=CFA+0 eip=[CFA-4] 627 // 36: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8] 628 // esp=CFA+0 eip=[CFA-4] 629 // 630 // ..... 631 // 632 // 37: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8] 633 // esp=CFA+0 eip=[CFA-4] 634 // 43: CFA=esp+20 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8] 635 // esp=CFA+0 eip=[CFA-4] 636 // 44: CFA=esp+16 => ebx=[CFA-12] edi=[CFA-16] ebp=[CFA-8] esp=CFA+0 637 // eip=[CFA-4] 638 // 45: CFA=esp+12 => ebx=[CFA-12] ebp=[CFA-8] esp=CFA+0 eip=[CFA-4] 639 // 46: CFA=esp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4] 640 // 47: CFA=esp +4 => esp=CFA+0 eip=[CFA-4] 641 // 48: CFA=esp+14480 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8] 642 // esp=CFA+0 eip=[CFA-4] 643 644 UnwindPlan::Row::RegisterLocation regloc; 645 UnwindPlan::RowSP row_sp; 646 647 // Check that we get the CFA correct for the pic base setup sequence 648 649 // CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8] 650 // esp=CFA+0 eip=[CFA-4] 651 row_sp = unwind_plan.GetRowForFunctionOffset(10); 652 EXPECT_EQ(10ull, row_sp->GetOffset()); 653 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp); 654 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 655 EXPECT_EQ(14464, row_sp->GetCFAValue().GetOffset()); 656 657 // 15: CFA=esp+14468 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8] 658 // esp=CFA+0 eip=[CFA-4] 659 row_sp = unwind_plan.GetRowForFunctionOffset(15); 660 EXPECT_EQ(15ull, row_sp->GetOffset()); 661 EXPECT_EQ(14468, row_sp->GetCFAValue().GetOffset()); 662 663 // 16: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8] 664 // esp=CFA+0 eip=[CFA-4] 665 row_sp = unwind_plan.GetRowForFunctionOffset(16); 666 EXPECT_EQ(16ull, row_sp->GetOffset()); 667 EXPECT_EQ(14464, row_sp->GetCFAValue().GetOffset()); 668 669 // Check that the row for offset 16 has the registers saved that we expect 670 671 EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc)); 672 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 673 EXPECT_EQ(-4, regloc.GetOffset()); 674 675 EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebp, regloc)); 676 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 677 EXPECT_EQ(-8, regloc.GetOffset()); 678 679 EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebx, regloc)); 680 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 681 EXPECT_EQ(-12, regloc.GetOffset()); 682 683 EXPECT_TRUE(row_sp->GetRegisterInfo(k_edi, regloc)); 684 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 685 EXPECT_EQ(-16, regloc.GetOffset()); 686 687 EXPECT_TRUE(row_sp->GetRegisterInfo(k_esi, regloc)); 688 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 689 EXPECT_EQ(-20, regloc.GetOffset()); 690 691 // 692 // Check the pushing & popping around the call printf instruction 693 694 // 23: CFA=esp+14472 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8] 695 // esp=CFA+0 eip=[CFA-4] 696 row_sp = unwind_plan.GetRowForFunctionOffset(23); 697 EXPECT_EQ(23ull, row_sp->GetOffset()); 698 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp); 699 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 700 EXPECT_EQ(14472, row_sp->GetCFAValue().GetOffset()); 701 702 // 24: CFA=esp+14476 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8] 703 // esp=CFA+0 eip=[CFA-4] 704 row_sp = unwind_plan.GetRowForFunctionOffset(24); 705 EXPECT_EQ(24ull, row_sp->GetOffset()); 706 EXPECT_EQ(14476, row_sp->GetCFAValue().GetOffset()); 707 708 // 28: CFA=esp+14480 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8] 709 // esp=CFA+0 eip=[CFA-4] 710 row_sp = unwind_plan.GetRowForFunctionOffset(28); 711 EXPECT_EQ(28ull, row_sp->GetOffset()); 712 EXPECT_EQ(14480, row_sp->GetCFAValue().GetOffset()); 713 714 // 36: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8] 715 // esp=CFA+0 eip=[CFA-4] 716 row_sp = unwind_plan.GetRowForFunctionOffset(36); 717 EXPECT_EQ(36ull, row_sp->GetOffset()); 718 EXPECT_EQ(14464, row_sp->GetCFAValue().GetOffset()); 719 720 // Check that the epilogue gets us back to the original unwind state 721 722 // 47: CFA=esp +4 => esp=CFA+0 eip=[CFA-4] 723 row_sp = unwind_plan.GetRowForFunctionOffset(47); 724 EXPECT_EQ(47ull, row_sp->GetOffset()); 725 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp); 726 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 727 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset()); 728 729 EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc)); 730 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 731 EXPECT_EQ(-4, regloc.GetOffset()); 732 733 EXPECT_TRUE(row_sp->GetRegisterInfo(k_esp, regloc)); 734 EXPECT_TRUE(regloc.IsCFAPlusOffset()); 735 EXPECT_EQ(0, regloc.GetOffset()); 736 737 // Check that no unexpected registers were saved 738 739 EXPECT_FALSE(row_sp->GetRegisterInfo(k_eax, regloc)); 740 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebx, regloc)); 741 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ecx, regloc)); 742 EXPECT_FALSE(row_sp->GetRegisterInfo(k_edx, regloc)); 743 EXPECT_FALSE(row_sp->GetRegisterInfo(k_esi, regloc)); 744 EXPECT_FALSE(row_sp->GetRegisterInfo(k_edi, regloc)); 745 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc)); 746 } 747 748 TEST_F(Testx86AssemblyInspectionEngine, Test64bitFramelessSmallStackFrame) { 749 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector(); 750 751 // this source file: 752 // #include <stdio.h> 753 // int main () { 754 // puts ("HI"); 755 // } 756 // 757 // compiled 'clang -fomit-frame-pointer' for x86_64-apple-macosx 758 759 uint8_t data[] = { 760 0x50, 761 // offset 0 -- pushq %rax 762 763 0x48, 0x8d, 0x3d, 0x32, 0x00, 0x00, 0x00, 764 // offset 1 -- leaq 0x32(%rip), %rdi ; "HI" 765 766 0xe8, 0x0b, 0x00, 0x00, 0x00, 767 // offset 8 -- callq 0x100000f58 ; puts 768 769 0x31, 0xc9, 770 // offset 13 -- xorl %ecx, %ecx 771 772 0x89, 0x44, 0x24, 0x04, 773 // offset 15 -- movl %eax, 0x4(%rsp) 774 775 0x89, 0xc8, 776 // offset 19 -- movl %ecx, %eax 777 778 0x59, 779 // offset 21 -- popq %rcx 780 781 0xc3 782 // offset 22 -- retq 783 }; 784 785 AddressRange sample_range(0x1000, sizeof(data)); 786 787 UnwindPlan unwind_plan(eRegisterKindLLDB); 788 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 789 data, sizeof(data), sample_range, unwind_plan)); 790 791 // Unwind rules should look like 792 // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8] 793 // 1: CFA=rsp+16 => rsp=CFA+0 rip=[CFA-8] 794 // 22: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8] 795 796 UnwindPlan::Row::RegisterLocation regloc; 797 798 // grab the Row for when the prologue has finished executing: 799 // 1: CFA=rsp+16 => rsp=CFA+0 rip=[CFA-8] 800 801 UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(13); 802 803 EXPECT_EQ(1ull, row_sp->GetOffset()); 804 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 805 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 806 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); 807 808 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc)); 809 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 810 EXPECT_EQ(-8, regloc.GetOffset()); 811 812 // none of these were spilled 813 814 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rax, regloc)); 815 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbx, regloc)); 816 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rcx, regloc)); 817 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rdx, regloc)); 818 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc)); 819 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rsi, regloc)); 820 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rdi, regloc)); 821 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r8, regloc)); 822 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r9, regloc)); 823 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r10, regloc)); 824 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r11, regloc)); 825 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r12, regloc)); 826 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r13, regloc)); 827 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r14, regloc)); 828 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r15, regloc)); 829 830 // grab the Row for when the epilogue has finished executing: 831 // 22: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8] 832 833 row_sp = unwind_plan.GetRowForFunctionOffset(22); 834 835 EXPECT_EQ(22ull, row_sp->GetOffset()); 836 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 837 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 838 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 839 840 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc)); 841 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 842 EXPECT_EQ(-8, regloc.GetOffset()); 843 } 844 845 TEST_F(Testx86AssemblyInspectionEngine, Test32bitFramelessSmallStackFrame) { 846 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector(); 847 848 // this source file: 849 // #include <stdio.h> 850 // int main () { 851 // puts ("HI"); 852 // } 853 // 854 // compiled 'clang -arch i386 -fomit-frame-pointer' for i386-apple-macosx 855 856 uint8_t data[] = { 857 0x83, 0xec, 0x0c, 858 // offset 0 -- subl $0xc, %esp 859 860 0xe8, 0x00, 0x00, 0x00, 0x00, 861 // offset 3 -- calll 0 {call the next instruction, to put the pc on 862 // the stack} 863 864 0x58, 865 // offset 8 -- popl %eax {pop the saved pc value off stack, into eax} 866 867 0x8d, 0x80, 0x3a, 0x00, 0x00, 0x00, 868 // offset 9 -- leal 0x3a(%eax),%eax 869 870 0x89, 0x04, 0x24, 871 // offset 15 -- movl %eax, (%esp) 872 873 0xe8, 0x0d, 0x00, 0x00, 0x00, 874 // offset 18 -- calll 0x1f94 (puts) 875 876 0x31, 0xc9, 877 // offset 23 -- xorl %ecx, %ecx 878 879 0x89, 0x44, 0x24, 0x08, 880 // offset 25 -- movl %eax, 0x8(%esp) 881 882 0x89, 0xc8, 883 // offset 29 -- movl %ecx, %eax 884 885 0x83, 0xc4, 0x0c, 886 // offset 31 -- addl $0xc, %esp 887 888 0xc3 889 // offset 34 -- retl 890 }; 891 892 AddressRange sample_range(0x1000, sizeof(data)); 893 894 UnwindPlan unwind_plan(eRegisterKindLLDB); 895 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 896 data, sizeof(data), sample_range, unwind_plan)); 897 898 // Unwind rules should look like 899 // row[0]: 0: CFA=esp +4 => esp=CFA+0 eip=[CFA-4] 900 // row[1]: 3: CFA=esp+16 => esp=CFA+0 eip=[CFA-4] 901 // row[2]: 8: CFA=esp+20 => esp=CFA+0 eip=[CFA-4] 902 // row[3]: 9: CFA=esp+16 => esp=CFA+0 eip=[CFA-4] 903 // row[4]: 34: CFA=esp +4 => esp=CFA+0 eip=[CFA-4] 904 905 UnwindPlan::Row::RegisterLocation regloc; 906 907 // Check unwind state before we set up the picbase register 908 // 3: CFA=esp+16 => esp=CFA+0 eip=[CFA-4] 909 910 UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(3); 911 912 EXPECT_EQ(3ull, row_sp->GetOffset()); 913 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 914 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 915 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); 916 917 // Check unwind state after we call the next instruction 918 // 8: CFA=esp+20 => esp=CFA+0 eip=[CFA-4] 919 920 row_sp = unwind_plan.GetRowForFunctionOffset(8); 921 EXPECT_EQ(8ull, row_sp->GetOffset()); 922 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 923 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 924 EXPECT_EQ(20, row_sp->GetCFAValue().GetOffset()); 925 926 // Check unwind state after we pop the pic base value off the stack 927 // row[3]: 9: CFA=esp+16 => esp=CFA+0 eip=[CFA-4] 928 929 row_sp = unwind_plan.GetRowForFunctionOffset(9); 930 EXPECT_EQ(9ull, row_sp->GetOffset()); 931 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 932 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 933 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); 934 935 // Check that no unexpected registers were saved 936 937 EXPECT_FALSE(row_sp->GetRegisterInfo(k_eax, regloc)); 938 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebx, regloc)); 939 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ecx, regloc)); 940 EXPECT_FALSE(row_sp->GetRegisterInfo(k_edx, regloc)); 941 EXPECT_FALSE(row_sp->GetRegisterInfo(k_esi, regloc)); 942 EXPECT_FALSE(row_sp->GetRegisterInfo(k_edi, regloc)); 943 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc)); 944 945 // verify that we get back to the original unwind state before the ret 946 // 34: CFA=esp +4 => esp=CFA+0 eip=[CFA-4] 947 948 row_sp = unwind_plan.GetRowForFunctionOffset(34); 949 EXPECT_EQ(34ull, row_sp->GetOffset()); 950 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 951 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 952 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset()); 953 } 954 955 TEST_F(Testx86AssemblyInspectionEngine, TestPushRBP) { 956 UnwindPlan::Row::RegisterLocation regloc; 957 UnwindPlan::RowSP row_sp; 958 959 uint8_t data[] = { 960 0x55, // pushq %rbp 961 0x90 // nop 962 }; 963 964 AddressRange sample_range(0x1000, sizeof(data)); 965 UnwindPlan unwind_plan(eRegisterKindLLDB); 966 967 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector(); 968 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly( 969 data, sizeof(data), sample_range, unwind_plan)); 970 971 row_sp = unwind_plan.GetRowForFunctionOffset(1); 972 973 EXPECT_EQ(1ull, row_sp->GetOffset()); 974 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 975 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 976 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); 977 978 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbp, regloc)); 979 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 980 EXPECT_EQ(-16, regloc.GetOffset()); 981 982 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector(); 983 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly( 984 data, sizeof(data), sample_range, unwind_plan)); 985 986 row_sp = unwind_plan.GetRowForFunctionOffset(1); 987 988 EXPECT_EQ(1ull, row_sp->GetOffset()); 989 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 990 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 991 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 992 993 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbp, regloc)); 994 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 995 EXPECT_EQ(-8, regloc.GetOffset()); 996 } 997 998 TEST_F(Testx86AssemblyInspectionEngine, TestPushImm) { 999 UnwindPlan::Row::RegisterLocation regloc; 1000 UnwindPlan::RowSP row_sp; 1001 1002 uint8_t data[] = { 1003 0x68, 0xff, 0xff, 0x01, 0x69, // pushq $0x6901ffff 1004 0x6a, 0x7d, // pushl $0x7d 1005 0x90 // nop 1006 }; 1007 1008 AddressRange sample_range(0x1000, sizeof(data)); 1009 UnwindPlan unwind_plan(eRegisterKindLLDB); 1010 1011 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector(); 1012 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly( 1013 data, sizeof(data), sample_range, unwind_plan)); 1014 1015 row_sp = unwind_plan.GetRowForFunctionOffset(5); 1016 EXPECT_EQ(5ull, row_sp->GetOffset()); 1017 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1018 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1019 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); 1020 1021 row_sp = unwind_plan.GetRowForFunctionOffset(7); 1022 EXPECT_EQ(7ull, row_sp->GetOffset()); 1023 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1024 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1025 EXPECT_EQ(24, row_sp->GetCFAValue().GetOffset()); 1026 1027 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector(); 1028 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly( 1029 data, sizeof(data), sample_range, unwind_plan)); 1030 1031 row_sp = unwind_plan.GetRowForFunctionOffset(5); 1032 EXPECT_EQ(5ull, row_sp->GetOffset()); 1033 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1034 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1035 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 1036 1037 row_sp = unwind_plan.GetRowForFunctionOffset(7); 1038 EXPECT_EQ(7ull, row_sp->GetOffset()); 1039 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1040 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1041 EXPECT_EQ(12, row_sp->GetCFAValue().GetOffset()); 1042 } 1043 1044 // We treat 'pushq $0' / 'pushl $0' specially - this shows up 1045 // in the first function called in a new thread and it needs to 1046 // put a 0 as the saved pc. We pretend it didn't change the CFA. 1047 TEST_F(Testx86AssemblyInspectionEngine, TestPush0) { 1048 UnwindPlan::Row::RegisterLocation regloc; 1049 UnwindPlan::RowSP row_sp; 1050 1051 uint8_t data[] = { 1052 0x6a, 0x00, // pushq $0 1053 0x90 // nop 1054 }; 1055 1056 AddressRange sample_range(0x1000, sizeof(data)); 1057 UnwindPlan unwind_plan(eRegisterKindLLDB); 1058 1059 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector(); 1060 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly( 1061 data, sizeof(data), sample_range, unwind_plan)); 1062 1063 row_sp = unwind_plan.GetRowForFunctionOffset(2); 1064 1065 // We're verifying that no row was created for the 'pushq $0' 1066 EXPECT_EQ(0ull, row_sp->GetOffset()); 1067 1068 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector(); 1069 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly( 1070 data, sizeof(data), sample_range, unwind_plan)); 1071 1072 row_sp = unwind_plan.GetRowForFunctionOffset(2); 1073 1074 // We're verifying that no row was created for the 'pushq $0' 1075 EXPECT_EQ(0ull, row_sp->GetOffset()); 1076 } 1077 1078 TEST_F(Testx86AssemblyInspectionEngine, TestPushExtended) { 1079 UnwindPlan::Row::RegisterLocation regloc; 1080 UnwindPlan::RowSP row_sp; 1081 1082 uint8_t data[] = { 1083 0xff, 0x74, 0x24, 0x20, // pushl 0x20(%esp) 1084 0xff, 0xb6, 0xce, 0x01, 0xf0, 0x00, // pushl 0xf001ce(%esi) 1085 0xff, 0x30, // pushl (%eax) 1086 0x90 // nop 1087 }; 1088 1089 AddressRange sample_range(0x1000, sizeof(data)); 1090 UnwindPlan unwind_plan(eRegisterKindLLDB); 1091 1092 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector(); 1093 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly( 1094 data, sizeof(data), sample_range, unwind_plan)); 1095 1096 row_sp = unwind_plan.GetRowForFunctionOffset(4); 1097 1098 EXPECT_EQ(4ull, row_sp->GetOffset()); 1099 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1100 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1101 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); 1102 1103 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector(); 1104 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly( 1105 data, sizeof(data), sample_range, unwind_plan)); 1106 1107 row_sp = unwind_plan.GetRowForFunctionOffset(4); 1108 EXPECT_EQ(4ull, row_sp->GetOffset()); 1109 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1110 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1111 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 1112 1113 row_sp = unwind_plan.GetRowForFunctionOffset(10); 1114 EXPECT_EQ(10ull, row_sp->GetOffset()); 1115 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1116 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1117 EXPECT_EQ(12, row_sp->GetCFAValue().GetOffset()); 1118 1119 row_sp = unwind_plan.GetRowForFunctionOffset(12); 1120 EXPECT_EQ(12ull, row_sp->GetOffset()); 1121 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1122 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1123 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); 1124 } 1125 1126 TEST_F(Testx86AssemblyInspectionEngine, TestPushR15) { 1127 UnwindPlan::Row::RegisterLocation regloc; 1128 UnwindPlan::RowSP row_sp; 1129 1130 uint8_t data[] = { 1131 0x41, 0x57, // pushq %r15 1132 0x90 // nop 1133 }; 1134 1135 AddressRange sample_range(0x1000, sizeof(data)); 1136 UnwindPlan unwind_plan(eRegisterKindLLDB); 1137 1138 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector(); 1139 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly( 1140 data, sizeof(data), sample_range, unwind_plan)); 1141 1142 row_sp = unwind_plan.GetRowForFunctionOffset(2); 1143 1144 EXPECT_EQ(2ull, row_sp->GetOffset()); 1145 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1146 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1147 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); 1148 1149 EXPECT_TRUE(row_sp->GetRegisterInfo(k_r15, regloc)); 1150 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 1151 EXPECT_EQ(-16, regloc.GetOffset()); 1152 } 1153 1154 TEST_F(Testx86AssemblyInspectionEngine, TestPushR14) { 1155 UnwindPlan::Row::RegisterLocation regloc; 1156 UnwindPlan::RowSP row_sp; 1157 1158 uint8_t data[] = { 1159 0x41, 0x56, // pushq %r14 1160 0x90 // nop 1161 }; 1162 1163 AddressRange sample_range(0x1000, sizeof(data)); 1164 UnwindPlan unwind_plan(eRegisterKindLLDB); 1165 1166 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector(); 1167 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly( 1168 data, sizeof(data), sample_range, unwind_plan)); 1169 1170 row_sp = unwind_plan.GetRowForFunctionOffset(2); 1171 1172 EXPECT_EQ(2ull, row_sp->GetOffset()); 1173 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1174 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1175 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); 1176 1177 EXPECT_TRUE(row_sp->GetRegisterInfo(k_r14, regloc)); 1178 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 1179 EXPECT_EQ(-16, regloc.GetOffset()); 1180 } 1181 1182 TEST_F(Testx86AssemblyInspectionEngine, TestPushR13) { 1183 UnwindPlan::Row::RegisterLocation regloc; 1184 UnwindPlan::RowSP row_sp; 1185 1186 uint8_t data[] = { 1187 0x41, 0x55, // pushq %r13 1188 0x90 // nop 1189 }; 1190 1191 AddressRange sample_range(0x1000, sizeof(data)); 1192 UnwindPlan unwind_plan(eRegisterKindLLDB); 1193 1194 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector(); 1195 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly( 1196 data, sizeof(data), sample_range, unwind_plan)); 1197 1198 row_sp = unwind_plan.GetRowForFunctionOffset(2); 1199 1200 EXPECT_EQ(2ull, row_sp->GetOffset()); 1201 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1202 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1203 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); 1204 1205 EXPECT_TRUE(row_sp->GetRegisterInfo(k_r13, regloc)); 1206 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 1207 EXPECT_EQ(-16, regloc.GetOffset()); 1208 } 1209 1210 TEST_F(Testx86AssemblyInspectionEngine, TestPushR12) { 1211 UnwindPlan::Row::RegisterLocation regloc; 1212 UnwindPlan::RowSP row_sp; 1213 1214 uint8_t data[] = { 1215 0x41, 0x54, // pushq %r13 1216 0x90 // nop 1217 }; 1218 1219 AddressRange sample_range(0x1000, sizeof(data)); 1220 UnwindPlan unwind_plan(eRegisterKindLLDB); 1221 1222 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector(); 1223 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly( 1224 data, sizeof(data), sample_range, unwind_plan)); 1225 1226 row_sp = unwind_plan.GetRowForFunctionOffset(2); 1227 1228 EXPECT_EQ(2ull, row_sp->GetOffset()); 1229 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1230 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1231 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); 1232 1233 EXPECT_TRUE(row_sp->GetRegisterInfo(k_r12, regloc)); 1234 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 1235 EXPECT_EQ(-16, regloc.GetOffset()); 1236 } 1237 1238 TEST_F(Testx86AssemblyInspectionEngine, TestPushRBX) { 1239 UnwindPlan::Row::RegisterLocation regloc; 1240 UnwindPlan::RowSP row_sp; 1241 1242 uint8_t data[] = { 1243 0x53, // pushq %rbx 1244 0x90 // nop 1245 }; 1246 1247 AddressRange sample_range(0x1000, sizeof(data)); 1248 UnwindPlan unwind_plan(eRegisterKindLLDB); 1249 1250 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector(); 1251 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly( 1252 data, sizeof(data), sample_range, unwind_plan)); 1253 1254 row_sp = unwind_plan.GetRowForFunctionOffset(1); 1255 1256 EXPECT_EQ(1ull, row_sp->GetOffset()); 1257 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1258 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1259 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); 1260 1261 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbx, regloc)); 1262 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 1263 EXPECT_EQ(-16, regloc.GetOffset()); 1264 } 1265 1266 // The ABI is hardcoded in x86AssemblyInspectionEngine such that 1267 // eax, ecx, edx are all considered volatile and push/pops of them are 1268 // not tracked (except to keep track of stack pointer movement) 1269 TEST_F(Testx86AssemblyInspectionEngine, TestPushEAX) { 1270 UnwindPlan::Row::RegisterLocation regloc; 1271 UnwindPlan::RowSP row_sp; 1272 AddressRange sample_range; 1273 UnwindPlan unwind_plan(eRegisterKindLLDB); 1274 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector(); 1275 1276 uint8_t data[] = { 1277 0x50, // pushl %eax 1278 0x90 // nop 1279 }; 1280 1281 sample_range = AddressRange(0x1000, sizeof(data)); 1282 1283 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly( 1284 data, sizeof(data), sample_range, unwind_plan)); 1285 1286 row_sp = unwind_plan.GetRowForFunctionOffset(1); 1287 EXPECT_EQ(1ull, row_sp->GetOffset()); 1288 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp); 1289 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1290 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 1291 1292 EXPECT_FALSE(row_sp->GetRegisterInfo(k_eax, regloc)); 1293 } 1294 1295 // The ABI is hardcoded in x86AssemblyInspectionEngine such that 1296 // eax, ecx, edx are all considered volatile and push/pops of them are 1297 // not tracked (except to keep track of stack pointer movement) 1298 TEST_F(Testx86AssemblyInspectionEngine, TestPushECX) { 1299 UnwindPlan::Row::RegisterLocation regloc; 1300 UnwindPlan::RowSP row_sp; 1301 AddressRange sample_range; 1302 UnwindPlan unwind_plan(eRegisterKindLLDB); 1303 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector(); 1304 1305 uint8_t data[] = { 1306 0x51, // pushl %ecx 1307 0x90 // nop 1308 }; 1309 1310 sample_range = AddressRange(0x1000, sizeof(data)); 1311 1312 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly( 1313 data, sizeof(data), sample_range, unwind_plan)); 1314 1315 row_sp = unwind_plan.GetRowForFunctionOffset(1); 1316 EXPECT_EQ(1ull, row_sp->GetOffset()); 1317 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp); 1318 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1319 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 1320 1321 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ecx, regloc)); 1322 } 1323 1324 // The ABI is hardcoded in x86AssemblyInspectionEngine such that 1325 // eax, ecx, edx are all considered volatile and push/pops of them are 1326 // not tracked (except to keep track of stack pointer movement) 1327 TEST_F(Testx86AssemblyInspectionEngine, TestPushEDX) { 1328 UnwindPlan::Row::RegisterLocation regloc; 1329 UnwindPlan::RowSP row_sp; 1330 AddressRange sample_range; 1331 UnwindPlan unwind_plan(eRegisterKindLLDB); 1332 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector(); 1333 1334 uint8_t data[] = { 1335 0x52, // pushl %edx 1336 0x90 // nop 1337 }; 1338 1339 sample_range = AddressRange(0x1000, sizeof(data)); 1340 1341 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly( 1342 data, sizeof(data), sample_range, unwind_plan)); 1343 1344 row_sp = unwind_plan.GetRowForFunctionOffset(1); 1345 EXPECT_EQ(1ull, row_sp->GetOffset()); 1346 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp); 1347 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1348 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 1349 1350 EXPECT_FALSE(row_sp->GetRegisterInfo(k_edx, regloc)); 1351 } 1352 1353 TEST_F(Testx86AssemblyInspectionEngine, TestPushEBX) { 1354 UnwindPlan::Row::RegisterLocation regloc; 1355 UnwindPlan::RowSP row_sp; 1356 AddressRange sample_range; 1357 UnwindPlan unwind_plan(eRegisterKindLLDB); 1358 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector(); 1359 1360 uint8_t data[] = { 1361 0x53, // pushl %ebx 1362 0x90 // nop 1363 }; 1364 1365 sample_range = AddressRange(0x1000, sizeof(data)); 1366 1367 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly( 1368 data, sizeof(data), sample_range, unwind_plan)); 1369 1370 row_sp = unwind_plan.GetRowForFunctionOffset(1); 1371 EXPECT_EQ(1ull, row_sp->GetOffset()); 1372 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp); 1373 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1374 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 1375 1376 EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebx, regloc)); 1377 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 1378 EXPECT_EQ(-8, regloc.GetOffset()); 1379 } 1380 1381 TEST_F(Testx86AssemblyInspectionEngine, TestPushEBP) { 1382 UnwindPlan::Row::RegisterLocation regloc; 1383 UnwindPlan::RowSP row_sp; 1384 AddressRange sample_range; 1385 UnwindPlan unwind_plan(eRegisterKindLLDB); 1386 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector(); 1387 1388 uint8_t data[] = { 1389 0x55, // pushl %ebp 1390 0x90 // nop 1391 }; 1392 1393 sample_range = AddressRange(0x1000, sizeof(data)); 1394 1395 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly( 1396 data, sizeof(data), sample_range, unwind_plan)); 1397 1398 row_sp = unwind_plan.GetRowForFunctionOffset(1); 1399 EXPECT_EQ(1ull, row_sp->GetOffset()); 1400 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp); 1401 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1402 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 1403 1404 EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebp, regloc)); 1405 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 1406 EXPECT_EQ(-8, regloc.GetOffset()); 1407 } 1408 1409 TEST_F(Testx86AssemblyInspectionEngine, TestPushESI) { 1410 UnwindPlan::Row::RegisterLocation regloc; 1411 UnwindPlan::RowSP row_sp; 1412 AddressRange sample_range; 1413 UnwindPlan unwind_plan(eRegisterKindLLDB); 1414 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector(); 1415 1416 uint8_t data[] = { 1417 0x56, // pushl %esi 1418 0x90 // nop 1419 }; 1420 1421 sample_range = AddressRange(0x1000, sizeof(data)); 1422 1423 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly( 1424 data, sizeof(data), sample_range, unwind_plan)); 1425 1426 row_sp = unwind_plan.GetRowForFunctionOffset(1); 1427 EXPECT_EQ(1ull, row_sp->GetOffset()); 1428 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp); 1429 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1430 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 1431 1432 EXPECT_TRUE(row_sp->GetRegisterInfo(k_esi, regloc)); 1433 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 1434 EXPECT_EQ(-8, regloc.GetOffset()); 1435 } 1436 1437 TEST_F(Testx86AssemblyInspectionEngine, TestPushEDI) { 1438 UnwindPlan::Row::RegisterLocation regloc; 1439 UnwindPlan::RowSP row_sp; 1440 AddressRange sample_range; 1441 UnwindPlan unwind_plan(eRegisterKindLLDB); 1442 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector(); 1443 1444 uint8_t data[] = { 1445 0x57, // pushl %edi 1446 0x90 // nop 1447 }; 1448 1449 sample_range = AddressRange(0x1000, sizeof(data)); 1450 1451 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly( 1452 data, sizeof(data), sample_range, unwind_plan)); 1453 1454 row_sp = unwind_plan.GetRowForFunctionOffset(1); 1455 EXPECT_EQ(1ull, row_sp->GetOffset()); 1456 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp); 1457 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1458 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 1459 1460 EXPECT_TRUE(row_sp->GetRegisterInfo(k_edi, regloc)); 1461 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 1462 EXPECT_EQ(-8, regloc.GetOffset()); 1463 } 1464 1465 TEST_F(Testx86AssemblyInspectionEngine, TestMovRSPtoRBP) { 1466 UnwindPlan::Row::RegisterLocation regloc; 1467 UnwindPlan::RowSP row_sp; 1468 1469 uint8_t data64_1[] = { 1470 0x48, 0x8b, 0xec, // movq %rsp, %rbp 1471 0x90 // nop 1472 }; 1473 1474 AddressRange sample_range(0x1000, sizeof(data64_1)); 1475 UnwindPlan unwind_plan(eRegisterKindLLDB); 1476 1477 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector(); 1478 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly( 1479 data64_1, sizeof(data64_1), sample_range, unwind_plan)); 1480 1481 row_sp = unwind_plan.GetRowForFunctionOffset(3); 1482 1483 EXPECT_EQ(3ull, row_sp->GetOffset()); 1484 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp); 1485 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1486 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 1487 1488 uint8_t data64_2[] = { 1489 0x48, 0x89, 0xe5, // movq %rsp, %rbp 1490 0x90 // nop 1491 }; 1492 1493 sample_range = AddressRange(0x1000, sizeof(data64_2)); 1494 unwind_plan.Clear(); 1495 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly( 1496 data64_2, sizeof(data64_2), sample_range, unwind_plan)); 1497 1498 row_sp = unwind_plan.GetRowForFunctionOffset(3); 1499 EXPECT_EQ(3ull, row_sp->GetOffset()); 1500 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp); 1501 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1502 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 1503 1504 uint8_t data32_1[] = { 1505 0x8b, 0xec, // movl %rsp, %rbp 1506 0x90 // nop 1507 }; 1508 1509 sample_range = AddressRange(0x1000, sizeof(data32_1)); 1510 unwind_plan.Clear(); 1511 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly( 1512 data32_1, sizeof(data32_1), sample_range, unwind_plan)); 1513 1514 row_sp = unwind_plan.GetRowForFunctionOffset(2); 1515 EXPECT_EQ(2ull, row_sp->GetOffset()); 1516 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp); 1517 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1518 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 1519 1520 uint8_t data32_2[] = { 1521 0x89, 0xe5, // movl %rsp, %rbp 1522 0x90 // nop 1523 }; 1524 1525 sample_range = AddressRange(0x1000, sizeof(data32_2)); 1526 unwind_plan.Clear(); 1527 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly( 1528 data32_2, sizeof(data32_2), sample_range, unwind_plan)); 1529 1530 row_sp = unwind_plan.GetRowForFunctionOffset(2); 1531 EXPECT_EQ(2ull, row_sp->GetOffset()); 1532 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp); 1533 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1534 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 1535 } 1536 1537 TEST_F(Testx86AssemblyInspectionEngine, TestSubRSP) { 1538 UnwindPlan::Row::RegisterLocation regloc; 1539 UnwindPlan::RowSP row_sp; 1540 AddressRange sample_range; 1541 UnwindPlan unwind_plan(eRegisterKindLLDB); 1542 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector(); 1543 1544 uint8_t data1[] = { 1545 0x48, 0x81, 0xec, 0x00, 0x01, 0x00, 0x00, // subq $0x100, $rsp 1546 0x90 // nop 1547 }; 1548 1549 sample_range = AddressRange(0x1000, sizeof(data1)); 1550 1551 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly( 1552 data1, sizeof(data1), sample_range, unwind_plan)); 1553 1554 row_sp = unwind_plan.GetRowForFunctionOffset(7); 1555 EXPECT_EQ(7ull, row_sp->GetOffset()); 1556 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1557 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1558 EXPECT_EQ(264, row_sp->GetCFAValue().GetOffset()); 1559 1560 uint8_t data2[] = { 1561 0x48, 0x83, 0xec, 0x10, // subq $0x10, %rsp 1562 0x90 // nop 1563 }; 1564 1565 sample_range = AddressRange(0x1000, sizeof(data2)); 1566 1567 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly( 1568 data2, sizeof(data2), sample_range, unwind_plan)); 1569 1570 row_sp = unwind_plan.GetRowForFunctionOffset(4); 1571 EXPECT_EQ(4ull, row_sp->GetOffset()); 1572 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1573 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1574 EXPECT_EQ(24, row_sp->GetCFAValue().GetOffset()); 1575 } 1576 1577 TEST_F(Testx86AssemblyInspectionEngine, TestSubESP) { 1578 UnwindPlan::Row::RegisterLocation regloc; 1579 UnwindPlan::RowSP row_sp; 1580 AddressRange sample_range; 1581 UnwindPlan unwind_plan(eRegisterKindLLDB); 1582 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector(); 1583 1584 uint8_t data1[] = { 1585 0x81, 0xec, 0x00, 0x01, 0x00, 0x00, // subl $0x100, %esp 1586 0x90 // nop 1587 }; 1588 1589 sample_range = AddressRange(0x1000, sizeof(data1)); 1590 1591 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly( 1592 data1, sizeof(data1), sample_range, unwind_plan)); 1593 1594 row_sp = unwind_plan.GetRowForFunctionOffset(6); 1595 EXPECT_EQ(6ull, row_sp->GetOffset()); 1596 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1597 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1598 EXPECT_EQ(260, row_sp->GetCFAValue().GetOffset()); 1599 1600 uint8_t data2[] = { 1601 0x83, 0xec, 0x10, // subq $0x10, %esp 1602 0x90 // nop 1603 }; 1604 1605 sample_range = AddressRange(0x1000, sizeof(data2)); 1606 1607 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly( 1608 data2, sizeof(data2), sample_range, unwind_plan)); 1609 1610 row_sp = unwind_plan.GetRowForFunctionOffset(3); 1611 EXPECT_EQ(3ull, row_sp->GetOffset()); 1612 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1613 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1614 EXPECT_EQ(20, row_sp->GetCFAValue().GetOffset()); 1615 } 1616 1617 TEST_F(Testx86AssemblyInspectionEngine, TestAddRSP) { 1618 UnwindPlan::Row::RegisterLocation regloc; 1619 UnwindPlan::RowSP row_sp; 1620 AddressRange sample_range; 1621 UnwindPlan unwind_plan(eRegisterKindLLDB); 1622 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector(); 1623 1624 uint8_t data1[] = { 1625 0x48, 0x81, 0xc4, 0x00, 0x01, 0x00, 0x00, // addq $0x100, %rsp 1626 0x90 // nop 1627 }; 1628 1629 sample_range = AddressRange(0x1000, sizeof(data1)); 1630 1631 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly( 1632 data1, sizeof(data1), sample_range, unwind_plan)); 1633 1634 row_sp = unwind_plan.GetRowForFunctionOffset(7); 1635 EXPECT_EQ(7ull, row_sp->GetOffset()); 1636 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1637 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1638 EXPECT_EQ(8 - 256, row_sp->GetCFAValue().GetOffset()); 1639 1640 uint8_t data2[] = { 1641 0x48, 0x83, 0xc4, 0x10, // addq $0x10, %rsp 1642 0x90 // nop 1643 }; 1644 1645 sample_range = AddressRange(0x1000, sizeof(data2)); 1646 1647 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly( 1648 data2, sizeof(data2), sample_range, unwind_plan)); 1649 1650 row_sp = unwind_plan.GetRowForFunctionOffset(4); 1651 EXPECT_EQ(4ull, row_sp->GetOffset()); 1652 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1653 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1654 EXPECT_EQ(8 - 16, row_sp->GetCFAValue().GetOffset()); 1655 } 1656 1657 TEST_F(Testx86AssemblyInspectionEngine, TestAddESP) { 1658 UnwindPlan::Row::RegisterLocation regloc; 1659 UnwindPlan::RowSP row_sp; 1660 AddressRange sample_range; 1661 UnwindPlan unwind_plan(eRegisterKindLLDB); 1662 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector(); 1663 1664 uint8_t data1[] = { 1665 0x81, 0xc4, 0x00, 0x01, 0x00, 0x00, // addl $0x100, %esp 1666 0x90 // nop 1667 }; 1668 1669 sample_range = AddressRange(0x1000, sizeof(data1)); 1670 1671 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly( 1672 data1, sizeof(data1), sample_range, unwind_plan)); 1673 1674 row_sp = unwind_plan.GetRowForFunctionOffset(6); 1675 EXPECT_EQ(6ull, row_sp->GetOffset()); 1676 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1677 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1678 EXPECT_EQ(4 - 256, row_sp->GetCFAValue().GetOffset()); 1679 1680 uint8_t data2[] = { 1681 0x83, 0xc4, 0x10, // addq $0x10, %esp 1682 0x90 // nop 1683 }; 1684 1685 sample_range = AddressRange(0x1000, sizeof(data2)); 1686 1687 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly( 1688 data2, sizeof(data2), sample_range, unwind_plan)); 1689 1690 row_sp = unwind_plan.GetRowForFunctionOffset(3); 1691 EXPECT_EQ(3ull, row_sp->GetOffset()); 1692 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1693 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1694 EXPECT_EQ(4 - 16, row_sp->GetCFAValue().GetOffset()); 1695 } 1696 1697 // FIXME add test for lea_rsp_pattern_p 1698 1699 TEST_F(Testx86AssemblyInspectionEngine, TestPopRBX) { 1700 UnwindPlan::Row::RegisterLocation regloc; 1701 UnwindPlan::RowSP row_sp; 1702 AddressRange sample_range; 1703 UnwindPlan unwind_plan(eRegisterKindLLDB); 1704 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector(); 1705 1706 uint8_t data[] = { 1707 0x53, // pushq %rbx 1708 0x5b, // popq %rbx 1709 0x90 // nop 1710 }; 1711 1712 sample_range = AddressRange(0x1000, sizeof(data)); 1713 1714 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 1715 data, sizeof(data), sample_range, unwind_plan)); 1716 1717 row_sp = unwind_plan.GetRowForFunctionOffset(2); 1718 EXPECT_EQ(2ull, row_sp->GetOffset()); 1719 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1720 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1721 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 1722 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbx, regloc)); 1723 } 1724 1725 TEST_F(Testx86AssemblyInspectionEngine, TestPopRBP) { 1726 UnwindPlan::Row::RegisterLocation regloc; 1727 UnwindPlan::RowSP row_sp; 1728 AddressRange sample_range; 1729 UnwindPlan unwind_plan(eRegisterKindLLDB); 1730 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector(); 1731 1732 uint8_t data[] = { 1733 0x55, // pushq %rbp 1734 0x5d, // popq %rbp 1735 0x90 // nop 1736 }; 1737 1738 sample_range = AddressRange(0x1000, sizeof(data)); 1739 1740 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 1741 data, sizeof(data), sample_range, unwind_plan)); 1742 1743 row_sp = unwind_plan.GetRowForFunctionOffset(2); 1744 EXPECT_EQ(2ull, row_sp->GetOffset()); 1745 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1746 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1747 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 1748 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc)); 1749 } 1750 1751 TEST_F(Testx86AssemblyInspectionEngine, TestPopR12) { 1752 UnwindPlan::Row::RegisterLocation regloc; 1753 UnwindPlan::RowSP row_sp; 1754 AddressRange sample_range; 1755 UnwindPlan unwind_plan(eRegisterKindLLDB); 1756 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector(); 1757 1758 uint8_t data[] = { 1759 0x41, 0x54, // pushq %r12 1760 0x41, 0x5c, // popq %r12 1761 0x90 // nop 1762 }; 1763 1764 sample_range = AddressRange(0x1000, sizeof(data)); 1765 1766 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 1767 data, sizeof(data), sample_range, unwind_plan)); 1768 1769 row_sp = unwind_plan.GetRowForFunctionOffset(4); 1770 EXPECT_EQ(4ull, row_sp->GetOffset()); 1771 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1772 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1773 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 1774 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r12, regloc)); 1775 } 1776 1777 TEST_F(Testx86AssemblyInspectionEngine, TestPopR13) { 1778 UnwindPlan::Row::RegisterLocation regloc; 1779 UnwindPlan::RowSP row_sp; 1780 AddressRange sample_range; 1781 UnwindPlan unwind_plan(eRegisterKindLLDB); 1782 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector(); 1783 1784 uint8_t data[] = { 1785 0x41, 0x55, // pushq %r13 1786 0x41, 0x5d, // popq %r13 1787 0x90 // nop 1788 }; 1789 1790 sample_range = AddressRange(0x1000, sizeof(data)); 1791 1792 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 1793 data, sizeof(data), sample_range, unwind_plan)); 1794 1795 row_sp = unwind_plan.GetRowForFunctionOffset(4); 1796 EXPECT_EQ(4ull, row_sp->GetOffset()); 1797 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1798 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1799 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 1800 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r13, regloc)); 1801 } 1802 1803 TEST_F(Testx86AssemblyInspectionEngine, TestPopR14) { 1804 UnwindPlan::Row::RegisterLocation regloc; 1805 UnwindPlan::RowSP row_sp; 1806 AddressRange sample_range; 1807 UnwindPlan unwind_plan(eRegisterKindLLDB); 1808 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector(); 1809 1810 uint8_t data[] = { 1811 0x41, 0x56, // pushq %r14 1812 0x41, 0x5e, // popq %r14 1813 0x90 // nop 1814 }; 1815 1816 sample_range = AddressRange(0x1000, sizeof(data)); 1817 1818 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 1819 data, sizeof(data), sample_range, unwind_plan)); 1820 1821 row_sp = unwind_plan.GetRowForFunctionOffset(4); 1822 EXPECT_EQ(4ull, row_sp->GetOffset()); 1823 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1824 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1825 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 1826 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r14, regloc)); 1827 } 1828 1829 TEST_F(Testx86AssemblyInspectionEngine, TestPopR15) { 1830 UnwindPlan::Row::RegisterLocation regloc; 1831 UnwindPlan::RowSP row_sp; 1832 AddressRange sample_range; 1833 UnwindPlan unwind_plan(eRegisterKindLLDB); 1834 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector(); 1835 1836 uint8_t data[] = { 1837 0x41, 0x57, // pushq %r15 1838 0x41, 0x5f, // popq %r15 1839 0x90 // nop 1840 }; 1841 1842 sample_range = AddressRange(0x1000, sizeof(data)); 1843 1844 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 1845 data, sizeof(data), sample_range, unwind_plan)); 1846 1847 row_sp = unwind_plan.GetRowForFunctionOffset(4); 1848 EXPECT_EQ(4ull, row_sp->GetOffset()); 1849 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1850 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1851 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 1852 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r15, regloc)); 1853 } 1854 1855 TEST_F(Testx86AssemblyInspectionEngine, TestPopEBX) { 1856 UnwindPlan::Row::RegisterLocation regloc; 1857 UnwindPlan::RowSP row_sp; 1858 AddressRange sample_range; 1859 UnwindPlan unwind_plan(eRegisterKindLLDB); 1860 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector(); 1861 1862 uint8_t data[] = { 1863 0x53, // pushl %ebx 1864 0x5b, // popl %ebx 1865 0x90 // nop 1866 }; 1867 1868 sample_range = AddressRange(0x1000, sizeof(data)); 1869 1870 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 1871 data, sizeof(data), sample_range, unwind_plan)); 1872 1873 row_sp = unwind_plan.GetRowForFunctionOffset(2); 1874 EXPECT_EQ(2ull, row_sp->GetOffset()); 1875 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1876 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1877 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset()); 1878 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebx, regloc)); 1879 } 1880 1881 TEST_F(Testx86AssemblyInspectionEngine, TestPopEBP) { 1882 UnwindPlan::Row::RegisterLocation regloc; 1883 UnwindPlan::RowSP row_sp; 1884 AddressRange sample_range; 1885 UnwindPlan unwind_plan(eRegisterKindLLDB); 1886 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector(); 1887 1888 uint8_t data[] = { 1889 0x55, // pushl %ebp 1890 0x5d, // popl %ebp 1891 0x90 // nop 1892 }; 1893 1894 sample_range = AddressRange(0x1000, sizeof(data)); 1895 1896 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 1897 data, sizeof(data), sample_range, unwind_plan)); 1898 1899 row_sp = unwind_plan.GetRowForFunctionOffset(2); 1900 EXPECT_EQ(2ull, row_sp->GetOffset()); 1901 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1902 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1903 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset()); 1904 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc)); 1905 } 1906 1907 TEST_F(Testx86AssemblyInspectionEngine, TestPopESI) { 1908 UnwindPlan::Row::RegisterLocation regloc; 1909 UnwindPlan::RowSP row_sp; 1910 AddressRange sample_range; 1911 UnwindPlan unwind_plan(eRegisterKindLLDB); 1912 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector(); 1913 1914 uint8_t data[] = { 1915 0x56, // pushl %esi 1916 0x5e, // popl %esi 1917 0x90 // nop 1918 }; 1919 1920 sample_range = AddressRange(0x1000, sizeof(data)); 1921 1922 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 1923 data, sizeof(data), sample_range, unwind_plan)); 1924 1925 row_sp = unwind_plan.GetRowForFunctionOffset(2); 1926 EXPECT_EQ(2ull, row_sp->GetOffset()); 1927 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1928 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1929 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset()); 1930 EXPECT_FALSE(row_sp->GetRegisterInfo(k_esi, regloc)); 1931 } 1932 1933 TEST_F(Testx86AssemblyInspectionEngine, TestPopEDI) { 1934 UnwindPlan::Row::RegisterLocation regloc; 1935 UnwindPlan::RowSP row_sp; 1936 AddressRange sample_range; 1937 UnwindPlan unwind_plan(eRegisterKindLLDB); 1938 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector(); 1939 1940 uint8_t data[] = { 1941 0x57, // pushl %edi 1942 0x5f, // popl %edi 1943 0x90 // nop 1944 }; 1945 1946 sample_range = AddressRange(0x1000, sizeof(data)); 1947 1948 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 1949 data, sizeof(data), sample_range, unwind_plan)); 1950 1951 row_sp = unwind_plan.GetRowForFunctionOffset(2); 1952 EXPECT_EQ(2ull, row_sp->GetOffset()); 1953 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1954 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1955 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset()); 1956 EXPECT_FALSE(row_sp->GetRegisterInfo(k_edi, regloc)); 1957 } 1958 1959 // We don't track these registers, but make sure the CFA address is updated 1960 // if we're defining the CFA in term of esp. 1961 TEST_F(Testx86AssemblyInspectionEngine, Testi386IgnoredRegisters) { 1962 UnwindPlan::Row::RegisterLocation regloc; 1963 UnwindPlan::RowSP row_sp; 1964 AddressRange sample_range; 1965 UnwindPlan unwind_plan(eRegisterKindLLDB); 1966 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector(); 1967 1968 uint8_t data[] = { 1969 0x0e, // push cs 1970 0x16, // push ss 1971 0x1e, // push ds 1972 0x06, // push es 1973 1974 0x07, // pop es 1975 0x1f, // pop ds 1976 0x17, // pop ss 1977 1978 0x90 // nop 1979 }; 1980 1981 sample_range = AddressRange(0x1000, sizeof(data)); 1982 1983 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 1984 data, sizeof(data), sample_range, unwind_plan)); 1985 1986 row_sp = unwind_plan.GetRowForFunctionOffset(4); 1987 EXPECT_EQ(4ull, row_sp->GetOffset()); 1988 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1989 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1990 EXPECT_EQ(20, row_sp->GetCFAValue().GetOffset()); 1991 1992 row_sp = unwind_plan.GetRowForFunctionOffset(7); 1993 EXPECT_EQ(7ull, row_sp->GetOffset()); 1994 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1995 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1996 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 1997 } 1998 1999 TEST_F(Testx86AssemblyInspectionEngine, TestLEAVE) { 2000 UnwindPlan::Row::RegisterLocation regloc; 2001 UnwindPlan::RowSP row_sp; 2002 AddressRange sample_range; 2003 UnwindPlan unwind_plan(eRegisterKindLLDB); 2004 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector(); 2005 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector(); 2006 2007 uint8_t data[] = { 2008 0x55, // push %rbp/ebp 2009 0xc9, // leave 2010 0x90 // nop 2011 }; 2012 2013 sample_range = AddressRange(0x1000, sizeof(data)); 2014 2015 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly( 2016 data, sizeof(data), sample_range, unwind_plan)); 2017 2018 row_sp = unwind_plan.GetRowForFunctionOffset(2); 2019 EXPECT_EQ(2ull, row_sp->GetOffset()); 2020 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 2021 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 2022 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 2023 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc)); 2024 2025 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly( 2026 data, sizeof(data), sample_range, unwind_plan)); 2027 2028 row_sp = unwind_plan.GetRowForFunctionOffset(2); 2029 EXPECT_EQ(2ull, row_sp->GetOffset()); 2030 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 2031 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 2032 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset()); 2033 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc)); 2034 } 2035 2036 // In i386, which lacks pc-relative addressing, a common code sequence 2037 // is to call the next instruction (i.e. call imm32, value of 0) which 2038 // pushes the addr of the next insn on the stack, and then pop that value 2039 // into a register (the "pic base" register). 2040 TEST_F(Testx86AssemblyInspectionEngine, TestCALLNextInsn) { 2041 UnwindPlan::Row::RegisterLocation regloc; 2042 UnwindPlan::RowSP row_sp; 2043 AddressRange sample_range; 2044 UnwindPlan unwind_plan(eRegisterKindLLDB); 2045 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector(); 2046 2047 uint8_t data[] = { 2048 0xe8, 0x00, 0x00, 0x00, 0x00, // call 0 2049 0x90 // nop 2050 }; 2051 2052 sample_range = AddressRange(0x1000, sizeof(data)); 2053 2054 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly( 2055 data, sizeof(data), sample_range, unwind_plan)); 2056 2057 row_sp = unwind_plan.GetRowForFunctionOffset(5); 2058 EXPECT_EQ(5ull, row_sp->GetOffset()); 2059 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 2060 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 2061 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 2062 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc)); 2063 } 2064 2065 TEST_F(Testx86AssemblyInspectionEngine, TestSpillRegToStackViaMOVx86_64) { 2066 UnwindPlan::Row::RegisterLocation regloc; 2067 UnwindPlan::RowSP row_sp; 2068 AddressRange sample_range; 2069 UnwindPlan unwind_plan(eRegisterKindLLDB); 2070 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector(); 2071 2072 uint8_t data[] = { 2073 0x55, // pushq %rbp 2074 0x48, 0x89, 0xe5, // movq %rsp, %rbp 2075 0x4c, 0x89, 0x75, 0xc0, // movq %r14, -0x40(%rbp) 2076 0x4c, 0x89, 0xbd, 0x28, 0xfa, 0xff, 0xff, // movq %r15, -0x5d8(%rbp) 2077 0x48, 0x89, 0x5d, 0xb8, // movq %rbx, -0x48(%rbp) 2078 0x90 // nop 2079 }; 2080 2081 sample_range = AddressRange(0x1000, sizeof(data)); 2082 2083 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly( 2084 data, sizeof(data), sample_range, unwind_plan)); 2085 2086 row_sp = unwind_plan.GetRowForFunctionOffset(19); 2087 EXPECT_EQ(19ull, row_sp->GetOffset()); 2088 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp); 2089 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); 2090 2091 EXPECT_TRUE(row_sp->GetRegisterInfo(k_r14, regloc)); 2092 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 2093 EXPECT_EQ(-80, regloc.GetOffset()); 2094 2095 EXPECT_TRUE(row_sp->GetRegisterInfo(k_r15, regloc)); 2096 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 2097 EXPECT_EQ(-1512, regloc.GetOffset()); 2098 2099 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbx, regloc)); 2100 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 2101 EXPECT_EQ(-88, regloc.GetOffset()); 2102 } 2103 2104 TEST_F(Testx86AssemblyInspectionEngine, TestSpillRegToStackViaMOVi386) { 2105 UnwindPlan::Row::RegisterLocation regloc; 2106 UnwindPlan::RowSP row_sp; 2107 AddressRange sample_range; 2108 UnwindPlan unwind_plan(eRegisterKindLLDB); 2109 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector(); 2110 2111 uint8_t data[] = { 2112 0x55, // pushl %ebp 2113 0x89, 0xe5, // movl %esp, %ebp 2114 0x89, 0x9d, 0xb0, 0xfe, 0xff, 0xff, // movl %ebx, -0x150(%ebp) 2115 0x89, 0x75, 0xe0, // movl %esi, -0x20(%ebp) 2116 0x90 // nop 2117 }; 2118 2119 sample_range = AddressRange(0x1000, sizeof(data)); 2120 2121 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly( 2122 data, sizeof(data), sample_range, unwind_plan)); 2123 2124 row_sp = unwind_plan.GetRowForFunctionOffset(12); 2125 EXPECT_EQ(12ull, row_sp->GetOffset()); 2126 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp); 2127 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 2128 2129 EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebx, regloc)); 2130 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 2131 EXPECT_EQ(-344, regloc.GetOffset()); 2132 2133 EXPECT_TRUE(row_sp->GetRegisterInfo(k_esi, regloc)); 2134 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 2135 EXPECT_EQ(-40, regloc.GetOffset()); 2136 } 2137 2138 TEST_F(Testx86AssemblyInspectionEngine, TestSimplex86_64Augmented) { 2139 UnwindPlan::Row::RegisterLocation regloc; 2140 UnwindPlan::RowSP row_sp; 2141 AddressRange sample_range; 2142 UnwindPlan unwind_plan(eRegisterKindLLDB); 2143 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector(); 2144 2145 uint8_t data[] = { 2146 0x55, // pushq %rbp 2147 0x48, 0x89, 0xe5, // movq %rsp, %rbp 2148 2149 // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite 2150 // has a bug where it can't augment a function that is just 2151 // prologue+epilogue - it needs at least one other instruction 2152 // in between. 2153 0x90, // nop 2154 2155 0x5d, // popq %rbp 2156 0xc3 // retq 2157 }; 2158 2159 sample_range = AddressRange(0x1000, sizeof(data)); 2160 2161 unwind_plan.SetSourceName("unit testing hand-created unwind plan"); 2162 unwind_plan.SetPlanValidAddressRange(sample_range); 2163 unwind_plan.SetRegisterKind(eRegisterKindLLDB); 2164 2165 row_sp.reset(new UnwindPlan::Row); 2166 2167 // Describe offset 0 2168 row_sp->SetOffset(0); 2169 row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_rsp, 8); 2170 2171 regloc.SetAtCFAPlusOffset(-8); 2172 row_sp->SetRegisterInfo(k_rip, regloc); 2173 2174 unwind_plan.AppendRow(row_sp); 2175 2176 // Allocate a new Row, populate it with the existing Row contents. 2177 UnwindPlan::Row *new_row = new UnwindPlan::Row; 2178 *new_row = *row_sp.get(); 2179 row_sp.reset(new_row); 2180 2181 // Describe offset 1 2182 row_sp->SetOffset(1); 2183 row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_rsp, 16); 2184 regloc.SetAtCFAPlusOffset(-16); 2185 row_sp->SetRegisterInfo(k_rbp, regloc); 2186 unwind_plan.AppendRow(row_sp); 2187 2188 // Allocate a new Row, populate it with the existing Row contents. 2189 new_row = new UnwindPlan::Row; 2190 *new_row = *row_sp.get(); 2191 row_sp.reset(new_row); 2192 2193 // Describe offset 4 2194 row_sp->SetOffset(4); 2195 row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_rbp, 16); 2196 unwind_plan.AppendRow(row_sp); 2197 2198 RegisterContextSP reg_ctx_sp; 2199 EXPECT_TRUE(engine64->AugmentUnwindPlanFromCallSite( 2200 data, sizeof(data), sample_range, unwind_plan, reg_ctx_sp)); 2201 2202 row_sp = unwind_plan.GetRowForFunctionOffset(6); 2203 EXPECT_EQ(6ull, row_sp->GetOffset()); 2204 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 2205 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 2206 2207 // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite 2208 // doesn't track register restores (pop'ing a reg value back from 2209 // the stack) - it was just written to make stepping work correctly. 2210 // Technically we should be able to do the following test, but it 2211 // won't work today - the unwind plan will still say that the caller's 2212 // rbp is on the stack. 2213 // EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc)); 2214 } 2215 2216 TEST_F(Testx86AssemblyInspectionEngine, TestSimplei386ugmented) { 2217 UnwindPlan::Row::RegisterLocation regloc; 2218 UnwindPlan::RowSP row_sp; 2219 AddressRange sample_range; 2220 UnwindPlan unwind_plan(eRegisterKindLLDB); 2221 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector(); 2222 2223 uint8_t data[] = { 2224 0x55, // pushl %ebp 2225 0x89, 0xe5, // movl %esp, %ebp 2226 2227 // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite 2228 // has a bug where it can't augment a function that is just 2229 // prologue+epilogue - it needs at least one other instruction 2230 // in between. 2231 0x90, // nop 2232 2233 0x5d, // popl %ebp 2234 0xc3 // retl 2235 }; 2236 2237 sample_range = AddressRange(0x1000, sizeof(data)); 2238 2239 unwind_plan.SetSourceName("unit testing hand-created unwind plan"); 2240 unwind_plan.SetPlanValidAddressRange(sample_range); 2241 unwind_plan.SetRegisterKind(eRegisterKindLLDB); 2242 2243 row_sp.reset(new UnwindPlan::Row); 2244 2245 // Describe offset 0 2246 row_sp->SetOffset(0); 2247 row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_esp, 4); 2248 2249 regloc.SetAtCFAPlusOffset(-4); 2250 row_sp->SetRegisterInfo(k_eip, regloc); 2251 2252 unwind_plan.AppendRow(row_sp); 2253 2254 // Allocate a new Row, populate it with the existing Row contents. 2255 UnwindPlan::Row *new_row = new UnwindPlan::Row; 2256 *new_row = *row_sp.get(); 2257 row_sp.reset(new_row); 2258 2259 // Describe offset 1 2260 row_sp->SetOffset(1); 2261 row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_esp, 8); 2262 regloc.SetAtCFAPlusOffset(-8); 2263 row_sp->SetRegisterInfo(k_ebp, regloc); 2264 unwind_plan.AppendRow(row_sp); 2265 2266 // Allocate a new Row, populate it with the existing Row contents. 2267 new_row = new UnwindPlan::Row; 2268 *new_row = *row_sp.get(); 2269 row_sp.reset(new_row); 2270 2271 // Describe offset 3 2272 row_sp->SetOffset(3); 2273 row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_ebp, 8); 2274 unwind_plan.AppendRow(row_sp); 2275 2276 RegisterContextSP reg_ctx_sp; 2277 EXPECT_TRUE(engine32->AugmentUnwindPlanFromCallSite( 2278 data, sizeof(data), sample_range, unwind_plan, reg_ctx_sp)); 2279 2280 row_sp = unwind_plan.GetRowForFunctionOffset(5); 2281 EXPECT_EQ(5ull, row_sp->GetOffset()); 2282 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp); 2283 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset()); 2284 2285 // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite 2286 // doesn't track register restores (pop'ing a reg value back from 2287 // the stack) - it was just written to make stepping work correctly. 2288 // Technically we should be able to do the following test, but it 2289 // won't work today - the unwind plan will still say that the caller's 2290 // ebp is on the stack. 2291 // EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc)); 2292 } 2293 2294 // Check that the i386 disassembler disassembles past an opcode that 2295 // is only valid in 32-bit mode (non-long mode), and the x86_64 disassembler 2296 // stops 2297 // disassembling at that point (long-mode). 2298 TEST_F(Testx86AssemblyInspectionEngine, Test32BitOnlyInstruction) { 2299 UnwindPlan::Row::RegisterLocation regloc; 2300 UnwindPlan::RowSP row_sp; 2301 AddressRange sample_range; 2302 UnwindPlan unwind_plan(eRegisterKindLLDB); 2303 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector(); 2304 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector(); 2305 2306 uint8_t data[] = { 2307 0x43, // incl $ebx --- an invalid opcode in 64-bit mode 2308 0x55, // pushl %ebp 2309 0x90 // nop 2310 }; 2311 2312 sample_range = AddressRange(0x1000, sizeof(data)); 2313 2314 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly( 2315 data, sizeof(data), sample_range, unwind_plan)); 2316 2317 row_sp = unwind_plan.GetRowForFunctionOffset(2); 2318 EXPECT_EQ(2ull, row_sp->GetOffset()); 2319 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp); 2320 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 2321 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 2322 2323 EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebp, regloc)); 2324 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 2325 EXPECT_EQ(-8, regloc.GetOffset()); 2326 2327 unwind_plan.Clear(); 2328 2329 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly( 2330 data, sizeof(data), sample_range, unwind_plan)); 2331 2332 row_sp = unwind_plan.GetRowForFunctionOffset(2); 2333 EXPECT_EQ(0ull, row_sp->GetOffset()); 2334 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 2335 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 2336 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 2337 2338 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc)); 2339 } 2340