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