1 /* 2 * Copyright 2012, Alex Smith, alex@alex-smith.me.uk. 3 * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de. 4 * Copyright 2011-2016, Rene Gollent, rene@gollent.com. 5 * Distributed under the terms of the MIT License. 6 */ 7 8 9 #include "ArchitectureX8664.h" 10 11 #include <new> 12 13 #include <String.h> 14 15 #include <AutoDeleter.h> 16 17 #include "CfaContext.h" 18 #include "CpuStateX8664.h" 19 #include "DisassembledCode.h" 20 #include "FunctionDebugInfo.h" 21 #include "InstructionInfo.h" 22 #include "NoOpStackFrameDebugInfo.h" 23 #include "RegisterMap.h" 24 #include "StackFrame.h" 25 #include "Statement.h" 26 #include "TeamMemory.h" 27 #include "ValueLocation.h" 28 #include "X86AssemblyLanguage.h" 29 30 #include "disasm/DisassemblerX8664.h" 31 32 #define X86_64_EXTENDED_FEATURE_AVX (1 << 28) 33 34 static const int32 kFromDwarfRegisters[] = { 35 X86_64_REGISTER_RAX, 36 X86_64_REGISTER_RDX, 37 X86_64_REGISTER_RCX, 38 X86_64_REGISTER_RBX, 39 X86_64_REGISTER_RSI, 40 X86_64_REGISTER_RDI, 41 X86_64_REGISTER_RBP, 42 X86_64_REGISTER_RSP, 43 X86_64_REGISTER_R8, 44 X86_64_REGISTER_R9, 45 X86_64_REGISTER_R10, 46 X86_64_REGISTER_R11, 47 X86_64_REGISTER_R12, 48 X86_64_REGISTER_R13, 49 X86_64_REGISTER_R14, 50 X86_64_REGISTER_R15, 51 X86_64_REGISTER_RIP, 52 X86_64_REGISTER_XMM0, 53 X86_64_REGISTER_XMM1, 54 X86_64_REGISTER_XMM2, 55 X86_64_REGISTER_XMM3, 56 X86_64_REGISTER_XMM4, 57 X86_64_REGISTER_XMM5, 58 X86_64_REGISTER_XMM6, 59 X86_64_REGISTER_XMM7, 60 X86_64_REGISTER_XMM8, 61 X86_64_REGISTER_XMM9, 62 X86_64_REGISTER_XMM10, 63 X86_64_REGISTER_XMM11, 64 X86_64_REGISTER_XMM12, 65 X86_64_REGISTER_XMM13, 66 X86_64_REGISTER_XMM14, 67 X86_64_REGISTER_XMM15, 68 X86_64_REGISTER_ST0, 69 X86_64_REGISTER_ST1, 70 X86_64_REGISTER_ST2, 71 X86_64_REGISTER_ST3, 72 X86_64_REGISTER_ST4, 73 X86_64_REGISTER_ST5, 74 X86_64_REGISTER_ST6, 75 X86_64_REGISTER_ST7, 76 X86_64_REGISTER_MM0, 77 X86_64_REGISTER_MM1, 78 X86_64_REGISTER_MM2, 79 X86_64_REGISTER_MM3, 80 X86_64_REGISTER_MM4, 81 X86_64_REGISTER_MM5, 82 X86_64_REGISTER_MM6, 83 X86_64_REGISTER_MM7, 84 -1, // rflags 85 X86_64_REGISTER_ES, 86 X86_64_REGISTER_CS, 87 X86_64_REGISTER_SS, 88 X86_64_REGISTER_DS, 89 X86_64_REGISTER_FS, 90 X86_64_REGISTER_GS, 91 }; 92 93 static const int32 kFromDwarfRegisterCount = sizeof(kFromDwarfRegisters) / 4; 94 static const uint16 kFunctionPrologueSize = 4; 95 96 97 // #pragma mark - ToDwarfRegisterMap 98 99 100 struct ArchitectureX8664::ToDwarfRegisterMap : RegisterMap { 101 ToDwarfRegisterMap() 102 { 103 // init the index array from the reverse map 104 memset(fIndices, -1, sizeof(fIndices)); 105 for (int32 i = 0; i < kFromDwarfRegisterCount; i++) { 106 if (kFromDwarfRegisters[i] >= 0) 107 fIndices[kFromDwarfRegisters[i]] = i; 108 } 109 } 110 111 virtual int32 CountRegisters() const 112 { 113 return X86_64_REGISTER_COUNT; 114 } 115 116 virtual int32 MapRegisterIndex(int32 index) const 117 { 118 return index >= 0 && index < X86_64_REGISTER_COUNT ? fIndices[index] : -1; 119 } 120 121 private: 122 int32 fIndices[X86_64_REGISTER_COUNT]; 123 }; 124 125 126 // #pragma mark - FromDwarfRegisterMap 127 128 129 struct ArchitectureX8664::FromDwarfRegisterMap : RegisterMap { 130 virtual int32 CountRegisters() const 131 { 132 return kFromDwarfRegisterCount; 133 } 134 135 virtual int32 MapRegisterIndex(int32 index) const 136 { 137 return index >= 0 && index < kFromDwarfRegisterCount 138 ? kFromDwarfRegisters[index] : -1; 139 } 140 }; 141 142 143 // #pragma mark - ArchitectureX8664 144 145 146 ArchitectureX8664::ArchitectureX8664(TeamMemory* teamMemory) 147 : 148 Architecture(teamMemory, 8, sizeof(x86_64_debug_cpu_state), false), 149 fAssemblyLanguage(NULL), 150 fToDwarfRegisterMap(NULL), 151 fFromDwarfRegisterMap(NULL) 152 { 153 } 154 155 156 ArchitectureX8664::~ArchitectureX8664() 157 { 158 if (fToDwarfRegisterMap != NULL) 159 fToDwarfRegisterMap->ReleaseReference(); 160 if (fFromDwarfRegisterMap != NULL) 161 fFromDwarfRegisterMap->ReleaseReference(); 162 if (fAssemblyLanguage != NULL) 163 fAssemblyLanguage->ReleaseReference(); 164 } 165 166 167 status_t 168 ArchitectureX8664::Init() 169 { 170 fAssemblyLanguage = new(std::nothrow) X86AssemblyLanguage; 171 if (fAssemblyLanguage == NULL) 172 return B_NO_MEMORY; 173 174 int featureFlags = 0; 175 #ifdef __x86_64__ 176 // TODO: this needs to be determined/retrieved indirectly from the 177 // target host interface, as in the remote case the CPU features may 178 // differ from those of the local CPU. 179 cpuid_info info; 180 status_t error = get_cpuid(&info, 1, 0); 181 if (error != B_OK) 182 return error; 183 184 if ((info.eax_1.extended_features & X86_64_EXTENDED_FEATURE_AVX) != 0) 185 featureFlags |= X86_64_CPU_FEATURE_FLAG_AVX; 186 #endif 187 188 try { 189 _AddIntegerRegister(X86_64_REGISTER_RIP, "rip", B_UINT64_TYPE, 190 REGISTER_TYPE_INSTRUCTION_POINTER, false); 191 _AddIntegerRegister(X86_64_REGISTER_RSP, "rsp", B_UINT64_TYPE, 192 REGISTER_TYPE_STACK_POINTER, true); 193 _AddIntegerRegister(X86_64_REGISTER_RBP, "rbp", B_UINT64_TYPE, 194 REGISTER_TYPE_GENERAL_PURPOSE, true); 195 196 _AddIntegerRegister(X86_64_REGISTER_RAX, "rax", B_UINT64_TYPE, 197 REGISTER_TYPE_GENERAL_PURPOSE, false); 198 _AddIntegerRegister(X86_64_REGISTER_RBX, "rbx", B_UINT64_TYPE, 199 REGISTER_TYPE_GENERAL_PURPOSE, true); 200 _AddIntegerRegister(X86_64_REGISTER_RCX, "rcx", B_UINT64_TYPE, 201 REGISTER_TYPE_GENERAL_PURPOSE, false); 202 _AddIntegerRegister(X86_64_REGISTER_RDX, "rdx", B_UINT64_TYPE, 203 REGISTER_TYPE_GENERAL_PURPOSE, false); 204 205 _AddIntegerRegister(X86_64_REGISTER_RSI, "rsi", B_UINT64_TYPE, 206 REGISTER_TYPE_GENERAL_PURPOSE, false); 207 _AddIntegerRegister(X86_64_REGISTER_RDI, "rdi", B_UINT64_TYPE, 208 REGISTER_TYPE_GENERAL_PURPOSE, false); 209 210 _AddIntegerRegister(X86_64_REGISTER_R8, "r8", B_UINT64_TYPE, 211 REGISTER_TYPE_GENERAL_PURPOSE, false); 212 _AddIntegerRegister(X86_64_REGISTER_R9, "r9", B_UINT64_TYPE, 213 REGISTER_TYPE_GENERAL_PURPOSE, false); 214 _AddIntegerRegister(X86_64_REGISTER_R10, "r10", B_UINT64_TYPE, 215 REGISTER_TYPE_GENERAL_PURPOSE, false); 216 _AddIntegerRegister(X86_64_REGISTER_R11, "r11", B_UINT64_TYPE, 217 REGISTER_TYPE_GENERAL_PURPOSE, false); 218 _AddIntegerRegister(X86_64_REGISTER_R12, "r12", B_UINT64_TYPE, 219 REGISTER_TYPE_GENERAL_PURPOSE, true); 220 _AddIntegerRegister(X86_64_REGISTER_R13, "r13", B_UINT64_TYPE, 221 REGISTER_TYPE_GENERAL_PURPOSE, true); 222 _AddIntegerRegister(X86_64_REGISTER_R14, "r14", B_UINT64_TYPE, 223 REGISTER_TYPE_GENERAL_PURPOSE, true); 224 _AddIntegerRegister(X86_64_REGISTER_R15, "r15", B_UINT64_TYPE, 225 REGISTER_TYPE_GENERAL_PURPOSE, true); 226 227 _AddIntegerRegister(X86_64_REGISTER_CS, "cs", B_UINT16_TYPE, 228 REGISTER_TYPE_SPECIAL_PURPOSE, true); 229 _AddIntegerRegister(X86_64_REGISTER_DS, "ds", B_UINT16_TYPE, 230 REGISTER_TYPE_SPECIAL_PURPOSE, true); 231 _AddIntegerRegister(X86_64_REGISTER_ES, "es", B_UINT16_TYPE, 232 REGISTER_TYPE_SPECIAL_PURPOSE, true); 233 _AddIntegerRegister(X86_64_REGISTER_FS, "fs", B_UINT16_TYPE, 234 REGISTER_TYPE_SPECIAL_PURPOSE, true); 235 _AddIntegerRegister(X86_64_REGISTER_GS, "gs", B_UINT16_TYPE, 236 REGISTER_TYPE_SPECIAL_PURPOSE, true); 237 _AddIntegerRegister(X86_64_REGISTER_SS, "ss", B_UINT16_TYPE, 238 REGISTER_TYPE_SPECIAL_PURPOSE, true); 239 240 _AddFPRegister(X86_64_REGISTER_ST0, "st0"); 241 _AddFPRegister(X86_64_REGISTER_ST1, "st1"); 242 _AddFPRegister(X86_64_REGISTER_ST2, "st2"); 243 _AddFPRegister(X86_64_REGISTER_ST3, "st3"); 244 _AddFPRegister(X86_64_REGISTER_ST4, "st4"); 245 _AddFPRegister(X86_64_REGISTER_ST5, "st5"); 246 _AddFPRegister(X86_64_REGISTER_ST6, "st6"); 247 _AddFPRegister(X86_64_REGISTER_ST7, "st7"); 248 249 _AddSIMDRegister(X86_64_REGISTER_MM0, "mm0", sizeof(uint64)); 250 _AddSIMDRegister(X86_64_REGISTER_MM1, "mm1", sizeof(uint64)); 251 _AddSIMDRegister(X86_64_REGISTER_MM2, "mm2", sizeof(uint64)); 252 _AddSIMDRegister(X86_64_REGISTER_MM3, "mm3", sizeof(uint64)); 253 _AddSIMDRegister(X86_64_REGISTER_MM4, "mm4", sizeof(uint64)); 254 _AddSIMDRegister(X86_64_REGISTER_MM5, "mm5", sizeof(uint64)); 255 _AddSIMDRegister(X86_64_REGISTER_MM6, "mm6", sizeof(uint64)); 256 _AddSIMDRegister(X86_64_REGISTER_MM7, "mm7", sizeof(uint64)); 257 258 if ((featureFlags & X86_64_CPU_FEATURE_FLAG_AVX) != 0) { 259 _AddSIMDRegister(X86_64_REGISTER_XMM0, "ymm0", 260 sizeof(x86_64_xmm_register) * 2); 261 _AddSIMDRegister(X86_64_REGISTER_XMM1, "ymm1", 262 sizeof(x86_64_xmm_register) * 2); 263 _AddSIMDRegister(X86_64_REGISTER_XMM2, "ymm2", 264 sizeof(x86_64_xmm_register) * 2); 265 _AddSIMDRegister(X86_64_REGISTER_XMM3, "ymm3", 266 sizeof(x86_64_xmm_register) * 2); 267 _AddSIMDRegister(X86_64_REGISTER_XMM4, "ymm4", 268 sizeof(x86_64_xmm_register) * 2); 269 _AddSIMDRegister(X86_64_REGISTER_XMM5, "ymm5", 270 sizeof(x86_64_xmm_register) * 2); 271 _AddSIMDRegister(X86_64_REGISTER_XMM6, "ymm6", 272 sizeof(x86_64_xmm_register) * 2); 273 _AddSIMDRegister(X86_64_REGISTER_XMM7, "ymm7", 274 sizeof(x86_64_xmm_register) * 2); 275 _AddSIMDRegister(X86_64_REGISTER_XMM8, "ymm8", 276 sizeof(x86_64_xmm_register) * 2); 277 _AddSIMDRegister(X86_64_REGISTER_XMM9, "ymm9", 278 sizeof(x86_64_xmm_register) * 2); 279 _AddSIMDRegister(X86_64_REGISTER_XMM10, "ymm10", 280 sizeof(x86_64_xmm_register) * 2); 281 _AddSIMDRegister(X86_64_REGISTER_XMM11, "ymm11", 282 sizeof(x86_64_xmm_register) * 2); 283 _AddSIMDRegister(X86_64_REGISTER_XMM12, "ymm12", 284 sizeof(x86_64_xmm_register) * 2); 285 _AddSIMDRegister(X86_64_REGISTER_XMM13, "ymm13", 286 sizeof(x86_64_xmm_register) * 2); 287 _AddSIMDRegister(X86_64_REGISTER_XMM14, "ymm14", 288 sizeof(x86_64_xmm_register) * 2); 289 _AddSIMDRegister(X86_64_REGISTER_XMM15, "ymm15", 290 sizeof(x86_64_xmm_register) * 2); 291 } else { 292 _AddSIMDRegister(X86_64_REGISTER_XMM0, "xmm0", 293 sizeof(x86_64_xmm_register)); 294 _AddSIMDRegister(X86_64_REGISTER_XMM1, "xmm1", 295 sizeof(x86_64_xmm_register)); 296 _AddSIMDRegister(X86_64_REGISTER_XMM2, "xmm2", 297 sizeof(x86_64_xmm_register)); 298 _AddSIMDRegister(X86_64_REGISTER_XMM3, "xmm3", 299 sizeof(x86_64_xmm_register)); 300 _AddSIMDRegister(X86_64_REGISTER_XMM4, "xmm4", 301 sizeof(x86_64_xmm_register)); 302 _AddSIMDRegister(X86_64_REGISTER_XMM5, "xmm5", 303 sizeof(x86_64_xmm_register)); 304 _AddSIMDRegister(X86_64_REGISTER_XMM6, "xmm6", 305 sizeof(x86_64_xmm_register)); 306 _AddSIMDRegister(X86_64_REGISTER_XMM7, "xmm7", 307 sizeof(x86_64_xmm_register)); 308 _AddSIMDRegister(X86_64_REGISTER_XMM8, "xmm8", 309 sizeof(x86_64_xmm_register)); 310 _AddSIMDRegister(X86_64_REGISTER_XMM9, "xmm9", 311 sizeof(x86_64_xmm_register)); 312 _AddSIMDRegister(X86_64_REGISTER_XMM10, "xmm10", 313 sizeof(x86_64_xmm_register)); 314 _AddSIMDRegister(X86_64_REGISTER_XMM11, "xmm11", 315 sizeof(x86_64_xmm_register)); 316 _AddSIMDRegister(X86_64_REGISTER_XMM12, "xmm12", 317 sizeof(x86_64_xmm_register)); 318 _AddSIMDRegister(X86_64_REGISTER_XMM13, "xmm13", 319 sizeof(x86_64_xmm_register)); 320 _AddSIMDRegister(X86_64_REGISTER_XMM14, "xmm14", 321 sizeof(x86_64_xmm_register)); 322 _AddSIMDRegister(X86_64_REGISTER_XMM15, "xmm15", 323 sizeof(x86_64_xmm_register)); 324 } 325 326 } catch (std::bad_alloc&) { 327 return B_NO_MEMORY; 328 } 329 330 fToDwarfRegisterMap = new(std::nothrow) ToDwarfRegisterMap; 331 fFromDwarfRegisterMap = new(std::nothrow) FromDwarfRegisterMap; 332 333 if (fToDwarfRegisterMap == NULL || fFromDwarfRegisterMap == NULL) 334 return B_NO_MEMORY; 335 336 return B_OK; 337 } 338 339 340 int32 341 ArchitectureX8664::StackGrowthDirection() const 342 { 343 return STACK_GROWTH_DIRECTION_NEGATIVE; 344 } 345 346 347 int32 348 ArchitectureX8664::CountRegisters() const 349 { 350 return fRegisters.Count(); 351 } 352 353 354 const Register* 355 ArchitectureX8664::Registers() const 356 { 357 return fRegisters.Elements(); 358 } 359 360 361 status_t 362 ArchitectureX8664::InitRegisterRules(CfaContext& context) const 363 { 364 status_t error = Architecture::InitRegisterRules(context); 365 if (error != B_OK) 366 return error; 367 368 // set up rule for RIP register 369 context.RegisterRule(fToDwarfRegisterMap->MapRegisterIndex( 370 X86_64_REGISTER_RIP))->SetToLocationOffset(0); 371 372 return B_OK; 373 } 374 375 376 status_t 377 ArchitectureX8664::GetDwarfRegisterMaps(RegisterMap** _toDwarf, 378 RegisterMap** _fromDwarf) const 379 { 380 if (_toDwarf != NULL) { 381 *_toDwarf = fToDwarfRegisterMap; 382 fToDwarfRegisterMap->AcquireReference(); 383 } 384 385 if (_fromDwarf != NULL) { 386 *_fromDwarf = fFromDwarfRegisterMap; 387 fFromDwarfRegisterMap->AcquireReference(); 388 } 389 390 return B_OK; 391 } 392 393 394 status_t 395 ArchitectureX8664::GetCpuFeatures(uint32& flags) 396 { 397 // TODO: implement if/when it winds up being needed. 398 flags = 0; 399 return B_OK; 400 } 401 402 403 status_t 404 ArchitectureX8664::CreateCpuState(CpuState*& _state) 405 { 406 CpuStateX8664* state = new(std::nothrow) CpuStateX8664; 407 if (state == NULL) 408 return B_NO_MEMORY; 409 410 _state = state; 411 return B_OK; 412 } 413 414 415 status_t 416 ArchitectureX8664::CreateCpuState(const void* cpuStateData, size_t size, 417 CpuState*& _state) 418 { 419 if (size != sizeof(x86_64_debug_cpu_state)) 420 return B_BAD_VALUE; 421 422 CpuStateX8664* state = new(std::nothrow) CpuStateX8664( 423 *(const x86_64_debug_cpu_state*)cpuStateData); 424 if (state == NULL) 425 return B_NO_MEMORY; 426 427 _state = state; 428 return B_OK; 429 } 430 431 432 status_t 433 ArchitectureX8664::CreateStackFrame(Image* image, FunctionDebugInfo* function, 434 CpuState* _cpuState, bool isTopFrame, StackFrame*& _frame, 435 CpuState*& _previousCpuState) 436 { 437 CpuStateX8664* cpuState = dynamic_cast<CpuStateX8664*>(_cpuState); 438 uint64 framePointer = cpuState->IntRegisterValue(X86_64_REGISTER_RBP); 439 uint64 rip = cpuState->IntRegisterValue(X86_64_REGISTER_RIP); 440 441 bool readStandardFrame = true; 442 uint64 previousFramePointer = 0; 443 uint64 returnAddress = 0; 444 445 // check for syscall frames 446 stack_frame_type frameType; 447 bool hasPrologue = false; 448 if (isTopFrame && cpuState->InterruptVector() == 99) { 449 // The thread is performing a syscall. So this frame is not really the 450 // top-most frame and we need to adjust the rip. 451 frameType = STACK_FRAME_TYPE_SYSCALL; 452 rip -= 2; 453 // int 99, sysenter, and syscall all are 2 byte instructions 454 455 // The syscall stubs are frameless, the return address is on top of the 456 // stack. 457 uint64 rsp = cpuState->IntRegisterValue(X86_64_REGISTER_RSP); 458 uint64 address; 459 if (fTeamMemory->ReadMemory(rsp, &address, 8) == 8) { 460 returnAddress = address; 461 previousFramePointer = framePointer; 462 framePointer = 0; 463 readStandardFrame = false; 464 } 465 } else { 466 hasPrologue = _HasFunctionPrologue(function); 467 if (hasPrologue) 468 frameType = STACK_FRAME_TYPE_STANDARD; 469 else 470 frameType = STACK_FRAME_TYPE_FRAMELESS; 471 // TODO: Handling for frameless functions. It's not trivial to find the 472 // return address on the stack, though. 473 474 // If the function is not frameless and we're at the top frame we need 475 // to check whether the prologue has not been executed (completely) or 476 // we're already after the epilogue. 477 if (isTopFrame) { 478 uint64 stack = 0; 479 if (hasPrologue) { 480 if (rip < function->Address() + kFunctionPrologueSize) { 481 // The prologue has not been executed yet, i.e. there's no 482 // stack frame yet. Get the return address from the stack. 483 stack = cpuState->IntRegisterValue(X86_64_REGISTER_RSP); 484 if (rip > function->Address()) { 485 // The "push %rbp" has already been executed. 486 stack += 8; 487 } 488 } else { 489 // Not in the function prologue, but maybe after the 490 // epilogue. The epilogue is a single "pop %rbp", so we 491 // check whether the current instruction is already a 492 // "ret". 493 uint8 code[1]; 494 if (fTeamMemory->ReadMemory(rip, &code, 1) == 1 495 && code[0] == 0xc3) { 496 stack = cpuState->IntRegisterValue( 497 X86_64_REGISTER_RSP); 498 } 499 } 500 } else { 501 // Check if the instruction pointer is at a readable location. 502 // If it isn't, then chances are we got here via a bogus 503 // function pointer, and the prologue hasn't actually been 504 // executed. In such a case, what we need is right at the top 505 // of the stack. 506 uint8 data[1]; 507 if (fTeamMemory->ReadMemory(rip, &data, 1) != 1) 508 stack = cpuState->IntRegisterValue(X86_64_REGISTER_RSP); 509 } 510 511 if (stack != 0) { 512 uint64 address; 513 if (fTeamMemory->ReadMemory(stack, &address, 8) == 8) { 514 returnAddress = address; 515 previousFramePointer = framePointer; 516 framePointer = 0; 517 readStandardFrame = false; 518 frameType = STACK_FRAME_TYPE_FRAMELESS; 519 } 520 } 521 } 522 } 523 524 // create the stack frame 525 StackFrameDebugInfo* stackFrameDebugInfo 526 = new(std::nothrow) NoOpStackFrameDebugInfo; 527 if (stackFrameDebugInfo == NULL) 528 return B_NO_MEMORY; 529 BReference<StackFrameDebugInfo> stackFrameDebugInfoReference( 530 stackFrameDebugInfo, true); 531 532 StackFrame* frame = new(std::nothrow) StackFrame(frameType, cpuState, 533 framePointer, rip, stackFrameDebugInfo); 534 if (frame == NULL) 535 return B_NO_MEMORY; 536 BReference<StackFrame> frameReference(frame, true); 537 538 status_t error = frame->Init(); 539 if (error != B_OK) 540 return error; 541 542 // read the previous frame and return address, if this is a standard frame 543 if (readStandardFrame) { 544 uint64 frameData[2]; 545 if (framePointer != 0 546 && fTeamMemory->ReadMemory(framePointer, frameData, 16) == 16) { 547 previousFramePointer = frameData[0]; 548 returnAddress = frameData[1]; 549 } 550 } 551 552 // create the CPU state, if we have any info 553 CpuStateX8664* previousCpuState = NULL; 554 if (returnAddress != 0) { 555 // prepare the previous CPU state 556 previousCpuState = new(std::nothrow) CpuStateX8664; 557 if (previousCpuState == NULL) 558 return B_NO_MEMORY; 559 560 previousCpuState->SetIntRegister(X86_64_REGISTER_RBP, 561 previousFramePointer); 562 previousCpuState->SetIntRegister(X86_64_REGISTER_RIP, returnAddress); 563 frame->SetPreviousCpuState(previousCpuState); 564 } 565 566 frame->SetReturnAddress(returnAddress); 567 568 _frame = frameReference.Detach(); 569 _previousCpuState = previousCpuState; 570 return B_OK; 571 } 572 573 574 void 575 ArchitectureX8664::UpdateStackFrameCpuState(const StackFrame* frame, 576 Image* previousImage, FunctionDebugInfo* previousFunction, 577 CpuState* previousCpuState) 578 { 579 // This is not a top frame, so we want to offset rip to the previous 580 // (calling) instruction. 581 CpuStateX8664* cpuState = dynamic_cast<CpuStateX8664*>(previousCpuState); 582 583 // get rip 584 uint64 rip = cpuState->IntRegisterValue(X86_64_REGISTER_RIP); 585 if (previousFunction == NULL || rip <= previousFunction->Address()) 586 return; 587 target_addr_t functionAddress = previousFunction->Address(); 588 589 // allocate a buffer for the function code to disassemble 590 size_t bufferSize = rip - functionAddress; 591 void* buffer = malloc(bufferSize); 592 if (buffer == NULL) 593 return; 594 MemoryDeleter bufferDeleter(buffer); 595 596 // read the code 597 ssize_t bytesRead = fTeamMemory->ReadMemory(functionAddress, buffer, 598 bufferSize); 599 if (bytesRead != (ssize_t)bufferSize) 600 return; 601 602 // disassemble to get the previous instruction 603 DisassemblerX8664 disassembler; 604 target_addr_t instructionAddress; 605 target_size_t instructionSize; 606 if (disassembler.Init(functionAddress, buffer, bufferSize) == B_OK 607 && disassembler.GetPreviousInstruction(rip, instructionAddress, 608 instructionSize) == B_OK) { 609 rip -= instructionSize; 610 cpuState->SetIntRegister(X86_64_REGISTER_RIP, rip); 611 } 612 } 613 614 615 status_t 616 ArchitectureX8664::ReadValueFromMemory(target_addr_t address, uint32 valueType, 617 BVariant& _value) const 618 { 619 uint8 buffer[64]; 620 size_t size = BVariant::SizeOfType(valueType); 621 if (size == 0 || size > sizeof(buffer)) 622 return B_BAD_VALUE; 623 624 ssize_t bytesRead = fTeamMemory->ReadMemory(address, buffer, size); 625 if (bytesRead < 0) 626 return bytesRead; 627 if ((size_t)bytesRead != size) 628 return B_ERROR; 629 630 // TODO: We need to swap endianess, if the host is big endian! 631 632 switch (valueType) { 633 case B_INT8_TYPE: 634 _value.SetTo(*(int8*)buffer); 635 return B_OK; 636 case B_UINT8_TYPE: 637 _value.SetTo(*(uint8*)buffer); 638 return B_OK; 639 case B_INT16_TYPE: 640 _value.SetTo(*(int16*)buffer); 641 return B_OK; 642 case B_UINT16_TYPE: 643 _value.SetTo(*(uint16*)buffer); 644 return B_OK; 645 case B_INT32_TYPE: 646 _value.SetTo(*(int32*)buffer); 647 return B_OK; 648 case B_UINT32_TYPE: 649 _value.SetTo(*(uint32*)buffer); 650 return B_OK; 651 case B_INT64_TYPE: 652 _value.SetTo(*(int64*)buffer); 653 return B_OK; 654 case B_UINT64_TYPE: 655 _value.SetTo(*(uint64*)buffer); 656 return B_OK; 657 case B_FLOAT_TYPE: 658 _value.SetTo(*(float*)buffer); 659 // TODO: float on the host might work differently! 660 return B_OK; 661 case B_DOUBLE_TYPE: 662 _value.SetTo(*(double*)buffer); 663 // TODO: double on the host might work differently! 664 return B_OK; 665 default: 666 return B_BAD_VALUE; 667 } 668 } 669 670 671 status_t 672 ArchitectureX8664::ReadValueFromMemory(target_addr_t addressSpace, 673 target_addr_t address, uint32 valueType, BVariant& _value) const 674 { 675 // n/a on this architecture 676 return B_BAD_VALUE; 677 } 678 679 680 status_t 681 ArchitectureX8664::DisassembleCode(FunctionDebugInfo* function, 682 const void* buffer, size_t bufferSize, DisassembledCode*& _sourceCode) 683 { 684 DisassembledCode* source = new(std::nothrow) DisassembledCode( 685 fAssemblyLanguage); 686 if (source == NULL) 687 return B_NO_MEMORY; 688 BReference<DisassembledCode> sourceReference(source, true); 689 690 // init disassembler 691 DisassemblerX8664 disassembler; 692 status_t error = disassembler.Init(function->Address(), buffer, bufferSize); 693 if (error != B_OK) 694 return error; 695 696 // add a function name line 697 BString functionName(function->PrettyName()); 698 if (!source->AddCommentLine((functionName << ':').String())) 699 return B_NO_MEMORY; 700 701 // disassemble the instructions 702 BString line; 703 target_addr_t instructionAddress; 704 target_size_t instructionSize; 705 bool breakpointAllowed; 706 while (disassembler.GetNextInstruction(line, instructionAddress, 707 instructionSize, breakpointAllowed) == B_OK) { 708 // TODO: Respect breakpointAllowed! 709 if (!source->AddInstructionLine(line, instructionAddress, 710 instructionSize)) { 711 return B_NO_MEMORY; 712 } 713 } 714 715 _sourceCode = sourceReference.Detach(); 716 return B_OK; 717 } 718 719 720 status_t 721 ArchitectureX8664::GetStatement(FunctionDebugInfo* function, 722 target_addr_t address, Statement*& _statement) 723 { 724 // TODO: This is not architecture dependent anymore! 725 // get the instruction info 726 InstructionInfo info; 727 status_t error = GetInstructionInfo(address, info, NULL); 728 if (error != B_OK) 729 return error; 730 731 // create a statement 732 ContiguousStatement* statement = new(std::nothrow) ContiguousStatement( 733 SourceLocation(-1), TargetAddressRange(info.Address(), info.Size())); 734 if (statement == NULL) 735 return B_NO_MEMORY; 736 737 _statement = statement; 738 return B_OK; 739 } 740 741 742 status_t 743 ArchitectureX8664::GetInstructionInfo(target_addr_t address, 744 InstructionInfo& _info, CpuState* state) 745 { 746 // read the code - maximum x86{-64} instruction size = 15 bytes 747 uint8 buffer[16]; 748 ssize_t bytesRead = fTeamMemory->ReadMemory(address, buffer, 749 sizeof(buffer)); 750 if (bytesRead < 0) 751 return bytesRead; 752 753 // init disassembler 754 DisassemblerX8664 disassembler; 755 status_t error = disassembler.Init(address, buffer, bytesRead); 756 if (error != B_OK) 757 return error; 758 759 return disassembler.GetNextInstructionInfo(_info, state); 760 } 761 762 763 status_t 764 ArchitectureX8664::ResolvePICFunctionAddress(target_addr_t instructionAddress, 765 CpuState* state, target_addr_t& _targetAddress) 766 { 767 target_addr_t previousIP = state->InstructionPointer(); 768 // if the function in question is position-independent, the call 769 // will actually have taken us to its corresponding PLT slot. 770 // in such a case, look at the disassembled jump to determine 771 // where to find the actual function address. 772 InstructionInfo info; 773 if (GetInstructionInfo(instructionAddress, info, state) != B_OK) 774 return B_BAD_VALUE; 775 776 // x86-64 is likely to use a RIP-relative jump here 777 // as such, set our instruction pointer to the address 778 // after this instruction (where it would be during actual 779 // execution), and recalculate the target address of the jump 780 state->SetInstructionPointer(info.Address() + info.Size()); 781 status_t result = GetInstructionInfo(info.Address(), info, state); 782 state->SetInstructionPointer(previousIP); 783 if (result != B_OK) 784 return result; 785 786 target_addr_t subroutineAddress; 787 ssize_t bytesRead = fTeamMemory->ReadMemory(info.TargetAddress(), 788 &subroutineAddress, fAddressSize); 789 790 if (bytesRead != fAddressSize) 791 return B_BAD_VALUE; 792 793 _targetAddress = subroutineAddress; 794 return B_OK; 795 } 796 797 798 status_t 799 ArchitectureX8664::GetWatchpointDebugCapabilities(int32& _maxRegisterCount, 800 int32& _maxBytesPerRegister, uint8& _watchpointCapabilityFlags) 801 { 802 // Have 4 debug registers, 1 is required for breakpoint support, which 803 // leaves 3 available for watchpoints. 804 _maxRegisterCount = 3; 805 _maxBytesPerRegister = 8; 806 807 // x86 only supports write and read/write watchpoints. 808 _watchpointCapabilityFlags = WATCHPOINT_CAPABILITY_FLAG_WRITE 809 | WATCHPOINT_CAPABILITY_FLAG_READ_WRITE; 810 811 return B_OK; 812 } 813 814 815 status_t 816 ArchitectureX8664::GetReturnAddressLocation(StackFrame* frame, 817 target_size_t valueSize, ValueLocation*& _location) 818 { 819 // for the calling conventions currently in use on Haiku, 820 // the x86-64 rules for how values are returned are as follows: 821 // 822 // - 64 bit or smaller values are returned in RAX. 823 // - > 64 bit values are returned on the stack. 824 ValueLocation* location = new(std::nothrow) ValueLocation( 825 IsBigEndian()); 826 if (location == NULL) 827 return B_NO_MEMORY; 828 BReference<ValueLocation> locationReference(location, 829 true); 830 831 if (valueSize <= 8) { 832 ValuePieceLocation piece; 833 piece.SetSize(valueSize); 834 piece.SetToRegister(X86_64_REGISTER_RAX); 835 if (!location->AddPiece(piece)) 836 return B_NO_MEMORY; 837 } else { 838 ValuePieceLocation piece; 839 CpuStateX8664* state = dynamic_cast<CpuStateX8664*>(frame->GetCpuState()); 840 piece.SetToMemory(state->IntRegisterValue(X86_64_REGISTER_RAX)); 841 piece.SetSize(valueSize); 842 if (!location->AddPiece(piece)) 843 return B_NO_MEMORY; 844 } 845 846 _location = locationReference.Detach(); 847 return B_OK; 848 } 849 850 851 void 852 ArchitectureX8664::_AddRegister(int32 index, const char* name, 853 uint32 bitSize, uint32 valueType, register_type type, bool calleePreserved) 854 { 855 if (!fRegisters.Add(Register(index, name, bitSize, valueType, type, 856 calleePreserved))) { 857 throw std::bad_alloc(); 858 } 859 } 860 861 862 void 863 ArchitectureX8664::_AddIntegerRegister(int32 index, const char* name, 864 uint32 valueType, register_type type, bool calleePreserved) 865 { 866 _AddRegister(index, name, 8 * BVariant::SizeOfType(valueType), valueType, 867 type, calleePreserved); 868 } 869 870 871 void 872 ArchitectureX8664::_AddFPRegister(int32 index, const char* name) 873 { 874 _AddRegister(index, name, 8 * BVariant::SizeOfType(B_DOUBLE_TYPE), 875 B_DOUBLE_TYPE, REGISTER_TYPE_GENERAL_PURPOSE, true); 876 } 877 878 879 void 880 ArchitectureX8664::_AddSIMDRegister(int32 index, const char* name, 881 uint32 byteSize) 882 { 883 _AddRegister(index, name, byteSize * 8, B_RAW_TYPE, 884 REGISTER_TYPE_GENERAL_PURPOSE, true); 885 } 886 887 888 bool 889 ArchitectureX8664::_HasFunctionPrologue(FunctionDebugInfo* function) const 890 { 891 if (function == NULL) 892 return false; 893 894 // check whether the function has the typical prologue 895 if (function->Size() < kFunctionPrologueSize) 896 return false; 897 898 uint8 buffer[kFunctionPrologueSize]; 899 if (fTeamMemory->ReadMemory(function->Address(), buffer, 900 kFunctionPrologueSize) != kFunctionPrologueSize) { 901 return false; 902 } 903 904 return buffer[0] == 0x55 && buffer[1] == 0x48 && buffer[2] == 0x89 905 && buffer[3] == 0xe5; 906 } 907