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
36static 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
76static const int32 kFromDwarfRegisterCount = sizeof(kFromDwarfRegisters) / 4;
77
78
79// #pragma mark - ToDwarfRegisterMap
80
81
82struct 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
103private:
104	int32	fIndices[X86_REGISTER_COUNT];
105};
106
107
108// #pragma mark - FromDwarfRegisterMap
109
110
111struct 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
128ArchitectureX86::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
139ArchitectureX86::~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
150status_t
151ArchitectureX86::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
262int32
263ArchitectureX86::StackGrowthDirection() const
264{
265	return STACK_GROWTH_DIRECTION_NEGATIVE;
266}
267
268
269int32
270ArchitectureX86::CountRegisters() const
271{
272	return fRegisters.Count();
273}
274
275
276const Register*
277ArchitectureX86::Registers() const
278{
279	return fRegisters.Elements();
280}
281
282
283
284status_t
285ArchitectureX86::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
299status_t
300ArchitectureX86::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
317status_t
318ArchitectureX86::GetCpuFeatures(uint32& flags)
319{
320	flags = fFeatureFlags;
321
322	return B_OK;
323}
324
325
326status_t
327ArchitectureX86::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
338status_t
339ArchitectureX86::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
355status_t
356ArchitectureX86::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
497void
498ArchitectureX86::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
538status_t
539ArchitectureX86::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
594status_t
595ArchitectureX86::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
603status_t
604ArchitectureX86::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
643status_t
644ArchitectureX86::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
665status_t
666ArchitectureX86::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
686status_t
687ArchitectureX86::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
711status_t
712ArchitectureX86::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
729status_t
730ArchitectureX86::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
776void
777ArchitectureX86::_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
787void
788ArchitectureX86::_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
796void
797ArchitectureX86::_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
804void
805ArchitectureX86::_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
813bool
814ArchitectureX86::_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