xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/ABI/X86/ABIMacOSX_i386.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
15ffd83dbSDimitry Andric //===-- ABIMacOSX_i386.cpp ------------------------------------------------===//
25ffd83dbSDimitry Andric //
35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65ffd83dbSDimitry Andric //
75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
85ffd83dbSDimitry Andric 
95ffd83dbSDimitry Andric #include "ABIMacOSX_i386.h"
105ffd83dbSDimitry Andric 
11bdd1243dSDimitry Andric #include <optional>
125ffd83dbSDimitry Andric #include <vector>
135ffd83dbSDimitry Andric 
145ffd83dbSDimitry Andric #include "llvm/ADT/STLExtras.h"
15*06c3fb27SDimitry Andric #include "llvm/TargetParser/Triple.h"
165ffd83dbSDimitry Andric 
175ffd83dbSDimitry Andric #include "lldb/Core/Module.h"
185ffd83dbSDimitry Andric #include "lldb/Core/PluginManager.h"
195ffd83dbSDimitry Andric #include "lldb/Core/ValueObjectConstResult.h"
205ffd83dbSDimitry Andric #include "lldb/Symbol/UnwindPlan.h"
215ffd83dbSDimitry Andric #include "lldb/Target/Process.h"
225ffd83dbSDimitry Andric #include "lldb/Target/RegisterContext.h"
235ffd83dbSDimitry Andric #include "lldb/Target/Target.h"
245ffd83dbSDimitry Andric #include "lldb/Target/Thread.h"
255ffd83dbSDimitry Andric #include "lldb/Utility/ConstString.h"
265ffd83dbSDimitry Andric #include "lldb/Utility/RegisterValue.h"
275ffd83dbSDimitry Andric #include "lldb/Utility/Scalar.h"
285ffd83dbSDimitry Andric #include "lldb/Utility/Status.h"
295ffd83dbSDimitry Andric 
305ffd83dbSDimitry Andric using namespace lldb;
315ffd83dbSDimitry Andric using namespace lldb_private;
325ffd83dbSDimitry Andric 
335ffd83dbSDimitry Andric LLDB_PLUGIN_DEFINE(ABIMacOSX_i386)
345ffd83dbSDimitry Andric 
355ffd83dbSDimitry Andric enum {
365ffd83dbSDimitry Andric   dwarf_eax = 0,
375ffd83dbSDimitry Andric   dwarf_ecx,
385ffd83dbSDimitry Andric   dwarf_edx,
395ffd83dbSDimitry Andric   dwarf_ebx,
405ffd83dbSDimitry Andric   dwarf_esp,
415ffd83dbSDimitry Andric   dwarf_ebp,
425ffd83dbSDimitry Andric   dwarf_esi,
435ffd83dbSDimitry Andric   dwarf_edi,
445ffd83dbSDimitry Andric   dwarf_eip,
455ffd83dbSDimitry Andric };
465ffd83dbSDimitry Andric 
GetRedZoneSize() const475ffd83dbSDimitry Andric size_t ABIMacOSX_i386::GetRedZoneSize() const { return 0; }
485ffd83dbSDimitry Andric 
495ffd83dbSDimitry Andric // Static Functions
505ffd83dbSDimitry Andric 
515ffd83dbSDimitry Andric ABISP
CreateInstance(lldb::ProcessSP process_sp,const ArchSpec & arch)525ffd83dbSDimitry Andric ABIMacOSX_i386::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) {
535ffd83dbSDimitry Andric   if ((arch.GetTriple().getArch() == llvm::Triple::x86) &&
545ffd83dbSDimitry Andric       (arch.GetTriple().isMacOSX() || arch.GetTriple().isiOS() ||
555ffd83dbSDimitry Andric        arch.GetTriple().isWatchOS())) {
565ffd83dbSDimitry Andric     return ABISP(
575ffd83dbSDimitry Andric         new ABIMacOSX_i386(std::move(process_sp), MakeMCRegisterInfo(arch)));
585ffd83dbSDimitry Andric   }
595ffd83dbSDimitry Andric   return ABISP();
605ffd83dbSDimitry Andric }
615ffd83dbSDimitry Andric 
PrepareTrivialCall(Thread & thread,addr_t sp,addr_t func_addr,addr_t return_addr,llvm::ArrayRef<addr_t> args) const625ffd83dbSDimitry Andric bool ABIMacOSX_i386::PrepareTrivialCall(Thread &thread, addr_t sp,
635ffd83dbSDimitry Andric                                         addr_t func_addr, addr_t return_addr,
645ffd83dbSDimitry Andric                                         llvm::ArrayRef<addr_t> args) const {
655ffd83dbSDimitry Andric   RegisterContext *reg_ctx = thread.GetRegisterContext().get();
665ffd83dbSDimitry Andric   if (!reg_ctx)
675ffd83dbSDimitry Andric     return false;
685ffd83dbSDimitry Andric   uint32_t pc_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(
695ffd83dbSDimitry Andric       eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
705ffd83dbSDimitry Andric   uint32_t sp_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(
715ffd83dbSDimitry Andric       eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
725ffd83dbSDimitry Andric 
735ffd83dbSDimitry Andric   // When writing a register value down to memory, the register info used to
745ffd83dbSDimitry Andric   // write memory just needs to have the correct size of a 32 bit register, the
755ffd83dbSDimitry Andric   // actual register it pertains to is not important, just the size needs to be
765ffd83dbSDimitry Andric   // correct. Here we use "eax"...
775ffd83dbSDimitry Andric   const RegisterInfo *reg_info_32 = reg_ctx->GetRegisterInfoByName("eax");
785ffd83dbSDimitry Andric   if (!reg_info_32)
795ffd83dbSDimitry Andric     return false; // TODO this should actually never happen
805ffd83dbSDimitry Andric 
815ffd83dbSDimitry Andric   // Make room for the argument(s) on the stack
825ffd83dbSDimitry Andric 
835ffd83dbSDimitry Andric   Status error;
845ffd83dbSDimitry Andric   RegisterValue reg_value;
855ffd83dbSDimitry Andric 
865ffd83dbSDimitry Andric   // Write any arguments onto the stack
875ffd83dbSDimitry Andric   sp -= 4 * args.size();
885ffd83dbSDimitry Andric 
895ffd83dbSDimitry Andric   // Align the SP
905ffd83dbSDimitry Andric   sp &= ~(16ull - 1ull); // 16-byte alignment
915ffd83dbSDimitry Andric 
925ffd83dbSDimitry Andric   addr_t arg_pos = sp;
935ffd83dbSDimitry Andric 
945ffd83dbSDimitry Andric   for (addr_t arg : args) {
955ffd83dbSDimitry Andric     reg_value.SetUInt32(arg);
965ffd83dbSDimitry Andric     error = reg_ctx->WriteRegisterValueToMemory(
975ffd83dbSDimitry Andric         reg_info_32, arg_pos, reg_info_32->byte_size, reg_value);
985ffd83dbSDimitry Andric     if (error.Fail())
995ffd83dbSDimitry Andric       return false;
1005ffd83dbSDimitry Andric     arg_pos += 4;
1015ffd83dbSDimitry Andric   }
1025ffd83dbSDimitry Andric 
1035ffd83dbSDimitry Andric   // The return address is pushed onto the stack (yes after we just set the
1045ffd83dbSDimitry Andric   // alignment above!).
1055ffd83dbSDimitry Andric   sp -= 4;
1065ffd83dbSDimitry Andric   reg_value.SetUInt32(return_addr);
1075ffd83dbSDimitry Andric   error = reg_ctx->WriteRegisterValueToMemory(
1085ffd83dbSDimitry Andric       reg_info_32, sp, reg_info_32->byte_size, reg_value);
1095ffd83dbSDimitry Andric   if (error.Fail())
1105ffd83dbSDimitry Andric     return false;
1115ffd83dbSDimitry Andric 
1125ffd83dbSDimitry Andric   // %esp is set to the actual stack value.
1135ffd83dbSDimitry Andric 
1145ffd83dbSDimitry Andric   if (!reg_ctx->WriteRegisterFromUnsigned(sp_reg_num, sp))
1155ffd83dbSDimitry Andric     return false;
1165ffd83dbSDimitry Andric 
1175ffd83dbSDimitry Andric   // %eip is set to the address of the called function.
1185ffd83dbSDimitry Andric 
1195ffd83dbSDimitry Andric   if (!reg_ctx->WriteRegisterFromUnsigned(pc_reg_num, func_addr))
1205ffd83dbSDimitry Andric     return false;
1215ffd83dbSDimitry Andric 
1225ffd83dbSDimitry Andric   return true;
1235ffd83dbSDimitry Andric }
1245ffd83dbSDimitry Andric 
ReadIntegerArgument(Scalar & scalar,unsigned int bit_width,bool is_signed,Process * process,addr_t & current_stack_argument)1255ffd83dbSDimitry Andric static bool ReadIntegerArgument(Scalar &scalar, unsigned int bit_width,
1265ffd83dbSDimitry Andric                                 bool is_signed, Process *process,
1275ffd83dbSDimitry Andric                                 addr_t &current_stack_argument) {
1285ffd83dbSDimitry Andric 
1295ffd83dbSDimitry Andric   uint32_t byte_size = (bit_width + (8 - 1)) / 8;
1305ffd83dbSDimitry Andric   Status error;
1315ffd83dbSDimitry Andric   if (process->ReadScalarIntegerFromMemory(current_stack_argument, byte_size,
1325ffd83dbSDimitry Andric                                            is_signed, scalar, error)) {
1335ffd83dbSDimitry Andric     current_stack_argument += byte_size;
1345ffd83dbSDimitry Andric     return true;
1355ffd83dbSDimitry Andric   }
1365ffd83dbSDimitry Andric   return false;
1375ffd83dbSDimitry Andric }
1385ffd83dbSDimitry Andric 
GetArgumentValues(Thread & thread,ValueList & values) const1395ffd83dbSDimitry Andric bool ABIMacOSX_i386::GetArgumentValues(Thread &thread,
1405ffd83dbSDimitry Andric                                        ValueList &values) const {
1415ffd83dbSDimitry Andric   unsigned int num_values = values.GetSize();
1425ffd83dbSDimitry Andric   unsigned int value_index;
1435ffd83dbSDimitry Andric 
1445ffd83dbSDimitry Andric   // Get the pointer to the first stack argument so we have a place to start
1455ffd83dbSDimitry Andric   // when reading data
1465ffd83dbSDimitry Andric 
1475ffd83dbSDimitry Andric   RegisterContext *reg_ctx = thread.GetRegisterContext().get();
1485ffd83dbSDimitry Andric 
1495ffd83dbSDimitry Andric   if (!reg_ctx)
1505ffd83dbSDimitry Andric     return false;
1515ffd83dbSDimitry Andric 
1525ffd83dbSDimitry Andric   addr_t sp = reg_ctx->GetSP(0);
1535ffd83dbSDimitry Andric 
1545ffd83dbSDimitry Andric   if (!sp)
1555ffd83dbSDimitry Andric     return false;
1565ffd83dbSDimitry Andric 
1575ffd83dbSDimitry Andric   addr_t current_stack_argument = sp + 4; // jump over return address
1585ffd83dbSDimitry Andric 
1595ffd83dbSDimitry Andric   for (value_index = 0; value_index < num_values; ++value_index) {
1605ffd83dbSDimitry Andric     Value *value = values.GetValueAtIndex(value_index);
1615ffd83dbSDimitry Andric 
1625ffd83dbSDimitry Andric     if (!value)
1635ffd83dbSDimitry Andric       return false;
1645ffd83dbSDimitry Andric 
1655ffd83dbSDimitry Andric     // We currently only support extracting values with Clang QualTypes. Do we
1665ffd83dbSDimitry Andric     // care about others?
1675ffd83dbSDimitry Andric     CompilerType compiler_type(value->GetCompilerType());
168bdd1243dSDimitry Andric     std::optional<uint64_t> bit_size = compiler_type.GetBitSize(&thread);
1695ffd83dbSDimitry Andric     if (bit_size) {
1705ffd83dbSDimitry Andric       bool is_signed;
1715ffd83dbSDimitry Andric       if (compiler_type.IsIntegerOrEnumerationType(is_signed))
1725ffd83dbSDimitry Andric         ReadIntegerArgument(value->GetScalar(), *bit_size, is_signed,
1735ffd83dbSDimitry Andric                             thread.GetProcess().get(), current_stack_argument);
1745ffd83dbSDimitry Andric       else if (compiler_type.IsPointerType())
1755ffd83dbSDimitry Andric         ReadIntegerArgument(value->GetScalar(), *bit_size, false,
1765ffd83dbSDimitry Andric                             thread.GetProcess().get(), current_stack_argument);
1775ffd83dbSDimitry Andric     }
1785ffd83dbSDimitry Andric   }
1795ffd83dbSDimitry Andric 
1805ffd83dbSDimitry Andric   return true;
1815ffd83dbSDimitry Andric }
1825ffd83dbSDimitry Andric 
SetReturnValueObject(lldb::StackFrameSP & frame_sp,lldb::ValueObjectSP & new_value_sp)1835ffd83dbSDimitry Andric Status ABIMacOSX_i386::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
1845ffd83dbSDimitry Andric                                             lldb::ValueObjectSP &new_value_sp) {
1855ffd83dbSDimitry Andric   Status error;
1865ffd83dbSDimitry Andric   if (!new_value_sp) {
1875ffd83dbSDimitry Andric     error.SetErrorString("Empty value object for return value.");
1885ffd83dbSDimitry Andric     return error;
1895ffd83dbSDimitry Andric   }
1905ffd83dbSDimitry Andric 
1915ffd83dbSDimitry Andric   CompilerType compiler_type = new_value_sp->GetCompilerType();
1925ffd83dbSDimitry Andric   if (!compiler_type) {
1935ffd83dbSDimitry Andric     error.SetErrorString("Null clang type for return value.");
1945ffd83dbSDimitry Andric     return error;
1955ffd83dbSDimitry Andric   }
1965ffd83dbSDimitry Andric 
1975ffd83dbSDimitry Andric   Thread *thread = frame_sp->GetThread().get();
1985ffd83dbSDimitry Andric 
1995ffd83dbSDimitry Andric   bool is_signed;
2005ffd83dbSDimitry Andric   uint32_t count;
2015ffd83dbSDimitry Andric   bool is_complex;
2025ffd83dbSDimitry Andric 
2035ffd83dbSDimitry Andric   RegisterContext *reg_ctx = thread->GetRegisterContext().get();
2045ffd83dbSDimitry Andric 
2055ffd83dbSDimitry Andric   bool set_it_simple = false;
2065ffd83dbSDimitry Andric   if (compiler_type.IsIntegerOrEnumerationType(is_signed) ||
2075ffd83dbSDimitry Andric       compiler_type.IsPointerType()) {
2085ffd83dbSDimitry Andric     DataExtractor data;
2095ffd83dbSDimitry Andric     Status data_error;
2105ffd83dbSDimitry Andric     size_t num_bytes = new_value_sp->GetData(data, data_error);
2115ffd83dbSDimitry Andric     if (data_error.Fail()) {
2125ffd83dbSDimitry Andric       error.SetErrorStringWithFormat(
2135ffd83dbSDimitry Andric           "Couldn't convert return value to raw data: %s",
2145ffd83dbSDimitry Andric           data_error.AsCString());
2155ffd83dbSDimitry Andric       return error;
2165ffd83dbSDimitry Andric     }
2175ffd83dbSDimitry Andric     lldb::offset_t offset = 0;
2185ffd83dbSDimitry Andric     if (num_bytes <= 8) {
2195ffd83dbSDimitry Andric       const RegisterInfo *eax_info = reg_ctx->GetRegisterInfoByName("eax", 0);
2205ffd83dbSDimitry Andric       if (num_bytes <= 4) {
2215ffd83dbSDimitry Andric         uint32_t raw_value = data.GetMaxU32(&offset, num_bytes);
2225ffd83dbSDimitry Andric 
2235ffd83dbSDimitry Andric         if (reg_ctx->WriteRegisterFromUnsigned(eax_info, raw_value))
2245ffd83dbSDimitry Andric           set_it_simple = true;
2255ffd83dbSDimitry Andric       } else {
2265ffd83dbSDimitry Andric         uint32_t raw_value = data.GetMaxU32(&offset, 4);
2275ffd83dbSDimitry Andric 
2285ffd83dbSDimitry Andric         if (reg_ctx->WriteRegisterFromUnsigned(eax_info, raw_value)) {
2295ffd83dbSDimitry Andric           const RegisterInfo *edx_info =
2305ffd83dbSDimitry Andric               reg_ctx->GetRegisterInfoByName("edx", 0);
2315ffd83dbSDimitry Andric           uint32_t raw_value = data.GetMaxU32(&offset, num_bytes - offset);
2325ffd83dbSDimitry Andric 
2335ffd83dbSDimitry Andric           if (reg_ctx->WriteRegisterFromUnsigned(edx_info, raw_value))
2345ffd83dbSDimitry Andric             set_it_simple = true;
2355ffd83dbSDimitry Andric         }
2365ffd83dbSDimitry Andric       }
2375ffd83dbSDimitry Andric     } else {
2385ffd83dbSDimitry Andric       error.SetErrorString("We don't support returning longer than 64 bit "
2395ffd83dbSDimitry Andric                            "integer values at present.");
2405ffd83dbSDimitry Andric     }
2415ffd83dbSDimitry Andric   } else if (compiler_type.IsFloatingPointType(count, is_complex)) {
2425ffd83dbSDimitry Andric     if (is_complex)
2435ffd83dbSDimitry Andric       error.SetErrorString(
2445ffd83dbSDimitry Andric           "We don't support returning complex values at present");
2455ffd83dbSDimitry Andric     else
2465ffd83dbSDimitry Andric       error.SetErrorString(
2475ffd83dbSDimitry Andric           "We don't support returning float values at present");
2485ffd83dbSDimitry Andric   }
2495ffd83dbSDimitry Andric 
2505ffd83dbSDimitry Andric   if (!set_it_simple)
2515ffd83dbSDimitry Andric     error.SetErrorString(
2525ffd83dbSDimitry Andric         "We only support setting simple integer return types at present.");
2535ffd83dbSDimitry Andric 
2545ffd83dbSDimitry Andric   return error;
2555ffd83dbSDimitry Andric }
2565ffd83dbSDimitry Andric 
2575ffd83dbSDimitry Andric ValueObjectSP
GetReturnValueObjectImpl(Thread & thread,CompilerType & compiler_type) const2585ffd83dbSDimitry Andric ABIMacOSX_i386::GetReturnValueObjectImpl(Thread &thread,
2595ffd83dbSDimitry Andric                                          CompilerType &compiler_type) const {
2605ffd83dbSDimitry Andric   Value value;
2615ffd83dbSDimitry Andric   ValueObjectSP return_valobj_sp;
2625ffd83dbSDimitry Andric 
2635ffd83dbSDimitry Andric   if (!compiler_type)
2645ffd83dbSDimitry Andric     return return_valobj_sp;
2655ffd83dbSDimitry Andric 
2665ffd83dbSDimitry Andric   // value.SetContext (Value::eContextTypeClangType,
2675ffd83dbSDimitry Andric   // compiler_type.GetOpaqueQualType());
2685ffd83dbSDimitry Andric   value.SetCompilerType(compiler_type);
2695ffd83dbSDimitry Andric 
2705ffd83dbSDimitry Andric   RegisterContext *reg_ctx = thread.GetRegisterContext().get();
2715ffd83dbSDimitry Andric   if (!reg_ctx)
2725ffd83dbSDimitry Andric     return return_valobj_sp;
2735ffd83dbSDimitry Andric 
2745ffd83dbSDimitry Andric   bool is_signed;
2755ffd83dbSDimitry Andric 
2765ffd83dbSDimitry Andric   if (compiler_type.IsIntegerOrEnumerationType(is_signed)) {
277bdd1243dSDimitry Andric     std::optional<uint64_t> bit_width = compiler_type.GetBitSize(&thread);
2785ffd83dbSDimitry Andric     if (!bit_width)
2795ffd83dbSDimitry Andric       return return_valobj_sp;
2805ffd83dbSDimitry Andric     unsigned eax_id =
2815ffd83dbSDimitry Andric         reg_ctx->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB];
2825ffd83dbSDimitry Andric     unsigned edx_id =
2835ffd83dbSDimitry Andric         reg_ctx->GetRegisterInfoByName("edx", 0)->kinds[eRegisterKindLLDB];
2845ffd83dbSDimitry Andric 
2855ffd83dbSDimitry Andric     switch (*bit_width) {
2865ffd83dbSDimitry Andric     default:
2875ffd83dbSDimitry Andric     case 128:
2885ffd83dbSDimitry Andric       // Scalar can't hold 128-bit literals, so we don't handle this
2895ffd83dbSDimitry Andric       return return_valobj_sp;
2905ffd83dbSDimitry Andric     case 64:
2915ffd83dbSDimitry Andric       uint64_t raw_value;
2925ffd83dbSDimitry Andric       raw_value =
2935ffd83dbSDimitry Andric           thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
2945ffd83dbSDimitry Andric           0xffffffff;
2955ffd83dbSDimitry Andric       raw_value |=
2965ffd83dbSDimitry Andric           (thread.GetRegisterContext()->ReadRegisterAsUnsigned(edx_id, 0) &
2975ffd83dbSDimitry Andric            0xffffffff)
2985ffd83dbSDimitry Andric           << 32;
2995ffd83dbSDimitry Andric       if (is_signed)
3005ffd83dbSDimitry Andric         value.GetScalar() = (int64_t)raw_value;
3015ffd83dbSDimitry Andric       else
3025ffd83dbSDimitry Andric         value.GetScalar() = (uint64_t)raw_value;
3035ffd83dbSDimitry Andric       break;
3045ffd83dbSDimitry Andric     case 32:
3055ffd83dbSDimitry Andric       if (is_signed)
3065ffd83dbSDimitry Andric         value.GetScalar() = (int32_t)(
3075ffd83dbSDimitry Andric             thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
3085ffd83dbSDimitry Andric             0xffffffff);
3095ffd83dbSDimitry Andric       else
3105ffd83dbSDimitry Andric         value.GetScalar() = (uint32_t)(
3115ffd83dbSDimitry Andric             thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
3125ffd83dbSDimitry Andric             0xffffffff);
3135ffd83dbSDimitry Andric       break;
3145ffd83dbSDimitry Andric     case 16:
3155ffd83dbSDimitry Andric       if (is_signed)
3165ffd83dbSDimitry Andric         value.GetScalar() = (int16_t)(
3175ffd83dbSDimitry Andric             thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
3185ffd83dbSDimitry Andric             0xffff);
3195ffd83dbSDimitry Andric       else
3205ffd83dbSDimitry Andric         value.GetScalar() = (uint16_t)(
3215ffd83dbSDimitry Andric             thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
3225ffd83dbSDimitry Andric             0xffff);
3235ffd83dbSDimitry Andric       break;
3245ffd83dbSDimitry Andric     case 8:
3255ffd83dbSDimitry Andric       if (is_signed)
3265ffd83dbSDimitry Andric         value.GetScalar() = (int8_t)(
3275ffd83dbSDimitry Andric             thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
3285ffd83dbSDimitry Andric             0xff);
3295ffd83dbSDimitry Andric       else
3305ffd83dbSDimitry Andric         value.GetScalar() = (uint8_t)(
3315ffd83dbSDimitry Andric             thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
3325ffd83dbSDimitry Andric             0xff);
3335ffd83dbSDimitry Andric       break;
3345ffd83dbSDimitry Andric     }
3355ffd83dbSDimitry Andric   } else if (compiler_type.IsPointerType()) {
3365ffd83dbSDimitry Andric     unsigned eax_id =
3375ffd83dbSDimitry Andric         reg_ctx->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB];
3385ffd83dbSDimitry Andric     uint32_t ptr =
3395ffd83dbSDimitry Andric         thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
3405ffd83dbSDimitry Andric         0xffffffff;
3415ffd83dbSDimitry Andric     value.GetScalar() = ptr;
3425ffd83dbSDimitry Andric   } else {
3435ffd83dbSDimitry Andric     // not handled yet
3445ffd83dbSDimitry Andric     return return_valobj_sp;
3455ffd83dbSDimitry Andric   }
3465ffd83dbSDimitry Andric 
3475ffd83dbSDimitry Andric   // If we get here, we have a valid Value, so make our ValueObject out of it:
3485ffd83dbSDimitry Andric 
3495ffd83dbSDimitry Andric   return_valobj_sp = ValueObjectConstResult::Create(
3505ffd83dbSDimitry Andric       thread.GetStackFrameAtIndex(0).get(), value, ConstString(""));
3515ffd83dbSDimitry Andric   return return_valobj_sp;
3525ffd83dbSDimitry Andric }
3535ffd83dbSDimitry Andric 
3545ffd83dbSDimitry Andric // This defines the CFA as esp+4
3555ffd83dbSDimitry Andric // the saved pc is at CFA-4 (i.e. esp+0)
3565ffd83dbSDimitry Andric // The saved esp is CFA+0
3575ffd83dbSDimitry Andric 
CreateFunctionEntryUnwindPlan(UnwindPlan & unwind_plan)3585ffd83dbSDimitry Andric bool ABIMacOSX_i386::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) {
3595ffd83dbSDimitry Andric   unwind_plan.Clear();
3605ffd83dbSDimitry Andric   unwind_plan.SetRegisterKind(eRegisterKindDWARF);
3615ffd83dbSDimitry Andric 
3625ffd83dbSDimitry Andric   uint32_t sp_reg_num = dwarf_esp;
3635ffd83dbSDimitry Andric   uint32_t pc_reg_num = dwarf_eip;
3645ffd83dbSDimitry Andric 
3655ffd83dbSDimitry Andric   UnwindPlan::RowSP row(new UnwindPlan::Row);
3665ffd83dbSDimitry Andric   row->GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 4);
3675ffd83dbSDimitry Andric   row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, -4, false);
3685ffd83dbSDimitry Andric   row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);
3695ffd83dbSDimitry Andric   unwind_plan.AppendRow(row);
3705ffd83dbSDimitry Andric   unwind_plan.SetSourceName("i386 at-func-entry default");
3715ffd83dbSDimitry Andric   unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
3725ffd83dbSDimitry Andric   return true;
3735ffd83dbSDimitry Andric }
3745ffd83dbSDimitry Andric 
3755ffd83dbSDimitry Andric // This defines the CFA as ebp+8
3765ffd83dbSDimitry Andric // The saved pc is at CFA-4 (i.e. ebp+4)
3775ffd83dbSDimitry Andric // The saved ebp is at CFA-8 (i.e. ebp+0)
3785ffd83dbSDimitry Andric // The saved esp is CFA+0
3795ffd83dbSDimitry Andric 
CreateDefaultUnwindPlan(UnwindPlan & unwind_plan)3805ffd83dbSDimitry Andric bool ABIMacOSX_i386::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
3815ffd83dbSDimitry Andric   unwind_plan.Clear();
3825ffd83dbSDimitry Andric   unwind_plan.SetRegisterKind(eRegisterKindDWARF);
3835ffd83dbSDimitry Andric 
3845ffd83dbSDimitry Andric   uint32_t fp_reg_num = dwarf_ebp;
3855ffd83dbSDimitry Andric   uint32_t sp_reg_num = dwarf_esp;
3865ffd83dbSDimitry Andric   uint32_t pc_reg_num = dwarf_eip;
3875ffd83dbSDimitry Andric 
3885ffd83dbSDimitry Andric   UnwindPlan::RowSP row(new UnwindPlan::Row);
3895ffd83dbSDimitry Andric   const int32_t ptr_size = 4;
3905ffd83dbSDimitry Andric 
3915ffd83dbSDimitry Andric   row->GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size);
3925ffd83dbSDimitry Andric   row->SetOffset(0);
393fe6060f1SDimitry Andric   row->SetUnspecifiedRegistersAreUndefined(true);
3945ffd83dbSDimitry Andric 
3955ffd83dbSDimitry Andric   row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true);
3965ffd83dbSDimitry Andric   row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true);
3975ffd83dbSDimitry Andric   row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);
3985ffd83dbSDimitry Andric 
3995ffd83dbSDimitry Andric   unwind_plan.AppendRow(row);
4005ffd83dbSDimitry Andric   unwind_plan.SetSourceName("i386 default unwind plan");
4015ffd83dbSDimitry Andric   unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
4025ffd83dbSDimitry Andric   unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
4035ffd83dbSDimitry Andric   unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
4045ffd83dbSDimitry Andric   return true;
4055ffd83dbSDimitry Andric }
4065ffd83dbSDimitry Andric 
RegisterIsVolatile(const RegisterInfo * reg_info)4075ffd83dbSDimitry Andric bool ABIMacOSX_i386::RegisterIsVolatile(const RegisterInfo *reg_info) {
4085ffd83dbSDimitry Andric   return !RegisterIsCalleeSaved(reg_info);
4095ffd83dbSDimitry Andric }
4105ffd83dbSDimitry Andric 
4115ffd83dbSDimitry Andric // v.
4125ffd83dbSDimitry Andric // http://developer.apple.com/library/mac/#documentation/developertools/Conceptual/LowLevelABI/130
4135ffd83dbSDimitry Andric // -IA-
4145ffd83dbSDimitry Andric // 32_Function_Calling_Conventions/IA32.html#//apple_ref/doc/uid/TP40002492-SW4
4155ffd83dbSDimitry Andric //
4165ffd83dbSDimitry Andric // This document ("OS X ABI Function Call Guide", chapter "IA-32 Function
4175ffd83dbSDimitry Andric // Calling Conventions") says that the following registers on i386 are
4185ffd83dbSDimitry Andric // preserved aka non-volatile aka callee-saved:
4195ffd83dbSDimitry Andric //
4205ffd83dbSDimitry Andric // ebx, ebp, esi, edi, esp
4215ffd83dbSDimitry Andric 
RegisterIsCalleeSaved(const RegisterInfo * reg_info)4225ffd83dbSDimitry Andric bool ABIMacOSX_i386::RegisterIsCalleeSaved(const RegisterInfo *reg_info) {
4235ffd83dbSDimitry Andric   if (reg_info) {
4245ffd83dbSDimitry Andric     // Saved registers are ebx, ebp, esi, edi, esp, eip
4255ffd83dbSDimitry Andric     const char *name = reg_info->name;
4265ffd83dbSDimitry Andric     if (name[0] == 'e') {
4275ffd83dbSDimitry Andric       switch (name[1]) {
4285ffd83dbSDimitry Andric       case 'b':
4295ffd83dbSDimitry Andric         if (name[2] == 'x' || name[2] == 'p')
4305ffd83dbSDimitry Andric           return name[3] == '\0';
4315ffd83dbSDimitry Andric         break;
4325ffd83dbSDimitry Andric       case 'd':
4335ffd83dbSDimitry Andric         if (name[2] == 'i')
4345ffd83dbSDimitry Andric           return name[3] == '\0';
4355ffd83dbSDimitry Andric         break;
4365ffd83dbSDimitry Andric       case 'i':
4375ffd83dbSDimitry Andric         if (name[2] == 'p')
4385ffd83dbSDimitry Andric           return name[3] == '\0';
4395ffd83dbSDimitry Andric         break;
4405ffd83dbSDimitry Andric       case 's':
4415ffd83dbSDimitry Andric         if (name[2] == 'i' || name[2] == 'p')
4425ffd83dbSDimitry Andric           return name[3] == '\0';
4435ffd83dbSDimitry Andric         break;
4445ffd83dbSDimitry Andric       }
4455ffd83dbSDimitry Andric     }
4465ffd83dbSDimitry Andric     if (name[0] == 's' && name[1] == 'p' && name[2] == '\0') // sp
4475ffd83dbSDimitry Andric       return true;
4485ffd83dbSDimitry Andric     if (name[0] == 'f' && name[1] == 'p' && name[2] == '\0') // fp
4495ffd83dbSDimitry Andric       return true;
4505ffd83dbSDimitry Andric     if (name[0] == 'p' && name[1] == 'c' && name[2] == '\0') // pc
4515ffd83dbSDimitry Andric       return true;
4525ffd83dbSDimitry Andric   }
4535ffd83dbSDimitry Andric   return false;
4545ffd83dbSDimitry Andric }
4555ffd83dbSDimitry Andric 
Initialize()4565ffd83dbSDimitry Andric void ABIMacOSX_i386::Initialize() {
4575ffd83dbSDimitry Andric   PluginManager::RegisterPlugin(
4585ffd83dbSDimitry Andric       GetPluginNameStatic(), "Mac OS X ABI for i386 targets", CreateInstance);
4595ffd83dbSDimitry Andric }
4605ffd83dbSDimitry Andric 
Terminate()4615ffd83dbSDimitry Andric void ABIMacOSX_i386::Terminate() {
4625ffd83dbSDimitry Andric   PluginManager::UnregisterPlugin(CreateInstance);
4635ffd83dbSDimitry Andric }
464