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