xref: /haiku/src/kits/debugger/arch/x86_64/ArchitectureX8664.cpp (revision 6f3a5c9ab0c2f388ef0ff6efff713732a710cd93)
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 
34 static 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 
93 static const int32 kFromDwarfRegisterCount = sizeof(kFromDwarfRegisters) / 4;
94 static const uint16 kFunctionPrologueSize = 4;
95 
96 
97 // #pragma mark - ToDwarfRegisterMap
98 
99 
100 struct ArchitectureX8664::ToDwarfRegisterMap : RegisterMap {
ToDwarfRegisterMapArchitectureX8664::ToDwarfRegisterMap101 	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 
CountRegistersArchitectureX8664::ToDwarfRegisterMap111 	virtual int32 CountRegisters() const
112 	{
113 		return X86_64_REGISTER_COUNT;
114 	}
115 
MapRegisterIndexArchitectureX8664::ToDwarfRegisterMap116 	virtual int32 MapRegisterIndex(int32 index) const
117 	{
118 		return index >= 0 && index < X86_64_REGISTER_COUNT ? fIndices[index] : -1;
119 	}
120 
121 private:
122 	int32	fIndices[X86_64_REGISTER_COUNT];
123 };
124 
125 
126 // #pragma mark - FromDwarfRegisterMap
127 
128 
129 struct ArchitectureX8664::FromDwarfRegisterMap : RegisterMap {
CountRegistersArchitectureX8664::FromDwarfRegisterMap130 	virtual int32 CountRegisters() const
131 	{
132 		return kFromDwarfRegisterCount;
133 	}
134 
MapRegisterIndexArchitectureX8664::FromDwarfRegisterMap135 	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 
ArchitectureX8664(TeamMemory * teamMemory)146 ArchitectureX8664::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 
~ArchitectureX8664()156 ArchitectureX8664::~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 
167 status_t
Init()168 ArchitectureX8664::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 
340 int32
StackGrowthDirection() const341 ArchitectureX8664::StackGrowthDirection() const
342 {
343 	return STACK_GROWTH_DIRECTION_NEGATIVE;
344 }
345 
346 
347 int32
CountRegisters() const348 ArchitectureX8664::CountRegisters() const
349 {
350 	return fRegisters.Count();
351 }
352 
353 
354 const Register*
Registers() const355 ArchitectureX8664::Registers() const
356 {
357 	return fRegisters.Elements();
358 }
359 
360 
361 status_t
InitRegisterRules(CfaContext & context) const362 ArchitectureX8664::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 
376 status_t
GetDwarfRegisterMaps(RegisterMap ** _toDwarf,RegisterMap ** _fromDwarf) const377 ArchitectureX8664::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 
394 status_t
GetCpuFeatures(uint32 & flags)395 ArchitectureX8664::GetCpuFeatures(uint32& flags)
396 {
397 	// TODO: implement if/when it winds up being needed.
398 	flags = 0;
399 	return B_OK;
400 }
401 
402 
403 status_t
CreateCpuState(CpuState * & _state)404 ArchitectureX8664::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 
415 status_t
CreateCpuState(const void * cpuStateData,size_t size,CpuState * & _state)416 ArchitectureX8664::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 
432 status_t
CreateStackFrame(Image * image,FunctionDebugInfo * function,CpuState * _cpuState,bool isTopFrame,StackFrame * & _frame,CpuState * & _previousCpuState)433 ArchitectureX8664::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 
574 void
UpdateStackFrameCpuState(const StackFrame * frame,Image * previousImage,FunctionDebugInfo * previousFunction,CpuState * previousCpuState)575 ArchitectureX8664::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 
615 status_t
ReadValueFromMemory(target_addr_t address,uint32 valueType,BVariant & _value) const616 ArchitectureX8664::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 
671 status_t
ReadValueFromMemory(target_addr_t addressSpace,target_addr_t address,uint32 valueType,BVariant & _value) const672 ArchitectureX8664::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 
680 status_t
DisassembleCode(FunctionDebugInfo * function,const void * buffer,size_t bufferSize,DisassembledCode * & _sourceCode)681 ArchitectureX8664::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 
720 status_t
GetStatement(FunctionDebugInfo * function,target_addr_t address,Statement * & _statement)721 ArchitectureX8664::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 
742 status_t
GetInstructionInfo(target_addr_t address,InstructionInfo & _info,CpuState * state)743 ArchitectureX8664::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 
763 status_t
ResolvePICFunctionAddress(target_addr_t instructionAddress,CpuState * state,target_addr_t & _targetAddress)764 ArchitectureX8664::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 
798 status_t
GetWatchpointDebugCapabilities(int32 & _maxRegisterCount,int32 & _maxBytesPerRegister,uint8 & _watchpointCapabilityFlags)799 ArchitectureX8664::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 
815 status_t
GetReturnAddressLocation(StackFrame * frame,target_size_t valueSize,ValueLocation * & _location)816 ArchitectureX8664::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 
851 void
_AddRegister(int32 index,const char * name,uint32 bitSize,uint32 valueType,register_type type,bool calleePreserved)852 ArchitectureX8664::_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 
862 void
_AddIntegerRegister(int32 index,const char * name,uint32 valueType,register_type type,bool calleePreserved)863 ArchitectureX8664::_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 
871 void
_AddFPRegister(int32 index,const char * name)872 ArchitectureX8664::_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 
879 void
_AddSIMDRegister(int32 index,const char * name,uint32 byteSize)880 ArchitectureX8664::_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 
888 bool
_HasFunctionPrologue(FunctionDebugInfo * function) const889 ArchitectureX8664::_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