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