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