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