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