1 //===-- ABIMacOSX_i386.cpp ------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "ABIMacOSX_i386.h"
14 #include "llvm/ADT/STLExtras.h"
15 #include "llvm/TargetParser/Triple.h"
17 #include "lldb/Core/Module.h"
18 #include "lldb/Core/PluginManager.h"
19 #include "lldb/Core/ValueObjectConstResult.h"
20 #include "lldb/Symbol/UnwindPlan.h"
21 #include "lldb/Target/Process.h"
22 #include "lldb/Target/RegisterContext.h"
23 #include "lldb/Target/Target.h"
24 #include "lldb/Target/Thread.h"
25 #include "lldb/Utility/ConstString.h"
26 #include "lldb/Utility/RegisterValue.h"
27 #include "lldb/Utility/Scalar.h"
28 #include "lldb/Utility/Status.h"
31 using namespace lldb_private;
33 LLDB_PLUGIN_DEFINE(ABIMacOSX_i386)
47 size_t ABIMacOSX_i386::GetRedZoneSize() const { return 0; }
52 ABIMacOSX_i386::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) {
53 if ((arch.GetTriple().getArch() == llvm::Triple::x86) &&
54 (arch.GetTriple().isMacOSX() || arch.GetTriple().isiOS() ||
55 arch.GetTriple().isWatchOS())) {
57 new ABIMacOSX_i386(std::move(process_sp), MakeMCRegisterInfo(arch)));
62 bool ABIMacOSX_i386::PrepareTrivialCall(Thread &thread, addr_t sp,
63 addr_t func_addr, addr_t return_addr,
64 llvm::ArrayRef<addr_t> args) const {
65 RegisterContext *reg_ctx = thread.GetRegisterContext().get();
68 uint32_t pc_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(
69 eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
70 uint32_t sp_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(
71 eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
73 // When writing a register value down to memory, the register info used to
74 // write memory just needs to have the correct size of a 32 bit register, the
75 // actual register it pertains to is not important, just the size needs to be
76 // correct. Here we use "eax"...
77 const RegisterInfo *reg_info_32 = reg_ctx->GetRegisterInfoByName("eax");
79 return false; // TODO this should actually never happen
81 // Make room for the argument(s) on the stack
84 RegisterValue reg_value;
86 // Write any arguments onto the stack
87 sp -= 4 * args.size();
90 sp &= ~(16ull - 1ull); // 16-byte alignment
94 for (addr_t arg : args) {
95 reg_value.SetUInt32(arg);
96 error = reg_ctx->WriteRegisterValueToMemory(
97 reg_info_32, arg_pos, reg_info_32->byte_size, reg_value);
103 // The return address is pushed onto the stack (yes after we just set the
104 // alignment above!).
106 reg_value.SetUInt32(return_addr);
107 error = reg_ctx->WriteRegisterValueToMemory(
108 reg_info_32, sp, reg_info_32->byte_size, reg_value);
112 // %esp is set to the actual stack value.
114 if (!reg_ctx->WriteRegisterFromUnsigned(sp_reg_num, sp))
117 // %eip is set to the address of the called function.
119 if (!reg_ctx->WriteRegisterFromUnsigned(pc_reg_num, func_addr))
125 static bool ReadIntegerArgument(Scalar &scalar, unsigned int bit_width,
126 bool is_signed, Process *process,
127 addr_t ¤t_stack_argument) {
129 uint32_t byte_size = (bit_width + (8 - 1)) / 8;
131 if (process->ReadScalarIntegerFromMemory(current_stack_argument, byte_size,
132 is_signed, scalar, error)) {
133 current_stack_argument += byte_size;
139 bool ABIMacOSX_i386::GetArgumentValues(Thread &thread,
140 ValueList &values) const {
141 unsigned int num_values = values.GetSize();
142 unsigned int value_index;
144 // Get the pointer to the first stack argument so we have a place to start
147 RegisterContext *reg_ctx = thread.GetRegisterContext().get();
152 addr_t sp = reg_ctx->GetSP(0);
157 addr_t current_stack_argument = sp + 4; // jump over return address
159 for (value_index = 0; value_index < num_values; ++value_index) {
160 Value *value = values.GetValueAtIndex(value_index);
165 // We currently only support extracting values with Clang QualTypes. Do we
166 // care about others?
167 CompilerType compiler_type(value->GetCompilerType());
168 std::optional<uint64_t> bit_size = compiler_type.GetBitSize(&thread);
171 if (compiler_type.IsIntegerOrEnumerationType(is_signed))
172 ReadIntegerArgument(value->GetScalar(), *bit_size, is_signed,
173 thread.GetProcess().get(), current_stack_argument);
174 else if (compiler_type.IsPointerType())
175 ReadIntegerArgument(value->GetScalar(), *bit_size, false,
176 thread.GetProcess().get(), current_stack_argument);
183 Status ABIMacOSX_i386::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
184 lldb::ValueObjectSP &new_value_sp) {
187 error.SetErrorString("Empty value object for return value.");
191 CompilerType compiler_type = new_value_sp->GetCompilerType();
192 if (!compiler_type) {
193 error.SetErrorString("Null clang type for return value.");
197 Thread *thread = frame_sp->GetThread().get();
203 RegisterContext *reg_ctx = thread->GetRegisterContext().get();
205 bool set_it_simple = false;
206 if (compiler_type.IsIntegerOrEnumerationType(is_signed) ||
207 compiler_type.IsPointerType()) {
210 size_t num_bytes = new_value_sp->GetData(data, data_error);
211 if (data_error.Fail()) {
212 error.SetErrorStringWithFormat(
213 "Couldn't convert return value to raw data: %s",
214 data_error.AsCString());
217 lldb::offset_t offset = 0;
218 if (num_bytes <= 8) {
219 const RegisterInfo *eax_info = reg_ctx->GetRegisterInfoByName("eax", 0);
220 if (num_bytes <= 4) {
221 uint32_t raw_value = data.GetMaxU32(&offset, num_bytes);
223 if (reg_ctx->WriteRegisterFromUnsigned(eax_info, raw_value))
224 set_it_simple = true;
226 uint32_t raw_value = data.GetMaxU32(&offset, 4);
228 if (reg_ctx->WriteRegisterFromUnsigned(eax_info, raw_value)) {
229 const RegisterInfo *edx_info =
230 reg_ctx->GetRegisterInfoByName("edx", 0);
231 uint32_t raw_value = data.GetMaxU32(&offset, num_bytes - offset);
233 if (reg_ctx->WriteRegisterFromUnsigned(edx_info, raw_value))
234 set_it_simple = true;
238 error.SetErrorString("We don't support returning longer than 64 bit "
239 "integer values at present.");
241 } else if (compiler_type.IsFloatingPointType(count, is_complex)) {
243 error.SetErrorString(
244 "We don't support returning complex values at present");
246 error.SetErrorString(
247 "We don't support returning float values at present");
251 error.SetErrorString(
252 "We only support setting simple integer return types at present.");
258 ABIMacOSX_i386::GetReturnValueObjectImpl(Thread &thread,
259 CompilerType &compiler_type) const {
261 ValueObjectSP return_valobj_sp;
264 return return_valobj_sp;
266 // value.SetContext (Value::eContextTypeClangType,
267 // compiler_type.GetOpaqueQualType());
268 value.SetCompilerType(compiler_type);
270 RegisterContext *reg_ctx = thread.GetRegisterContext().get();
272 return return_valobj_sp;
276 if (compiler_type.IsIntegerOrEnumerationType(is_signed)) {
277 std::optional<uint64_t> bit_width = compiler_type.GetBitSize(&thread);
279 return return_valobj_sp;
281 reg_ctx->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB];
283 reg_ctx->GetRegisterInfoByName("edx", 0)->kinds[eRegisterKindLLDB];
285 switch (*bit_width) {
288 // Scalar can't hold 128-bit literals, so we don't handle this
289 return return_valobj_sp;
293 thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
296 (thread.GetRegisterContext()->ReadRegisterAsUnsigned(edx_id, 0) &
300 value.GetScalar() = (int64_t)raw_value;
302 value.GetScalar() = (uint64_t)raw_value;
306 value.GetScalar() = (int32_t)(
307 thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
310 value.GetScalar() = (uint32_t)(
311 thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
316 value.GetScalar() = (int16_t)(
317 thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
320 value.GetScalar() = (uint16_t)(
321 thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
326 value.GetScalar() = (int8_t)(
327 thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
330 value.GetScalar() = (uint8_t)(
331 thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
335 } else if (compiler_type.IsPointerType()) {
337 reg_ctx->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB];
339 thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
341 value.GetScalar() = ptr;
344 return return_valobj_sp;
347 // If we get here, we have a valid Value, so make our ValueObject out of it:
349 return_valobj_sp = ValueObjectConstResult::Create(
350 thread.GetStackFrameAtIndex(0).get(), value, ConstString(""));
351 return return_valobj_sp;
354 // This defines the CFA as esp+4
355 // the saved pc is at CFA-4 (i.e. esp+0)
356 // The saved esp is CFA+0
358 bool ABIMacOSX_i386::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) {
360 unwind_plan.SetRegisterKind(eRegisterKindDWARF);
362 uint32_t sp_reg_num = dwarf_esp;
363 uint32_t pc_reg_num = dwarf_eip;
365 UnwindPlan::RowSP row(new UnwindPlan::Row);
366 row->GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 4);
367 row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, -4, false);
368 row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);
369 unwind_plan.AppendRow(row);
370 unwind_plan.SetSourceName("i386 at-func-entry default");
371 unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
375 // This defines the CFA as ebp+8
376 // The saved pc is at CFA-4 (i.e. ebp+4)
377 // The saved ebp is at CFA-8 (i.e. ebp+0)
378 // The saved esp is CFA+0
380 bool ABIMacOSX_i386::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
382 unwind_plan.SetRegisterKind(eRegisterKindDWARF);
384 uint32_t fp_reg_num = dwarf_ebp;
385 uint32_t sp_reg_num = dwarf_esp;
386 uint32_t pc_reg_num = dwarf_eip;
388 UnwindPlan::RowSP row(new UnwindPlan::Row);
389 const int32_t ptr_size = 4;
391 row->GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size);
393 row->SetUnspecifiedRegistersAreUndefined(true);
395 row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true);
396 row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true);
397 row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);
399 unwind_plan.AppendRow(row);
400 unwind_plan.SetSourceName("i386 default unwind plan");
401 unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
402 unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
403 unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
407 bool ABIMacOSX_i386::RegisterIsVolatile(const RegisterInfo *reg_info) {
408 return !RegisterIsCalleeSaved(reg_info);
412 // http://developer.apple.com/library/mac/#documentation/developertools/Conceptual/LowLevelABI/130
414 // 32_Function_Calling_Conventions/IA32.html#//apple_ref/doc/uid/TP40002492-SW4
416 // This document ("OS X ABI Function Call Guide", chapter "IA-32 Function
417 // Calling Conventions") says that the following registers on i386 are
418 // preserved aka non-volatile aka callee-saved:
420 // ebx, ebp, esi, edi, esp
422 bool ABIMacOSX_i386::RegisterIsCalleeSaved(const RegisterInfo *reg_info) {
424 // Saved registers are ebx, ebp, esi, edi, esp, eip
425 const char *name = reg_info->name;
426 if (name[0] == 'e') {
429 if (name[2] == 'x' || name[2] == 'p')
430 return name[3] == '\0';
434 return name[3] == '\0';
438 return name[3] == '\0';
441 if (name[2] == 'i' || name[2] == 'p')
442 return name[3] == '\0';
446 if (name[0] == 's' && name[1] == 'p' && name[2] == '\0') // sp
448 if (name[0] == 'f' && name[1] == 'p' && name[2] == '\0') // fp
450 if (name[0] == 'p' && name[1] == 'c' && name[2] == '\0') // pc
456 void ABIMacOSX_i386::Initialize() {
457 PluginManager::RegisterPlugin(
458 GetPluginNameStatic(), "Mac OS X ABI for i386 targets", CreateInstance);
461 void ABIMacOSX_i386::Terminate() {
462 PluginManager::UnregisterPlugin(CreateInstance);