xref: /haiku/src/kits/debugger/arch/x86/ArchitectureX86.cpp (revision 5ffbe7d778424c9c59f00b37a3baff5c4c648790)
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 {
ToDwarfRegisterMapArchitectureX86::ToDwarfRegisterMap83 	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 
CountRegistersArchitectureX86::ToDwarfRegisterMap93 	virtual int32 CountRegisters() const
94 	{
95 		return X86_REGISTER_COUNT;
96 	}
97 
MapRegisterIndexArchitectureX86::ToDwarfRegisterMap98 	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 {
CountRegistersArchitectureX86::FromDwarfRegisterMap112 	virtual int32 CountRegisters() const
113 	{
114 		return kFromDwarfRegisterCount;
115 	}
116 
MapRegisterIndexArchitectureX86::FromDwarfRegisterMap117 	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 
ArchitectureX86(TeamMemory * teamMemory)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 
~ArchitectureX86()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
Init()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
StackGrowthDirection() const263 ArchitectureX86::StackGrowthDirection() const
264 {
265 	return STACK_GROWTH_DIRECTION_NEGATIVE;
266 }
267 
268 
269 int32
CountRegisters() const270 ArchitectureX86::CountRegisters() const
271 {
272 	return fRegisters.Count();
273 }
274 
275 
276 const Register*
Registers() const277 ArchitectureX86::Registers() const
278 {
279 	return fRegisters.Elements();
280 }
281 
282 
283 
284 status_t
InitRegisterRules(CfaContext & context) const285 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
GetDwarfRegisterMaps(RegisterMap ** _toDwarf,RegisterMap ** _fromDwarf) const300 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
GetCpuFeatures(uint32 & flags)318 ArchitectureX86::GetCpuFeatures(uint32& flags)
319 {
320 	flags = fFeatureFlags;
321 
322 	return B_OK;
323 }
324 
325 
326 status_t
CreateCpuState(CpuState * & _state)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
CreateCpuState(const void * cpuStateData,size_t size,CpuState * & _state)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
CreateStackFrame(Image * image,FunctionDebugInfo * function,CpuState * _cpuState,bool isTopFrame,StackFrame * & _frame,CpuState * & _previousCpuState)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
UpdateStackFrameCpuState(const StackFrame * frame,Image * previousImage,FunctionDebugInfo * previousFunction,CpuState * previousCpuState)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
ReadValueFromMemory(target_addr_t address,uint32 valueType,BVariant & _value) const539 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
ReadValueFromMemory(target_addr_t addressSpace,target_addr_t address,uint32 valueType,BVariant & _value) const595 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
DisassembleCode(FunctionDebugInfo * function,const void * buffer,size_t bufferSize,DisassembledCode * & _sourceCode)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
GetStatement(FunctionDebugInfo * function,target_addr_t address,Statement * & _statement)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
GetInstructionInfo(target_addr_t address,InstructionInfo & _info,CpuState * state)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
ResolvePICFunctionAddress(target_addr_t instructionAddress,CpuState * state,target_addr_t & _targetAddress)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
GetWatchpointDebugCapabilities(int32 & _maxRegisterCount,int32 & _maxBytesPerRegister,uint8 & _watchpointCapabilityFlags)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
GetReturnAddressLocation(StackFrame * frame,target_size_t valueSize,ValueLocation * & _location)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
_AddRegister(int32 index,const char * name,uint32 bitSize,uint32 valueType,register_type type,bool calleePreserved)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
_AddIntegerRegister(int32 index,const char * name,uint32 valueType,register_type type,bool calleePreserved)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
_AddFPRegister(int32 index,const char * name)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
_AddSIMDRegister(int32 index,const char * name,uint32 byteSize)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
_HasFunctionPrologue(FunctionDebugInfo * function) const814 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