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 ¤t_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