aboutsummaryrefslogtreecommitdiff
path: root/lldb/source/Plugins/ABI/X86/ABISysV_i386.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/ABI/X86/ABISysV_i386.cpp')
-rw-r--r--lldb/source/Plugins/ABI/X86/ABISysV_i386.cpp726
1 files changed, 726 insertions, 0 deletions
diff --git a/lldb/source/Plugins/ABI/X86/ABISysV_i386.cpp b/lldb/source/Plugins/ABI/X86/ABISysV_i386.cpp
new file mode 100644
index 000000000000..2ac87d1512e9
--- /dev/null
+++ b/lldb/source/Plugins/ABI/X86/ABISysV_i386.cpp
@@ -0,0 +1,726 @@
+//===-- ABISysV_i386.cpp --------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//===----------------------------------------------------------------------===//
+
+#include "ABISysV_i386.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Triple.h"
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Core/ValueObjectMemory.h"
+#include "lldb/Core/ValueObjectRegister.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/Status.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+LLDB_PLUGIN_DEFINE(ABISysV_i386)
+
+// This source file uses the following document as a reference:
+//====================================================================
+// System V Application Binary Interface
+// Intel386 Architecture Processor Supplement, Version 1.0
+// Edited by
+// H.J. Lu, David L Kreitzer, Milind Girkar, Zia Ansari
+//
+// (Based on
+// System V Application Binary Interface,
+// AMD64 Architecture Processor Supplement,
+// Edited by
+// H.J. Lu, Michael Matz, Milind Girkar, Jan Hubicka,
+// Andreas Jaeger, Mark Mitchell)
+//
+// February 3, 2015
+//====================================================================
+
+// DWARF Register Number Mapping
+// See Table 2.14 of the reference document (specified on top of this file)
+// Comment: Table 2.14 is followed till 'mm' entries. After that, all entries
+// are ignored here.
+
+enum dwarf_regnums {
+ dwarf_eax = 0,
+ dwarf_ecx,
+ dwarf_edx,
+ dwarf_ebx,
+ dwarf_esp,
+ dwarf_ebp,
+ dwarf_esi,
+ dwarf_edi,
+ dwarf_eip,
+};
+
+// Static Functions
+
+ABISP
+ABISysV_i386::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) {
+ if (arch.GetTriple().getVendor() != llvm::Triple::Apple) {
+ if (arch.GetTriple().getArch() == llvm::Triple::x86) {
+ return ABISP(
+ new ABISysV_i386(std::move(process_sp), MakeMCRegisterInfo(arch)));
+ }
+ }
+ return ABISP();
+}
+
+bool ABISysV_i386::PrepareTrivialCall(Thread &thread, addr_t sp,
+ addr_t func_addr, addr_t return_addr,
+ llvm::ArrayRef<addr_t> args) const {
+ RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+
+ if (!reg_ctx)
+ return false;
+
+ uint32_t pc_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(
+ eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ uint32_t sp_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(
+ eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+
+ // While using register info to write a register value to memory, the
+ // register info just needs to have the correct size of a 32 bit register,
+ // the actual register it pertains to is not important, just the size needs
+ // to be correct. "eax" is used here for this purpose.
+ const RegisterInfo *reg_info_32 = reg_ctx->GetRegisterInfoByName("eax");
+ if (!reg_info_32)
+ return false; // TODO this should actually never happen
+
+ Status error;
+ RegisterValue reg_value;
+
+ // Make room for the argument(s) on the stack
+ sp -= 4 * args.size();
+
+ // SP Alignment
+ sp &= ~(16ull - 1ull); // 16-byte alignment
+
+ // Write arguments onto the stack
+ addr_t arg_pos = sp;
+ for (addr_t arg : args) {
+ reg_value.SetUInt32(arg);
+ error = reg_ctx->WriteRegisterValueToMemory(
+ reg_info_32, arg_pos, reg_info_32->byte_size, reg_value);
+ if (error.Fail())
+ return false;
+ arg_pos += 4;
+ }
+
+ // The return address is pushed onto the stack
+ sp -= 4;
+ reg_value.SetUInt32(return_addr);
+ error = reg_ctx->WriteRegisterValueToMemory(
+ reg_info_32, sp, reg_info_32->byte_size, reg_value);
+ if (error.Fail())
+ return false;
+
+ // Setting %esp to the actual stack value.
+ if (!reg_ctx->WriteRegisterFromUnsigned(sp_reg_num, sp))
+ return false;
+
+ // Setting %eip to the address of the called function.
+ if (!reg_ctx->WriteRegisterFromUnsigned(pc_reg_num, func_addr))
+ return false;
+
+ return true;
+}
+
+static bool ReadIntegerArgument(Scalar &scalar, unsigned int bit_width,
+ bool is_signed, Process *process,
+ addr_t &current_stack_argument) {
+ uint32_t byte_size = (bit_width + (8 - 1)) / 8;
+ Status error;
+
+ if (!process)
+ return false;
+
+ if (process->ReadScalarIntegerFromMemory(current_stack_argument, byte_size,
+ is_signed, scalar, error)) {
+ current_stack_argument += byte_size;
+ return true;
+ }
+ return false;
+}
+
+bool ABISysV_i386::GetArgumentValues(Thread &thread, ValueList &values) const {
+ unsigned int num_values = values.GetSize();
+ unsigned int value_index;
+
+ RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+
+ if (!reg_ctx)
+ return false;
+
+ // Get pointer to the first stack argument
+ addr_t sp = reg_ctx->GetSP(0);
+ if (!sp)
+ return false;
+
+ addr_t current_stack_argument = sp + 4; // jump over return address
+
+ for (value_index = 0; value_index < num_values; ++value_index) {
+ Value *value = values.GetValueAtIndex(value_index);
+
+ if (!value)
+ return false;
+
+ // Currently: Support for extracting values with Clang QualTypes only.
+ CompilerType compiler_type(value->GetCompilerType());
+ llvm::Optional<uint64_t> bit_size = compiler_type.GetBitSize(&thread);
+ if (bit_size) {
+ bool is_signed;
+ if (compiler_type.IsIntegerOrEnumerationType(is_signed)) {
+ ReadIntegerArgument(value->GetScalar(), *bit_size, is_signed,
+ thread.GetProcess().get(), current_stack_argument);
+ } else if (compiler_type.IsPointerType()) {
+ ReadIntegerArgument(value->GetScalar(), *bit_size, false,
+ thread.GetProcess().get(), current_stack_argument);
+ }
+ }
+ }
+ return true;
+}
+
+Status ABISysV_i386::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
+ lldb::ValueObjectSP &new_value_sp) {
+ Status error;
+ if (!new_value_sp) {
+ error.SetErrorString("Empty value object for return value.");
+ return error;
+ }
+
+ CompilerType compiler_type = new_value_sp->GetCompilerType();
+ if (!compiler_type) {
+ error.SetErrorString("Null clang type for return value.");
+ return error;
+ }
+
+ const uint32_t type_flags = compiler_type.GetTypeInfo();
+ Thread *thread = frame_sp->GetThread().get();
+ RegisterContext *reg_ctx = thread->GetRegisterContext().get();
+ DataExtractor data;
+ Status data_error;
+ size_t num_bytes = new_value_sp->GetData(data, data_error);
+ bool register_write_successful = true;
+
+ if (data_error.Fail()) {
+ error.SetErrorStringWithFormat(
+ "Couldn't convert return value to raw data: %s",
+ data_error.AsCString());
+ return error;
+ }
+
+ // Following "IF ELSE" block categorizes various 'Fundamental Data Types'.
+ // The terminology 'Fundamental Data Types' used here is adopted from Table
+ // 2.1 of the reference document (specified on top of this file)
+
+ if (type_flags & eTypeIsPointer) // 'Pointer'
+ {
+ if (num_bytes != sizeof(uint32_t)) {
+ error.SetErrorString("Pointer to be returned is not 4 bytes wide");
+ return error;
+ }
+ lldb::offset_t offset = 0;
+ const RegisterInfo *eax_info = reg_ctx->GetRegisterInfoByName("eax", 0);
+ uint32_t raw_value = data.GetMaxU32(&offset, num_bytes);
+ register_write_successful =
+ reg_ctx->WriteRegisterFromUnsigned(eax_info, raw_value);
+ } else if ((type_flags & eTypeIsScalar) ||
+ (type_flags & eTypeIsEnumeration)) //'Integral' + 'Floating Point'
+ {
+ lldb::offset_t offset = 0;
+ const RegisterInfo *eax_info = reg_ctx->GetRegisterInfoByName("eax", 0);
+
+ if (type_flags & eTypeIsInteger) // 'Integral' except enum
+ {
+ switch (num_bytes) {
+ default:
+ break;
+ case 16:
+ // For clang::BuiltinType::UInt128 & Int128 ToDo: Need to decide how to
+ // handle it
+ break;
+ case 8: {
+ uint32_t raw_value_low = data.GetMaxU32(&offset, 4);
+ const RegisterInfo *edx_info = reg_ctx->GetRegisterInfoByName("edx", 0);
+ uint32_t raw_value_high = data.GetMaxU32(&offset, num_bytes - offset);
+ register_write_successful =
+ (reg_ctx->WriteRegisterFromUnsigned(eax_info, raw_value_low) &&
+ reg_ctx->WriteRegisterFromUnsigned(edx_info, raw_value_high));
+ break;
+ }
+ case 4:
+ case 2:
+ case 1: {
+ uint32_t raw_value = data.GetMaxU32(&offset, num_bytes);
+ register_write_successful =
+ reg_ctx->WriteRegisterFromUnsigned(eax_info, raw_value);
+ break;
+ }
+ }
+ } else if (type_flags & eTypeIsEnumeration) // handles enum
+ {
+ uint32_t raw_value = data.GetMaxU32(&offset, num_bytes);
+ register_write_successful =
+ reg_ctx->WriteRegisterFromUnsigned(eax_info, raw_value);
+ } else if (type_flags & eTypeIsFloat) // 'Floating Point'
+ {
+ RegisterValue st0_value, fstat_value, ftag_value;
+ const RegisterInfo *st0_info = reg_ctx->GetRegisterInfoByName("st0", 0);
+ const RegisterInfo *fstat_info =
+ reg_ctx->GetRegisterInfoByName("fstat", 0);
+ const RegisterInfo *ftag_info = reg_ctx->GetRegisterInfoByName("ftag", 0);
+
+ /* According to Page 3-12 of document
+ System V Application Binary Interface, Intel386 Architecture Processor
+ Supplement, Fourth Edition
+ To return Floating Point values, all st% registers except st0 should be
+ empty after exiting from
+ a function. This requires setting fstat and ftag registers to specific
+ values.
+ fstat: The TOP field of fstat should be set to a value [0,7]. ABI doesn't
+ specify the specific
+ value of TOP in case of function return. Hence, we set the TOP field to 7
+ by our choice. */
+ uint32_t value_fstat_u32 = 0x00003800;
+
+ /* ftag: Implication of setting TOP to 7 and indicating all st% registers
+ empty except st0 is to set
+ 7th bit of 4th byte of FXSAVE area to 1 and all other bits of this byte to
+ 0. This is in accordance
+ with the document Intel 64 and IA-32 Architectures Software Developer's
+ Manual, January 2015 */
+ uint32_t value_ftag_u32 = 0x00000080;
+
+ if (num_bytes <= 12) // handles float, double, long double, __float80
+ {
+ long double value_long_dbl = 0.0;
+ if (num_bytes == 4)
+ value_long_dbl = data.GetFloat(&offset);
+ else if (num_bytes == 8)
+ value_long_dbl = data.GetDouble(&offset);
+ else if (num_bytes == 12)
+ value_long_dbl = data.GetLongDouble(&offset);
+ else {
+ error.SetErrorString("Invalid number of bytes for this return type");
+ return error;
+ }
+ st0_value.SetLongDouble(value_long_dbl);
+ fstat_value.SetUInt32(value_fstat_u32);
+ ftag_value.SetUInt32(value_ftag_u32);
+ register_write_successful =
+ reg_ctx->WriteRegister(st0_info, st0_value) &&
+ reg_ctx->WriteRegister(fstat_info, fstat_value) &&
+ reg_ctx->WriteRegister(ftag_info, ftag_value);
+ } else if (num_bytes == 16) // handles __float128
+ {
+ error.SetErrorString("Implementation is missing for this clang type.");
+ }
+ } else {
+ // Neither 'Integral' nor 'Floating Point'. If flow reaches here then
+ // check type_flags. This type_flags is not a valid type.
+ error.SetErrorString("Invalid clang type");
+ }
+ } else {
+ /* 'Complex Floating Point', 'Packed', 'Decimal Floating Point' and
+ 'Aggregate' data types
+ are yet to be implemented */
+ error.SetErrorString("Currently only Integral and Floating Point clang "
+ "types are supported.");
+ }
+ if (!register_write_successful)
+ error.SetErrorString("Register writing failed");
+ return error;
+}
+
+ValueObjectSP ABISysV_i386::GetReturnValueObjectSimple(
+ Thread &thread, CompilerType &return_compiler_type) const {
+ ValueObjectSP return_valobj_sp;
+ Value value;
+
+ if (!return_compiler_type)
+ return return_valobj_sp;
+
+ value.SetCompilerType(return_compiler_type);
+
+ RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+ if (!reg_ctx)
+ return return_valobj_sp;
+
+ const uint32_t type_flags = return_compiler_type.GetTypeInfo();
+
+ unsigned eax_id =
+ reg_ctx->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB];
+ unsigned edx_id =
+ reg_ctx->GetRegisterInfoByName("edx", 0)->kinds[eRegisterKindLLDB];
+
+ // Following "IF ELSE" block categorizes various 'Fundamental Data Types'.
+ // The terminology 'Fundamental Data Types' used here is adopted from Table
+ // 2.1 of the reference document (specified on top of this file)
+
+ if (type_flags & eTypeIsPointer) // 'Pointer'
+ {
+ uint32_t ptr =
+ thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
+ 0xffffffff;
+ value.SetValueType(Value::eValueTypeScalar);
+ value.GetScalar() = ptr;
+ return_valobj_sp = ValueObjectConstResult::Create(
+ thread.GetStackFrameAtIndex(0).get(), value, ConstString(""));
+ } else if ((type_flags & eTypeIsScalar) ||
+ (type_flags & eTypeIsEnumeration)) //'Integral' + 'Floating Point'
+ {
+ value.SetValueType(Value::eValueTypeScalar);
+ llvm::Optional<uint64_t> byte_size =
+ return_compiler_type.GetByteSize(nullptr);
+ if (!byte_size)
+ return return_valobj_sp;
+ bool success = false;
+
+ if (type_flags & eTypeIsInteger) // 'Integral' except enum
+ {
+ const bool is_signed = ((type_flags & eTypeIsSigned) != 0);
+ uint64_t raw_value =
+ thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
+ 0xffffffff;
+ raw_value |=
+ (thread.GetRegisterContext()->ReadRegisterAsUnsigned(edx_id, 0) &
+ 0xffffffff)
+ << 32;
+
+ switch (*byte_size) {
+ default:
+ break;
+
+ case 16:
+ // For clang::BuiltinType::UInt128 & Int128 ToDo: Need to decide how to
+ // handle it
+ break;
+
+ case 8:
+ if (is_signed)
+ value.GetScalar() = (int64_t)(raw_value);
+ else
+ value.GetScalar() = (uint64_t)(raw_value);
+ success = true;
+ break;
+
+ case 4:
+ if (is_signed)
+ value.GetScalar() = (int32_t)(raw_value & UINT32_MAX);
+ else
+ value.GetScalar() = (uint32_t)(raw_value & UINT32_MAX);
+ success = true;
+ break;
+
+ case 2:
+ if (is_signed)
+ value.GetScalar() = (int16_t)(raw_value & UINT16_MAX);
+ else
+ value.GetScalar() = (uint16_t)(raw_value & UINT16_MAX);
+ success = true;
+ break;
+
+ case 1:
+ if (is_signed)
+ value.GetScalar() = (int8_t)(raw_value & UINT8_MAX);
+ else
+ value.GetScalar() = (uint8_t)(raw_value & UINT8_MAX);
+ success = true;
+ break;
+ }
+
+ if (success)
+ return_valobj_sp = ValueObjectConstResult::Create(
+ thread.GetStackFrameAtIndex(0).get(), value, ConstString(""));
+ } else if (type_flags & eTypeIsEnumeration) // handles enum
+ {
+ uint32_t enm =
+ thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
+ 0xffffffff;
+ value.SetValueType(Value::eValueTypeScalar);
+ value.GetScalar() = enm;
+ return_valobj_sp = ValueObjectConstResult::Create(
+ thread.GetStackFrameAtIndex(0).get(), value, ConstString(""));
+ } else if (type_flags & eTypeIsFloat) // 'Floating Point'
+ {
+ if (*byte_size <= 12) // handles float, double, long double, __float80
+ {
+ const RegisterInfo *st0_info = reg_ctx->GetRegisterInfoByName("st0", 0);
+ RegisterValue st0_value;
+
+ if (reg_ctx->ReadRegister(st0_info, st0_value)) {
+ DataExtractor data;
+ if (st0_value.GetData(data)) {
+ lldb::offset_t offset = 0;
+ long double value_long_double = data.GetLongDouble(&offset);
+
+ // float is 4 bytes.
+ if (*byte_size == 4) {
+ float value_float = (float)value_long_double;
+ value.GetScalar() = value_float;
+ success = true;
+ } else if (*byte_size == 8) {
+ // double is 8 bytes
+ // On Android Platform: long double is also 8 bytes It will be
+ // handled here only.
+ double value_double = (double)value_long_double;
+ value.GetScalar() = value_double;
+ success = true;
+ } else if (*byte_size == 12) {
+ // long double and __float80 are 12 bytes on i386.
+ value.GetScalar() = value_long_double;
+ success = true;
+ }
+ }
+ }
+
+ if (success)
+ return_valobj_sp = ValueObjectConstResult::Create(
+ thread.GetStackFrameAtIndex(0).get(), value, ConstString(""));
+ } else if (*byte_size == 16) // handles __float128
+ {
+ lldb::addr_t storage_addr = (uint32_t)(
+ thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
+ 0xffffffff);
+ return_valobj_sp = ValueObjectMemory::Create(
+ &thread, "", Address(storage_addr, nullptr), return_compiler_type);
+ }
+ } else // Neither 'Integral' nor 'Floating Point'
+ {
+ // If flow reaches here then check type_flags This type_flags is
+ // unhandled
+ }
+ } else if (type_flags & eTypeIsComplex) // 'Complex Floating Point'
+ {
+ // ToDo: Yet to be implemented
+ } else if (type_flags & eTypeIsVector) // 'Packed'
+ {
+ llvm::Optional<uint64_t> byte_size =
+ return_compiler_type.GetByteSize(nullptr);
+ if (byte_size && *byte_size > 0) {
+ const RegisterInfo *vec_reg = reg_ctx->GetRegisterInfoByName("xmm0", 0);
+ if (vec_reg == nullptr)
+ vec_reg = reg_ctx->GetRegisterInfoByName("mm0", 0);
+
+ if (vec_reg) {
+ if (*byte_size <= vec_reg->byte_size) {
+ ProcessSP process_sp(thread.GetProcess());
+ if (process_sp) {
+ std::unique_ptr<DataBufferHeap> heap_data_up(
+ new DataBufferHeap(*byte_size, 0));
+ const ByteOrder byte_order = process_sp->GetByteOrder();
+ RegisterValue reg_value;
+ if (reg_ctx->ReadRegister(vec_reg, reg_value)) {
+ Status error;
+ if (reg_value.GetAsMemoryData(vec_reg, heap_data_up->GetBytes(),
+ heap_data_up->GetByteSize(),
+ byte_order, error)) {
+ DataExtractor data(DataBufferSP(heap_data_up.release()),
+ byte_order,
+ process_sp->GetTarget()
+ .GetArchitecture()
+ .GetAddressByteSize());
+ return_valobj_sp = ValueObjectConstResult::Create(
+ &thread, return_compiler_type, ConstString(""), data);
+ }
+ }
+ }
+ } else if (*byte_size <= vec_reg->byte_size * 2) {
+ const RegisterInfo *vec_reg2 =
+ reg_ctx->GetRegisterInfoByName("xmm1", 0);
+ if (vec_reg2) {
+ ProcessSP process_sp(thread.GetProcess());
+ if (process_sp) {
+ std::unique_ptr<DataBufferHeap> heap_data_up(
+ new DataBufferHeap(*byte_size, 0));
+ const ByteOrder byte_order = process_sp->GetByteOrder();
+ RegisterValue reg_value;
+ RegisterValue reg_value2;
+ if (reg_ctx->ReadRegister(vec_reg, reg_value) &&
+ reg_ctx->ReadRegister(vec_reg2, reg_value2)) {
+
+ Status error;
+ if (reg_value.GetAsMemoryData(vec_reg, heap_data_up->GetBytes(),
+ vec_reg->byte_size, byte_order,
+ error) &&
+ reg_value2.GetAsMemoryData(
+ vec_reg2, heap_data_up->GetBytes() + vec_reg->byte_size,
+ heap_data_up->GetByteSize() - vec_reg->byte_size,
+ byte_order, error)) {
+ DataExtractor data(DataBufferSP(heap_data_up.release()),
+ byte_order,
+ process_sp->GetTarget()
+ .GetArchitecture()
+ .GetAddressByteSize());
+ return_valobj_sp = ValueObjectConstResult::Create(
+ &thread, return_compiler_type, ConstString(""), data);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ } else // 'Decimal Floating Point'
+ {
+ // ToDo: Yet to be implemented
+ }
+ return return_valobj_sp;
+}
+
+ValueObjectSP ABISysV_i386::GetReturnValueObjectImpl(
+ Thread &thread, CompilerType &return_compiler_type) const {
+ ValueObjectSP return_valobj_sp;
+
+ if (!return_compiler_type)
+ return return_valobj_sp;
+
+ ExecutionContext exe_ctx(thread.shared_from_this());
+ return_valobj_sp = GetReturnValueObjectSimple(thread, return_compiler_type);
+ if (return_valobj_sp)
+ return return_valobj_sp;
+
+ RegisterContextSP reg_ctx_sp = thread.GetRegisterContext();
+ if (!reg_ctx_sp)
+ return return_valobj_sp;
+
+ if (return_compiler_type.IsAggregateType()) {
+ unsigned eax_id =
+ reg_ctx_sp->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB];
+ lldb::addr_t storage_addr = (uint32_t)(
+ thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
+ 0xffffffff);
+ return_valobj_sp = ValueObjectMemory::Create(
+ &thread, "", Address(storage_addr, nullptr), return_compiler_type);
+ }
+
+ return return_valobj_sp;
+}
+
+// This defines CFA as esp+4
+// The saved pc is at CFA-4 (i.e. esp+0)
+// The saved esp is CFA+0
+
+bool ABISysV_i386::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) {
+ unwind_plan.Clear();
+ unwind_plan.SetRegisterKind(eRegisterKindDWARF);
+
+ uint32_t sp_reg_num = dwarf_esp;
+ uint32_t pc_reg_num = dwarf_eip;
+
+ UnwindPlan::RowSP row(new UnwindPlan::Row);
+ row->GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 4);
+ row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, -4, false);
+ row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);
+ unwind_plan.AppendRow(row);
+ unwind_plan.SetSourceName("i386 at-func-entry default");
+ unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
+ return true;
+}
+
+// This defines CFA as ebp+8
+// The saved pc is at CFA-4 (i.e. ebp+4)
+// The saved ebp is at CFA-8 (i.e. ebp+0)
+// The saved esp is CFA+0
+
+bool ABISysV_i386::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
+ unwind_plan.Clear();
+ unwind_plan.SetRegisterKind(eRegisterKindDWARF);
+
+ uint32_t fp_reg_num = dwarf_ebp;
+ uint32_t sp_reg_num = dwarf_esp;
+ uint32_t pc_reg_num = dwarf_eip;
+
+ UnwindPlan::RowSP row(new UnwindPlan::Row);
+ const int32_t ptr_size = 4;
+
+ row->GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size);
+ row->SetOffset(0);
+
+ row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true);
+ row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true);
+ row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);
+
+ unwind_plan.AppendRow(row);
+ unwind_plan.SetSourceName("i386 default unwind plan");
+ unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
+ unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
+ unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
+ return true;
+}
+
+// According to "Register Usage" in reference document (specified on top of
+// this source file) ebx, ebp, esi, edi and esp registers are preserved i.e.
+// non-volatile i.e. callee-saved on i386
+bool ABISysV_i386::RegisterIsCalleeSaved(const RegisterInfo *reg_info) {
+ if (!reg_info)
+ return false;
+
+ // Saved registers are ebx, ebp, esi, edi, esp, eip
+ const char *name = reg_info->name;
+ if (name[0] == 'e') {
+ switch (name[1]) {
+ case 'b':
+ if (name[2] == 'x' || name[2] == 'p')
+ return name[3] == '\0';
+ break;
+ case 'd':
+ if (name[2] == 'i')
+ return name[3] == '\0';
+ break;
+ case 'i':
+ if (name[2] == 'p')
+ return name[3] == '\0';
+ break;
+ case 's':
+ if (name[2] == 'i' || name[2] == 'p')
+ return name[3] == '\0';
+ break;
+ }
+ }
+
+ if (name[0] == 's' && name[1] == 'p' && name[2] == '\0') // sp
+ return true;
+ if (name[0] == 'f' && name[1] == 'p' && name[2] == '\0') // fp
+ return true;
+ if (name[0] == 'p' && name[1] == 'c' && name[2] == '\0') // pc
+ return true;
+
+ return false;
+}
+
+void ABISysV_i386::Initialize() {
+ PluginManager::RegisterPlugin(
+ GetPluginNameStatic(), "System V ABI for i386 targets", CreateInstance);
+}
+
+void ABISysV_i386::Terminate() {
+ PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+// PluginInterface protocol
+
+lldb_private::ConstString ABISysV_i386::GetPluginNameStatic() {
+ static ConstString g_name("sysv-i386");
+ return g_name;
+}
+
+lldb_private::ConstString ABISysV_i386::GetPluginName() {
+ return GetPluginNameStatic();
+}