1/*
2 * Copyright 2012, Alex Smith, alex@alex-smith.me.uk.
3 * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de.
4 * Copyright 2011-2012, 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 "X86AssemblyLanguage.h"
28
29#include "disasm/DisassemblerX8664.h"
30
31
32static const int32 kFromDwarfRegisters[] = {
33	X86_64_REGISTER_RAX,
34	X86_64_REGISTER_RDX,
35	X86_64_REGISTER_RCX,
36	X86_64_REGISTER_RBX,
37	X86_64_REGISTER_RSI,
38	X86_64_REGISTER_RDI,
39	X86_64_REGISTER_RBP,
40	X86_64_REGISTER_RSP,
41	X86_64_REGISTER_R8,
42	X86_64_REGISTER_R9,
43	X86_64_REGISTER_R10,
44	X86_64_REGISTER_R11,
45	X86_64_REGISTER_R12,
46	X86_64_REGISTER_R13,
47	X86_64_REGISTER_R14,
48	X86_64_REGISTER_R15,
49	X86_64_REGISTER_RIP,
50	-1, -1, -1, -1, -1, -1, -1, -1,	// xmm0-xmm7
51	-1, -1, -1, -1, -1, -1, -1, -1,	// xmm8-xmm15
52	-1, -1, -1, -1, -1, -1, -1, -1,	// st0-st7
53	-1, -1, -1, -1, -1, -1, -1, -1,	// mm0-mm7
54	-1,								// rflags
55	X86_64_REGISTER_ES,
56	X86_64_REGISTER_CS,
57	X86_64_REGISTER_SS,
58	X86_64_REGISTER_DS,
59	X86_64_REGISTER_FS,
60	X86_64_REGISTER_GS,
61};
62
63static const int32 kFromDwarfRegisterCount = sizeof(kFromDwarfRegisters) / 4;
64
65
66// #pragma mark - ToDwarfRegisterMap
67
68
69struct ArchitectureX8664::ToDwarfRegisterMap : RegisterMap {
70	ToDwarfRegisterMap()
71	{
72		// init the index array from the reverse map
73		memset(fIndices, -1, sizeof(fIndices));
74		for (int32 i = 0; i < kFromDwarfRegisterCount; i++) {
75			if (kFromDwarfRegisters[i] >= 0)
76				fIndices[kFromDwarfRegisters[i]] = i;
77		}
78	}
79
80	virtual int32 CountRegisters() const
81	{
82		return X86_64_REGISTER_COUNT;
83	}
84
85	virtual int32 MapRegisterIndex(int32 index) const
86	{
87		return index >= 0 && index < X86_64_REGISTER_COUNT ? fIndices[index] : -1;
88	}
89
90private:
91	int32	fIndices[X86_64_REGISTER_COUNT];
92};
93
94
95// #pragma mark - FromDwarfRegisterMap
96
97
98struct ArchitectureX8664::FromDwarfRegisterMap : RegisterMap {
99	virtual int32 CountRegisters() const
100	{
101		return kFromDwarfRegisterCount;
102	}
103
104	virtual int32 MapRegisterIndex(int32 index) const
105	{
106		return index >= 0 && index < kFromDwarfRegisterCount
107			? kFromDwarfRegisters[index] : -1;
108	}
109};
110
111
112// #pragma mark - ArchitectureX8664
113
114
115ArchitectureX8664::ArchitectureX8664(TeamMemory* teamMemory)
116	:
117	Architecture(teamMemory, 8, false),
118	fAssemblyLanguage(NULL),
119	fToDwarfRegisterMap(NULL),
120	fFromDwarfRegisterMap(NULL)
121{
122}
123
124
125ArchitectureX8664::~ArchitectureX8664()
126{
127	if (fToDwarfRegisterMap != NULL)
128		fToDwarfRegisterMap->ReleaseReference();
129	if (fFromDwarfRegisterMap != NULL)
130		fFromDwarfRegisterMap->ReleaseReference();
131	if (fAssemblyLanguage != NULL)
132		fAssemblyLanguage->ReleaseReference();
133}
134
135
136status_t
137ArchitectureX8664::Init()
138{
139	fAssemblyLanguage = new(std::nothrow) X86AssemblyLanguage;
140	if (fAssemblyLanguage == NULL)
141		return B_NO_MEMORY;
142
143	try {
144		_AddIntegerRegister(X86_64_REGISTER_RIP, "rip", B_UINT64_TYPE,
145			REGISTER_TYPE_INSTRUCTION_POINTER, false);
146		_AddIntegerRegister(X86_64_REGISTER_RSP, "rsp", B_UINT64_TYPE,
147			REGISTER_TYPE_STACK_POINTER, true);
148		_AddIntegerRegister(X86_64_REGISTER_RBP, "rbp", B_UINT64_TYPE,
149			REGISTER_TYPE_GENERAL_PURPOSE, true);
150
151		_AddIntegerRegister(X86_64_REGISTER_RAX, "rax", B_UINT64_TYPE,
152			REGISTER_TYPE_GENERAL_PURPOSE, false);
153		_AddIntegerRegister(X86_64_REGISTER_RBX, "rbx", B_UINT64_TYPE,
154			REGISTER_TYPE_GENERAL_PURPOSE, true);
155		_AddIntegerRegister(X86_64_REGISTER_RCX, "rcx", B_UINT64_TYPE,
156			REGISTER_TYPE_GENERAL_PURPOSE, false);
157		_AddIntegerRegister(X86_64_REGISTER_RDX, "rdx", B_UINT64_TYPE,
158			REGISTER_TYPE_GENERAL_PURPOSE, false);
159
160		_AddIntegerRegister(X86_64_REGISTER_RSI, "rsi", B_UINT64_TYPE,
161			REGISTER_TYPE_GENERAL_PURPOSE, false);
162		_AddIntegerRegister(X86_64_REGISTER_RDI, "rdi", B_UINT64_TYPE,
163			REGISTER_TYPE_GENERAL_PURPOSE, false);
164
165		_AddIntegerRegister(X86_64_REGISTER_R8, "r8", B_UINT64_TYPE,
166			REGISTER_TYPE_GENERAL_PURPOSE, false);
167		_AddIntegerRegister(X86_64_REGISTER_R9, "r9", B_UINT64_TYPE,
168			REGISTER_TYPE_GENERAL_PURPOSE, false);
169		_AddIntegerRegister(X86_64_REGISTER_R10, "r10", B_UINT64_TYPE,
170			REGISTER_TYPE_GENERAL_PURPOSE, false);
171		_AddIntegerRegister(X86_64_REGISTER_R11, "r11", B_UINT64_TYPE,
172			REGISTER_TYPE_GENERAL_PURPOSE, false);
173		_AddIntegerRegister(X86_64_REGISTER_R12, "r12", B_UINT64_TYPE,
174			REGISTER_TYPE_GENERAL_PURPOSE, true);
175		_AddIntegerRegister(X86_64_REGISTER_R13, "r13", B_UINT64_TYPE,
176			REGISTER_TYPE_GENERAL_PURPOSE, true);
177		_AddIntegerRegister(X86_64_REGISTER_R14, "r14", B_UINT64_TYPE,
178			REGISTER_TYPE_GENERAL_PURPOSE, true);
179		_AddIntegerRegister(X86_64_REGISTER_R15, "r15", B_UINT64_TYPE,
180			REGISTER_TYPE_GENERAL_PURPOSE, true);
181
182		_AddIntegerRegister(X86_64_REGISTER_CS, "cs", B_UINT16_TYPE,
183			REGISTER_TYPE_SPECIAL_PURPOSE, true);
184		_AddIntegerRegister(X86_64_REGISTER_DS, "ds", B_UINT16_TYPE,
185			REGISTER_TYPE_SPECIAL_PURPOSE, true);
186		_AddIntegerRegister(X86_64_REGISTER_ES, "es", B_UINT16_TYPE,
187			REGISTER_TYPE_SPECIAL_PURPOSE, true);
188		_AddIntegerRegister(X86_64_REGISTER_FS, "fs", B_UINT16_TYPE,
189			REGISTER_TYPE_SPECIAL_PURPOSE, true);
190		_AddIntegerRegister(X86_64_REGISTER_GS, "gs", B_UINT16_TYPE,
191			REGISTER_TYPE_SPECIAL_PURPOSE, true);
192		_AddIntegerRegister(X86_64_REGISTER_SS, "ss", B_UINT16_TYPE,
193			REGISTER_TYPE_SPECIAL_PURPOSE, true);
194	} catch (std::bad_alloc) {
195		return B_NO_MEMORY;
196	}
197
198	fToDwarfRegisterMap = new(std::nothrow) ToDwarfRegisterMap;
199	fFromDwarfRegisterMap = new(std::nothrow) FromDwarfRegisterMap;
200
201	if (fToDwarfRegisterMap == NULL || fFromDwarfRegisterMap == NULL)
202		return B_NO_MEMORY;
203
204	return B_OK;
205}
206
207
208int32
209ArchitectureX8664::StackGrowthDirection() const
210{
211	return STACK_GROWTH_DIRECTION_NEGATIVE;
212}
213
214
215int32
216ArchitectureX8664::CountRegisters() const
217{
218	return fRegisters.Count();
219}
220
221
222const Register*
223ArchitectureX8664::Registers() const
224{
225	return fRegisters.Elements();
226}
227
228
229status_t
230ArchitectureX8664::InitRegisterRules(CfaContext& context) const
231{
232	status_t error = Architecture::InitRegisterRules(context);
233	if (error != B_OK)
234		return error;
235
236	// set up rule for RIP register
237	context.RegisterRule(fToDwarfRegisterMap->MapRegisterIndex(
238		X86_64_REGISTER_RIP))->SetToLocationOffset(0);
239
240	return B_OK;
241}
242
243
244status_t
245ArchitectureX8664::GetDwarfRegisterMaps(RegisterMap** _toDwarf,
246	RegisterMap** _fromDwarf) const
247{
248	if (_toDwarf != NULL) {
249		*_toDwarf = fToDwarfRegisterMap;
250		fToDwarfRegisterMap->AcquireReference();
251	}
252
253	if (_fromDwarf != NULL) {
254		*_fromDwarf = fFromDwarfRegisterMap;
255		fFromDwarfRegisterMap->AcquireReference();
256	}
257
258	return B_OK;
259}
260
261
262status_t
263ArchitectureX8664::CreateCpuState(CpuState*& _state)
264{
265	CpuStateX8664* state = new(std::nothrow) CpuStateX8664;
266	if (state == NULL)
267		return B_NO_MEMORY;
268
269	_state = state;
270	return B_OK;
271}
272
273
274status_t
275ArchitectureX8664::CreateCpuState(const void* cpuStateData, size_t size,
276	CpuState*& _state)
277{
278	if (size != sizeof(x86_64_debug_cpu_state))
279		return B_BAD_VALUE;
280
281	CpuStateX8664* state = new(std::nothrow) CpuStateX8664(
282		*(const x86_64_debug_cpu_state*)cpuStateData);
283	if (state == NULL)
284		return B_NO_MEMORY;
285
286	_state = state;
287	return B_OK;
288}
289
290
291status_t
292ArchitectureX8664::CreateStackFrame(Image* image, FunctionDebugInfo* function,
293	CpuState* _cpuState, bool isTopFrame, StackFrame*& _frame,
294	CpuState*& _previousCpuState)
295{
296	fprintf(stderr, "ArchitectureX8664::CreateStackFrame: TODO\n");
297	return B_UNSUPPORTED;
298}
299
300
301void
302ArchitectureX8664::UpdateStackFrameCpuState(const StackFrame* frame,
303	Image* previousImage, FunctionDebugInfo* previousFunction,
304	CpuState* previousCpuState)
305{
306	// This is not a top frame, so we want to offset rip to the previous
307	// (calling) instruction.
308	CpuStateX8664* cpuState = dynamic_cast<CpuStateX8664*>(previousCpuState);
309
310	// get rip
311	uint64 rip = cpuState->IntRegisterValue(X86_64_REGISTER_RIP);
312	if (previousFunction == NULL || rip <= previousFunction->Address())
313		return;
314	target_addr_t functionAddress = previousFunction->Address();
315
316	// allocate a buffer for the function code to disassemble
317	size_t bufferSize = rip - functionAddress;
318	void* buffer = malloc(bufferSize);
319	if (buffer == NULL)
320		return;
321	MemoryDeleter bufferDeleter(buffer);
322
323	// read the code
324	ssize_t bytesRead = fTeamMemory->ReadMemory(functionAddress, buffer,
325		bufferSize);
326	if (bytesRead != (ssize_t)bufferSize)
327		return;
328
329	// disassemble to get the previous instruction
330	DisassemblerX8664 disassembler;
331	target_addr_t instructionAddress;
332	target_size_t instructionSize;
333	if (disassembler.Init(functionAddress, buffer, bufferSize) == B_OK
334		&& disassembler.GetPreviousInstruction(rip, instructionAddress,
335			instructionSize) == B_OK) {
336		rip -= instructionSize;
337		cpuState->SetIntRegister(X86_64_REGISTER_RIP, rip);
338	}
339}
340
341
342status_t
343ArchitectureX8664::ReadValueFromMemory(target_addr_t address, uint32 valueType,
344	BVariant& _value) const
345{
346	uint8 buffer[64];
347	size_t size = BVariant::SizeOfType(valueType);
348	if (size == 0 || size > sizeof(buffer))
349		return B_BAD_VALUE;
350
351	ssize_t bytesRead = fTeamMemory->ReadMemory(address, buffer, size);
352	if (bytesRead < 0)
353		return bytesRead;
354	if ((size_t)bytesRead != size)
355		return B_ERROR;
356
357	// TODO: We need to swap endianess, if the host is big endian!
358
359	switch (valueType) {
360		case B_INT8_TYPE:
361			_value.SetTo(*(int8*)buffer);
362			return B_OK;
363		case B_UINT8_TYPE:
364			_value.SetTo(*(uint8*)buffer);
365			return B_OK;
366		case B_INT16_TYPE:
367			_value.SetTo(*(int16*)buffer);
368			return B_OK;
369		case B_UINT16_TYPE:
370			_value.SetTo(*(uint16*)buffer);
371			return B_OK;
372		case B_INT32_TYPE:
373			_value.SetTo(*(int32*)buffer);
374			return B_OK;
375		case B_UINT32_TYPE:
376			_value.SetTo(*(uint32*)buffer);
377			return B_OK;
378		case B_INT64_TYPE:
379			_value.SetTo(*(int64*)buffer);
380			return B_OK;
381		case B_UINT64_TYPE:
382			_value.SetTo(*(uint64*)buffer);
383			return B_OK;
384		case B_FLOAT_TYPE:
385			_value.SetTo(*(float*)buffer);
386				// TODO: float on the host might work differently!
387			return B_OK;
388		case B_DOUBLE_TYPE:
389			_value.SetTo(*(double*)buffer);
390				// TODO: double on the host might work differently!
391			return B_OK;
392		default:
393			return B_BAD_VALUE;
394	}
395}
396
397
398status_t
399ArchitectureX8664::ReadValueFromMemory(target_addr_t addressSpace,
400	target_addr_t address, uint32 valueType, BVariant& _value) const
401{
402	// n/a on this architecture
403	return B_BAD_VALUE;
404}
405
406
407status_t
408ArchitectureX8664::DisassembleCode(FunctionDebugInfo* function,
409	const void* buffer, size_t bufferSize, DisassembledCode*& _sourceCode)
410{
411	DisassembledCode* source = new(std::nothrow) DisassembledCode(
412		fAssemblyLanguage);
413	if (source == NULL)
414		return B_NO_MEMORY;
415	BReference<DisassembledCode> sourceReference(source, true);
416
417	// init disassembler
418	DisassemblerX8664 disassembler;
419	status_t error = disassembler.Init(function->Address(), buffer, bufferSize);
420	if (error != B_OK)
421		return error;
422
423	// add a function name line
424	BString functionName(function->PrettyName());
425	if (!source->AddCommentLine((functionName << ':').String()))
426		return B_NO_MEMORY;
427
428	// disassemble the instructions
429	BString line;
430	target_addr_t instructionAddress;
431	target_size_t instructionSize;
432	bool breakpointAllowed;
433	while (disassembler.GetNextInstruction(line, instructionAddress,
434				instructionSize, breakpointAllowed) == B_OK) {
435// TODO: Respect breakpointAllowed!
436		if (!source->AddInstructionLine(line, instructionAddress,
437				instructionSize)) {
438			return B_NO_MEMORY;
439		}
440	}
441
442	_sourceCode = sourceReference.Detach();
443	return B_OK;
444}
445
446
447status_t
448ArchitectureX8664::GetStatement(FunctionDebugInfo* function,
449	target_addr_t address, Statement*& _statement)
450{
451// TODO: This is not architecture dependent anymore!
452	// get the instruction info
453	InstructionInfo info;
454	status_t error = GetInstructionInfo(address, info, NULL);
455	if (error != B_OK)
456		return error;
457
458	// create a statement
459	ContiguousStatement* statement = new(std::nothrow) ContiguousStatement(
460		SourceLocation(-1), TargetAddressRange(info.Address(), info.Size()));
461	if (statement == NULL)
462		return B_NO_MEMORY;
463
464	_statement = statement;
465	return B_OK;
466}
467
468
469status_t
470ArchitectureX8664::GetInstructionInfo(target_addr_t address,
471	InstructionInfo& _info, CpuState* state)
472{
473	// read the code - maximum x86{-64} instruction size = 15 bytes
474	uint8 buffer[16];
475	ssize_t bytesRead = fTeamMemory->ReadMemory(address, buffer,
476		sizeof(buffer));
477	if (bytesRead < 0)
478		return bytesRead;
479
480	// init disassembler
481	DisassemblerX8664 disassembler;
482	status_t error = disassembler.Init(address, buffer, bytesRead);
483	if (error != B_OK)
484		return error;
485
486	return disassembler.GetNextInstructionInfo(_info, state);
487}
488
489
490status_t
491ArchitectureX8664::GetWatchpointDebugCapabilities(int32& _maxRegisterCount,
492	int32& _maxBytesPerRegister, uint8& _watchpointCapabilityFlags)
493{
494	// Have 4 debug registers, 1 is required for breakpoint support, which
495	// leaves 3 available for watchpoints.
496	_maxRegisterCount = 3;
497	_maxBytesPerRegister = 8;
498
499	// x86 only supports write and read/write watchpoints.
500	_watchpointCapabilityFlags = WATCHPOINT_CAPABILITY_FLAG_WRITE
501		| WATCHPOINT_CAPABILITY_FLAG_READ_WRITE;
502
503	return B_OK;
504}
505
506
507status_t
508ArchitectureX8664::GetReturnAddressLocation(StackFrame* frame,
509	target_size_t valueSize, ValueLocation*& _location) {
510	return B_NOT_SUPPORTED;
511}
512
513
514void
515ArchitectureX8664::_AddRegister(int32 index, const char* name,
516	uint32 bitSize, uint32 valueType, register_type type, bool calleePreserved)
517{
518	if (!fRegisters.Add(Register(index, name, bitSize, valueType, type,
519			calleePreserved))) {
520		throw std::bad_alloc();
521	}
522}
523
524
525void
526ArchitectureX8664::_AddIntegerRegister(int32 index, const char* name,
527	uint32 valueType, register_type type, bool calleePreserved)
528{
529	_AddRegister(index, name, 8 * BVariant::SizeOfType(valueType), valueType,
530		type, calleePreserved);
531}
532