1 //===-- ABIMacOSX_i386.cpp ------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "ABIMacOSX_i386.h"
10
11 #include <vector>
12
13 #include "llvm/ADT/STLExtras.h"
14 #include "llvm/ADT/Triple.h"
15
16 #include "lldb/Core/Module.h"
17 #include "lldb/Core/PluginManager.h"
18 #include "lldb/Core/ValueObjectConstResult.h"
19 #include "lldb/Symbol/UnwindPlan.h"
20 #include "lldb/Target/Process.h"
21 #include "lldb/Target/RegisterContext.h"
22 #include "lldb/Target/Target.h"
23 #include "lldb/Target/Thread.h"
24 #include "lldb/Utility/ConstString.h"
25 #include "lldb/Utility/RegisterValue.h"
26 #include "lldb/Utility/Scalar.h"
27 #include "lldb/Utility/Status.h"
28
29 using namespace lldb;
30 using namespace lldb_private;
31
32 LLDB_PLUGIN_DEFINE(ABIMacOSX_i386)
33
34 enum {
35 dwarf_eax = 0,
36 dwarf_ecx,
37 dwarf_edx,
38 dwarf_ebx,
39 dwarf_esp,
40 dwarf_ebp,
41 dwarf_esi,
42 dwarf_edi,
43 dwarf_eip,
44 };
45
GetRedZoneSize() const46 size_t ABIMacOSX_i386::GetRedZoneSize() const { return 0; }
47
48 // Static Functions
49
50 ABISP
CreateInstance(lldb::ProcessSP process_sp,const ArchSpec & arch)51 ABIMacOSX_i386::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) {
52 if ((arch.GetTriple().getArch() == llvm::Triple::x86) &&
53 (arch.GetTriple().isMacOSX() || arch.GetTriple().isiOS() ||
54 arch.GetTriple().isWatchOS())) {
55 return ABISP(
56 new ABIMacOSX_i386(std::move(process_sp), MakeMCRegisterInfo(arch)));
57 }
58 return ABISP();
59 }
60
PrepareTrivialCall(Thread & thread,addr_t sp,addr_t func_addr,addr_t return_addr,llvm::ArrayRef<addr_t> args) const61 bool ABIMacOSX_i386::PrepareTrivialCall(Thread &thread, addr_t sp,
62 addr_t func_addr, addr_t return_addr,
63 llvm::ArrayRef<addr_t> args) const {
64 RegisterContext *reg_ctx = thread.GetRegisterContext().get();
65 if (!reg_ctx)
66 return false;
67 uint32_t pc_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(
68 eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
69 uint32_t sp_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(
70 eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
71
72 // When writing a register value down to memory, the register info used to
73 // write memory just needs to have the correct size of a 32 bit register, the
74 // actual register it pertains to is not important, just the size needs to be
75 // correct. Here we use "eax"...
76 const RegisterInfo *reg_info_32 = reg_ctx->GetRegisterInfoByName("eax");
77 if (!reg_info_32)
78 return false; // TODO this should actually never happen
79
80 // Make room for the argument(s) on the stack
81
82 Status error;
83 RegisterValue reg_value;
84
85 // Write any arguments onto the stack
86 sp -= 4 * args.size();
87
88 // Align the SP
89 sp &= ~(16ull - 1ull); // 16-byte alignment
90
91 addr_t arg_pos = sp;
92
93 for (addr_t arg : args) {
94 reg_value.SetUInt32(arg);
95 error = reg_ctx->WriteRegisterValueToMemory(
96 reg_info_32, arg_pos, reg_info_32->byte_size, reg_value);
97 if (error.Fail())
98 return false;
99 arg_pos += 4;
100 }
101
102 // The return address is pushed onto the stack (yes after we just set the
103 // alignment above!).
104 sp -= 4;
105 reg_value.SetUInt32(return_addr);
106 error = reg_ctx->WriteRegisterValueToMemory(
107 reg_info_32, sp, reg_info_32->byte_size, reg_value);
108 if (error.Fail())
109 return false;
110
111 // %esp is set to the actual stack value.
112
113 if (!reg_ctx->WriteRegisterFromUnsigned(sp_reg_num, sp))
114 return false;
115
116 // %eip is set to the address of the called function.
117
118 if (!reg_ctx->WriteRegisterFromUnsigned(pc_reg_num, func_addr))
119 return false;
120
121 return true;
122 }
123
ReadIntegerArgument(Scalar & scalar,unsigned int bit_width,bool is_signed,Process * process,addr_t & current_stack_argument)124 static bool ReadIntegerArgument(Scalar &scalar, unsigned int bit_width,
125 bool is_signed, Process *process,
126 addr_t ¤t_stack_argument) {
127
128 uint32_t byte_size = (bit_width + (8 - 1)) / 8;
129 Status error;
130 if (process->ReadScalarIntegerFromMemory(current_stack_argument, byte_size,
131 is_signed, scalar, error)) {
132 current_stack_argument += byte_size;
133 return true;
134 }
135 return false;
136 }
137
GetArgumentValues(Thread & thread,ValueList & values) const138 bool ABIMacOSX_i386::GetArgumentValues(Thread &thread,
139 ValueList &values) const {
140 unsigned int num_values = values.GetSize();
141 unsigned int value_index;
142
143 // Get the pointer to the first stack argument so we have a place to start
144 // when reading data
145
146 RegisterContext *reg_ctx = thread.GetRegisterContext().get();
147
148 if (!reg_ctx)
149 return false;
150
151 addr_t sp = reg_ctx->GetSP(0);
152
153 if (!sp)
154 return false;
155
156 addr_t current_stack_argument = sp + 4; // jump over return address
157
158 for (value_index = 0; value_index < num_values; ++value_index) {
159 Value *value = values.GetValueAtIndex(value_index);
160
161 if (!value)
162 return false;
163
164 // We currently only support extracting values with Clang QualTypes. Do we
165 // care about others?
166 CompilerType compiler_type(value->GetCompilerType());
167 llvm::Optional<uint64_t> bit_size = compiler_type.GetBitSize(&thread);
168 if (bit_size) {
169 bool is_signed;
170 if (compiler_type.IsIntegerOrEnumerationType(is_signed))
171 ReadIntegerArgument(value->GetScalar(), *bit_size, is_signed,
172 thread.GetProcess().get(), current_stack_argument);
173 else if (compiler_type.IsPointerType())
174 ReadIntegerArgument(value->GetScalar(), *bit_size, false,
175 thread.GetProcess().get(), current_stack_argument);
176 }
177 }
178
179 return true;
180 }
181
SetReturnValueObject(lldb::StackFrameSP & frame_sp,lldb::ValueObjectSP & new_value_sp)182 Status ABIMacOSX_i386::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
183 lldb::ValueObjectSP &new_value_sp) {
184 Status error;
185 if (!new_value_sp) {
186 error.SetErrorString("Empty value object for return value.");
187 return error;
188 }
189
190 CompilerType compiler_type = new_value_sp->GetCompilerType();
191 if (!compiler_type) {
192 error.SetErrorString("Null clang type for return value.");
193 return error;
194 }
195
196 Thread *thread = frame_sp->GetThread().get();
197
198 bool is_signed;
199 uint32_t count;
200 bool is_complex;
201
202 RegisterContext *reg_ctx = thread->GetRegisterContext().get();
203
204 bool set_it_simple = false;
205 if (compiler_type.IsIntegerOrEnumerationType(is_signed) ||
206 compiler_type.IsPointerType()) {
207 DataExtractor data;
208 Status data_error;
209 size_t num_bytes = new_value_sp->GetData(data, data_error);
210 if (data_error.Fail()) {
211 error.SetErrorStringWithFormat(
212 "Couldn't convert return value to raw data: %s",
213 data_error.AsCString());
214 return error;
215 }
216 lldb::offset_t offset = 0;
217 if (num_bytes <= 8) {
218 const RegisterInfo *eax_info = reg_ctx->GetRegisterInfoByName("eax", 0);
219 if (num_bytes <= 4) {
220 uint32_t raw_value = data.GetMaxU32(&offset, num_bytes);
221
222 if (reg_ctx->WriteRegisterFromUnsigned(eax_info, raw_value))
223 set_it_simple = true;
224 } else {
225 uint32_t raw_value = data.GetMaxU32(&offset, 4);
226
227 if (reg_ctx->WriteRegisterFromUnsigned(eax_info, raw_value)) {
228 const RegisterInfo *edx_info =
229 reg_ctx->GetRegisterInfoByName("edx", 0);
230 uint32_t raw_value = data.GetMaxU32(&offset, num_bytes - offset);
231
232 if (reg_ctx->WriteRegisterFromUnsigned(edx_info, raw_value))
233 set_it_simple = true;
234 }
235 }
236 } else {
237 error.SetErrorString("We don't support returning longer than 64 bit "
238 "integer values at present.");
239 }
240 } else if (compiler_type.IsFloatingPointType(count, is_complex)) {
241 if (is_complex)
242 error.SetErrorString(
243 "We don't support returning complex values at present");
244 else
245 error.SetErrorString(
246 "We don't support returning float values at present");
247 }
248
249 if (!set_it_simple)
250 error.SetErrorString(
251 "We only support setting simple integer return types at present.");
252
253 return error;
254 }
255
256 ValueObjectSP
GetReturnValueObjectImpl(Thread & thread,CompilerType & compiler_type) const257 ABIMacOSX_i386::GetReturnValueObjectImpl(Thread &thread,
258 CompilerType &compiler_type) const {
259 Value value;
260 ValueObjectSP return_valobj_sp;
261
262 if (!compiler_type)
263 return return_valobj_sp;
264
265 // value.SetContext (Value::eContextTypeClangType,
266 // compiler_type.GetOpaqueQualType());
267 value.SetCompilerType(compiler_type);
268
269 RegisterContext *reg_ctx = thread.GetRegisterContext().get();
270 if (!reg_ctx)
271 return return_valobj_sp;
272
273 bool is_signed;
274
275 if (compiler_type.IsIntegerOrEnumerationType(is_signed)) {
276 llvm::Optional<uint64_t> bit_width = compiler_type.GetBitSize(&thread);
277 if (!bit_width)
278 return return_valobj_sp;
279 unsigned eax_id =
280 reg_ctx->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB];
281 unsigned edx_id =
282 reg_ctx->GetRegisterInfoByName("edx", 0)->kinds[eRegisterKindLLDB];
283
284 switch (*bit_width) {
285 default:
286 case 128:
287 // Scalar can't hold 128-bit literals, so we don't handle this
288 return return_valobj_sp;
289 case 64:
290 uint64_t raw_value;
291 raw_value =
292 thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
293 0xffffffff;
294 raw_value |=
295 (thread.GetRegisterContext()->ReadRegisterAsUnsigned(edx_id, 0) &
296 0xffffffff)
297 << 32;
298 if (is_signed)
299 value.GetScalar() = (int64_t)raw_value;
300 else
301 value.GetScalar() = (uint64_t)raw_value;
302 break;
303 case 32:
304 if (is_signed)
305 value.GetScalar() = (int32_t)(
306 thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
307 0xffffffff);
308 else
309 value.GetScalar() = (uint32_t)(
310 thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
311 0xffffffff);
312 break;
313 case 16:
314 if (is_signed)
315 value.GetScalar() = (int16_t)(
316 thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
317 0xffff);
318 else
319 value.GetScalar() = (uint16_t)(
320 thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
321 0xffff);
322 break;
323 case 8:
324 if (is_signed)
325 value.GetScalar() = (int8_t)(
326 thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
327 0xff);
328 else
329 value.GetScalar() = (uint8_t)(
330 thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
331 0xff);
332 break;
333 }
334 } else if (compiler_type.IsPointerType()) {
335 unsigned eax_id =
336 reg_ctx->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB];
337 uint32_t ptr =
338 thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
339 0xffffffff;
340 value.GetScalar() = ptr;
341 } else {
342 // not handled yet
343 return return_valobj_sp;
344 }
345
346 // If we get here, we have a valid Value, so make our ValueObject out of it:
347
348 return_valobj_sp = ValueObjectConstResult::Create(
349 thread.GetStackFrameAtIndex(0).get(), value, ConstString(""));
350 return return_valobj_sp;
351 }
352
353 // This defines the CFA as esp+4
354 // the saved pc is at CFA-4 (i.e. esp+0)
355 // The saved esp is CFA+0
356
CreateFunctionEntryUnwindPlan(UnwindPlan & unwind_plan)357 bool ABIMacOSX_i386::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) {
358 unwind_plan.Clear();
359 unwind_plan.SetRegisterKind(eRegisterKindDWARF);
360
361 uint32_t sp_reg_num = dwarf_esp;
362 uint32_t pc_reg_num = dwarf_eip;
363
364 UnwindPlan::RowSP row(new UnwindPlan::Row);
365 row->GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 4);
366 row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, -4, false);
367 row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);
368 unwind_plan.AppendRow(row);
369 unwind_plan.SetSourceName("i386 at-func-entry default");
370 unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
371 return true;
372 }
373
374 // This defines the CFA as ebp+8
375 // The saved pc is at CFA-4 (i.e. ebp+4)
376 // The saved ebp is at CFA-8 (i.e. ebp+0)
377 // The saved esp is CFA+0
378
CreateDefaultUnwindPlan(UnwindPlan & unwind_plan)379 bool ABIMacOSX_i386::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
380 unwind_plan.Clear();
381 unwind_plan.SetRegisterKind(eRegisterKindDWARF);
382
383 uint32_t fp_reg_num = dwarf_ebp;
384 uint32_t sp_reg_num = dwarf_esp;
385 uint32_t pc_reg_num = dwarf_eip;
386
387 UnwindPlan::RowSP row(new UnwindPlan::Row);
388 const int32_t ptr_size = 4;
389
390 row->GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size);
391 row->SetOffset(0);
392 row->SetUnspecifiedRegistersAreUndefined(true);
393
394 row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true);
395 row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true);
396 row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);
397
398 unwind_plan.AppendRow(row);
399 unwind_plan.SetSourceName("i386 default unwind plan");
400 unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
401 unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
402 unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
403 return true;
404 }
405
RegisterIsVolatile(const RegisterInfo * reg_info)406 bool ABIMacOSX_i386::RegisterIsVolatile(const RegisterInfo *reg_info) {
407 return !RegisterIsCalleeSaved(reg_info);
408 }
409
410 // v.
411 // http://developer.apple.com/library/mac/#documentation/developertools/Conceptual/LowLevelABI/130
412 // -IA-
413 // 32_Function_Calling_Conventions/IA32.html#//apple_ref/doc/uid/TP40002492-SW4
414 //
415 // This document ("OS X ABI Function Call Guide", chapter "IA-32 Function
416 // Calling Conventions") says that the following registers on i386 are
417 // preserved aka non-volatile aka callee-saved:
418 //
419 // ebx, ebp, esi, edi, esp
420
RegisterIsCalleeSaved(const RegisterInfo * reg_info)421 bool ABIMacOSX_i386::RegisterIsCalleeSaved(const RegisterInfo *reg_info) {
422 if (reg_info) {
423 // Saved registers are ebx, ebp, esi, edi, esp, eip
424 const char *name = reg_info->name;
425 if (name[0] == 'e') {
426 switch (name[1]) {
427 case 'b':
428 if (name[2] == 'x' || name[2] == 'p')
429 return name[3] == '\0';
430 break;
431 case 'd':
432 if (name[2] == 'i')
433 return name[3] == '\0';
434 break;
435 case 'i':
436 if (name[2] == 'p')
437 return name[3] == '\0';
438 break;
439 case 's':
440 if (name[2] == 'i' || name[2] == 'p')
441 return name[3] == '\0';
442 break;
443 }
444 }
445 if (name[0] == 's' && name[1] == 'p' && name[2] == '\0') // sp
446 return true;
447 if (name[0] == 'f' && name[1] == 'p' && name[2] == '\0') // fp
448 return true;
449 if (name[0] == 'p' && name[1] == 'c' && name[2] == '\0') // pc
450 return true;
451 }
452 return false;
453 }
454
Initialize()455 void ABIMacOSX_i386::Initialize() {
456 PluginManager::RegisterPlugin(
457 GetPluginNameStatic(), "Mac OS X ABI for i386 targets", CreateInstance);
458 }
459
Terminate()460 void ABIMacOSX_i386::Terminate() {
461 PluginManager::UnregisterPlugin(CreateInstance);
462 }
463
GetPluginNameStatic()464 lldb_private::ConstString ABIMacOSX_i386::GetPluginNameStatic() {
465 static ConstString g_short_name("abi.macosx-i386");
466 return g_short_name;
467 }
468
469 // PluginInterface protocol
470
GetPluginName()471 lldb_private::ConstString ABIMacOSX_i386::GetPluginName() {
472 return GetPluginNameStatic();
473 }
474
GetPluginVersion()475 uint32_t ABIMacOSX_i386::GetPluginVersion() { return 1; }
476