Path: blob/main/contrib/llvm-project/lldb/source/Plugins/ABI/X86/ABISysV_i386.cpp
39653 views
//===-- ABISysV_i386.cpp --------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//===----------------------------------------------------------------------===//67#include "ABISysV_i386.h"89#include "llvm/ADT/STLExtras.h"10#include "llvm/TargetParser/Triple.h"1112#include "lldb/Core/Module.h"13#include "lldb/Core/PluginManager.h"14#include "lldb/Core/Value.h"15#include "lldb/Core/ValueObjectConstResult.h"16#include "lldb/Core/ValueObjectMemory.h"17#include "lldb/Core/ValueObjectRegister.h"18#include "lldb/Symbol/UnwindPlan.h"19#include "lldb/Target/Process.h"20#include "lldb/Target/RegisterContext.h"21#include "lldb/Target/StackFrame.h"22#include "lldb/Target/Target.h"23#include "lldb/Target/Thread.h"24#include "lldb/Utility/ConstString.h"25#include "lldb/Utility/DataExtractor.h"26#include "lldb/Utility/Log.h"27#include "lldb/Utility/RegisterValue.h"28#include "lldb/Utility/Status.h"29#include <optional>3031using namespace lldb;32using namespace lldb_private;3334LLDB_PLUGIN_DEFINE(ABISysV_i386)3536// This source file uses the following document as a reference:37//====================================================================38// System V Application Binary Interface39// Intel386 Architecture Processor Supplement, Version 1.040// Edited by41// H.J. Lu, David L Kreitzer, Milind Girkar, Zia Ansari42//43// (Based on44// System V Application Binary Interface,45// AMD64 Architecture Processor Supplement,46// Edited by47// H.J. Lu, Michael Matz, Milind Girkar, Jan Hubicka,48// Andreas Jaeger, Mark Mitchell)49//50// February 3, 201551//====================================================================5253// DWARF Register Number Mapping54// See Table 2.14 of the reference document (specified on top of this file)55// Comment: Table 2.14 is followed till 'mm' entries. After that, all entries56// are ignored here.5758enum dwarf_regnums {59dwarf_eax = 0,60dwarf_ecx,61dwarf_edx,62dwarf_ebx,63dwarf_esp,64dwarf_ebp,65dwarf_esi,66dwarf_edi,67dwarf_eip,68};6970// Static Functions7172ABISP73ABISysV_i386::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) {74if (arch.GetTriple().getVendor() != llvm::Triple::Apple) {75if (arch.GetTriple().getArch() == llvm::Triple::x86) {76return ABISP(77new ABISysV_i386(std::move(process_sp), MakeMCRegisterInfo(arch)));78}79}80return ABISP();81}8283bool ABISysV_i386::PrepareTrivialCall(Thread &thread, addr_t sp,84addr_t func_addr, addr_t return_addr,85llvm::ArrayRef<addr_t> args) const {86RegisterContext *reg_ctx = thread.GetRegisterContext().get();8788if (!reg_ctx)89return false;9091uint32_t pc_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(92eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);93uint32_t sp_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(94eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);9596// While using register info to write a register value to memory, the97// register info just needs to have the correct size of a 32 bit register,98// the actual register it pertains to is not important, just the size needs99// to be correct. "eax" is used here for this purpose.100const RegisterInfo *reg_info_32 = reg_ctx->GetRegisterInfoByName("eax");101if (!reg_info_32)102return false; // TODO this should actually never happen103104Status error;105RegisterValue reg_value;106107// Make room for the argument(s) on the stack108sp -= 4 * args.size();109110// SP Alignment111sp &= ~(16ull - 1ull); // 16-byte alignment112113// Write arguments onto the stack114addr_t arg_pos = sp;115for (addr_t arg : args) {116reg_value.SetUInt32(arg);117error = reg_ctx->WriteRegisterValueToMemory(118reg_info_32, arg_pos, reg_info_32->byte_size, reg_value);119if (error.Fail())120return false;121arg_pos += 4;122}123124// The return address is pushed onto the stack125sp -= 4;126reg_value.SetUInt32(return_addr);127error = reg_ctx->WriteRegisterValueToMemory(128reg_info_32, sp, reg_info_32->byte_size, reg_value);129if (error.Fail())130return false;131132// Setting %esp to the actual stack value.133if (!reg_ctx->WriteRegisterFromUnsigned(sp_reg_num, sp))134return false;135136// Setting %eip to the address of the called function.137if (!reg_ctx->WriteRegisterFromUnsigned(pc_reg_num, func_addr))138return false;139140return true;141}142143static bool ReadIntegerArgument(Scalar &scalar, unsigned int bit_width,144bool is_signed, Process *process,145addr_t ¤t_stack_argument) {146uint32_t byte_size = (bit_width + (8 - 1)) / 8;147Status error;148149if (!process)150return false;151152if (process->ReadScalarIntegerFromMemory(current_stack_argument, byte_size,153is_signed, scalar, error)) {154current_stack_argument += byte_size;155return true;156}157return false;158}159160bool ABISysV_i386::GetArgumentValues(Thread &thread, ValueList &values) const {161unsigned int num_values = values.GetSize();162unsigned int value_index;163164RegisterContext *reg_ctx = thread.GetRegisterContext().get();165166if (!reg_ctx)167return false;168169// Get pointer to the first stack argument170addr_t sp = reg_ctx->GetSP(0);171if (!sp)172return false;173174addr_t current_stack_argument = sp + 4; // jump over return address175176for (value_index = 0; value_index < num_values; ++value_index) {177Value *value = values.GetValueAtIndex(value_index);178179if (!value)180return false;181182// Currently: Support for extracting values with Clang QualTypes only.183CompilerType compiler_type(value->GetCompilerType());184std::optional<uint64_t> bit_size = compiler_type.GetBitSize(&thread);185if (bit_size) {186bool is_signed;187if (compiler_type.IsIntegerOrEnumerationType(is_signed)) {188ReadIntegerArgument(value->GetScalar(), *bit_size, is_signed,189thread.GetProcess().get(), current_stack_argument);190} else if (compiler_type.IsPointerType()) {191ReadIntegerArgument(value->GetScalar(), *bit_size, false,192thread.GetProcess().get(), current_stack_argument);193}194}195}196return true;197}198199Status ABISysV_i386::SetReturnValueObject(lldb::StackFrameSP &frame_sp,200lldb::ValueObjectSP &new_value_sp) {201Status error;202if (!new_value_sp) {203error.SetErrorString("Empty value object for return value.");204return error;205}206207CompilerType compiler_type = new_value_sp->GetCompilerType();208if (!compiler_type) {209error.SetErrorString("Null clang type for return value.");210return error;211}212213const uint32_t type_flags = compiler_type.GetTypeInfo();214Thread *thread = frame_sp->GetThread().get();215RegisterContext *reg_ctx = thread->GetRegisterContext().get();216DataExtractor data;217Status data_error;218size_t num_bytes = new_value_sp->GetData(data, data_error);219bool register_write_successful = true;220221if (data_error.Fail()) {222error.SetErrorStringWithFormat(223"Couldn't convert return value to raw data: %s",224data_error.AsCString());225return error;226}227228// Following "IF ELSE" block categorizes various 'Fundamental Data Types'.229// The terminology 'Fundamental Data Types' used here is adopted from Table230// 2.1 of the reference document (specified on top of this file)231232if (type_flags & eTypeIsPointer) // 'Pointer'233{234if (num_bytes != sizeof(uint32_t)) {235error.SetErrorString("Pointer to be returned is not 4 bytes wide");236return error;237}238lldb::offset_t offset = 0;239const RegisterInfo *eax_info = reg_ctx->GetRegisterInfoByName("eax", 0);240uint32_t raw_value = data.GetMaxU32(&offset, num_bytes);241register_write_successful =242reg_ctx->WriteRegisterFromUnsigned(eax_info, raw_value);243} else if ((type_flags & eTypeIsScalar) ||244(type_flags & eTypeIsEnumeration)) //'Integral' + 'Floating Point'245{246lldb::offset_t offset = 0;247const RegisterInfo *eax_info = reg_ctx->GetRegisterInfoByName("eax", 0);248249if (type_flags & eTypeIsInteger) // 'Integral' except enum250{251switch (num_bytes) {252default:253break;254case 16:255// For clang::BuiltinType::UInt128 & Int128 ToDo: Need to decide how to256// handle it257break;258case 8: {259uint32_t raw_value_low = data.GetMaxU32(&offset, 4);260const RegisterInfo *edx_info = reg_ctx->GetRegisterInfoByName("edx", 0);261uint32_t raw_value_high = data.GetMaxU32(&offset, num_bytes - offset);262register_write_successful =263(reg_ctx->WriteRegisterFromUnsigned(eax_info, raw_value_low) &&264reg_ctx->WriteRegisterFromUnsigned(edx_info, raw_value_high));265break;266}267case 4:268case 2:269case 1: {270uint32_t raw_value = data.GetMaxU32(&offset, num_bytes);271register_write_successful =272reg_ctx->WriteRegisterFromUnsigned(eax_info, raw_value);273break;274}275}276} else if (type_flags & eTypeIsEnumeration) // handles enum277{278uint32_t raw_value = data.GetMaxU32(&offset, num_bytes);279register_write_successful =280reg_ctx->WriteRegisterFromUnsigned(eax_info, raw_value);281} else if (type_flags & eTypeIsFloat) // 'Floating Point'282{283RegisterValue st0_value, fstat_value, ftag_value;284const RegisterInfo *st0_info = reg_ctx->GetRegisterInfoByName("st0", 0);285const RegisterInfo *fstat_info =286reg_ctx->GetRegisterInfoByName("fstat", 0);287const RegisterInfo *ftag_info = reg_ctx->GetRegisterInfoByName("ftag", 0);288289/* According to Page 3-12 of document290System V Application Binary Interface, Intel386 Architecture Processor291Supplement, Fourth Edition292To return Floating Point values, all st% registers except st0 should be293empty after exiting from294a function. This requires setting fstat and ftag registers to specific295values.296fstat: The TOP field of fstat should be set to a value [0,7]. ABI doesn't297specify the specific298value of TOP in case of function return. Hence, we set the TOP field to 7299by our choice. */300uint32_t value_fstat_u32 = 0x00003800;301302/* ftag: Implication of setting TOP to 7 and indicating all st% registers303empty except st0 is to set3047th bit of 4th byte of FXSAVE area to 1 and all other bits of this byte to3050. This is in accordance306with the document Intel 64 and IA-32 Architectures Software Developer's307Manual, January 2015 */308uint32_t value_ftag_u32 = 0x00000080;309310if (num_bytes <= 12) // handles float, double, long double, __float80311{312long double value_long_dbl = 0.0;313if (num_bytes == 4)314value_long_dbl = data.GetFloat(&offset);315else if (num_bytes == 8)316value_long_dbl = data.GetDouble(&offset);317else if (num_bytes == 12)318value_long_dbl = data.GetLongDouble(&offset);319else {320error.SetErrorString("Invalid number of bytes for this return type");321return error;322}323st0_value.SetLongDouble(value_long_dbl);324fstat_value.SetUInt32(value_fstat_u32);325ftag_value.SetUInt32(value_ftag_u32);326register_write_successful =327reg_ctx->WriteRegister(st0_info, st0_value) &&328reg_ctx->WriteRegister(fstat_info, fstat_value) &&329reg_ctx->WriteRegister(ftag_info, ftag_value);330} else if (num_bytes == 16) // handles __float128331{332error.SetErrorString("Implementation is missing for this clang type.");333}334} else {335// Neither 'Integral' nor 'Floating Point'. If flow reaches here then336// check type_flags. This type_flags is not a valid type.337error.SetErrorString("Invalid clang type");338}339} else {340/* 'Complex Floating Point', 'Packed', 'Decimal Floating Point' and341'Aggregate' data types342are yet to be implemented */343error.SetErrorString("Currently only Integral and Floating Point clang "344"types are supported.");345}346if (!register_write_successful)347error.SetErrorString("Register writing failed");348return error;349}350351ValueObjectSP ABISysV_i386::GetReturnValueObjectSimple(352Thread &thread, CompilerType &return_compiler_type) const {353ValueObjectSP return_valobj_sp;354Value value;355356if (!return_compiler_type)357return return_valobj_sp;358359value.SetCompilerType(return_compiler_type);360361RegisterContext *reg_ctx = thread.GetRegisterContext().get();362if (!reg_ctx)363return return_valobj_sp;364365const uint32_t type_flags = return_compiler_type.GetTypeInfo();366367unsigned eax_id =368reg_ctx->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB];369unsigned edx_id =370reg_ctx->GetRegisterInfoByName("edx", 0)->kinds[eRegisterKindLLDB];371372// Following "IF ELSE" block categorizes various 'Fundamental Data Types'.373// The terminology 'Fundamental Data Types' used here is adopted from Table374// 2.1 of the reference document (specified on top of this file)375376if (type_flags & eTypeIsPointer) // 'Pointer'377{378uint32_t ptr =379thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &3800xffffffff;381value.SetValueType(Value::ValueType::Scalar);382value.GetScalar() = ptr;383return_valobj_sp = ValueObjectConstResult::Create(384thread.GetStackFrameAtIndex(0).get(), value, ConstString(""));385} else if ((type_flags & eTypeIsScalar) ||386(type_flags & eTypeIsEnumeration)) //'Integral' + 'Floating Point'387{388value.SetValueType(Value::ValueType::Scalar);389std::optional<uint64_t> byte_size =390return_compiler_type.GetByteSize(&thread);391if (!byte_size)392return return_valobj_sp;393bool success = false;394395if (type_flags & eTypeIsInteger) // 'Integral' except enum396{397const bool is_signed = ((type_flags & eTypeIsSigned) != 0);398uint64_t raw_value =399thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &4000xffffffff;401raw_value |=402(thread.GetRegisterContext()->ReadRegisterAsUnsigned(edx_id, 0) &4030xffffffff)404<< 32;405406switch (*byte_size) {407default:408break;409410case 16:411// For clang::BuiltinType::UInt128 & Int128 ToDo: Need to decide how to412// handle it413break;414415case 8:416if (is_signed)417value.GetScalar() = (int64_t)(raw_value);418else419value.GetScalar() = (uint64_t)(raw_value);420success = true;421break;422423case 4:424if (is_signed)425value.GetScalar() = (int32_t)(raw_value & UINT32_MAX);426else427value.GetScalar() = (uint32_t)(raw_value & UINT32_MAX);428success = true;429break;430431case 2:432if (is_signed)433value.GetScalar() = (int16_t)(raw_value & UINT16_MAX);434else435value.GetScalar() = (uint16_t)(raw_value & UINT16_MAX);436success = true;437break;438439case 1:440if (is_signed)441value.GetScalar() = (int8_t)(raw_value & UINT8_MAX);442else443value.GetScalar() = (uint8_t)(raw_value & UINT8_MAX);444success = true;445break;446}447448if (success)449return_valobj_sp = ValueObjectConstResult::Create(450thread.GetStackFrameAtIndex(0).get(), value, ConstString(""));451} else if (type_flags & eTypeIsEnumeration) // handles enum452{453uint32_t enm =454thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &4550xffffffff;456value.SetValueType(Value::ValueType::Scalar);457value.GetScalar() = enm;458return_valobj_sp = ValueObjectConstResult::Create(459thread.GetStackFrameAtIndex(0).get(), value, ConstString(""));460} else if (type_flags & eTypeIsFloat) // 'Floating Point'461{462if (*byte_size <= 12) // handles float, double, long double, __float80463{464const RegisterInfo *st0_info = reg_ctx->GetRegisterInfoByName("st0", 0);465RegisterValue st0_value;466467if (reg_ctx->ReadRegister(st0_info, st0_value)) {468DataExtractor data;469if (st0_value.GetData(data)) {470lldb::offset_t offset = 0;471long double value_long_double = data.GetLongDouble(&offset);472473// float is 4 bytes.474if (*byte_size == 4) {475float value_float = (float)value_long_double;476value.GetScalar() = value_float;477success = true;478} else if (*byte_size == 8) {479// double is 8 bytes480// On Android Platform: long double is also 8 bytes It will be481// handled here only.482double value_double = (double)value_long_double;483value.GetScalar() = value_double;484success = true;485} else if (*byte_size == 12) {486// long double and __float80 are 12 bytes on i386.487value.GetScalar() = value_long_double;488success = true;489}490}491}492493if (success)494return_valobj_sp = ValueObjectConstResult::Create(495thread.GetStackFrameAtIndex(0).get(), value, ConstString(""));496} else if (*byte_size == 16) // handles __float128497{498lldb::addr_t storage_addr = (uint32_t)(499thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &5000xffffffff);501return_valobj_sp = ValueObjectMemory::Create(502&thread, "", Address(storage_addr, nullptr), return_compiler_type);503}504} else // Neither 'Integral' nor 'Floating Point'505{506// If flow reaches here then check type_flags This type_flags is507// unhandled508}509} else if (type_flags & eTypeIsComplex) // 'Complex Floating Point'510{511// ToDo: Yet to be implemented512} else if (type_flags & eTypeIsVector) // 'Packed'513{514std::optional<uint64_t> byte_size =515return_compiler_type.GetByteSize(&thread);516if (byte_size && *byte_size > 0) {517const RegisterInfo *vec_reg = reg_ctx->GetRegisterInfoByName("xmm0", 0);518if (vec_reg == nullptr)519vec_reg = reg_ctx->GetRegisterInfoByName("mm0", 0);520521if (vec_reg) {522if (*byte_size <= vec_reg->byte_size) {523ProcessSP process_sp(thread.GetProcess());524if (process_sp) {525std::unique_ptr<DataBufferHeap> heap_data_up(526new DataBufferHeap(*byte_size, 0));527const ByteOrder byte_order = process_sp->GetByteOrder();528RegisterValue reg_value;529if (reg_ctx->ReadRegister(vec_reg, reg_value)) {530Status error;531if (reg_value.GetAsMemoryData(*vec_reg, heap_data_up->GetBytes(),532heap_data_up->GetByteSize(),533byte_order, error)) {534DataExtractor data(DataBufferSP(heap_data_up.release()),535byte_order,536process_sp->GetTarget()537.GetArchitecture()538.GetAddressByteSize());539return_valobj_sp = ValueObjectConstResult::Create(540&thread, return_compiler_type, ConstString(""), data);541}542}543}544} else if (*byte_size <= vec_reg->byte_size * 2) {545const RegisterInfo *vec_reg2 =546reg_ctx->GetRegisterInfoByName("xmm1", 0);547if (vec_reg2) {548ProcessSP process_sp(thread.GetProcess());549if (process_sp) {550std::unique_ptr<DataBufferHeap> heap_data_up(551new DataBufferHeap(*byte_size, 0));552const ByteOrder byte_order = process_sp->GetByteOrder();553RegisterValue reg_value;554RegisterValue reg_value2;555if (reg_ctx->ReadRegister(vec_reg, reg_value) &&556reg_ctx->ReadRegister(vec_reg2, reg_value2)) {557558Status error;559if (reg_value.GetAsMemoryData(560*vec_reg, heap_data_up->GetBytes(), vec_reg->byte_size,561byte_order, error) &&562reg_value2.GetAsMemoryData(563*vec_reg2,564heap_data_up->GetBytes() + vec_reg->byte_size,565heap_data_up->GetByteSize() - vec_reg->byte_size,566byte_order, error)) {567DataExtractor data(DataBufferSP(heap_data_up.release()),568byte_order,569process_sp->GetTarget()570.GetArchitecture()571.GetAddressByteSize());572return_valobj_sp = ValueObjectConstResult::Create(573&thread, return_compiler_type, ConstString(""), data);574}575}576}577}578}579}580}581} else // 'Decimal Floating Point'582{583// ToDo: Yet to be implemented584}585return return_valobj_sp;586}587588ValueObjectSP ABISysV_i386::GetReturnValueObjectImpl(589Thread &thread, CompilerType &return_compiler_type) const {590ValueObjectSP return_valobj_sp;591592if (!return_compiler_type)593return return_valobj_sp;594595ExecutionContext exe_ctx(thread.shared_from_this());596return_valobj_sp = GetReturnValueObjectSimple(thread, return_compiler_type);597if (return_valobj_sp)598return return_valobj_sp;599600RegisterContextSP reg_ctx_sp = thread.GetRegisterContext();601if (!reg_ctx_sp)602return return_valobj_sp;603604if (return_compiler_type.IsAggregateType()) {605unsigned eax_id =606reg_ctx_sp->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB];607lldb::addr_t storage_addr = (uint32_t)(608thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &6090xffffffff);610return_valobj_sp = ValueObjectMemory::Create(611&thread, "", Address(storage_addr, nullptr), return_compiler_type);612}613614return return_valobj_sp;615}616617// This defines CFA as esp+4618// The saved pc is at CFA-4 (i.e. esp+0)619// The saved esp is CFA+0620621bool ABISysV_i386::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) {622unwind_plan.Clear();623unwind_plan.SetRegisterKind(eRegisterKindDWARF);624625uint32_t sp_reg_num = dwarf_esp;626uint32_t pc_reg_num = dwarf_eip;627628UnwindPlan::RowSP row(new UnwindPlan::Row);629row->GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 4);630row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, -4, false);631row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);632unwind_plan.AppendRow(row);633unwind_plan.SetSourceName("i386 at-func-entry default");634unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);635return true;636}637638// This defines CFA as ebp+8639// The saved pc is at CFA-4 (i.e. ebp+4)640// The saved ebp is at CFA-8 (i.e. ebp+0)641// The saved esp is CFA+0642643bool ABISysV_i386::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {644unwind_plan.Clear();645unwind_plan.SetRegisterKind(eRegisterKindDWARF);646647uint32_t fp_reg_num = dwarf_ebp;648uint32_t sp_reg_num = dwarf_esp;649uint32_t pc_reg_num = dwarf_eip;650651UnwindPlan::RowSP row(new UnwindPlan::Row);652const int32_t ptr_size = 4;653654row->GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size);655row->SetOffset(0);656row->SetUnspecifiedRegistersAreUndefined(true);657658row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true);659row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true);660row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);661662unwind_plan.AppendRow(row);663unwind_plan.SetSourceName("i386 default unwind plan");664unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);665unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);666unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);667return true;668}669670// According to "Register Usage" in reference document (specified on top of671// this source file) ebx, ebp, esi, edi and esp registers are preserved i.e.672// non-volatile i.e. callee-saved on i386673bool ABISysV_i386::RegisterIsCalleeSaved(const RegisterInfo *reg_info) {674if (!reg_info)675return false;676677// Saved registers are ebx, ebp, esi, edi, esp, eip678const char *name = reg_info->name;679if (name[0] == 'e') {680switch (name[1]) {681case 'b':682if (name[2] == 'x' || name[2] == 'p')683return name[3] == '\0';684break;685case 'd':686if (name[2] == 'i')687return name[3] == '\0';688break;689case 'i':690if (name[2] == 'p')691return name[3] == '\0';692break;693case 's':694if (name[2] == 'i' || name[2] == 'p')695return name[3] == '\0';696break;697}698}699700if (name[0] == 's' && name[1] == 'p' && name[2] == '\0') // sp701return true;702if (name[0] == 'f' && name[1] == 'p' && name[2] == '\0') // fp703return true;704if (name[0] == 'p' && name[1] == 'c' && name[2] == '\0') // pc705return true;706707return false;708}709710void ABISysV_i386::Initialize() {711PluginManager::RegisterPlugin(712GetPluginNameStatic(), "System V ABI for i386 targets", CreateInstance);713}714715void ABISysV_i386::Terminate() {716PluginManager::UnregisterPlugin(CreateInstance);717}718719720