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