Debugger: Add dedicated functions for global {un}init.
[haiku.git] / src / apps / debugger / arch / x86 / ArchitectureX86.cpp
blobb423501fede10e250fa39d46ed414753396d928a
1 /*
2 * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2011-2015, Rene Gollent, rene@gollent.com.
4 * Distributed under the terms of the MIT License.
5 */
8 #include "ArchitectureX86.h"
10 #include <new>
12 #include <String.h>
14 #include <AutoDeleter.h>
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"
29 #include "disasm/DisassemblerX86.h"
32 #define IA32_FEATURE_MMX (1 << 23)
33 #define IA32_FEATURE_SSE (1 << 25)
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,
76 static const int32 kFromDwarfRegisterCount = sizeof(kFromDwarfRegisters) / 4;
79 // #pragma mark - ToDwarfRegisterMap
82 struct ArchitectureX86::ToDwarfRegisterMap : RegisterMap {
83 ToDwarfRegisterMap()
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;
93 virtual int32 CountRegisters() const
95 return X86_REGISTER_COUNT;
98 virtual int32 MapRegisterIndex(int32 index) const
100 return index >= 0 && index < X86_REGISTER_COUNT ? fIndices[index] : -1;
103 private:
104 int32 fIndices[X86_REGISTER_COUNT];
108 // #pragma mark - FromDwarfRegisterMap
111 struct ArchitectureX86::FromDwarfRegisterMap : RegisterMap {
112 virtual int32 CountRegisters() const
114 return kFromDwarfRegisterCount;
117 virtual int32 MapRegisterIndex(int32 index) const
119 return index >= 0 && index < kFromDwarfRegisterCount
120 ? kFromDwarfRegisters[index] : -1;
125 // #pragma mark - ArchitectureX86
128 ArchitectureX86::ArchitectureX86(TeamMemory* teamMemory)
130 Architecture(teamMemory, 4, false),
131 fFeatureFlags(0),
132 fAssemblyLanguage(NULL),
133 fToDwarfRegisterMap(NULL),
134 fFromDwarfRegisterMap(NULL)
139 ArchitectureX86::~ArchitectureX86()
141 if (fToDwarfRegisterMap != NULL)
142 fToDwarfRegisterMap->ReleaseReference();
143 if (fFromDwarfRegisterMap != NULL)
144 fFromDwarfRegisterMap->ReleaseReference();
145 if (fAssemblyLanguage != NULL)
146 fAssemblyLanguage->ReleaseReference();
150 status_t
151 ArchitectureX86::Init()
153 fAssemblyLanguage = new(std::nothrow) X86AssemblyLanguage;
154 if (fAssemblyLanguage == NULL)
155 return B_NO_MEMORY;
157 #if defined(__INTEL__)
158 cpuid_info info;
159 status_t error = get_cpuid(&info, 1, 0);
160 if (error != B_OK)
161 return error;
163 if ((info.eax_1.features & IA32_FEATURE_MMX) != 0)
164 fFeatureFlags |= X86_CPU_FEATURE_FLAG_MMX;
166 if ((info.eax_1.features & IA32_FEATURE_SSE) != 0)
167 fFeatureFlags |= X86_CPU_FEATURE_FLAG_SSE;
169 #endif
171 try {
172 _AddIntegerRegister(X86_REGISTER_EIP, "eip", B_UINT32_TYPE,
173 REGISTER_TYPE_INSTRUCTION_POINTER, false);
174 _AddIntegerRegister(X86_REGISTER_ESP, "esp", B_UINT32_TYPE,
175 REGISTER_TYPE_STACK_POINTER, true);
176 _AddIntegerRegister(X86_REGISTER_EBP, "ebp", B_UINT32_TYPE,
177 REGISTER_TYPE_GENERAL_PURPOSE, true);
179 _AddIntegerRegister(X86_REGISTER_EAX, "eax", B_UINT32_TYPE,
180 REGISTER_TYPE_GENERAL_PURPOSE, false);
181 _AddIntegerRegister(X86_REGISTER_EBX, "ebx", B_UINT32_TYPE,
182 REGISTER_TYPE_GENERAL_PURPOSE, true);
183 _AddIntegerRegister(X86_REGISTER_ECX, "ecx", B_UINT32_TYPE,
184 REGISTER_TYPE_GENERAL_PURPOSE, false);
185 _AddIntegerRegister(X86_REGISTER_EDX, "edx", B_UINT32_TYPE,
186 REGISTER_TYPE_GENERAL_PURPOSE, false);
188 _AddIntegerRegister(X86_REGISTER_ESI, "esi", B_UINT32_TYPE,
189 REGISTER_TYPE_GENERAL_PURPOSE, true);
190 _AddIntegerRegister(X86_REGISTER_EDI, "edi", B_UINT32_TYPE,
191 REGISTER_TYPE_GENERAL_PURPOSE, true);
193 _AddIntegerRegister(X86_REGISTER_CS, "cs", B_UINT16_TYPE,
194 REGISTER_TYPE_SPECIAL_PURPOSE, true);
195 _AddIntegerRegister(X86_REGISTER_DS, "ds", B_UINT16_TYPE,
196 REGISTER_TYPE_SPECIAL_PURPOSE, true);
197 _AddIntegerRegister(X86_REGISTER_ES, "es", B_UINT16_TYPE,
198 REGISTER_TYPE_SPECIAL_PURPOSE, true);
199 _AddIntegerRegister(X86_REGISTER_FS, "fs", B_UINT16_TYPE,
200 REGISTER_TYPE_SPECIAL_PURPOSE, true);
201 _AddIntegerRegister(X86_REGISTER_GS, "gs", B_UINT16_TYPE,
202 REGISTER_TYPE_SPECIAL_PURPOSE, true);
203 _AddIntegerRegister(X86_REGISTER_SS, "ss", B_UINT16_TYPE,
204 REGISTER_TYPE_SPECIAL_PURPOSE, true);
206 _AddFPRegister(X86_REGISTER_ST0, "st0");
207 _AddFPRegister(X86_REGISTER_ST1, "st1");
208 _AddFPRegister(X86_REGISTER_ST2, "st2");
209 _AddFPRegister(X86_REGISTER_ST3, "st3");
210 _AddFPRegister(X86_REGISTER_ST4, "st4");
211 _AddFPRegister(X86_REGISTER_ST5, "st5");
212 _AddFPRegister(X86_REGISTER_ST6, "st6");
213 _AddFPRegister(X86_REGISTER_ST7, "st7");
215 if ((fFeatureFlags & X86_CPU_FEATURE_FLAG_MMX) != 0) {
216 _AddSIMDRegister(X86_REGISTER_MM0, "mm0", sizeof(uint64));
217 _AddSIMDRegister(X86_REGISTER_MM1, "mm1", sizeof(uint64));
218 _AddSIMDRegister(X86_REGISTER_MM2, "mm2", sizeof(uint64));
219 _AddSIMDRegister(X86_REGISTER_MM3, "mm3", sizeof(uint64));
220 _AddSIMDRegister(X86_REGISTER_MM4, "mm4", sizeof(uint64));
221 _AddSIMDRegister(X86_REGISTER_MM5, "mm5", sizeof(uint64));
222 _AddSIMDRegister(X86_REGISTER_MM6, "mm6", sizeof(uint64));
223 _AddSIMDRegister(X86_REGISTER_MM7, "mm7", sizeof(uint64));
226 if ((fFeatureFlags & X86_CPU_FEATURE_FLAG_SSE) != 0) {
227 _AddSIMDRegister(X86_REGISTER_XMM0, "xmm0",
228 sizeof(x86_xmm_register));
229 _AddSIMDRegister(X86_REGISTER_XMM1, "xmm1",
230 sizeof(x86_xmm_register));
231 _AddSIMDRegister(X86_REGISTER_XMM2, "xmm2",
232 sizeof(x86_xmm_register));
233 _AddSIMDRegister(X86_REGISTER_XMM3, "xmm3",
234 sizeof(x86_xmm_register));
235 _AddSIMDRegister(X86_REGISTER_XMM4, "xmm4",
236 sizeof(x86_xmm_register));
237 _AddSIMDRegister(X86_REGISTER_XMM5, "xmm5",
238 sizeof(x86_xmm_register));
239 _AddSIMDRegister(X86_REGISTER_XMM6, "xmm6",
240 sizeof(x86_xmm_register));
241 _AddSIMDRegister(X86_REGISTER_XMM7, "xmm7",
242 sizeof(x86_xmm_register));
245 } catch (std::bad_alloc) {
246 return B_NO_MEMORY;
249 fToDwarfRegisterMap = new(std::nothrow) ToDwarfRegisterMap;
250 fFromDwarfRegisterMap = new(std::nothrow) FromDwarfRegisterMap;
252 if (fToDwarfRegisterMap == NULL || fFromDwarfRegisterMap == NULL)
253 return B_NO_MEMORY;
255 return B_OK;
259 int32
260 ArchitectureX86::StackGrowthDirection() const
262 return STACK_GROWTH_DIRECTION_NEGATIVE;
266 int32
267 ArchitectureX86::CountRegisters() const
269 return fRegisters.Count();
273 const Register*
274 ArchitectureX86::Registers() const
276 return fRegisters.Elements();
281 status_t
282 ArchitectureX86::InitRegisterRules(CfaContext& context) const
284 status_t error = Architecture::InitRegisterRules(context);
285 if (error != B_OK)
286 return error;
288 // set up rule for EIP register
289 context.RegisterRule(fToDwarfRegisterMap->MapRegisterIndex(
290 X86_REGISTER_EIP))->SetToLocationOffset(-4);
292 return B_OK;
296 status_t
297 ArchitectureX86::GetDwarfRegisterMaps(RegisterMap** _toDwarf,
298 RegisterMap** _fromDwarf) const
300 if (_toDwarf != NULL) {
301 *_toDwarf = fToDwarfRegisterMap;
302 fToDwarfRegisterMap->AcquireReference();
305 if (_fromDwarf != NULL) {
306 *_fromDwarf = fFromDwarfRegisterMap;
307 fFromDwarfRegisterMap->AcquireReference();
310 return B_OK;
314 status_t
315 ArchitectureX86::GetCpuFeatures(uint32& flags)
317 flags = fFeatureFlags;
319 return B_OK;
323 status_t
324 ArchitectureX86::CreateCpuState(CpuState*& _state)
326 CpuStateX86* state = new(std::nothrow) CpuStateX86;
327 if (state == NULL)
328 return B_NO_MEMORY;
330 _state = state;
331 return B_OK;
335 status_t
336 ArchitectureX86::CreateCpuState(const void* cpuStateData, size_t size,
337 CpuState*& _state)
339 if (size != sizeof(x86_debug_cpu_state))
340 return B_BAD_VALUE;
342 CpuStateX86* state = new(std::nothrow) CpuStateX86(
343 *(const x86_debug_cpu_state*)cpuStateData);
344 if (state == NULL)
345 return B_NO_MEMORY;
347 _state = state;
348 return B_OK;
352 status_t
353 ArchitectureX86::CreateStackFrame(Image* image, FunctionDebugInfo* function,
354 CpuState* _cpuState, bool isTopFrame, StackFrame*& _frame,
355 CpuState*& _previousCpuState)
357 CpuStateX86* cpuState = dynamic_cast<CpuStateX86*>(_cpuState);
359 uint32 framePointer = cpuState->IntRegisterValue(X86_REGISTER_EBP);
360 uint32 eip = cpuState->IntRegisterValue(X86_REGISTER_EIP);
362 bool readStandardFrame = true;
363 uint32 previousFramePointer = 0;
364 uint32 returnAddress = 0;
366 // check for syscall frames
367 stack_frame_type frameType;
368 bool hasPrologue = false;
369 if (isTopFrame && cpuState->InterruptVector() == 99) {
370 // The thread is performing a syscall. So this frame is not really the
371 // top-most frame and we need to adjust the eip.
372 frameType = STACK_FRAME_TYPE_SYSCALL;
373 eip -= 2;
374 // int 99, sysenter, and syscall all are 2 byte instructions
376 // The syscall stubs are frameless, the return address is on top of the
377 // stack.
378 uint32 esp = cpuState->IntRegisterValue(X86_REGISTER_ESP);
379 uint32 address;
380 if (fTeamMemory->ReadMemory(esp, &address, 4) == 4) {
381 returnAddress = address;
382 previousFramePointer = framePointer;
383 framePointer = 0;
384 readStandardFrame = false;
386 } else {
387 hasPrologue = _HasFunctionPrologue(function);
388 if (hasPrologue)
389 frameType = STACK_FRAME_TYPE_STANDARD;
390 else
391 frameType = STACK_FRAME_TYPE_FRAMELESS;
392 // TODO: Handling for frameless functions. It's not trivial to find the
393 // return address on the stack, though.
395 // If the function is not frameless and we're at the top frame we need
396 // to check whether the prologue has not been executed (completely) or
397 // we're already after the epilogue.
398 if (isTopFrame) {
399 uint32 stack = 0;
400 if (hasPrologue) {
401 if (eip < function->Address() + 3) {
402 // The prologue has not been executed yet, i.e. there's no
403 // stack frame yet. Get the return address from the stack.
404 stack = cpuState->IntRegisterValue(X86_REGISTER_ESP);
405 if (eip > function->Address()) {
406 // The "push %ebp" has already been executed.
407 stack += 4;
409 } else {
410 // Not in the function prologue, but maybe after the
411 // epilogue. The epilogue is a single "pop %ebp", so we
412 // check whether the current instruction is already a
413 // "ret".
414 uint8 code[1];
415 if (fTeamMemory->ReadMemory(eip, &code, 1) == 1
416 && code[0] == 0xc3) {
417 stack = cpuState->IntRegisterValue(X86_REGISTER_ESP);
420 } else {
421 // Check if the instruction pointer is at a readable location.
422 // If it isn't, then chances are we got here via a bogus
423 // function pointer, and the prologue hasn't actually been
424 // executed. In such a case, what we need is right at the top
425 // of the stack.
426 uint8 data[1];
427 if (fTeamMemory->ReadMemory(eip, &data, 1) != 1)
428 stack = cpuState->IntRegisterValue(X86_REGISTER_ESP);
431 if (stack != 0) {
432 uint32 address;
433 if (fTeamMemory->ReadMemory(stack, &address, 4) == 4) {
434 returnAddress = address;
435 previousFramePointer = framePointer;
436 framePointer = 0;
437 readStandardFrame = false;
438 frameType = STACK_FRAME_TYPE_FRAMELESS;
444 // create the stack frame
445 StackFrameDebugInfo* stackFrameDebugInfo
446 = new(std::nothrow) NoOpStackFrameDebugInfo;
447 if (stackFrameDebugInfo == NULL)
448 return B_NO_MEMORY;
449 BReference<StackFrameDebugInfo> stackFrameDebugInfoReference(
450 stackFrameDebugInfo, true);
452 StackFrame* frame = new(std::nothrow) StackFrame(frameType, cpuState,
453 framePointer, eip, stackFrameDebugInfo);
454 if (frame == NULL)
455 return B_NO_MEMORY;
456 BReference<StackFrame> frameReference(frame, true);
458 status_t error = frame->Init();
459 if (error != B_OK)
460 return error;
462 // read the previous frame and return address, if this is a standard frame
463 if (readStandardFrame) {
464 uint32 frameData[2];
465 if (framePointer != 0
466 && fTeamMemory->ReadMemory(framePointer, frameData, 8) == 8) {
467 previousFramePointer = frameData[0];
468 returnAddress = frameData[1];
472 // create the CPU state, if we have any info
473 CpuStateX86* previousCpuState = NULL;
474 if (returnAddress != 0) {
475 // prepare the previous CPU state
476 previousCpuState = new(std::nothrow) CpuStateX86;
477 if (previousCpuState == NULL)
478 return B_NO_MEMORY;
480 previousCpuState->SetIntRegister(X86_REGISTER_EBP,
481 previousFramePointer);
482 previousCpuState->SetIntRegister(X86_REGISTER_EIP, returnAddress);
483 frame->SetPreviousCpuState(previousCpuState);
486 frame->SetReturnAddress(returnAddress);
488 _frame = frameReference.Detach();
489 _previousCpuState = previousCpuState;
490 return B_OK;
494 void
495 ArchitectureX86::UpdateStackFrameCpuState(const StackFrame* frame,
496 Image* previousImage, FunctionDebugInfo* previousFunction,
497 CpuState* previousCpuState)
499 // This is not a top frame, so we want to offset eip to the previous
500 // (calling) instruction.
501 CpuStateX86* cpuState = dynamic_cast<CpuStateX86*>(previousCpuState);
503 // get eip
504 uint32 eip = cpuState->IntRegisterValue(X86_REGISTER_EIP);
505 if (previousFunction == NULL || eip <= previousFunction->Address())
506 return;
507 target_addr_t functionAddress = previousFunction->Address();
509 // allocate a buffer for the function code to disassemble
510 size_t bufferSize = eip - functionAddress;
511 void* buffer = malloc(bufferSize);
512 if (buffer == NULL)
513 return;
514 MemoryDeleter bufferDeleter(buffer);
516 // read the code
517 ssize_t bytesRead = fTeamMemory->ReadMemory(functionAddress, buffer,
518 bufferSize);
519 if (bytesRead != (ssize_t)bufferSize)
520 return;
522 // disassemble to get the previous instruction
523 DisassemblerX86 disassembler;
524 target_addr_t instructionAddress;
525 target_size_t instructionSize;
526 if (disassembler.Init(functionAddress, buffer, bufferSize) == B_OK
527 && disassembler.GetPreviousInstruction(eip, instructionAddress,
528 instructionSize) == B_OK) {
529 eip -= instructionSize;
530 cpuState->SetIntRegister(X86_REGISTER_EIP, eip);
535 status_t
536 ArchitectureX86::ReadValueFromMemory(target_addr_t address, uint32 valueType,
537 BVariant& _value) const
539 uint8 buffer[64];
540 size_t size = BVariant::SizeOfType(valueType);
541 if (size == 0 || size > sizeof(buffer))
542 return B_BAD_VALUE;
544 ssize_t bytesRead = fTeamMemory->ReadMemory(address, buffer, size);
545 if (bytesRead < 0)
546 return bytesRead;
547 if ((size_t)bytesRead != size)
548 return B_ERROR;
550 // TODO: We need to swap endianess, if the host is big endian!
552 switch (valueType) {
553 case B_INT8_TYPE:
554 _value.SetTo(*(int8*)buffer);
555 return B_OK;
556 case B_UINT8_TYPE:
557 _value.SetTo(*(uint8*)buffer);
558 return B_OK;
559 case B_INT16_TYPE:
560 _value.SetTo(*(int16*)buffer);
561 return B_OK;
562 case B_UINT16_TYPE:
563 _value.SetTo(*(uint16*)buffer);
564 return B_OK;
565 case B_INT32_TYPE:
566 _value.SetTo(*(int32*)buffer);
567 return B_OK;
568 case B_UINT32_TYPE:
569 _value.SetTo(*(uint32*)buffer);
570 return B_OK;
571 case B_INT64_TYPE:
572 _value.SetTo(*(int64*)buffer);
573 return B_OK;
574 case B_UINT64_TYPE:
575 _value.SetTo(*(uint64*)buffer);
576 return B_OK;
577 case B_FLOAT_TYPE:
578 _value.SetTo(*(float*)buffer);
579 // TODO: float on the host might work differently!
580 return B_OK;
581 case B_DOUBLE_TYPE:
582 _value.SetTo(*(double*)buffer);
583 // TODO: double on the host might work differently!
584 return B_OK;
585 default:
586 return B_BAD_VALUE;
591 status_t
592 ArchitectureX86::ReadValueFromMemory(target_addr_t addressSpace,
593 target_addr_t address, uint32 valueType, BVariant& _value) const
595 // n/a on this architecture
596 return B_BAD_VALUE;
600 status_t
601 ArchitectureX86::DisassembleCode(FunctionDebugInfo* function,
602 const void* buffer, size_t bufferSize, DisassembledCode*& _sourceCode)
604 DisassembledCode* source = new(std::nothrow) DisassembledCode(
605 fAssemblyLanguage);
606 if (source == NULL)
607 return B_NO_MEMORY;
608 BReference<DisassembledCode> sourceReference(source, true);
610 // init disassembler
611 DisassemblerX86 disassembler;
612 status_t error = disassembler.Init(function->Address(), buffer, bufferSize);
613 if (error != B_OK)
614 return error;
616 // add a function name line
617 BString functionName(function->PrettyName());
618 if (!source->AddCommentLine((functionName << ':').String()))
619 return B_NO_MEMORY;
621 // disassemble the instructions
622 BString line;
623 target_addr_t instructionAddress;
624 target_size_t instructionSize;
625 bool breakpointAllowed;
626 while (disassembler.GetNextInstruction(line, instructionAddress,
627 instructionSize, breakpointAllowed) == B_OK) {
628 // TODO: Respect breakpointAllowed!
629 if (!source->AddInstructionLine(line, instructionAddress,
630 instructionSize)) {
631 return B_NO_MEMORY;
635 _sourceCode = sourceReference.Detach();
636 return B_OK;
640 status_t
641 ArchitectureX86::GetStatement(FunctionDebugInfo* function,
642 target_addr_t address, Statement*& _statement)
644 // TODO: This is not architecture dependent anymore!
645 // get the instruction info
646 InstructionInfo info;
647 status_t error = GetInstructionInfo(address, info, NULL);
648 if (error != B_OK)
649 return error;
651 // create a statement
652 ContiguousStatement* statement = new(std::nothrow) ContiguousStatement(
653 SourceLocation(-1), TargetAddressRange(info.Address(), info.Size()));
654 if (statement == NULL)
655 return B_NO_MEMORY;
657 _statement = statement;
658 return B_OK;
662 status_t
663 ArchitectureX86::GetInstructionInfo(target_addr_t address,
664 InstructionInfo& _info, CpuState* state)
666 // read the code - maximum x86{-64} instruction size = 15 bytes
667 uint8 buffer[16];
668 ssize_t bytesRead = fTeamMemory->ReadMemory(address, buffer,
669 sizeof(buffer));
670 if (bytesRead < 0)
671 return bytesRead;
673 // init disassembler
674 DisassemblerX86 disassembler;
675 status_t error = disassembler.Init(address, buffer, bytesRead);
676 if (error != B_OK)
677 return error;
679 return disassembler.GetNextInstructionInfo(_info, state);
683 status_t
684 ArchitectureX86::ResolvePICFunctionAddress(target_addr_t instructionAddress,
685 CpuState* state, target_addr_t& _targetAddress)
687 // if the function in question is position-independent, the call
688 // will actually have taken us to its corresponding PLT slot.
689 // in such a case, look at the disassembled jump to determine
690 // where to find the actual function address.
691 InstructionInfo info;
692 if (GetInstructionInfo(instructionAddress, info, state) != B_OK) {
693 return B_BAD_VALUE;
695 target_addr_t subroutineAddress = info.TargetAddress();
697 ssize_t bytesRead = fTeamMemory->ReadMemory(info.TargetAddress(),
698 &subroutineAddress, fAddressSize);
700 if (bytesRead != fAddressSize)
701 return B_BAD_VALUE;
703 _targetAddress = subroutineAddress;
704 return B_OK;
708 status_t
709 ArchitectureX86::GetWatchpointDebugCapabilities(int32& _maxRegisterCount,
710 int32& _maxBytesPerRegister, uint8& _watchpointCapabilityFlags)
712 // while x86 technically has 4 hardware debug registers, one is reserved by
713 // the kernel, and one is required for breakpoint support, which leaves
714 // two available for watchpoints.
715 _maxRegisterCount = 2;
716 _maxBytesPerRegister = 4;
718 // x86 only supports write and read/write watchpoints.
719 _watchpointCapabilityFlags = WATCHPOINT_CAPABILITY_FLAG_WRITE
720 | WATCHPOINT_CAPABILITY_FLAG_READ_WRITE;
722 return B_OK;
726 status_t
727 ArchitectureX86::GetReturnAddressLocation(StackFrame* frame,
728 target_size_t valueSize, ValueLocation*& _location)
730 // for the calling conventions currently in use on Haiku,
731 // the x86 rules for how values are returned are as follows:
733 // - 32 bits or smaller values are returned directly in EAX.
734 // - 32-64 bit values are returned across EAX:EDX.
735 // - > 64 bit values are returned on the stack.
736 ValueLocation* location = new(std::nothrow) ValueLocation(
737 IsBigEndian());
738 if (location == NULL)
739 return B_NO_MEMORY;
740 BReference<ValueLocation> locationReference(location,
741 true);
743 if (valueSize <= 4) {
744 ValuePieceLocation piece;
745 piece.SetSize(valueSize);
746 piece.SetToRegister(X86_REGISTER_EAX);
747 if (!location->AddPiece(piece))
748 return B_NO_MEMORY;
749 } else if (valueSize <= 8) {
750 ValuePieceLocation piece;
751 piece.SetSize(4);
752 piece.SetToRegister(X86_REGISTER_EAX);
753 if (!location->AddPiece(piece))
754 return B_NO_MEMORY;
755 piece.SetToRegister(X86_REGISTER_EDX);
756 piece.SetSize(valueSize - 4);
757 if (!location->AddPiece(piece))
758 return B_NO_MEMORY;
759 } else {
760 ValuePieceLocation piece;
761 CpuStateX86* state = dynamic_cast<CpuStateX86*>(frame->GetCpuState());
762 piece.SetToMemory(state->IntRegisterValue(X86_REGISTER_EAX));
763 piece.SetSize(valueSize);
764 if (!location->AddPiece(piece))
765 return B_NO_MEMORY;
768 _location = locationReference.Detach();
769 return B_OK;
773 void
774 ArchitectureX86::_AddRegister(int32 index, const char* name,
775 uint32 bitSize, uint32 valueType, register_type type, bool calleePreserved)
777 if (!fRegisters.Add(Register(index, name, bitSize, valueType, type,
778 calleePreserved))) {
779 throw std::bad_alloc();
784 void
785 ArchitectureX86::_AddIntegerRegister(int32 index, const char* name,
786 uint32 valueType, register_type type, bool calleePreserved)
788 _AddRegister(index, name, 8 * BVariant::SizeOfType(valueType), valueType,
789 type, calleePreserved);
793 void
794 ArchitectureX86::_AddFPRegister(int32 index, const char* name)
796 _AddRegister(index, name, 8 * BVariant::SizeOfType(B_DOUBLE_TYPE),
797 B_DOUBLE_TYPE, REGISTER_TYPE_GENERAL_PURPOSE, true);
801 void
802 ArchitectureX86::_AddSIMDRegister(int32 index, const char* name,
803 uint32 byteSize)
805 _AddRegister(index, name, byteSize * 8, B_RAW_TYPE,
806 REGISTER_TYPE_GENERAL_PURPOSE, true);
810 bool
811 ArchitectureX86::_HasFunctionPrologue(FunctionDebugInfo* function) const
813 if (function == NULL)
814 return false;
816 // check whether the function has the typical prologue
817 if (function->Size() < 3)
818 return false;
820 uint8 buffer[3];
821 if (fTeamMemory->ReadMemory(function->Address(), buffer, 3) != 3)
822 return false;
824 return buffer[0] == 0x55 && buffer[1] == 0x89 && buffer[2] == 0xe5;