xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/ABI/X86/ABISysV_i386.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
15ffd83dbSDimitry Andric //===-- ABISysV_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 #include "ABISysV_i386.h"
95ffd83dbSDimitry Andric 
105ffd83dbSDimitry Andric #include "llvm/ADT/STLExtras.h"
11*06c3fb27SDimitry Andric #include "llvm/TargetParser/Triple.h"
125ffd83dbSDimitry Andric 
135ffd83dbSDimitry Andric #include "lldb/Core/Module.h"
145ffd83dbSDimitry Andric #include "lldb/Core/PluginManager.h"
155ffd83dbSDimitry Andric #include "lldb/Core/Value.h"
165ffd83dbSDimitry Andric #include "lldb/Core/ValueObjectConstResult.h"
175ffd83dbSDimitry Andric #include "lldb/Core/ValueObjectMemory.h"
185ffd83dbSDimitry Andric #include "lldb/Core/ValueObjectRegister.h"
195ffd83dbSDimitry Andric #include "lldb/Symbol/UnwindPlan.h"
205ffd83dbSDimitry Andric #include "lldb/Target/Process.h"
215ffd83dbSDimitry Andric #include "lldb/Target/RegisterContext.h"
225ffd83dbSDimitry Andric #include "lldb/Target/StackFrame.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/DataExtractor.h"
275ffd83dbSDimitry Andric #include "lldb/Utility/Log.h"
285ffd83dbSDimitry Andric #include "lldb/Utility/RegisterValue.h"
295ffd83dbSDimitry Andric #include "lldb/Utility/Status.h"
30bdd1243dSDimitry Andric #include <optional>
315ffd83dbSDimitry Andric 
325ffd83dbSDimitry Andric using namespace lldb;
335ffd83dbSDimitry Andric using namespace lldb_private;
345ffd83dbSDimitry Andric 
355ffd83dbSDimitry Andric LLDB_PLUGIN_DEFINE(ABISysV_i386)
365ffd83dbSDimitry Andric 
375ffd83dbSDimitry Andric //   This source file uses the following document as a reference:
385ffd83dbSDimitry Andric //====================================================================
395ffd83dbSDimitry Andric //             System V Application Binary Interface
405ffd83dbSDimitry Andric //    Intel386 Architecture Processor Supplement, Version 1.0
415ffd83dbSDimitry Andric //                         Edited by
425ffd83dbSDimitry Andric //      H.J. Lu, David L Kreitzer, Milind Girkar, Zia Ansari
435ffd83dbSDimitry Andric //
445ffd83dbSDimitry Andric //                        (Based on
455ffd83dbSDimitry Andric //           System V Application Binary Interface,
465ffd83dbSDimitry Andric //          AMD64 Architecture Processor Supplement,
475ffd83dbSDimitry Andric //                         Edited by
485ffd83dbSDimitry Andric //     H.J. Lu, Michael Matz, Milind Girkar, Jan Hubicka,
495ffd83dbSDimitry Andric //               Andreas Jaeger, Mark Mitchell)
505ffd83dbSDimitry Andric //
515ffd83dbSDimitry Andric //                     February 3, 2015
525ffd83dbSDimitry Andric //====================================================================
535ffd83dbSDimitry Andric 
545ffd83dbSDimitry Andric // DWARF Register Number Mapping
555ffd83dbSDimitry Andric // See Table 2.14 of the reference document (specified on top of this file)
565ffd83dbSDimitry Andric // Comment: Table 2.14 is followed till 'mm' entries. After that, all entries
575ffd83dbSDimitry Andric // are ignored here.
585ffd83dbSDimitry Andric 
595ffd83dbSDimitry Andric enum dwarf_regnums {
605ffd83dbSDimitry Andric   dwarf_eax = 0,
615ffd83dbSDimitry Andric   dwarf_ecx,
625ffd83dbSDimitry Andric   dwarf_edx,
635ffd83dbSDimitry Andric   dwarf_ebx,
645ffd83dbSDimitry Andric   dwarf_esp,
655ffd83dbSDimitry Andric   dwarf_ebp,
665ffd83dbSDimitry Andric   dwarf_esi,
675ffd83dbSDimitry Andric   dwarf_edi,
685ffd83dbSDimitry Andric   dwarf_eip,
695ffd83dbSDimitry Andric };
705ffd83dbSDimitry Andric 
715ffd83dbSDimitry Andric // Static Functions
725ffd83dbSDimitry Andric 
735ffd83dbSDimitry Andric ABISP
CreateInstance(lldb::ProcessSP process_sp,const ArchSpec & arch)745ffd83dbSDimitry Andric ABISysV_i386::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) {
755ffd83dbSDimitry Andric   if (arch.GetTriple().getVendor() != llvm::Triple::Apple) {
765ffd83dbSDimitry Andric     if (arch.GetTriple().getArch() == llvm::Triple::x86) {
775ffd83dbSDimitry Andric       return ABISP(
785ffd83dbSDimitry Andric           new ABISysV_i386(std::move(process_sp), MakeMCRegisterInfo(arch)));
795ffd83dbSDimitry Andric     }
805ffd83dbSDimitry Andric   }
815ffd83dbSDimitry Andric   return ABISP();
825ffd83dbSDimitry Andric }
835ffd83dbSDimitry Andric 
PrepareTrivialCall(Thread & thread,addr_t sp,addr_t func_addr,addr_t return_addr,llvm::ArrayRef<addr_t> args) const845ffd83dbSDimitry Andric bool ABISysV_i386::PrepareTrivialCall(Thread &thread, addr_t sp,
855ffd83dbSDimitry Andric                                       addr_t func_addr, addr_t return_addr,
865ffd83dbSDimitry Andric                                       llvm::ArrayRef<addr_t> args) const {
875ffd83dbSDimitry Andric   RegisterContext *reg_ctx = thread.GetRegisterContext().get();
885ffd83dbSDimitry Andric 
895ffd83dbSDimitry Andric   if (!reg_ctx)
905ffd83dbSDimitry Andric     return false;
915ffd83dbSDimitry Andric 
925ffd83dbSDimitry Andric   uint32_t pc_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(
935ffd83dbSDimitry Andric       eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
945ffd83dbSDimitry Andric   uint32_t sp_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(
955ffd83dbSDimitry Andric       eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
965ffd83dbSDimitry Andric 
975ffd83dbSDimitry Andric   // While using register info to write a register value to memory, the
985ffd83dbSDimitry Andric   // register info just needs to have the correct size of a 32 bit register,
995ffd83dbSDimitry Andric   // the actual register it pertains to is not important, just the size needs
1005ffd83dbSDimitry Andric   // to be correct. "eax" is used here for this purpose.
1015ffd83dbSDimitry Andric   const RegisterInfo *reg_info_32 = reg_ctx->GetRegisterInfoByName("eax");
1025ffd83dbSDimitry Andric   if (!reg_info_32)
1035ffd83dbSDimitry Andric     return false; // TODO this should actually never happen
1045ffd83dbSDimitry Andric 
1055ffd83dbSDimitry Andric   Status error;
1065ffd83dbSDimitry Andric   RegisterValue reg_value;
1075ffd83dbSDimitry Andric 
1085ffd83dbSDimitry Andric   // Make room for the argument(s) on the stack
1095ffd83dbSDimitry Andric   sp -= 4 * args.size();
1105ffd83dbSDimitry Andric 
1115ffd83dbSDimitry Andric   // SP Alignment
1125ffd83dbSDimitry Andric   sp &= ~(16ull - 1ull); // 16-byte alignment
1135ffd83dbSDimitry Andric 
1145ffd83dbSDimitry Andric   // Write arguments onto the stack
1155ffd83dbSDimitry Andric   addr_t arg_pos = sp;
1165ffd83dbSDimitry Andric   for (addr_t arg : args) {
1175ffd83dbSDimitry Andric     reg_value.SetUInt32(arg);
1185ffd83dbSDimitry Andric     error = reg_ctx->WriteRegisterValueToMemory(
1195ffd83dbSDimitry Andric         reg_info_32, arg_pos, reg_info_32->byte_size, reg_value);
1205ffd83dbSDimitry Andric     if (error.Fail())
1215ffd83dbSDimitry Andric       return false;
1225ffd83dbSDimitry Andric     arg_pos += 4;
1235ffd83dbSDimitry Andric   }
1245ffd83dbSDimitry Andric 
1255ffd83dbSDimitry Andric   // The return address is pushed onto the stack
1265ffd83dbSDimitry Andric   sp -= 4;
1275ffd83dbSDimitry Andric   reg_value.SetUInt32(return_addr);
1285ffd83dbSDimitry Andric   error = reg_ctx->WriteRegisterValueToMemory(
1295ffd83dbSDimitry Andric       reg_info_32, sp, reg_info_32->byte_size, reg_value);
1305ffd83dbSDimitry Andric   if (error.Fail())
1315ffd83dbSDimitry Andric     return false;
1325ffd83dbSDimitry Andric 
1335ffd83dbSDimitry Andric   // Setting %esp to the actual stack value.
1345ffd83dbSDimitry Andric   if (!reg_ctx->WriteRegisterFromUnsigned(sp_reg_num, sp))
1355ffd83dbSDimitry Andric     return false;
1365ffd83dbSDimitry Andric 
1375ffd83dbSDimitry Andric   // Setting %eip to the address of the called function.
1385ffd83dbSDimitry Andric   if (!reg_ctx->WriteRegisterFromUnsigned(pc_reg_num, func_addr))
1395ffd83dbSDimitry Andric     return false;
1405ffd83dbSDimitry Andric 
1415ffd83dbSDimitry Andric   return true;
1425ffd83dbSDimitry Andric }
1435ffd83dbSDimitry Andric 
ReadIntegerArgument(Scalar & scalar,unsigned int bit_width,bool is_signed,Process * process,addr_t & current_stack_argument)1445ffd83dbSDimitry Andric static bool ReadIntegerArgument(Scalar &scalar, unsigned int bit_width,
1455ffd83dbSDimitry Andric                                 bool is_signed, Process *process,
1465ffd83dbSDimitry Andric                                 addr_t &current_stack_argument) {
1475ffd83dbSDimitry Andric   uint32_t byte_size = (bit_width + (8 - 1)) / 8;
1485ffd83dbSDimitry Andric   Status error;
1495ffd83dbSDimitry Andric 
1505ffd83dbSDimitry Andric   if (!process)
1515ffd83dbSDimitry Andric     return false;
1525ffd83dbSDimitry Andric 
1535ffd83dbSDimitry Andric   if (process->ReadScalarIntegerFromMemory(current_stack_argument, byte_size,
1545ffd83dbSDimitry Andric                                            is_signed, scalar, error)) {
1555ffd83dbSDimitry Andric     current_stack_argument += byte_size;
1565ffd83dbSDimitry Andric     return true;
1575ffd83dbSDimitry Andric   }
1585ffd83dbSDimitry Andric   return false;
1595ffd83dbSDimitry Andric }
1605ffd83dbSDimitry Andric 
GetArgumentValues(Thread & thread,ValueList & values) const1615ffd83dbSDimitry Andric bool ABISysV_i386::GetArgumentValues(Thread &thread, ValueList &values) const {
1625ffd83dbSDimitry Andric   unsigned int num_values = values.GetSize();
1635ffd83dbSDimitry Andric   unsigned int value_index;
1645ffd83dbSDimitry Andric 
1655ffd83dbSDimitry Andric   RegisterContext *reg_ctx = thread.GetRegisterContext().get();
1665ffd83dbSDimitry Andric 
1675ffd83dbSDimitry Andric   if (!reg_ctx)
1685ffd83dbSDimitry Andric     return false;
1695ffd83dbSDimitry Andric 
1705ffd83dbSDimitry Andric   // Get pointer to the first stack argument
1715ffd83dbSDimitry Andric   addr_t sp = reg_ctx->GetSP(0);
1725ffd83dbSDimitry Andric   if (!sp)
1735ffd83dbSDimitry Andric     return false;
1745ffd83dbSDimitry Andric 
1755ffd83dbSDimitry Andric   addr_t current_stack_argument = sp + 4; // jump over return address
1765ffd83dbSDimitry Andric 
1775ffd83dbSDimitry Andric   for (value_index = 0; value_index < num_values; ++value_index) {
1785ffd83dbSDimitry Andric     Value *value = values.GetValueAtIndex(value_index);
1795ffd83dbSDimitry Andric 
1805ffd83dbSDimitry Andric     if (!value)
1815ffd83dbSDimitry Andric       return false;
1825ffd83dbSDimitry Andric 
1835ffd83dbSDimitry Andric     // Currently: Support for extracting values with Clang QualTypes only.
1845ffd83dbSDimitry Andric     CompilerType compiler_type(value->GetCompilerType());
185bdd1243dSDimitry Andric     std::optional<uint64_t> bit_size = compiler_type.GetBitSize(&thread);
1865ffd83dbSDimitry Andric     if (bit_size) {
1875ffd83dbSDimitry Andric       bool is_signed;
1885ffd83dbSDimitry Andric       if (compiler_type.IsIntegerOrEnumerationType(is_signed)) {
1895ffd83dbSDimitry Andric         ReadIntegerArgument(value->GetScalar(), *bit_size, is_signed,
1905ffd83dbSDimitry Andric                             thread.GetProcess().get(), current_stack_argument);
1915ffd83dbSDimitry Andric       } else if (compiler_type.IsPointerType()) {
1925ffd83dbSDimitry Andric         ReadIntegerArgument(value->GetScalar(), *bit_size, false,
1935ffd83dbSDimitry Andric                             thread.GetProcess().get(), current_stack_argument);
1945ffd83dbSDimitry Andric       }
1955ffd83dbSDimitry Andric     }
1965ffd83dbSDimitry Andric   }
1975ffd83dbSDimitry Andric   return true;
1985ffd83dbSDimitry Andric }
1995ffd83dbSDimitry Andric 
SetReturnValueObject(lldb::StackFrameSP & frame_sp,lldb::ValueObjectSP & new_value_sp)2005ffd83dbSDimitry Andric Status ABISysV_i386::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
2015ffd83dbSDimitry Andric                                           lldb::ValueObjectSP &new_value_sp) {
2025ffd83dbSDimitry Andric   Status error;
2035ffd83dbSDimitry Andric   if (!new_value_sp) {
2045ffd83dbSDimitry Andric     error.SetErrorString("Empty value object for return value.");
2055ffd83dbSDimitry Andric     return error;
2065ffd83dbSDimitry Andric   }
2075ffd83dbSDimitry Andric 
2085ffd83dbSDimitry Andric   CompilerType compiler_type = new_value_sp->GetCompilerType();
2095ffd83dbSDimitry Andric   if (!compiler_type) {
2105ffd83dbSDimitry Andric     error.SetErrorString("Null clang type for return value.");
2115ffd83dbSDimitry Andric     return error;
2125ffd83dbSDimitry Andric   }
2135ffd83dbSDimitry Andric 
2145ffd83dbSDimitry Andric   const uint32_t type_flags = compiler_type.GetTypeInfo();
2155ffd83dbSDimitry Andric   Thread *thread = frame_sp->GetThread().get();
2165ffd83dbSDimitry Andric   RegisterContext *reg_ctx = thread->GetRegisterContext().get();
2175ffd83dbSDimitry Andric   DataExtractor data;
2185ffd83dbSDimitry Andric   Status data_error;
2195ffd83dbSDimitry Andric   size_t num_bytes = new_value_sp->GetData(data, data_error);
2205ffd83dbSDimitry Andric   bool register_write_successful = true;
2215ffd83dbSDimitry Andric 
2225ffd83dbSDimitry Andric   if (data_error.Fail()) {
2235ffd83dbSDimitry Andric     error.SetErrorStringWithFormat(
2245ffd83dbSDimitry Andric         "Couldn't convert return value to raw data: %s",
2255ffd83dbSDimitry Andric         data_error.AsCString());
2265ffd83dbSDimitry Andric     return error;
2275ffd83dbSDimitry Andric   }
2285ffd83dbSDimitry Andric 
2295ffd83dbSDimitry Andric   // Following "IF ELSE" block categorizes various 'Fundamental Data Types'.
2305ffd83dbSDimitry Andric   // The terminology 'Fundamental Data Types' used here is adopted from Table
2315ffd83dbSDimitry Andric   // 2.1 of the reference document (specified on top of this file)
2325ffd83dbSDimitry Andric 
2335ffd83dbSDimitry Andric   if (type_flags & eTypeIsPointer) // 'Pointer'
2345ffd83dbSDimitry Andric   {
2355ffd83dbSDimitry Andric     if (num_bytes != sizeof(uint32_t)) {
2365ffd83dbSDimitry Andric       error.SetErrorString("Pointer to be returned is not 4 bytes wide");
2375ffd83dbSDimitry Andric       return error;
2385ffd83dbSDimitry Andric     }
2395ffd83dbSDimitry Andric     lldb::offset_t offset = 0;
2405ffd83dbSDimitry Andric     const RegisterInfo *eax_info = reg_ctx->GetRegisterInfoByName("eax", 0);
2415ffd83dbSDimitry Andric     uint32_t raw_value = data.GetMaxU32(&offset, num_bytes);
2425ffd83dbSDimitry Andric     register_write_successful =
2435ffd83dbSDimitry Andric         reg_ctx->WriteRegisterFromUnsigned(eax_info, raw_value);
2445ffd83dbSDimitry Andric   } else if ((type_flags & eTypeIsScalar) ||
2455ffd83dbSDimitry Andric              (type_flags & eTypeIsEnumeration)) //'Integral' + 'Floating Point'
2465ffd83dbSDimitry Andric   {
2475ffd83dbSDimitry Andric     lldb::offset_t offset = 0;
2485ffd83dbSDimitry Andric     const RegisterInfo *eax_info = reg_ctx->GetRegisterInfoByName("eax", 0);
2495ffd83dbSDimitry Andric 
2505ffd83dbSDimitry Andric     if (type_flags & eTypeIsInteger) // 'Integral' except enum
2515ffd83dbSDimitry Andric     {
2525ffd83dbSDimitry Andric       switch (num_bytes) {
2535ffd83dbSDimitry Andric       default:
2545ffd83dbSDimitry Andric         break;
2555ffd83dbSDimitry Andric       case 16:
2565ffd83dbSDimitry Andric         // For clang::BuiltinType::UInt128 & Int128 ToDo: Need to decide how to
2575ffd83dbSDimitry Andric         // handle it
2585ffd83dbSDimitry Andric         break;
2595ffd83dbSDimitry Andric       case 8: {
2605ffd83dbSDimitry Andric         uint32_t raw_value_low = data.GetMaxU32(&offset, 4);
2615ffd83dbSDimitry Andric         const RegisterInfo *edx_info = reg_ctx->GetRegisterInfoByName("edx", 0);
2625ffd83dbSDimitry Andric         uint32_t raw_value_high = data.GetMaxU32(&offset, num_bytes - offset);
2635ffd83dbSDimitry Andric         register_write_successful =
2645ffd83dbSDimitry Andric             (reg_ctx->WriteRegisterFromUnsigned(eax_info, raw_value_low) &&
2655ffd83dbSDimitry Andric              reg_ctx->WriteRegisterFromUnsigned(edx_info, raw_value_high));
2665ffd83dbSDimitry Andric         break;
2675ffd83dbSDimitry Andric       }
2685ffd83dbSDimitry Andric       case 4:
2695ffd83dbSDimitry Andric       case 2:
2705ffd83dbSDimitry Andric       case 1: {
2715ffd83dbSDimitry Andric         uint32_t raw_value = data.GetMaxU32(&offset, num_bytes);
2725ffd83dbSDimitry Andric         register_write_successful =
2735ffd83dbSDimitry Andric             reg_ctx->WriteRegisterFromUnsigned(eax_info, raw_value);
2745ffd83dbSDimitry Andric         break;
2755ffd83dbSDimitry Andric       }
2765ffd83dbSDimitry Andric       }
2775ffd83dbSDimitry Andric     } else if (type_flags & eTypeIsEnumeration) // handles enum
2785ffd83dbSDimitry Andric     {
2795ffd83dbSDimitry Andric       uint32_t raw_value = data.GetMaxU32(&offset, num_bytes);
2805ffd83dbSDimitry Andric       register_write_successful =
2815ffd83dbSDimitry Andric           reg_ctx->WriteRegisterFromUnsigned(eax_info, raw_value);
2825ffd83dbSDimitry Andric     } else if (type_flags & eTypeIsFloat) // 'Floating Point'
2835ffd83dbSDimitry Andric     {
2845ffd83dbSDimitry Andric       RegisterValue st0_value, fstat_value, ftag_value;
2855ffd83dbSDimitry Andric       const RegisterInfo *st0_info = reg_ctx->GetRegisterInfoByName("st0", 0);
2865ffd83dbSDimitry Andric       const RegisterInfo *fstat_info =
2875ffd83dbSDimitry Andric           reg_ctx->GetRegisterInfoByName("fstat", 0);
2885ffd83dbSDimitry Andric       const RegisterInfo *ftag_info = reg_ctx->GetRegisterInfoByName("ftag", 0);
2895ffd83dbSDimitry Andric 
2905ffd83dbSDimitry Andric       /* According to Page 3-12 of document
2915ffd83dbSDimitry Andric       System V Application Binary Interface, Intel386 Architecture Processor
2925ffd83dbSDimitry Andric       Supplement, Fourth Edition
2935ffd83dbSDimitry Andric       To return Floating Point values, all st% registers except st0 should be
2945ffd83dbSDimitry Andric       empty after exiting from
2955ffd83dbSDimitry Andric       a function. This requires setting fstat and ftag registers to specific
2965ffd83dbSDimitry Andric       values.
2975ffd83dbSDimitry Andric       fstat: The TOP field of fstat should be set to a value [0,7]. ABI doesn't
2985ffd83dbSDimitry Andric       specify the specific
2995ffd83dbSDimitry Andric       value of TOP in case of function return. Hence, we set the TOP field to 7
3005ffd83dbSDimitry Andric       by our choice. */
3015ffd83dbSDimitry Andric       uint32_t value_fstat_u32 = 0x00003800;
3025ffd83dbSDimitry Andric 
3035ffd83dbSDimitry Andric       /* ftag: Implication of setting TOP to 7 and indicating all st% registers
3045ffd83dbSDimitry Andric       empty except st0 is to set
3055ffd83dbSDimitry Andric       7th bit of 4th byte of FXSAVE area to 1 and all other bits of this byte to
3065ffd83dbSDimitry Andric       0. This is in accordance
3075ffd83dbSDimitry Andric       with the document Intel 64 and IA-32 Architectures Software Developer's
3085ffd83dbSDimitry Andric       Manual, January 2015 */
3095ffd83dbSDimitry Andric       uint32_t value_ftag_u32 = 0x00000080;
3105ffd83dbSDimitry Andric 
3115ffd83dbSDimitry Andric       if (num_bytes <= 12) // handles float, double, long double, __float80
3125ffd83dbSDimitry Andric       {
3135ffd83dbSDimitry Andric         long double value_long_dbl = 0.0;
3145ffd83dbSDimitry Andric         if (num_bytes == 4)
3155ffd83dbSDimitry Andric           value_long_dbl = data.GetFloat(&offset);
3165ffd83dbSDimitry Andric         else if (num_bytes == 8)
3175ffd83dbSDimitry Andric           value_long_dbl = data.GetDouble(&offset);
3185ffd83dbSDimitry Andric         else if (num_bytes == 12)
3195ffd83dbSDimitry Andric           value_long_dbl = data.GetLongDouble(&offset);
3205ffd83dbSDimitry Andric         else {
3215ffd83dbSDimitry Andric           error.SetErrorString("Invalid number of bytes for this return type");
3225ffd83dbSDimitry Andric           return error;
3235ffd83dbSDimitry Andric         }
3245ffd83dbSDimitry Andric         st0_value.SetLongDouble(value_long_dbl);
3255ffd83dbSDimitry Andric         fstat_value.SetUInt32(value_fstat_u32);
3265ffd83dbSDimitry Andric         ftag_value.SetUInt32(value_ftag_u32);
3275ffd83dbSDimitry Andric         register_write_successful =
3285ffd83dbSDimitry Andric             reg_ctx->WriteRegister(st0_info, st0_value) &&
3295ffd83dbSDimitry Andric             reg_ctx->WriteRegister(fstat_info, fstat_value) &&
3305ffd83dbSDimitry Andric             reg_ctx->WriteRegister(ftag_info, ftag_value);
3315ffd83dbSDimitry Andric       } else if (num_bytes == 16) // handles __float128
3325ffd83dbSDimitry Andric       {
3335ffd83dbSDimitry Andric         error.SetErrorString("Implementation is missing for this clang type.");
3345ffd83dbSDimitry Andric       }
3355ffd83dbSDimitry Andric     } else {
3365ffd83dbSDimitry Andric       // Neither 'Integral' nor 'Floating Point'. If flow reaches here then
3375ffd83dbSDimitry Andric       // check type_flags. This type_flags is not a valid type.
3385ffd83dbSDimitry Andric       error.SetErrorString("Invalid clang type");
3395ffd83dbSDimitry Andric     }
3405ffd83dbSDimitry Andric   } else {
3415ffd83dbSDimitry Andric     /* 'Complex Floating Point', 'Packed', 'Decimal Floating Point' and
3425ffd83dbSDimitry Andric     'Aggregate' data types
3435ffd83dbSDimitry Andric     are yet to be implemented */
3445ffd83dbSDimitry Andric     error.SetErrorString("Currently only Integral and Floating Point clang "
3455ffd83dbSDimitry Andric                          "types are supported.");
3465ffd83dbSDimitry Andric   }
3475ffd83dbSDimitry Andric   if (!register_write_successful)
3485ffd83dbSDimitry Andric     error.SetErrorString("Register writing failed");
3495ffd83dbSDimitry Andric   return error;
3505ffd83dbSDimitry Andric }
3515ffd83dbSDimitry Andric 
GetReturnValueObjectSimple(Thread & thread,CompilerType & return_compiler_type) const3525ffd83dbSDimitry Andric ValueObjectSP ABISysV_i386::GetReturnValueObjectSimple(
3535ffd83dbSDimitry Andric     Thread &thread, CompilerType &return_compiler_type) const {
3545ffd83dbSDimitry Andric   ValueObjectSP return_valobj_sp;
3555ffd83dbSDimitry Andric   Value value;
3565ffd83dbSDimitry Andric 
3575ffd83dbSDimitry Andric   if (!return_compiler_type)
3585ffd83dbSDimitry Andric     return return_valobj_sp;
3595ffd83dbSDimitry Andric 
3605ffd83dbSDimitry Andric   value.SetCompilerType(return_compiler_type);
3615ffd83dbSDimitry Andric 
3625ffd83dbSDimitry Andric   RegisterContext *reg_ctx = thread.GetRegisterContext().get();
3635ffd83dbSDimitry Andric   if (!reg_ctx)
3645ffd83dbSDimitry Andric     return return_valobj_sp;
3655ffd83dbSDimitry Andric 
3665ffd83dbSDimitry Andric   const uint32_t type_flags = return_compiler_type.GetTypeInfo();
3675ffd83dbSDimitry Andric 
3685ffd83dbSDimitry Andric   unsigned eax_id =
3695ffd83dbSDimitry Andric       reg_ctx->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB];
3705ffd83dbSDimitry Andric   unsigned edx_id =
3715ffd83dbSDimitry Andric       reg_ctx->GetRegisterInfoByName("edx", 0)->kinds[eRegisterKindLLDB];
3725ffd83dbSDimitry Andric 
3735ffd83dbSDimitry Andric   // Following "IF ELSE" block categorizes various 'Fundamental Data Types'.
3745ffd83dbSDimitry Andric   // The terminology 'Fundamental Data Types' used here is adopted from Table
3755ffd83dbSDimitry Andric   // 2.1 of the reference document (specified on top of this file)
3765ffd83dbSDimitry Andric 
3775ffd83dbSDimitry Andric   if (type_flags & eTypeIsPointer) // 'Pointer'
3785ffd83dbSDimitry Andric   {
3795ffd83dbSDimitry Andric     uint32_t ptr =
3805ffd83dbSDimitry Andric         thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
3815ffd83dbSDimitry Andric         0xffffffff;
382fe6060f1SDimitry Andric     value.SetValueType(Value::ValueType::Scalar);
3835ffd83dbSDimitry Andric     value.GetScalar() = ptr;
3845ffd83dbSDimitry Andric     return_valobj_sp = ValueObjectConstResult::Create(
3855ffd83dbSDimitry Andric         thread.GetStackFrameAtIndex(0).get(), value, ConstString(""));
3865ffd83dbSDimitry Andric   } else if ((type_flags & eTypeIsScalar) ||
3875ffd83dbSDimitry Andric              (type_flags & eTypeIsEnumeration)) //'Integral' + 'Floating Point'
3885ffd83dbSDimitry Andric   {
389fe6060f1SDimitry Andric     value.SetValueType(Value::ValueType::Scalar);
390bdd1243dSDimitry Andric     std::optional<uint64_t> byte_size =
391e8d8bef9SDimitry Andric         return_compiler_type.GetByteSize(&thread);
3925ffd83dbSDimitry Andric     if (!byte_size)
3935ffd83dbSDimitry Andric       return return_valobj_sp;
3945ffd83dbSDimitry Andric     bool success = false;
3955ffd83dbSDimitry Andric 
3965ffd83dbSDimitry Andric     if (type_flags & eTypeIsInteger) // 'Integral' except enum
3975ffd83dbSDimitry Andric     {
3985ffd83dbSDimitry Andric       const bool is_signed = ((type_flags & eTypeIsSigned) != 0);
3995ffd83dbSDimitry Andric       uint64_t raw_value =
4005ffd83dbSDimitry Andric           thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
4015ffd83dbSDimitry Andric           0xffffffff;
4025ffd83dbSDimitry Andric       raw_value |=
4035ffd83dbSDimitry Andric           (thread.GetRegisterContext()->ReadRegisterAsUnsigned(edx_id, 0) &
4045ffd83dbSDimitry Andric            0xffffffff)
4055ffd83dbSDimitry Andric           << 32;
4065ffd83dbSDimitry Andric 
4075ffd83dbSDimitry Andric       switch (*byte_size) {
4085ffd83dbSDimitry Andric       default:
4095ffd83dbSDimitry Andric         break;
4105ffd83dbSDimitry Andric 
4115ffd83dbSDimitry Andric       case 16:
4125ffd83dbSDimitry Andric         // For clang::BuiltinType::UInt128 & Int128 ToDo: Need to decide how to
4135ffd83dbSDimitry Andric         // handle it
4145ffd83dbSDimitry Andric         break;
4155ffd83dbSDimitry Andric 
4165ffd83dbSDimitry Andric       case 8:
4175ffd83dbSDimitry Andric         if (is_signed)
4185ffd83dbSDimitry Andric           value.GetScalar() = (int64_t)(raw_value);
4195ffd83dbSDimitry Andric         else
4205ffd83dbSDimitry Andric           value.GetScalar() = (uint64_t)(raw_value);
4215ffd83dbSDimitry Andric         success = true;
4225ffd83dbSDimitry Andric         break;
4235ffd83dbSDimitry Andric 
4245ffd83dbSDimitry Andric       case 4:
4255ffd83dbSDimitry Andric         if (is_signed)
4265ffd83dbSDimitry Andric           value.GetScalar() = (int32_t)(raw_value & UINT32_MAX);
4275ffd83dbSDimitry Andric         else
4285ffd83dbSDimitry Andric           value.GetScalar() = (uint32_t)(raw_value & UINT32_MAX);
4295ffd83dbSDimitry Andric         success = true;
4305ffd83dbSDimitry Andric         break;
4315ffd83dbSDimitry Andric 
4325ffd83dbSDimitry Andric       case 2:
4335ffd83dbSDimitry Andric         if (is_signed)
4345ffd83dbSDimitry Andric           value.GetScalar() = (int16_t)(raw_value & UINT16_MAX);
4355ffd83dbSDimitry Andric         else
4365ffd83dbSDimitry Andric           value.GetScalar() = (uint16_t)(raw_value & UINT16_MAX);
4375ffd83dbSDimitry Andric         success = true;
4385ffd83dbSDimitry Andric         break;
4395ffd83dbSDimitry Andric 
4405ffd83dbSDimitry Andric       case 1:
4415ffd83dbSDimitry Andric         if (is_signed)
4425ffd83dbSDimitry Andric           value.GetScalar() = (int8_t)(raw_value & UINT8_MAX);
4435ffd83dbSDimitry Andric         else
4445ffd83dbSDimitry Andric           value.GetScalar() = (uint8_t)(raw_value & UINT8_MAX);
4455ffd83dbSDimitry Andric         success = true;
4465ffd83dbSDimitry Andric         break;
4475ffd83dbSDimitry Andric       }
4485ffd83dbSDimitry Andric 
4495ffd83dbSDimitry Andric       if (success)
4505ffd83dbSDimitry Andric         return_valobj_sp = ValueObjectConstResult::Create(
4515ffd83dbSDimitry Andric             thread.GetStackFrameAtIndex(0).get(), value, ConstString(""));
4525ffd83dbSDimitry Andric     } else if (type_flags & eTypeIsEnumeration) // handles enum
4535ffd83dbSDimitry Andric     {
4545ffd83dbSDimitry Andric       uint32_t enm =
4555ffd83dbSDimitry Andric           thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
4565ffd83dbSDimitry Andric           0xffffffff;
457fe6060f1SDimitry Andric       value.SetValueType(Value::ValueType::Scalar);
4585ffd83dbSDimitry Andric       value.GetScalar() = enm;
4595ffd83dbSDimitry Andric       return_valobj_sp = ValueObjectConstResult::Create(
4605ffd83dbSDimitry Andric           thread.GetStackFrameAtIndex(0).get(), value, ConstString(""));
4615ffd83dbSDimitry Andric     } else if (type_flags & eTypeIsFloat) // 'Floating Point'
4625ffd83dbSDimitry Andric     {
4635ffd83dbSDimitry Andric       if (*byte_size <= 12) // handles float, double, long double, __float80
4645ffd83dbSDimitry Andric       {
4655ffd83dbSDimitry Andric         const RegisterInfo *st0_info = reg_ctx->GetRegisterInfoByName("st0", 0);
4665ffd83dbSDimitry Andric         RegisterValue st0_value;
4675ffd83dbSDimitry Andric 
4685ffd83dbSDimitry Andric         if (reg_ctx->ReadRegister(st0_info, st0_value)) {
4695ffd83dbSDimitry Andric           DataExtractor data;
4705ffd83dbSDimitry Andric           if (st0_value.GetData(data)) {
4715ffd83dbSDimitry Andric             lldb::offset_t offset = 0;
4725ffd83dbSDimitry Andric             long double value_long_double = data.GetLongDouble(&offset);
4735ffd83dbSDimitry Andric 
4745ffd83dbSDimitry Andric             // float is 4 bytes.
4755ffd83dbSDimitry Andric             if (*byte_size == 4) {
4765ffd83dbSDimitry Andric               float value_float = (float)value_long_double;
4775ffd83dbSDimitry Andric               value.GetScalar() = value_float;
4785ffd83dbSDimitry Andric               success = true;
4795ffd83dbSDimitry Andric             } else if (*byte_size == 8) {
4805ffd83dbSDimitry Andric               // double is 8 bytes
4815ffd83dbSDimitry Andric               // On Android Platform: long double is also 8 bytes It will be
4825ffd83dbSDimitry Andric               // handled here only.
4835ffd83dbSDimitry Andric               double value_double = (double)value_long_double;
4845ffd83dbSDimitry Andric               value.GetScalar() = value_double;
4855ffd83dbSDimitry Andric               success = true;
4865ffd83dbSDimitry Andric             } else if (*byte_size == 12) {
4875ffd83dbSDimitry Andric               // long double and __float80 are 12 bytes on i386.
4885ffd83dbSDimitry Andric               value.GetScalar() = value_long_double;
4895ffd83dbSDimitry Andric               success = true;
4905ffd83dbSDimitry Andric             }
4915ffd83dbSDimitry Andric           }
4925ffd83dbSDimitry Andric         }
4935ffd83dbSDimitry Andric 
4945ffd83dbSDimitry Andric         if (success)
4955ffd83dbSDimitry Andric           return_valobj_sp = ValueObjectConstResult::Create(
4965ffd83dbSDimitry Andric               thread.GetStackFrameAtIndex(0).get(), value, ConstString(""));
4975ffd83dbSDimitry Andric       } else if (*byte_size == 16) // handles __float128
4985ffd83dbSDimitry Andric       {
4995ffd83dbSDimitry Andric         lldb::addr_t storage_addr = (uint32_t)(
5005ffd83dbSDimitry Andric             thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
5015ffd83dbSDimitry Andric             0xffffffff);
5025ffd83dbSDimitry Andric         return_valobj_sp = ValueObjectMemory::Create(
5035ffd83dbSDimitry Andric             &thread, "", Address(storage_addr, nullptr), return_compiler_type);
5045ffd83dbSDimitry Andric       }
5055ffd83dbSDimitry Andric     } else // Neither 'Integral' nor 'Floating Point'
5065ffd83dbSDimitry Andric     {
5075ffd83dbSDimitry Andric       // If flow reaches here then check type_flags This type_flags is
5085ffd83dbSDimitry Andric       // unhandled
5095ffd83dbSDimitry Andric     }
5105ffd83dbSDimitry Andric   } else if (type_flags & eTypeIsComplex) // 'Complex Floating Point'
5115ffd83dbSDimitry Andric   {
5125ffd83dbSDimitry Andric     // ToDo: Yet to be implemented
5135ffd83dbSDimitry Andric   } else if (type_flags & eTypeIsVector) // 'Packed'
5145ffd83dbSDimitry Andric   {
515bdd1243dSDimitry Andric     std::optional<uint64_t> byte_size =
516e8d8bef9SDimitry Andric         return_compiler_type.GetByteSize(&thread);
5175ffd83dbSDimitry Andric     if (byte_size && *byte_size > 0) {
5185ffd83dbSDimitry Andric       const RegisterInfo *vec_reg = reg_ctx->GetRegisterInfoByName("xmm0", 0);
5195ffd83dbSDimitry Andric       if (vec_reg == nullptr)
5205ffd83dbSDimitry Andric         vec_reg = reg_ctx->GetRegisterInfoByName("mm0", 0);
5215ffd83dbSDimitry Andric 
5225ffd83dbSDimitry Andric       if (vec_reg) {
5235ffd83dbSDimitry Andric         if (*byte_size <= vec_reg->byte_size) {
5245ffd83dbSDimitry Andric           ProcessSP process_sp(thread.GetProcess());
5255ffd83dbSDimitry Andric           if (process_sp) {
5265ffd83dbSDimitry Andric             std::unique_ptr<DataBufferHeap> heap_data_up(
5275ffd83dbSDimitry Andric                 new DataBufferHeap(*byte_size, 0));
5285ffd83dbSDimitry Andric             const ByteOrder byte_order = process_sp->GetByteOrder();
5295ffd83dbSDimitry Andric             RegisterValue reg_value;
5305ffd83dbSDimitry Andric             if (reg_ctx->ReadRegister(vec_reg, reg_value)) {
5315ffd83dbSDimitry Andric               Status error;
532bdd1243dSDimitry Andric               if (reg_value.GetAsMemoryData(*vec_reg, heap_data_up->GetBytes(),
5335ffd83dbSDimitry Andric                                             heap_data_up->GetByteSize(),
5345ffd83dbSDimitry Andric                                             byte_order, error)) {
5355ffd83dbSDimitry Andric                 DataExtractor data(DataBufferSP(heap_data_up.release()),
5365ffd83dbSDimitry Andric                                    byte_order,
5375ffd83dbSDimitry Andric                                    process_sp->GetTarget()
5385ffd83dbSDimitry Andric                                        .GetArchitecture()
5395ffd83dbSDimitry Andric                                        .GetAddressByteSize());
5405ffd83dbSDimitry Andric                 return_valobj_sp = ValueObjectConstResult::Create(
5415ffd83dbSDimitry Andric                     &thread, return_compiler_type, ConstString(""), data);
5425ffd83dbSDimitry Andric               }
5435ffd83dbSDimitry Andric             }
5445ffd83dbSDimitry Andric           }
5455ffd83dbSDimitry Andric         } else if (*byte_size <= vec_reg->byte_size * 2) {
5465ffd83dbSDimitry Andric           const RegisterInfo *vec_reg2 =
5475ffd83dbSDimitry Andric               reg_ctx->GetRegisterInfoByName("xmm1", 0);
5485ffd83dbSDimitry Andric           if (vec_reg2) {
5495ffd83dbSDimitry Andric             ProcessSP process_sp(thread.GetProcess());
5505ffd83dbSDimitry Andric             if (process_sp) {
5515ffd83dbSDimitry Andric               std::unique_ptr<DataBufferHeap> heap_data_up(
5525ffd83dbSDimitry Andric                   new DataBufferHeap(*byte_size, 0));
5535ffd83dbSDimitry Andric               const ByteOrder byte_order = process_sp->GetByteOrder();
5545ffd83dbSDimitry Andric               RegisterValue reg_value;
5555ffd83dbSDimitry Andric               RegisterValue reg_value2;
5565ffd83dbSDimitry Andric               if (reg_ctx->ReadRegister(vec_reg, reg_value) &&
5575ffd83dbSDimitry Andric                   reg_ctx->ReadRegister(vec_reg2, reg_value2)) {
5585ffd83dbSDimitry Andric 
5595ffd83dbSDimitry Andric                 Status error;
560bdd1243dSDimitry Andric                 if (reg_value.GetAsMemoryData(
561bdd1243dSDimitry Andric                         *vec_reg, heap_data_up->GetBytes(), vec_reg->byte_size,
562bdd1243dSDimitry Andric                         byte_order, error) &&
5635ffd83dbSDimitry Andric                     reg_value2.GetAsMemoryData(
564bdd1243dSDimitry Andric                         *vec_reg2,
565bdd1243dSDimitry Andric                         heap_data_up->GetBytes() + vec_reg->byte_size,
5665ffd83dbSDimitry Andric                         heap_data_up->GetByteSize() - vec_reg->byte_size,
5675ffd83dbSDimitry Andric                         byte_order, error)) {
5685ffd83dbSDimitry Andric                   DataExtractor data(DataBufferSP(heap_data_up.release()),
5695ffd83dbSDimitry Andric                                      byte_order,
5705ffd83dbSDimitry Andric                                      process_sp->GetTarget()
5715ffd83dbSDimitry Andric                                          .GetArchitecture()
5725ffd83dbSDimitry Andric                                          .GetAddressByteSize());
5735ffd83dbSDimitry Andric                   return_valobj_sp = ValueObjectConstResult::Create(
5745ffd83dbSDimitry Andric                       &thread, return_compiler_type, ConstString(""), data);
5755ffd83dbSDimitry Andric                 }
5765ffd83dbSDimitry Andric               }
5775ffd83dbSDimitry Andric             }
5785ffd83dbSDimitry Andric           }
5795ffd83dbSDimitry Andric         }
5805ffd83dbSDimitry Andric       }
5815ffd83dbSDimitry Andric     }
5825ffd83dbSDimitry Andric   } else // 'Decimal Floating Point'
5835ffd83dbSDimitry Andric   {
5845ffd83dbSDimitry Andric     // ToDo: Yet to be implemented
5855ffd83dbSDimitry Andric   }
5865ffd83dbSDimitry Andric   return return_valobj_sp;
5875ffd83dbSDimitry Andric }
5885ffd83dbSDimitry Andric 
GetReturnValueObjectImpl(Thread & thread,CompilerType & return_compiler_type) const5895ffd83dbSDimitry Andric ValueObjectSP ABISysV_i386::GetReturnValueObjectImpl(
5905ffd83dbSDimitry Andric     Thread &thread, CompilerType &return_compiler_type) const {
5915ffd83dbSDimitry Andric   ValueObjectSP return_valobj_sp;
5925ffd83dbSDimitry Andric 
5935ffd83dbSDimitry Andric   if (!return_compiler_type)
5945ffd83dbSDimitry Andric     return return_valobj_sp;
5955ffd83dbSDimitry Andric 
5965ffd83dbSDimitry Andric   ExecutionContext exe_ctx(thread.shared_from_this());
5975ffd83dbSDimitry Andric   return_valobj_sp = GetReturnValueObjectSimple(thread, return_compiler_type);
5985ffd83dbSDimitry Andric   if (return_valobj_sp)
5995ffd83dbSDimitry Andric     return return_valobj_sp;
6005ffd83dbSDimitry Andric 
6015ffd83dbSDimitry Andric   RegisterContextSP reg_ctx_sp = thread.GetRegisterContext();
6025ffd83dbSDimitry Andric   if (!reg_ctx_sp)
6035ffd83dbSDimitry Andric     return return_valobj_sp;
6045ffd83dbSDimitry Andric 
6055ffd83dbSDimitry Andric   if (return_compiler_type.IsAggregateType()) {
6065ffd83dbSDimitry Andric     unsigned eax_id =
6075ffd83dbSDimitry Andric         reg_ctx_sp->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB];
6085ffd83dbSDimitry Andric     lldb::addr_t storage_addr = (uint32_t)(
6095ffd83dbSDimitry Andric         thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
6105ffd83dbSDimitry Andric         0xffffffff);
6115ffd83dbSDimitry Andric     return_valobj_sp = ValueObjectMemory::Create(
6125ffd83dbSDimitry Andric         &thread, "", Address(storage_addr, nullptr), return_compiler_type);
6135ffd83dbSDimitry Andric   }
6145ffd83dbSDimitry Andric 
6155ffd83dbSDimitry Andric   return return_valobj_sp;
6165ffd83dbSDimitry Andric }
6175ffd83dbSDimitry Andric 
6185ffd83dbSDimitry Andric // This defines CFA as esp+4
6195ffd83dbSDimitry Andric // The saved pc is at CFA-4 (i.e. esp+0)
6205ffd83dbSDimitry Andric // The saved esp is CFA+0
6215ffd83dbSDimitry Andric 
CreateFunctionEntryUnwindPlan(UnwindPlan & unwind_plan)6225ffd83dbSDimitry Andric bool ABISysV_i386::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) {
6235ffd83dbSDimitry Andric   unwind_plan.Clear();
6245ffd83dbSDimitry Andric   unwind_plan.SetRegisterKind(eRegisterKindDWARF);
6255ffd83dbSDimitry Andric 
6265ffd83dbSDimitry Andric   uint32_t sp_reg_num = dwarf_esp;
6275ffd83dbSDimitry Andric   uint32_t pc_reg_num = dwarf_eip;
6285ffd83dbSDimitry Andric 
6295ffd83dbSDimitry Andric   UnwindPlan::RowSP row(new UnwindPlan::Row);
6305ffd83dbSDimitry Andric   row->GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 4);
6315ffd83dbSDimitry Andric   row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, -4, false);
6325ffd83dbSDimitry Andric   row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);
6335ffd83dbSDimitry Andric   unwind_plan.AppendRow(row);
6345ffd83dbSDimitry Andric   unwind_plan.SetSourceName("i386 at-func-entry default");
6355ffd83dbSDimitry Andric   unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
6365ffd83dbSDimitry Andric   return true;
6375ffd83dbSDimitry Andric }
6385ffd83dbSDimitry Andric 
6395ffd83dbSDimitry Andric // This defines CFA as ebp+8
6405ffd83dbSDimitry Andric // The saved pc is at CFA-4 (i.e. ebp+4)
6415ffd83dbSDimitry Andric // The saved ebp is at CFA-8 (i.e. ebp+0)
6425ffd83dbSDimitry Andric // The saved esp is CFA+0
6435ffd83dbSDimitry Andric 
CreateDefaultUnwindPlan(UnwindPlan & unwind_plan)6445ffd83dbSDimitry Andric bool ABISysV_i386::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
6455ffd83dbSDimitry Andric   unwind_plan.Clear();
6465ffd83dbSDimitry Andric   unwind_plan.SetRegisterKind(eRegisterKindDWARF);
6475ffd83dbSDimitry Andric 
6485ffd83dbSDimitry Andric   uint32_t fp_reg_num = dwarf_ebp;
6495ffd83dbSDimitry Andric   uint32_t sp_reg_num = dwarf_esp;
6505ffd83dbSDimitry Andric   uint32_t pc_reg_num = dwarf_eip;
6515ffd83dbSDimitry Andric 
6525ffd83dbSDimitry Andric   UnwindPlan::RowSP row(new UnwindPlan::Row);
6535ffd83dbSDimitry Andric   const int32_t ptr_size = 4;
6545ffd83dbSDimitry Andric 
6555ffd83dbSDimitry Andric   row->GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size);
6565ffd83dbSDimitry Andric   row->SetOffset(0);
657fe6060f1SDimitry Andric   row->SetUnspecifiedRegistersAreUndefined(true);
6585ffd83dbSDimitry Andric 
6595ffd83dbSDimitry Andric   row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true);
6605ffd83dbSDimitry Andric   row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true);
6615ffd83dbSDimitry Andric   row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);
6625ffd83dbSDimitry Andric 
6635ffd83dbSDimitry Andric   unwind_plan.AppendRow(row);
6645ffd83dbSDimitry Andric   unwind_plan.SetSourceName("i386 default unwind plan");
6655ffd83dbSDimitry Andric   unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
6665ffd83dbSDimitry Andric   unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
6675ffd83dbSDimitry Andric   unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
6685ffd83dbSDimitry Andric   return true;
6695ffd83dbSDimitry Andric }
6705ffd83dbSDimitry Andric 
6715ffd83dbSDimitry Andric // According to "Register Usage" in reference document (specified on top of
6725ffd83dbSDimitry Andric // this source file) ebx, ebp, esi, edi and esp registers are preserved i.e.
6735ffd83dbSDimitry Andric // non-volatile i.e. callee-saved on i386
RegisterIsCalleeSaved(const RegisterInfo * reg_info)6745ffd83dbSDimitry Andric bool ABISysV_i386::RegisterIsCalleeSaved(const RegisterInfo *reg_info) {
6755ffd83dbSDimitry Andric   if (!reg_info)
6765ffd83dbSDimitry Andric     return false;
6775ffd83dbSDimitry Andric 
6785ffd83dbSDimitry Andric   // Saved registers are ebx, ebp, esi, edi, esp, eip
6795ffd83dbSDimitry Andric   const char *name = reg_info->name;
6805ffd83dbSDimitry Andric   if (name[0] == 'e') {
6815ffd83dbSDimitry Andric     switch (name[1]) {
6825ffd83dbSDimitry Andric     case 'b':
6835ffd83dbSDimitry Andric       if (name[2] == 'x' || name[2] == 'p')
6845ffd83dbSDimitry Andric         return name[3] == '\0';
6855ffd83dbSDimitry Andric       break;
6865ffd83dbSDimitry Andric     case 'd':
6875ffd83dbSDimitry Andric       if (name[2] == 'i')
6885ffd83dbSDimitry Andric         return name[3] == '\0';
6895ffd83dbSDimitry Andric       break;
6905ffd83dbSDimitry Andric     case 'i':
6915ffd83dbSDimitry Andric       if (name[2] == 'p')
6925ffd83dbSDimitry Andric         return name[3] == '\0';
6935ffd83dbSDimitry Andric       break;
6945ffd83dbSDimitry Andric     case 's':
6955ffd83dbSDimitry Andric       if (name[2] == 'i' || name[2] == 'p')
6965ffd83dbSDimitry Andric         return name[3] == '\0';
6975ffd83dbSDimitry Andric       break;
6985ffd83dbSDimitry Andric     }
6995ffd83dbSDimitry Andric   }
7005ffd83dbSDimitry Andric 
7015ffd83dbSDimitry Andric   if (name[0] == 's' && name[1] == 'p' && name[2] == '\0') // sp
7025ffd83dbSDimitry Andric     return true;
7035ffd83dbSDimitry Andric   if (name[0] == 'f' && name[1] == 'p' && name[2] == '\0') // fp
7045ffd83dbSDimitry Andric     return true;
7055ffd83dbSDimitry Andric   if (name[0] == 'p' && name[1] == 'c' && name[2] == '\0') // pc
7065ffd83dbSDimitry Andric     return true;
7075ffd83dbSDimitry Andric 
7085ffd83dbSDimitry Andric   return false;
7095ffd83dbSDimitry Andric }
7105ffd83dbSDimitry Andric 
Initialize()7115ffd83dbSDimitry Andric void ABISysV_i386::Initialize() {
7125ffd83dbSDimitry Andric   PluginManager::RegisterPlugin(
7135ffd83dbSDimitry Andric       GetPluginNameStatic(), "System V ABI for i386 targets", CreateInstance);
7145ffd83dbSDimitry Andric }
7155ffd83dbSDimitry Andric 
Terminate()7165ffd83dbSDimitry Andric void ABISysV_i386::Terminate() {
7175ffd83dbSDimitry Andric   PluginManager::UnregisterPlugin(CreateInstance);
7185ffd83dbSDimitry Andric }
719