1 //===-- Testx86AssemblyInspectionEngine.cpp ---------------------------*- C++ 2 //-*-===// 3 4 // 5 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 6 // See https://llvm.org/LICENSE.txt for license information. 7 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 8 // 9 //===----------------------------------------------------------------------===// 10 11 #include "gtest/gtest.h" 12 13 #include <memory> 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/Symbol/UnwindPlan.h" 20 #include "lldb/Utility/ArchSpec.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::FAValue &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, TestPushRBPWithREX) { 1420 UnwindPlan::Row::RegisterLocation regloc; 1421 UnwindPlan::RowSP row_sp; 1422 1423 uint8_t data[] = { 1424 0x40, 0x55, // pushq %rbp 1425 0x90 // nop 1426 }; 1427 1428 AddressRange sample_range(0x1000, sizeof(data)); 1429 UnwindPlan unwind_plan(eRegisterKindLLDB); 1430 1431 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector(); 1432 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly( 1433 data, sizeof(data), sample_range, unwind_plan)); 1434 1435 row_sp = unwind_plan.GetRowForFunctionOffset(2); 1436 1437 EXPECT_EQ(2ull, row_sp->GetOffset()); 1438 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1439 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1440 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); 1441 1442 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbp, regloc)); 1443 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 1444 EXPECT_EQ(-16, regloc.GetOffset()); 1445 } 1446 1447 TEST_F(Testx86AssemblyInspectionEngine, TestPushESI) { 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 0x56, // pushl %esi 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_esi, regloc)); 1471 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 1472 EXPECT_EQ(-8, regloc.GetOffset()); 1473 } 1474 1475 TEST_F(Testx86AssemblyInspectionEngine, TestPushEDI) { 1476 UnwindPlan::Row::RegisterLocation regloc; 1477 UnwindPlan::RowSP row_sp; 1478 AddressRange sample_range; 1479 UnwindPlan unwind_plan(eRegisterKindLLDB); 1480 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector(); 1481 1482 uint8_t data[] = { 1483 0x57, // pushl %edi 1484 0x90 // nop 1485 }; 1486 1487 sample_range = AddressRange(0x1000, sizeof(data)); 1488 1489 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly( 1490 data, sizeof(data), sample_range, unwind_plan)); 1491 1492 row_sp = unwind_plan.GetRowForFunctionOffset(1); 1493 EXPECT_EQ(1ull, row_sp->GetOffset()); 1494 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp); 1495 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1496 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 1497 1498 EXPECT_TRUE(row_sp->GetRegisterInfo(k_edi, regloc)); 1499 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 1500 EXPECT_EQ(-8, regloc.GetOffset()); 1501 } 1502 1503 TEST_F(Testx86AssemblyInspectionEngine, TestMovRSPtoRBP) { 1504 UnwindPlan::Row::RegisterLocation regloc; 1505 UnwindPlan::RowSP row_sp; 1506 1507 uint8_t data64_1[] = { 1508 0x48, 0x8b, 0xec, // movq %rsp, %rbp 1509 0x90 // nop 1510 }; 1511 1512 AddressRange sample_range(0x1000, sizeof(data64_1)); 1513 UnwindPlan unwind_plan(eRegisterKindLLDB); 1514 1515 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector(); 1516 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly( 1517 data64_1, sizeof(data64_1), sample_range, unwind_plan)); 1518 1519 row_sp = unwind_plan.GetRowForFunctionOffset(3); 1520 1521 EXPECT_EQ(3ull, row_sp->GetOffset()); 1522 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp); 1523 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1524 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 1525 1526 uint8_t data64_2[] = { 1527 0x48, 0x89, 0xe5, // movq %rsp, %rbp 1528 0x90 // nop 1529 }; 1530 1531 sample_range = AddressRange(0x1000, sizeof(data64_2)); 1532 unwind_plan.Clear(); 1533 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly( 1534 data64_2, sizeof(data64_2), sample_range, unwind_plan)); 1535 1536 row_sp = unwind_plan.GetRowForFunctionOffset(3); 1537 EXPECT_EQ(3ull, row_sp->GetOffset()); 1538 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp); 1539 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1540 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 1541 1542 uint8_t data32_1[] = { 1543 0x8b, 0xec, // movl %rsp, %rbp 1544 0x90 // nop 1545 }; 1546 1547 sample_range = AddressRange(0x1000, sizeof(data32_1)); 1548 unwind_plan.Clear(); 1549 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly( 1550 data32_1, sizeof(data32_1), sample_range, unwind_plan)); 1551 1552 row_sp = unwind_plan.GetRowForFunctionOffset(2); 1553 EXPECT_EQ(2ull, row_sp->GetOffset()); 1554 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp); 1555 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1556 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 1557 1558 uint8_t data32_2[] = { 1559 0x89, 0xe5, // movl %rsp, %rbp 1560 0x90 // nop 1561 }; 1562 1563 sample_range = AddressRange(0x1000, sizeof(data32_2)); 1564 unwind_plan.Clear(); 1565 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly( 1566 data32_2, sizeof(data32_2), sample_range, unwind_plan)); 1567 1568 row_sp = unwind_plan.GetRowForFunctionOffset(2); 1569 EXPECT_EQ(2ull, row_sp->GetOffset()); 1570 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp); 1571 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1572 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 1573 } 1574 1575 TEST_F(Testx86AssemblyInspectionEngine, TestSubRSP) { 1576 UnwindPlan::Row::RegisterLocation regloc; 1577 UnwindPlan::RowSP row_sp; 1578 AddressRange sample_range; 1579 UnwindPlan unwind_plan(eRegisterKindLLDB); 1580 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector(); 1581 1582 uint8_t data1[] = { 1583 0x48, 0x81, 0xec, 0x00, 0x01, 0x00, 0x00, // subq $0x100, $rsp 1584 0x90 // nop 1585 }; 1586 1587 sample_range = AddressRange(0x1000, sizeof(data1)); 1588 1589 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly( 1590 data1, sizeof(data1), sample_range, unwind_plan)); 1591 1592 row_sp = unwind_plan.GetRowForFunctionOffset(7); 1593 EXPECT_EQ(7ull, row_sp->GetOffset()); 1594 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1595 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1596 EXPECT_EQ(264, row_sp->GetCFAValue().GetOffset()); 1597 1598 uint8_t data2[] = { 1599 0x48, 0x83, 0xec, 0x10, // subq $0x10, %rsp 1600 0x90 // nop 1601 }; 1602 1603 sample_range = AddressRange(0x1000, sizeof(data2)); 1604 1605 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly( 1606 data2, sizeof(data2), sample_range, unwind_plan)); 1607 1608 row_sp = unwind_plan.GetRowForFunctionOffset(4); 1609 EXPECT_EQ(4ull, row_sp->GetOffset()); 1610 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1611 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1612 EXPECT_EQ(24, row_sp->GetCFAValue().GetOffset()); 1613 } 1614 1615 TEST_F(Testx86AssemblyInspectionEngine, TestSubESP) { 1616 UnwindPlan::Row::RegisterLocation regloc; 1617 UnwindPlan::RowSP row_sp; 1618 AddressRange sample_range; 1619 UnwindPlan unwind_plan(eRegisterKindLLDB); 1620 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector(); 1621 1622 uint8_t data1[] = { 1623 0x81, 0xec, 0x00, 0x01, 0x00, 0x00, // subl $0x100, %esp 1624 0x90 // nop 1625 }; 1626 1627 sample_range = AddressRange(0x1000, sizeof(data1)); 1628 1629 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly( 1630 data1, sizeof(data1), sample_range, unwind_plan)); 1631 1632 row_sp = unwind_plan.GetRowForFunctionOffset(6); 1633 EXPECT_EQ(6ull, row_sp->GetOffset()); 1634 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1635 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1636 EXPECT_EQ(260, row_sp->GetCFAValue().GetOffset()); 1637 1638 uint8_t data2[] = { 1639 0x83, 0xec, 0x10, // subq $0x10, %esp 1640 0x90 // nop 1641 }; 1642 1643 sample_range = AddressRange(0x1000, sizeof(data2)); 1644 1645 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly( 1646 data2, sizeof(data2), sample_range, unwind_plan)); 1647 1648 row_sp = unwind_plan.GetRowForFunctionOffset(3); 1649 EXPECT_EQ(3ull, row_sp->GetOffset()); 1650 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1651 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1652 EXPECT_EQ(20, row_sp->GetCFAValue().GetOffset()); 1653 } 1654 1655 TEST_F(Testx86AssemblyInspectionEngine, TestAddRSP) { 1656 UnwindPlan::Row::RegisterLocation regloc; 1657 UnwindPlan::RowSP row_sp; 1658 AddressRange sample_range; 1659 UnwindPlan unwind_plan(eRegisterKindLLDB); 1660 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector(); 1661 1662 uint8_t data1[] = { 1663 0x48, 0x81, 0xc4, 0x00, 0x01, 0x00, 0x00, // addq $0x100, %rsp 1664 0x90 // nop 1665 }; 1666 1667 sample_range = AddressRange(0x1000, sizeof(data1)); 1668 1669 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly( 1670 data1, sizeof(data1), sample_range, unwind_plan)); 1671 1672 row_sp = unwind_plan.GetRowForFunctionOffset(7); 1673 EXPECT_EQ(7ull, row_sp->GetOffset()); 1674 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1675 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1676 EXPECT_EQ(8 - 256, row_sp->GetCFAValue().GetOffset()); 1677 1678 uint8_t data2[] = { 1679 0x48, 0x83, 0xc4, 0x10, // addq $0x10, %rsp 1680 0x90 // nop 1681 }; 1682 1683 sample_range = AddressRange(0x1000, sizeof(data2)); 1684 1685 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly( 1686 data2, sizeof(data2), sample_range, unwind_plan)); 1687 1688 row_sp = unwind_plan.GetRowForFunctionOffset(4); 1689 EXPECT_EQ(4ull, row_sp->GetOffset()); 1690 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1691 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1692 EXPECT_EQ(8 - 16, row_sp->GetCFAValue().GetOffset()); 1693 } 1694 1695 TEST_F(Testx86AssemblyInspectionEngine, TestAddESP) { 1696 UnwindPlan::Row::RegisterLocation regloc; 1697 UnwindPlan::RowSP row_sp; 1698 AddressRange sample_range; 1699 UnwindPlan unwind_plan(eRegisterKindLLDB); 1700 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector(); 1701 1702 uint8_t data1[] = { 1703 0x81, 0xc4, 0x00, 0x01, 0x00, 0x00, // addl $0x100, %esp 1704 0x90 // nop 1705 }; 1706 1707 sample_range = AddressRange(0x1000, sizeof(data1)); 1708 1709 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly( 1710 data1, sizeof(data1), sample_range, unwind_plan)); 1711 1712 row_sp = unwind_plan.GetRowForFunctionOffset(6); 1713 EXPECT_EQ(6ull, row_sp->GetOffset()); 1714 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1715 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1716 EXPECT_EQ(4 - 256, row_sp->GetCFAValue().GetOffset()); 1717 1718 uint8_t data2[] = { 1719 0x83, 0xc4, 0x10, // addq $0x10, %esp 1720 0x90 // nop 1721 }; 1722 1723 sample_range = AddressRange(0x1000, sizeof(data2)); 1724 1725 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly( 1726 data2, sizeof(data2), sample_range, unwind_plan)); 1727 1728 row_sp = unwind_plan.GetRowForFunctionOffset(3); 1729 EXPECT_EQ(3ull, row_sp->GetOffset()); 1730 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1731 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1732 EXPECT_EQ(4 - 16, row_sp->GetCFAValue().GetOffset()); 1733 } 1734 1735 // FIXME add test for lea_rsp_pattern_p 1736 1737 TEST_F(Testx86AssemblyInspectionEngine, TestPopRBX) { 1738 UnwindPlan::Row::RegisterLocation regloc; 1739 UnwindPlan::RowSP row_sp; 1740 AddressRange sample_range; 1741 UnwindPlan unwind_plan(eRegisterKindLLDB); 1742 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector(); 1743 1744 uint8_t data[] = { 1745 0x53, // pushq %rbx 1746 0x5b, // popq %rbx 1747 0x90 // nop 1748 }; 1749 1750 sample_range = AddressRange(0x1000, sizeof(data)); 1751 1752 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 1753 data, sizeof(data), sample_range, unwind_plan)); 1754 1755 row_sp = unwind_plan.GetRowForFunctionOffset(2); 1756 EXPECT_EQ(2ull, row_sp->GetOffset()); 1757 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1758 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1759 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 1760 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbx, regloc)); 1761 } 1762 1763 TEST_F(Testx86AssemblyInspectionEngine, TestPopRBP) { 1764 UnwindPlan::Row::RegisterLocation regloc; 1765 UnwindPlan::RowSP row_sp; 1766 AddressRange sample_range; 1767 UnwindPlan unwind_plan(eRegisterKindLLDB); 1768 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector(); 1769 1770 uint8_t data[] = { 1771 0x55, // pushq %rbp 1772 0x5d, // popq %rbp 1773 0x90 // nop 1774 }; 1775 1776 sample_range = AddressRange(0x1000, sizeof(data)); 1777 1778 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 1779 data, sizeof(data), sample_range, unwind_plan)); 1780 1781 row_sp = unwind_plan.GetRowForFunctionOffset(2); 1782 EXPECT_EQ(2ull, row_sp->GetOffset()); 1783 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1784 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1785 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 1786 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc)); 1787 } 1788 1789 TEST_F(Testx86AssemblyInspectionEngine, TestPopR12) { 1790 UnwindPlan::Row::RegisterLocation regloc; 1791 UnwindPlan::RowSP row_sp; 1792 AddressRange sample_range; 1793 UnwindPlan unwind_plan(eRegisterKindLLDB); 1794 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector(); 1795 1796 uint8_t data[] = { 1797 0x41, 0x54, // pushq %r12 1798 0x41, 0x5c, // popq %r12 1799 0x90 // nop 1800 }; 1801 1802 sample_range = AddressRange(0x1000, sizeof(data)); 1803 1804 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 1805 data, sizeof(data), sample_range, unwind_plan)); 1806 1807 row_sp = unwind_plan.GetRowForFunctionOffset(4); 1808 EXPECT_EQ(4ull, row_sp->GetOffset()); 1809 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1810 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1811 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 1812 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r12, regloc)); 1813 } 1814 1815 TEST_F(Testx86AssemblyInspectionEngine, TestPopR13) { 1816 UnwindPlan::Row::RegisterLocation regloc; 1817 UnwindPlan::RowSP row_sp; 1818 AddressRange sample_range; 1819 UnwindPlan unwind_plan(eRegisterKindLLDB); 1820 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector(); 1821 1822 uint8_t data[] = { 1823 0x41, 0x55, // pushq %r13 1824 0x41, 0x5d, // popq %r13 1825 0x90 // nop 1826 }; 1827 1828 sample_range = AddressRange(0x1000, sizeof(data)); 1829 1830 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 1831 data, sizeof(data), sample_range, unwind_plan)); 1832 1833 row_sp = unwind_plan.GetRowForFunctionOffset(4); 1834 EXPECT_EQ(4ull, row_sp->GetOffset()); 1835 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1836 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1837 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 1838 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r13, regloc)); 1839 } 1840 1841 TEST_F(Testx86AssemblyInspectionEngine, TestPopR14) { 1842 UnwindPlan::Row::RegisterLocation regloc; 1843 UnwindPlan::RowSP row_sp; 1844 AddressRange sample_range; 1845 UnwindPlan unwind_plan(eRegisterKindLLDB); 1846 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector(); 1847 1848 uint8_t data[] = { 1849 0x41, 0x56, // pushq %r14 1850 0x41, 0x5e, // popq %r14 1851 0x90 // nop 1852 }; 1853 1854 sample_range = AddressRange(0x1000, sizeof(data)); 1855 1856 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 1857 data, sizeof(data), sample_range, unwind_plan)); 1858 1859 row_sp = unwind_plan.GetRowForFunctionOffset(4); 1860 EXPECT_EQ(4ull, row_sp->GetOffset()); 1861 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1862 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1863 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 1864 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r14, regloc)); 1865 } 1866 1867 TEST_F(Testx86AssemblyInspectionEngine, TestPopR15) { 1868 UnwindPlan::Row::RegisterLocation regloc; 1869 UnwindPlan::RowSP row_sp; 1870 AddressRange sample_range; 1871 UnwindPlan unwind_plan(eRegisterKindLLDB); 1872 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector(); 1873 1874 uint8_t data[] = { 1875 0x41, 0x57, // pushq %r15 1876 0x41, 0x5f, // popq %r15 1877 0x90 // nop 1878 }; 1879 1880 sample_range = AddressRange(0x1000, sizeof(data)); 1881 1882 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 1883 data, sizeof(data), sample_range, unwind_plan)); 1884 1885 row_sp = unwind_plan.GetRowForFunctionOffset(4); 1886 EXPECT_EQ(4ull, row_sp->GetOffset()); 1887 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1888 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1889 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 1890 EXPECT_FALSE(row_sp->GetRegisterInfo(k_r15, regloc)); 1891 } 1892 1893 TEST_F(Testx86AssemblyInspectionEngine, TestPopEBX) { 1894 UnwindPlan::Row::RegisterLocation regloc; 1895 UnwindPlan::RowSP row_sp; 1896 AddressRange sample_range; 1897 UnwindPlan unwind_plan(eRegisterKindLLDB); 1898 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector(); 1899 1900 uint8_t data[] = { 1901 0x53, // pushl %ebx 1902 0x5b, // popl %ebx 1903 0x90 // nop 1904 }; 1905 1906 sample_range = AddressRange(0x1000, sizeof(data)); 1907 1908 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 1909 data, sizeof(data), sample_range, unwind_plan)); 1910 1911 row_sp = unwind_plan.GetRowForFunctionOffset(2); 1912 EXPECT_EQ(2ull, row_sp->GetOffset()); 1913 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1914 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1915 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset()); 1916 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebx, regloc)); 1917 } 1918 1919 TEST_F(Testx86AssemblyInspectionEngine, TestPopEBP) { 1920 UnwindPlan::Row::RegisterLocation regloc; 1921 UnwindPlan::RowSP row_sp; 1922 AddressRange sample_range; 1923 UnwindPlan unwind_plan(eRegisterKindLLDB); 1924 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector(); 1925 1926 uint8_t data[] = { 1927 0x55, // pushl %ebp 1928 0x5d, // popl %ebp 1929 0x90 // nop 1930 }; 1931 1932 sample_range = AddressRange(0x1000, sizeof(data)); 1933 1934 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 1935 data, sizeof(data), sample_range, unwind_plan)); 1936 1937 row_sp = unwind_plan.GetRowForFunctionOffset(2); 1938 EXPECT_EQ(2ull, row_sp->GetOffset()); 1939 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1940 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1941 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset()); 1942 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc)); 1943 } 1944 1945 TEST_F(Testx86AssemblyInspectionEngine, TestPopRBPWithREX) { 1946 UnwindPlan::Row::RegisterLocation regloc; 1947 UnwindPlan::RowSP row_sp; 1948 AddressRange sample_range; 1949 UnwindPlan unwind_plan(eRegisterKindLLDB); 1950 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector(); 1951 1952 uint8_t data[] = { 1953 0x40, 0x55, // pushq %rbp 1954 0x40, 0x5d, // popq %rbp 1955 0x90 // nop 1956 }; 1957 1958 sample_range = AddressRange(0x1000, sizeof(data)); 1959 1960 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 1961 data, sizeof(data), sample_range, unwind_plan)); 1962 1963 row_sp = unwind_plan.GetRowForFunctionOffset(4); 1964 EXPECT_EQ(4ull, row_sp->GetOffset()); 1965 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1966 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1967 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 1968 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc)); 1969 } 1970 1971 TEST_F(Testx86AssemblyInspectionEngine, TestPopESI) { 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 0x56, // pushl %esi 1980 0x5e, // popl %esi 1981 0x90 // nop 1982 }; 1983 1984 sample_range = AddressRange(0x1000, sizeof(data)); 1985 1986 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 1987 data, sizeof(data), sample_range, unwind_plan)); 1988 1989 row_sp = unwind_plan.GetRowForFunctionOffset(2); 1990 EXPECT_EQ(2ull, row_sp->GetOffset()); 1991 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 1992 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 1993 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset()); 1994 EXPECT_FALSE(row_sp->GetRegisterInfo(k_esi, regloc)); 1995 } 1996 1997 TEST_F(Testx86AssemblyInspectionEngine, TestPopEDI) { 1998 UnwindPlan::Row::RegisterLocation regloc; 1999 UnwindPlan::RowSP row_sp; 2000 AddressRange sample_range; 2001 UnwindPlan unwind_plan(eRegisterKindLLDB); 2002 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector(); 2003 2004 uint8_t data[] = { 2005 0x57, // pushl %edi 2006 0x5f, // popl %edi 2007 0x90 // nop 2008 }; 2009 2010 sample_range = AddressRange(0x1000, sizeof(data)); 2011 2012 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 2013 data, sizeof(data), sample_range, unwind_plan)); 2014 2015 row_sp = unwind_plan.GetRowForFunctionOffset(2); 2016 EXPECT_EQ(2ull, row_sp->GetOffset()); 2017 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 2018 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 2019 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset()); 2020 EXPECT_FALSE(row_sp->GetRegisterInfo(k_edi, regloc)); 2021 } 2022 2023 // We don't track these registers, but make sure the CFA address is updated 2024 // if we're defining the CFA in term of esp. 2025 TEST_F(Testx86AssemblyInspectionEngine, Testi386IgnoredRegisters) { 2026 UnwindPlan::Row::RegisterLocation regloc; 2027 UnwindPlan::RowSP row_sp; 2028 AddressRange sample_range; 2029 UnwindPlan unwind_plan(eRegisterKindLLDB); 2030 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector(); 2031 2032 uint8_t data[] = { 2033 0x0e, // push cs 2034 0x16, // push ss 2035 0x1e, // push ds 2036 0x06, // push es 2037 2038 0x07, // pop es 2039 0x1f, // pop ds 2040 0x17, // pop ss 2041 2042 0x90 // nop 2043 }; 2044 2045 sample_range = AddressRange(0x1000, sizeof(data)); 2046 2047 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 2048 data, sizeof(data), sample_range, unwind_plan)); 2049 2050 row_sp = unwind_plan.GetRowForFunctionOffset(4); 2051 EXPECT_EQ(4ull, row_sp->GetOffset()); 2052 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 2053 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 2054 EXPECT_EQ(20, row_sp->GetCFAValue().GetOffset()); 2055 2056 row_sp = unwind_plan.GetRowForFunctionOffset(7); 2057 EXPECT_EQ(7ull, row_sp->GetOffset()); 2058 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 2059 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 2060 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 2061 } 2062 2063 TEST_F(Testx86AssemblyInspectionEngine, TestLEAVE) { 2064 UnwindPlan::Row::RegisterLocation regloc; 2065 UnwindPlan::RowSP row_sp; 2066 AddressRange sample_range; 2067 UnwindPlan unwind_plan(eRegisterKindLLDB); 2068 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector(); 2069 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector(); 2070 2071 uint8_t data[] = { 2072 0x55, // push %rbp/ebp 2073 0xc9, // leave 2074 0x90 // nop 2075 }; 2076 2077 sample_range = AddressRange(0x1000, sizeof(data)); 2078 2079 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly( 2080 data, sizeof(data), sample_range, unwind_plan)); 2081 2082 row_sp = unwind_plan.GetRowForFunctionOffset(2); 2083 EXPECT_EQ(2ull, row_sp->GetOffset()); 2084 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 2085 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 2086 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 2087 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc)); 2088 2089 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly( 2090 data, sizeof(data), sample_range, unwind_plan)); 2091 2092 row_sp = unwind_plan.GetRowForFunctionOffset(2); 2093 EXPECT_EQ(2ull, row_sp->GetOffset()); 2094 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 2095 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 2096 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset()); 2097 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc)); 2098 } 2099 2100 // In i386, which lacks pc-relative addressing, a common code sequence 2101 // is to call the next instruction (i.e. call imm32, value of 0) which 2102 // pushes the addr of the next insn on the stack, and then pop that value 2103 // into a register (the "pic base" register). 2104 TEST_F(Testx86AssemblyInspectionEngine, TestCALLNextInsn) { 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 0xe8, 0x00, 0x00, 0x00, 0x00, // call 0 2113 0x90 // nop 2114 }; 2115 2116 sample_range = AddressRange(0x1000, sizeof(data)); 2117 2118 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly( 2119 data, sizeof(data), sample_range, unwind_plan)); 2120 2121 row_sp = unwind_plan.GetRowForFunctionOffset(5); 2122 EXPECT_EQ(5ull, row_sp->GetOffset()); 2123 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 2124 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 2125 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 2126 EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc)); 2127 } 2128 2129 TEST_F(Testx86AssemblyInspectionEngine, TestSpillRegToStackViaMOVx86_64) { 2130 UnwindPlan::Row::RegisterLocation regloc; 2131 UnwindPlan::RowSP row_sp; 2132 AddressRange sample_range; 2133 UnwindPlan unwind_plan(eRegisterKindLLDB); 2134 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector(); 2135 2136 uint8_t data[] = { 2137 0x55, // pushq %rbp 2138 0x48, 0x89, 0xe5, // movq %rsp, %rbp 2139 0x4c, 0x89, 0x75, 0xc0, // movq %r14, -0x40(%rbp) 2140 0x4c, 0x89, 0xbd, 0x28, 0xfa, 0xff, 0xff, // movq %r15, -0x5d8(%rbp) 2141 0x48, 0x89, 0x5d, 0xb8, // movq %rbx, -0x48(%rbp) 2142 0x90 // nop 2143 }; 2144 2145 sample_range = AddressRange(0x1000, sizeof(data)); 2146 2147 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly( 2148 data, sizeof(data), sample_range, unwind_plan)); 2149 2150 row_sp = unwind_plan.GetRowForFunctionOffset(19); 2151 EXPECT_EQ(19ull, row_sp->GetOffset()); 2152 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp); 2153 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); 2154 2155 EXPECT_TRUE(row_sp->GetRegisterInfo(k_r14, regloc)); 2156 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 2157 EXPECT_EQ(-80, regloc.GetOffset()); 2158 2159 EXPECT_TRUE(row_sp->GetRegisterInfo(k_r15, regloc)); 2160 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 2161 EXPECT_EQ(-1512, regloc.GetOffset()); 2162 2163 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbx, regloc)); 2164 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 2165 EXPECT_EQ(-88, regloc.GetOffset()); 2166 } 2167 2168 TEST_F(Testx86AssemblyInspectionEngine, TestSpillRegToStackViaMOVi386) { 2169 UnwindPlan::Row::RegisterLocation regloc; 2170 UnwindPlan::RowSP row_sp; 2171 AddressRange sample_range; 2172 UnwindPlan unwind_plan(eRegisterKindLLDB); 2173 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector(); 2174 2175 uint8_t data[] = { 2176 0x55, // pushl %ebp 2177 0x89, 0xe5, // movl %esp, %ebp 2178 0x89, 0x9d, 0xb0, 0xfe, 0xff, 0xff, // movl %ebx, -0x150(%ebp) 2179 0x89, 0x75, 0xe0, // movl %esi, -0x20(%ebp) 2180 0x90 // nop 2181 }; 2182 2183 sample_range = AddressRange(0x1000, sizeof(data)); 2184 2185 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly( 2186 data, sizeof(data), sample_range, unwind_plan)); 2187 2188 row_sp = unwind_plan.GetRowForFunctionOffset(12); 2189 EXPECT_EQ(12ull, row_sp->GetOffset()); 2190 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp); 2191 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 2192 2193 EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebx, regloc)); 2194 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 2195 EXPECT_EQ(-344, regloc.GetOffset()); 2196 2197 EXPECT_TRUE(row_sp->GetRegisterInfo(k_esi, regloc)); 2198 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 2199 EXPECT_EQ(-40, regloc.GetOffset()); 2200 } 2201 2202 TEST_F(Testx86AssemblyInspectionEngine, TestSimplex86_64Augmented) { 2203 UnwindPlan::Row::RegisterLocation regloc; 2204 UnwindPlan::RowSP row_sp; 2205 AddressRange sample_range; 2206 UnwindPlan unwind_plan(eRegisterKindLLDB); 2207 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector(); 2208 2209 uint8_t data[] = { 2210 0x55, // pushq %rbp 2211 0x48, 0x89, 0xe5, // movq %rsp, %rbp 2212 2213 // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite 2214 // has a bug where it can't augment a function that is just 2215 // prologue+epilogue - it needs at least one other instruction 2216 // in between. 2217 0x90, // nop 2218 2219 0x5d, // popq %rbp 2220 0xc3 // retq 2221 }; 2222 2223 sample_range = AddressRange(0x1000, sizeof(data)); 2224 2225 unwind_plan.SetSourceName("unit testing hand-created unwind plan"); 2226 unwind_plan.SetPlanValidAddressRange(sample_range); 2227 unwind_plan.SetRegisterKind(eRegisterKindLLDB); 2228 2229 row_sp = std::make_shared<UnwindPlan::Row>(); 2230 2231 // Describe offset 0 2232 row_sp->SetOffset(0); 2233 row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_rsp, 8); 2234 2235 regloc.SetAtCFAPlusOffset(-8); 2236 row_sp->SetRegisterInfo(k_rip, regloc); 2237 2238 unwind_plan.AppendRow(row_sp); 2239 2240 // Allocate a new Row, populate it with the existing Row contents. 2241 UnwindPlan::Row *new_row = new UnwindPlan::Row; 2242 *new_row = *row_sp.get(); 2243 row_sp.reset(new_row); 2244 2245 // Describe offset 1 2246 row_sp->SetOffset(1); 2247 row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_rsp, 16); 2248 regloc.SetAtCFAPlusOffset(-16); 2249 row_sp->SetRegisterInfo(k_rbp, regloc); 2250 unwind_plan.AppendRow(row_sp); 2251 2252 // Allocate a new Row, populate it with the existing Row contents. 2253 new_row = new UnwindPlan::Row; 2254 *new_row = *row_sp.get(); 2255 row_sp.reset(new_row); 2256 2257 // Describe offset 4 2258 row_sp->SetOffset(4); 2259 row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_rbp, 16); 2260 unwind_plan.AppendRow(row_sp); 2261 2262 RegisterContextSP reg_ctx_sp; 2263 EXPECT_TRUE(engine64->AugmentUnwindPlanFromCallSite( 2264 data, sizeof(data), sample_range, unwind_plan, reg_ctx_sp)); 2265 2266 row_sp = unwind_plan.GetRowForFunctionOffset(6); 2267 EXPECT_EQ(6ull, row_sp->GetOffset()); 2268 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 2269 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 2270 2271 // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite 2272 // doesn't track register restores (pop'ing a reg value back from 2273 // the stack) - it was just written to make stepping work correctly. 2274 // Technically we should be able to do the following test, but it 2275 // won't work today - the unwind plan will still say that the caller's 2276 // rbp is on the stack. 2277 // EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc)); 2278 } 2279 2280 TEST_F(Testx86AssemblyInspectionEngine, TestSimplei386ugmented) { 2281 UnwindPlan::Row::RegisterLocation regloc; 2282 UnwindPlan::RowSP row_sp; 2283 AddressRange sample_range; 2284 UnwindPlan unwind_plan(eRegisterKindLLDB); 2285 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector(); 2286 2287 uint8_t data[] = { 2288 0x55, // pushl %ebp 2289 0x89, 0xe5, // movl %esp, %ebp 2290 2291 // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite 2292 // has a bug where it can't augment a function that is just 2293 // prologue+epilogue - it needs at least one other instruction 2294 // in between. 2295 0x90, // nop 2296 2297 0x5d, // popl %ebp 2298 0xc3 // retl 2299 }; 2300 2301 sample_range = AddressRange(0x1000, sizeof(data)); 2302 2303 unwind_plan.SetSourceName("unit testing hand-created unwind plan"); 2304 unwind_plan.SetPlanValidAddressRange(sample_range); 2305 unwind_plan.SetRegisterKind(eRegisterKindLLDB); 2306 2307 row_sp = std::make_shared<UnwindPlan::Row>(); 2308 2309 // Describe offset 0 2310 row_sp->SetOffset(0); 2311 row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_esp, 4); 2312 2313 regloc.SetAtCFAPlusOffset(-4); 2314 row_sp->SetRegisterInfo(k_eip, regloc); 2315 2316 unwind_plan.AppendRow(row_sp); 2317 2318 // Allocate a new Row, populate it with the existing Row contents. 2319 UnwindPlan::Row *new_row = new UnwindPlan::Row; 2320 *new_row = *row_sp.get(); 2321 row_sp.reset(new_row); 2322 2323 // Describe offset 1 2324 row_sp->SetOffset(1); 2325 row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_esp, 8); 2326 regloc.SetAtCFAPlusOffset(-8); 2327 row_sp->SetRegisterInfo(k_ebp, regloc); 2328 unwind_plan.AppendRow(row_sp); 2329 2330 // Allocate a new Row, populate it with the existing Row contents. 2331 new_row = new UnwindPlan::Row; 2332 *new_row = *row_sp.get(); 2333 row_sp.reset(new_row); 2334 2335 // Describe offset 3 2336 row_sp->SetOffset(3); 2337 row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_ebp, 8); 2338 unwind_plan.AppendRow(row_sp); 2339 2340 RegisterContextSP reg_ctx_sp; 2341 EXPECT_TRUE(engine32->AugmentUnwindPlanFromCallSite( 2342 data, sizeof(data), sample_range, unwind_plan, reg_ctx_sp)); 2343 2344 row_sp = unwind_plan.GetRowForFunctionOffset(5); 2345 EXPECT_EQ(5ull, row_sp->GetOffset()); 2346 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp); 2347 EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset()); 2348 2349 // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite 2350 // doesn't track register restores (pop'ing a reg value back from 2351 // the stack) - it was just written to make stepping work correctly. 2352 // Technically we should be able to do the following test, but it 2353 // won't work today - the unwind plan will still say that the caller's 2354 // ebp is on the stack. 2355 // EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc)); 2356 } 2357 2358 // Check that the i386 disassembler disassembles past an opcode that 2359 // is only valid in 32-bit mode (non-long mode), and the x86_64 disassembler 2360 // stops 2361 // disassembling at that point (long-mode). 2362 TEST_F(Testx86AssemblyInspectionEngine, Test32BitOnlyInstruction) { 2363 UnwindPlan::Row::RegisterLocation regloc; 2364 UnwindPlan::RowSP row_sp; 2365 AddressRange sample_range; 2366 UnwindPlan unwind_plan(eRegisterKindLLDB); 2367 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector(); 2368 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector(); 2369 2370 uint8_t data[] = { 2371 0x43, // incl $ebx --- an invalid opcode in 64-bit mode 2372 0x55, // pushl %ebp 2373 0x90 // nop 2374 }; 2375 2376 sample_range = AddressRange(0x1000, sizeof(data)); 2377 2378 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly( 2379 data, sizeof(data), sample_range, unwind_plan)); 2380 2381 row_sp = unwind_plan.GetRowForFunctionOffset(2); 2382 EXPECT_EQ(2ull, row_sp->GetOffset()); 2383 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp); 2384 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 2385 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 2386 2387 EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebp, regloc)); 2388 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 2389 EXPECT_EQ(-8, regloc.GetOffset()); 2390 2391 unwind_plan.Clear(); 2392 2393 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly( 2394 data, sizeof(data), sample_range, unwind_plan)); 2395 2396 row_sp = unwind_plan.GetRowForFunctionOffset(2); 2397 EXPECT_EQ(0ull, row_sp->GetOffset()); 2398 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 2399 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 2400 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 2401 2402 EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc)); 2403 } 2404 2405 TEST_F(Testx86AssemblyInspectionEngine, TestStackRealign8BitDisp_i386) { 2406 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector(); 2407 2408 uint8_t data[] = { 2409 0x55, // pushl %ebp 2410 0x89, 0xe5, // movl %esp, %ebp 2411 0x53, // pushl %ebx 2412 0x83, 0xe4, 0xf0, // andl $-16, %esp 2413 0x83, 0xec, 0x10, // subl $16, %esp 2414 0x8d, 0x65, 0xfc, // leal -4(%ebp), %esp 2415 0x5b, // popl %ebx 2416 0x5d, // popl %ebp 2417 0xc3, // retl 2418 }; 2419 2420 AddressRange sample_range(0x1000, sizeof(data)); 2421 UnwindPlan plan(eRegisterKindLLDB); 2422 ASSERT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(data, sizeof(data), 2423 sample_range, plan)); 2424 2425 UnwindPlan::Row::FAValue esp_plus_4, esp_plus_8, ebp_plus_8; 2426 esp_plus_4.SetIsRegisterPlusOffset(k_esp, 4); 2427 esp_plus_8.SetIsRegisterPlusOffset(k_esp, 8); 2428 ebp_plus_8.SetIsRegisterPlusOffset(k_ebp, 8); 2429 2430 EXPECT_EQ(esp_plus_4, plan.GetRowForFunctionOffset(0)->GetCFAValue()); 2431 EXPECT_EQ(esp_plus_8, plan.GetRowForFunctionOffset(1)->GetCFAValue()); 2432 for (size_t i = 3; i < sizeof(data) - 2; ++i) 2433 EXPECT_EQ(ebp_plus_8, plan.GetRowForFunctionOffset(i)->GetCFAValue()) 2434 << "i: " << i; 2435 EXPECT_EQ(esp_plus_4, 2436 plan.GetRowForFunctionOffset(sizeof(data) - 1)->GetCFAValue()); 2437 } 2438 2439 TEST_F(Testx86AssemblyInspectionEngine, TestStackRealign32BitDisp_x86_64) { 2440 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector(); 2441 2442 uint8_t data[] = { 2443 0x55, // pushq %rbp 2444 0x48, 0x89, 0xe5, // movq %rsp, %rbp 2445 0x53, // pushl %rbx 2446 0x48, 0x83, 0xe4, 0xf0, // andq $-16, %rsp 2447 0x48, 0x81, 0xec, 0x00, 0x01, 0x00, 0x00, // subq $256, %rsp 2448 0x48, 0x8d, 0x65, 0xf8, // leaq -8(%rbp), %rsp 2449 0x5b, // popq %rbx 2450 0x5d, // popq %rbp 2451 0xc3, // retq 2452 }; 2453 2454 AddressRange sample_range(0x1000, sizeof(data)); 2455 UnwindPlan plan(eRegisterKindLLDB); 2456 ASSERT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(data, sizeof(data), 2457 sample_range, plan)); 2458 2459 UnwindPlan::Row::FAValue rsp_plus_8, rsp_plus_16, rbp_plus_16; 2460 rsp_plus_8.SetIsRegisterPlusOffset(k_rsp, 8); 2461 rsp_plus_16.SetIsRegisterPlusOffset(k_rsp, 16); 2462 rbp_plus_16.SetIsRegisterPlusOffset(k_rbp, 16); 2463 2464 EXPECT_EQ(rsp_plus_8, plan.GetRowForFunctionOffset(0)->GetCFAValue()); 2465 EXPECT_EQ(rsp_plus_16, plan.GetRowForFunctionOffset(1)->GetCFAValue()); 2466 for (size_t i = 4; i < sizeof(data) - 2; ++i) 2467 EXPECT_EQ(rbp_plus_16, plan.GetRowForFunctionOffset(i)->GetCFAValue()) 2468 << "i: " << i; 2469 EXPECT_EQ(rsp_plus_8, 2470 plan.GetRowForFunctionOffset(sizeof(data) - 1)->GetCFAValue()); 2471 } 2472 2473 TEST_F(Testx86AssemblyInspectionEngine, TestStackRealignMSVC_i386) { 2474 std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector(); 2475 2476 uint8_t data[] = { 2477 0x53, // offset 00 -- pushl %ebx 2478 0x8b, 0xdc, // offset 01 -- movl %esp, %ebx 2479 0x83, 0xec, 0x08, // offset 03 -- subl $8, %esp 2480 0x81, 0xe4, 0x00, 0xff, 0xff, 0xff, // offset 06 -- andl $-256, %esp 2481 0x83, 0xc4, 0x04, // offset 12 -- addl $4, %esp 2482 0x55, // offset 15 -- pushl %ebp 2483 0x8b, 0xec, // offset 16 -- movl %esp, %ebp 2484 0x81, 0xec, 0x00, 0x02, 0x00, 0x00, // offset 18 -- subl $512, %esp 2485 0x89, 0x7d, 0xfc, // offset 24 -- movl %edi, -4(%ebp) 2486 0x8b, 0xe5, // offset 27 -- movl %ebp, %esp 2487 0x5d, // offset 29 -- popl %ebp 2488 0x8b, 0xe3, // offset 30 -- movl %ebx, %esp 2489 0x5b, // offset 32 -- popl %ebx 2490 0xc3 // offset 33 -- retl 2491 }; 2492 2493 AddressRange sample_range(0x1000, sizeof(data)); 2494 UnwindPlan plan(eRegisterKindLLDB); 2495 ASSERT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(data, sizeof(data), 2496 sample_range, plan)); 2497 2498 UnwindPlan::Row::FAValue esp_minus_4, esp_plus_0, esp_plus_4, esp_plus_8, 2499 ebx_plus_8, ebp_plus_0; 2500 esp_minus_4.SetIsRegisterPlusOffset(k_esp, -4); 2501 esp_plus_0.SetIsRegisterPlusOffset(k_esp, 0); 2502 esp_plus_4.SetIsRegisterPlusOffset(k_esp, 4); 2503 esp_plus_8.SetIsRegisterPlusOffset(k_esp, 8); 2504 ebx_plus_8.SetIsRegisterPlusOffset(k_ebx, 8); 2505 ebp_plus_0.SetIsRegisterPlusOffset(k_ebp, 0); 2506 2507 // Test CFA 2508 EXPECT_EQ(esp_plus_4, plan.GetRowForFunctionOffset(0)->GetCFAValue()); 2509 EXPECT_EQ(esp_plus_8, plan.GetRowForFunctionOffset(1)->GetCFAValue()); 2510 for (size_t i = 3; i < 33; ++i) 2511 EXPECT_EQ(ebx_plus_8, plan.GetRowForFunctionOffset(i)->GetCFAValue()) 2512 << "i: " << i; 2513 EXPECT_EQ(esp_plus_4, plan.GetRowForFunctionOffset(33)->GetCFAValue()); 2514 2515 // Test AFA 2516 EXPECT_EQ(esp_plus_0, plan.GetRowForFunctionOffset(12)->GetAFAValue()); 2517 EXPECT_EQ(esp_minus_4, plan.GetRowForFunctionOffset(15)->GetAFAValue()); 2518 EXPECT_EQ(esp_plus_0, plan.GetRowForFunctionOffset(16)->GetAFAValue()); 2519 for (size_t i = 18; i < 30; ++i) 2520 EXPECT_EQ(ebp_plus_0, plan.GetRowForFunctionOffset(i)->GetAFAValue()) 2521 << "i: " << i; 2522 EXPECT_EQ(esp_minus_4, plan.GetRowForFunctionOffset(30)->GetAFAValue()); 2523 2524 // Test saved register 2525 UnwindPlan::Row::RegisterLocation reg_loc; 2526 EXPECT_TRUE( 2527 plan.GetRowForFunctionOffset(27)->GetRegisterInfo(k_edi, reg_loc)); 2528 EXPECT_TRUE(reg_loc.IsAtAFAPlusOffset()); 2529 EXPECT_EQ(-4, reg_loc.GetOffset()); 2530 } 2531 2532 // Give the disassembler random bytes to test that it doesn't exceed 2533 // the bounds of the array when run under clang's address sanitizer. 2534 TEST_F(Testx86AssemblyInspectionEngine, TestDisassemblyJunkBytes) { 2535 AddressRange sample_range; 2536 UnwindPlan unwind_plan(eRegisterKindLLDB); 2537 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector(); 2538 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector(); 2539 2540 uint8_t data[] = { 2541 0x10, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 2542 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; 2543 2544 sample_range = AddressRange(0x1000, sizeof(data)); 2545 2546 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly( 2547 data, sizeof(data), sample_range, unwind_plan)); 2548 2549 unwind_plan.Clear(); 2550 2551 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly( 2552 data, sizeof(data), sample_range, unwind_plan)); 2553 2554 } 2555 2556 TEST_F(Testx86AssemblyInspectionEngine, TestReturnDetect) { 2557 std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector(); 2558 2559 // Single fragment with all four return forms. 2560 // We want to verify that the unwind state is reset after each ret. 2561 uint8_t data[] = { 2562 0x55, // offset 0 -- pushq %rbp 2563 0x48, 0x89, 0xe5, // offset 1 -- movq %rsp, %rbp 2564 0x31, 0xc0, // offset 4 -- xorl %eax, %eax 2565 0x5d, // offset 6 -- popq %rbp 2566 0xc3, // offset 7 -- retq 2567 0x31, 0xc0, // offset 8 -- xorl %eax, %eax 2568 0x5d, // offset 10 -- popq %rbp 2569 0xcb, // offset 11 -- retf 2570 0x31, 0xc0, // offset 12 -- xorl %eax, %eax 2571 0x5d, // offset 14 -- popq %rbp 2572 0xc2, 0x22, 0x11, // offset 15 -- retq 0x1122 2573 0x31, 0xc0, // offset 18 -- xorl %eax, %eax 2574 0x5d, // offset 20 -- popq %rbp 2575 0xca, 0x44, 0x33, // offset 21 -- retf 0x3344 2576 0x31, 0xc0, // offset 24 -- xorl %eax, %eax 2577 }; 2578 2579 AddressRange sample_range(0x1000, sizeof(data)); 2580 2581 UnwindPlan unwind_plan(eRegisterKindLLDB); 2582 EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( 2583 data, sizeof(data), sample_range, unwind_plan)); 2584 2585 // Expect following unwind rows: 2586 // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8] 2587 // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8] 2588 // 4: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8] 2589 // 7: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8] 2590 // 8: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8] 2591 // 11: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8] 2592 // 12: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8] 2593 // 15: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8] 2594 // 18: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8] 2595 // 21: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8] 2596 // 24: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8] 2597 2598 EXPECT_TRUE(unwind_plan.GetInitialCFARegister() == k_rsp); 2599 EXPECT_TRUE(unwind_plan.GetUnwindPlanValidAtAllInstructions() == 2600 eLazyBoolYes); 2601 EXPECT_TRUE(unwind_plan.GetSourcedFromCompiler() == eLazyBoolNo); 2602 2603 UnwindPlan::Row::RegisterLocation regloc; 2604 2605 // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8] 2606 UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(0); 2607 EXPECT_EQ(0ull, row_sp->GetOffset()); 2608 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 2609 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 2610 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 2611 2612 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc)); 2613 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 2614 EXPECT_EQ(-8, regloc.GetOffset()); 2615 2616 // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8] 2617 row_sp = unwind_plan.GetRowForFunctionOffset(1); 2618 EXPECT_EQ(1ull, row_sp->GetOffset()); 2619 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 2620 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 2621 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); 2622 2623 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc)); 2624 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 2625 EXPECT_EQ(-8, regloc.GetOffset()); 2626 2627 // 4: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8] 2628 row_sp = unwind_plan.GetRowForFunctionOffset(4); 2629 EXPECT_EQ(4ull, row_sp->GetOffset()); 2630 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp); 2631 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 2632 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); 2633 2634 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc)); 2635 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 2636 EXPECT_EQ(-8, regloc.GetOffset()); 2637 2638 // 7: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8] 2639 row_sp = unwind_plan.GetRowForFunctionOffset(7); 2640 EXPECT_EQ(7ull, row_sp->GetOffset()); 2641 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 2642 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 2643 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 2644 2645 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc)); 2646 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 2647 EXPECT_EQ(-8, regloc.GetOffset()); 2648 2649 // 8: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8] 2650 row_sp = unwind_plan.GetRowForFunctionOffset(8); 2651 EXPECT_EQ(8ull, row_sp->GetOffset()); 2652 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp); 2653 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 2654 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); 2655 2656 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc)); 2657 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 2658 EXPECT_EQ(-8, regloc.GetOffset()); 2659 2660 // 11: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8] 2661 row_sp = unwind_plan.GetRowForFunctionOffset(11); 2662 EXPECT_EQ(11ull, row_sp->GetOffset()); 2663 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 2664 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 2665 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 2666 2667 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc)); 2668 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 2669 EXPECT_EQ(-8, regloc.GetOffset()); 2670 2671 // 12: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8] 2672 row_sp = unwind_plan.GetRowForFunctionOffset(12); 2673 EXPECT_EQ(12ull, row_sp->GetOffset()); 2674 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp); 2675 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 2676 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); 2677 2678 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc)); 2679 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 2680 EXPECT_EQ(-8, regloc.GetOffset()); 2681 2682 // 15: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8] 2683 row_sp = unwind_plan.GetRowForFunctionOffset(15); 2684 EXPECT_EQ(15ull, row_sp->GetOffset()); 2685 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 2686 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 2687 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 2688 2689 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc)); 2690 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 2691 EXPECT_EQ(-8, regloc.GetOffset()); 2692 2693 // 18: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8] 2694 row_sp = unwind_plan.GetRowForFunctionOffset(18); 2695 EXPECT_EQ(18ull, row_sp->GetOffset()); 2696 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp); 2697 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 2698 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); 2699 2700 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc)); 2701 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 2702 EXPECT_EQ(-8, regloc.GetOffset()); 2703 2704 // 21: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8] 2705 row_sp = unwind_plan.GetRowForFunctionOffset(21); 2706 EXPECT_EQ(21ull, row_sp->GetOffset()); 2707 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 2708 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 2709 EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset()); 2710 2711 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc)); 2712 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 2713 EXPECT_EQ(-8, regloc.GetOffset()); 2714 2715 // 24: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8] 2716 row_sp = unwind_plan.GetRowForFunctionOffset(24); 2717 EXPECT_EQ(24ull, row_sp->GetOffset()); 2718 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp); 2719 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 2720 EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); 2721 2722 EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc)); 2723 EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); 2724 EXPECT_EQ(-8, regloc.GetOffset()); 2725 } 2726 2727 2728 // Test mid-function epilogues - the unwind state post-prologue 2729 // should be re-instated. 2730 2731 TEST_F(Testx86AssemblyInspectionEngine, TestDisassemblyMidFunctionEpilogues) { 2732 AddressRange sample_range; 2733 UnwindPlan unwind_plan(eRegisterKindLLDB); 2734 std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector(); 2735 std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector(); 2736 2737 uint8_t data[] = { 2738 0x55, // <+0>: pushq %rbp 2739 0x48, 0x89, 0xe5, // <+1>: movq %rsp, %rbp 2740 0x48, 0x83, 0xec, 0x70, // <+4>: subq $0x70, %rsp 2741 0x90, // <+8>: nop // prologue set up 2742 2743 0x74, 0x7, // <+9>: je 7 <+18> 2744 0x48, 0x83, 0xc4, 0x70, // <+11>: addq $0x70, %rsp 2745 0x5d, // <+15>: popq %rbp 2746 0xff, 0xe0, // <+16>: jmpq *%rax // epilogue completed 2747 2748 0x90, // <+18>: nop // prologue setup back 2749 2750 0x74, 0x7, // <+19>: je 6 <+27> 2751 0x48, 0x83, 0xc4, 0x70, // <+21>: addq $0x70, %rsp 2752 0x5d, // <+25>: popq %rbp 2753 0xc3, // <+26>: retq // epilogue completed 2754 2755 0x90, // <+27>: nop // prologue setup back 2756 2757 0x48, 0x83, 0xc4, 0x70, // <+28>: addq $0x70, %rsp 2758 0x5d, // <+32>: popq %rbp 2759 0xc3, // <+33>: retq // epilogue completed 2760 2761 }; 2762 2763 sample_range = AddressRange(0x1000, sizeof(data)); 2764 2765 int wordsize = 4; 2766 EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly( 2767 data, sizeof(data), sample_range, unwind_plan)); 2768 2769 // Check that we've unwound the stack after the first mid-function epilogue 2770 // row: CFA=esp +4 => esp=CFA+0 eip=[CFA-4] 2771 UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(16); 2772 EXPECT_EQ(16ull, row_sp->GetOffset()); 2773 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp); 2774 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 2775 EXPECT_EQ(wordsize, row_sp->GetCFAValue().GetOffset()); 2776 2777 // Check that we've reinstated the stack frame setup 2778 // unwind instructions after a jmpq *%eax 2779 // row: CFA=ebp +8 => esp=CFA+0 eip=[CFA-8] 2780 row_sp = unwind_plan.GetRowForFunctionOffset(18); 2781 EXPECT_EQ(18ull, row_sp->GetOffset()); 2782 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp); 2783 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 2784 EXPECT_EQ(wordsize * 2, row_sp->GetCFAValue().GetOffset()); 2785 2786 // Check that we've reinstated the stack frame setup 2787 // unwind instructions after a mid-function retq 2788 // row: CFA=ebp +8 => esp=CFA+0 eip=[CFA-8] 2789 row_sp = unwind_plan.GetRowForFunctionOffset(27); 2790 EXPECT_EQ(27ull, row_sp->GetOffset()); 2791 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp); 2792 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 2793 EXPECT_EQ(wordsize * 2, row_sp->GetCFAValue().GetOffset()); 2794 2795 // After last instruction in the function, verify that 2796 // the stack frame has been unwound 2797 // row: CFA=esp +4 => esp=CFA+0 eip=[CFA-4] 2798 row_sp = unwind_plan.GetRowForFunctionOffset(33); 2799 EXPECT_EQ(33ull, row_sp->GetOffset()); 2800 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp); 2801 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 2802 EXPECT_EQ(wordsize, row_sp->GetCFAValue().GetOffset()); 2803 2804 2805 unwind_plan.Clear(); 2806 2807 wordsize = 8; 2808 EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly( 2809 data, sizeof(data), sample_range, unwind_plan)); 2810 2811 // Check that we've unwound the stack after the first mid-function epilogue 2812 // row: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8] 2813 row_sp = unwind_plan.GetRowForFunctionOffset(16); 2814 EXPECT_EQ(16ull, row_sp->GetOffset()); 2815 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 2816 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 2817 EXPECT_EQ(wordsize, row_sp->GetCFAValue().GetOffset()); 2818 2819 // Check that we've reinstated the stack frame setup 2820 // unwind instructions after a jmpq *%eax 2821 // row: CFA=rbp+16 => rsp=CFA+0 rip=[CFA-16] 2822 row_sp = unwind_plan.GetRowForFunctionOffset(18); 2823 EXPECT_EQ(18ull, row_sp->GetOffset()); 2824 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp); 2825 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 2826 EXPECT_EQ(wordsize * 2, row_sp->GetCFAValue().GetOffset()); 2827 2828 // Check that we've reinstated the stack frame setup 2829 // unwind instructions after a mid-function retq 2830 // row: CFA=rbp+16 => rsp=CFA+0 rip=[CFA-16] 2831 row_sp = unwind_plan.GetRowForFunctionOffset(27); 2832 EXPECT_EQ(27ull, row_sp->GetOffset()); 2833 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp); 2834 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 2835 EXPECT_EQ(wordsize * 2, row_sp->GetCFAValue().GetOffset()); 2836 2837 // After last instruction in the function, verify that 2838 // the stack frame has been unwound 2839 // row: CFA=rsp +8 => esp=CFA+0 rip=[CFA-8] 2840 row_sp = unwind_plan.GetRowForFunctionOffset(33); 2841 EXPECT_EQ(33ull, row_sp->GetOffset()); 2842 EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); 2843 EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); 2844 EXPECT_EQ(wordsize, row_sp->GetCFAValue().GetOffset()); 2845 2846 2847 } 2848