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