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