Index: source/API/SystemInitializerFull.cpp =================================================================== --- source/API/SystemInitializerFull.cpp +++ source/API/SystemInitializerFull.cpp @@ -40,6 +40,7 @@ #include "Plugins/ABI/SysV-mips64/ABISysV_mips64.h" #include "Plugins/ABI/SysV-ppc/ABISysV_ppc.h" #include "Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h" +#include "Plugins/ABI/SysV-ppc64le/ABISysV_ppc64le.h" #include "Plugins/ABI/SysV-s390x/ABISysV_s390x.h" #include "Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h" #include "Plugins/Architecture/Arm/ArchitectureArm.h" @@ -302,6 +303,7 @@ ABISysV_x86_64::Initialize(); ABISysV_ppc::Initialize(); ABISysV_ppc64::Initialize(); + ABISysV_ppc64le::Initialize(); ABISysV_mips::Initialize(); ABISysV_mips64::Initialize(); ABISysV_s390x::Initialize(); @@ -431,6 +433,7 @@ ABISysV_x86_64::Terminate(); ABISysV_ppc::Terminate(); ABISysV_ppc64::Terminate(); + ABISysV_ppc64le::Terminate(); ABISysV_mips::Terminate(); ABISysV_mips64::Terminate(); ABISysV_s390x::Terminate(); Index: source/Plugins/ABI/CMakeLists.txt =================================================================== --- source/Plugins/ABI/CMakeLists.txt +++ source/Plugins/ABI/CMakeLists.txt @@ -3,6 +3,7 @@ add_subdirectory(SysV-hexagon) add_subdirectory(SysV-ppc) add_subdirectory(SysV-ppc64) +add_subdirectory(SysV-ppc64le) add_subdirectory(SysV-mips) add_subdirectory(SysV-mips64) add_subdirectory(SysV-s390x) Index: source/Plugins/ABI/SysV-ppc64le/ABISysV_ppc64le.h =================================================================== --- /dev/null +++ source/Plugins/ABI/SysV-ppc64le/ABISysV_ppc64le.h @@ -0,0 +1,114 @@ +//===-- ABISysV_ppc64le.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ABISysV_ppc64le_h_ +#define liblldb_ABISysV_ppc64le_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Target/ABI.h" +#include "lldb/lldb-private.h" + +class ABISysV_ppc64le: public lldb_private::ABI { +public: + ~ABISysV_ppc64le() override = default; + + size_t GetRedZoneSize() const override; + + bool PrepareTrivialCall(lldb_private::Thread &thread, lldb::addr_t sp, + lldb::addr_t functionAddress, lldb::addr_t returnAddress, + llvm::ArrayRef args) const override; + + bool GetArgumentValues(lldb_private::Thread &thread, + lldb_private::ValueList &values) const override; + + lldb_private::Status + SetReturnValueObject(lldb::StackFrameSP &frame_sp, + lldb::ValueObjectSP &new_value) override; + + lldb::ValueObjectSP + GetReturnValueObjectImpl(lldb_private::Thread &thread, + lldb_private::CompilerType &type) const override; + + bool + CreateFunctionEntryUnwindPlan(lldb_private::UnwindPlan &unwind_plan) override; + + bool CreateDefaultUnwindPlan(lldb_private::UnwindPlan &unwind_plan) override; + + bool RegisterIsVolatile(const lldb_private::RegisterInfo *reg_info) override; + + // The SysV ppc64le ABI requires that stack frames be 16 byte aligned. + // When there is a trap handler on the stack, e.g. _sigtramp in userland + // code, we've seen that the stack pointer is often not aligned properly + // before the handler is invoked. This means that lldb will stop the unwind + // early -- before the function which caused the trap. + // + // To work around this, we relax that alignment to be just word-size + // (8-bytes). + // Whitelisting the trap handlers for user space would be easy (_sigtramp) + // but in other environments there can be a large number of different + // functions involved in async traps. + bool CallFrameAddressIsValid(lldb::addr_t cfa) override { + // Make sure the stack call frame addresses are 8 byte aligned + if (cfa & (8ull - 1ull)) + return false; // Not 8 byte aligned + if (cfa == 0) + return false; // Zero is not a valid stack address + return true; + } + + bool CodeAddressIsValid(lldb::addr_t pc) override { + // We have a 64 bit address space, so anything is valid as opcodes + // aren't fixed width... + return true; + } + + const lldb_private::RegisterInfo * + GetRegisterInfoArray(uint32_t &count) override; + + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + + static void Initialize(); + + static void Terminate(); + + static lldb::ABISP CreateInstance(lldb::ProcessSP process_sp, + const lldb_private::ArchSpec &arch); + + static lldb_private::ConstString GetPluginNameStatic(); + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + + lldb_private::ConstString GetPluginName() override; + + uint32_t GetPluginVersion() override; + +protected: + void CreateRegisterMapIfNeeded(); + + lldb::ValueObjectSP + GetReturnValueObjectSimple(lldb_private::Thread &thread, + lldb_private::CompilerType &ast_type) const; + + bool RegisterIsCalleeSaved(const lldb_private::RegisterInfo *reg_info); + +private: + ABISysV_ppc64le(lldb::ProcessSP process_sp) : + lldb_private::ABI(process_sp) { + // Call CreateInstance instead. + } +}; + +#endif // liblldb_ABISysV_ppc64le_h_ Index: source/Plugins/ABI/SysV-ppc64le/ABISysV_ppc64le.cpp =================================================================== --- /dev/null +++ source/Plugins/ABI/SysV-ppc64le/ABISysV_ppc64le.cpp @@ -0,0 +1,616 @@ +//===-- ABISysV_ppc64le.cpp -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ABISysV_ppc64le.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Triple.h" + +// Project includes +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/RegisterValue.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/Status.h" +#include "Utility/PPC64LE_DWARF_Registers.h" + +#define DECLARE_REGISTER_INFOS_PPC64LE_STRUCT +#include "Plugins/Process/Utility/RegisterInfos_ppc64le.h" +#undef DECLARE_REGISTER_INFOS_PPC64LE_STRUCT + +using namespace lldb; +using namespace lldb_private; + +static const uint32_t k_num_register_infos = llvm::array_lengthof( + g_register_infos_ppc64le); + +const lldb_private::RegisterInfo * +ABISysV_ppc64le::GetRegisterInfoArray(uint32_t &count) { + count = k_num_register_infos; + return g_register_infos_ppc64le; +} + +size_t ABISysV_ppc64le::GetRedZoneSize() const { + return 224; +} + +//------------------------------------------------------------------ +// Static Functions +//------------------------------------------------------------------ + +ABISP ABISysV_ppc64le::CreateInstance(lldb::ProcessSP process_sp, + const ArchSpec &arch) { + static ABISP g_abi_sp; + + if (arch.GetTriple().getArch() == llvm::Triple::ppc64le) { + if (!g_abi_sp) + g_abi_sp.reset(new ABISysV_ppc64le(process_sp)); + return g_abi_sp; + } + + return ABISP(); +} + +bool ABISysV_ppc64le::PrepareTrivialCall(Thread &thread, addr_t sp, + addr_t func_addr, addr_t return_addr, llvm::ArrayRef args) const { + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + + if (log) { + StreamString s; + + s.Printf("ABISysV_ppc64le::PrepareTrivialCall (tid = 0x%" PRIx64 + ", sp = 0x%" PRIx64 ", func_addr = 0x%" PRIx64 + ", return_addr = 0x%" PRIx64, + thread.GetID(), (uint64_t)sp, (uint64_t)func_addr, + (uint64_t)return_addr); + + for (size_t i = 0; i < args.size(); ++i) + s.Printf(", arg%" PRIu64 " = 0x%" PRIx64, static_cast(i + 1), + args[i]); + + s.PutCString(")"); + log->PutString(s.GetString()); + } + + RegisterContext *reg_ctx = thread.GetRegisterContext().get(); + if (!reg_ctx) + return false; + + const RegisterInfo *reg_info = nullptr; + + if (args.size() > 8) // TODO handle more than 8 arguments. + return false; + + for (size_t i = 0; i < args.size(); ++i) { + reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_ARG1 + i); + + if (log) + log->Printf("About to write arg%" PRIu64 " (0x%" PRIx64 ") into %s", + static_cast(i + 1), args[i], reg_info->name); + + if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i])) + return false; + } + + // First, align the SP. + if (log) + log->Printf("16-byte aligning SP: 0x%" PRIx64 " to 0x%" PRIx64, + (uint64_t)sp, (uint64_t)(sp & ~0xfull)); + + sp &= ~(0xfull); // 16-byte alignment. + sp -= 32; // allocate frame to save TOC, RA and SP. + + Status error; + uint64_t reg_value; + const RegisterInfo *pc_reg_info = + reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); + const RegisterInfo *sp_reg_info = + reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); + ProcessSP process_sp(thread.GetProcess()); + const RegisterInfo *lr_reg_info = + reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA); + const RegisterInfo *r2_reg_info = reg_ctx->GetRegisterInfoAtIndex(2); + const RegisterInfo *r12_reg_info = reg_ctx->GetRegisterInfoAtIndex(12); + + // Save return address onto the stack. + if (log) + log->Printf("Pushing the return address onto the stack: 0x%" PRIx64 + "(+16): 0x%" PRIx64, (uint64_t)sp, (uint64_t)return_addr); + if (!process_sp->WritePointerToMemory(sp + 16, return_addr, error)) + return false; + + // Write the return address to link register. + if (log) + log->Printf("Writing LR: 0x%" PRIx64, (uint64_t)return_addr); + if (!reg_ctx->WriteRegisterFromUnsigned(lr_reg_info, return_addr)) + return false; + + // Write target address to r12 register. + if (log) + log->Printf("Writing R12: 0x%" PRIx64, (uint64_t)func_addr); + if (!reg_ctx->WriteRegisterFromUnsigned(r12_reg_info, func_addr)) + return false; + + // Read TOC pointer value. + reg_value = reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0); + + // Write TOC pointer onto the stack. + if (log) + log->Printf("Writing R2 (TOC) at SP(0x%" PRIx64 ")+24: 0x%" PRIx64, + (uint64_t)sp+24, (uint64_t)reg_value); + if (!process_sp->WritePointerToMemory(sp + 24, reg_value, error)) + return false; + + // Read the current SP value. + reg_value = reg_ctx->ReadRegisterAsUnsigned(sp_reg_info, 0); + + // Save current SP onto the stack. + if (log) + log->Printf("Writing SP at SP(0x%" PRIx64 ")+0: 0x%" PRIx64, + (uint64_t)sp, (uint64_t)reg_value); + if (!process_sp->WritePointerToMemory(sp, reg_value, error)) + return false; + + // %r1 is set to the actual stack value. + if (log) + log->Printf("Writing SP: 0x%" PRIx64, (uint64_t)sp); + + if (!reg_ctx->WriteRegisterFromUnsigned(sp_reg_info, sp)) + return false; + + // %pc is set to the address of the called function. + if (log) + log->Printf("Writing IP: 0x%" PRIx64, (uint64_t)func_addr); + if (!reg_ctx->WriteRegisterFromUnsigned(pc_reg_info, func_addr)) + return false; + + return true; +} + +static bool ReadIntegerArgument(Scalar &scalar, unsigned int bit_width, + bool is_signed, Thread &thread, uint32_t *argument_register_ids, + unsigned int ¤t_argument_register, addr_t ¤t_stack_argument) { + if (bit_width > 64) + return false; // Scalar can't hold large integer arguments. + + if (current_argument_register < 6) { + scalar = thread.GetRegisterContext()->ReadRegisterAsUnsigned( + argument_register_ids[current_argument_register], 0); + current_argument_register++; + + if (is_signed) + scalar.SignExtend(bit_width); + } else { + uint32_t byte_size = (bit_width + (8 - 1)) / 8; + Status error; + + if (thread.GetProcess()->ReadScalarIntegerFromMemory(current_stack_argument, + byte_size, is_signed, scalar, error)) { + current_stack_argument += byte_size; + return true; + } + + return false; + } + + return true; +} + +bool ABISysV_ppc64le::GetArgumentValues(Thread &thread, + ValueList &values) const { + unsigned int num_values = values.GetSize(); + unsigned int value_index; + + // Extract the register context so we can read arguments from registers. + RegisterContext *reg_ctx = thread.GetRegisterContext().get(); + if (!reg_ctx) + return false; + + // Get the pointer to the first stack argument so we have a place to start + // when reading data. + addr_t sp = reg_ctx->GetSP(0); + + if (!sp) + return false; + + addr_t current_stack_argument = sp + 48; // jump over return address. + uint32_t argument_register_ids[8]; + + for (size_t i = 0; i < 8; ++i) { + argument_register_ids[i] = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_ARG1 + i)->kinds[eRegisterKindLLDB]; + } + + unsigned int current_argument_register = 0; + for (value_index = 0; value_index < num_values; ++value_index) { + Value *value = values.GetValueAtIndex(value_index); + + if (!value) + return false; + + // We currently only support extracting values with Clang QualTypes. + // Do we care about others? + CompilerType compiler_type = value->GetCompilerType(); + if (!compiler_type) + return false; + bool is_signed; + + if (compiler_type.IsIntegerOrEnumerationType(is_signed)) { + ReadIntegerArgument(value->GetScalar(), compiler_type.GetBitSize(&thread), + is_signed, thread, argument_register_ids, current_argument_register, + current_stack_argument); + } else if (compiler_type.IsPointerType()) { + ReadIntegerArgument(value->GetScalar(), compiler_type.GetBitSize(&thread), + false, thread, argument_register_ids, current_argument_register, + current_stack_argument); + } + } + + return true; +} + +Status ABISysV_ppc64le::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; + } + + bool is_signed; + uint32_t count; + bool is_complex; + Thread *thread = frame_sp->GetThread().get(); + RegisterContext *reg_ctx = thread->GetRegisterContext().get(); + + bool set_it_simple = false; + if (compiler_type.IsIntegerOrEnumerationType(is_signed) + || compiler_type.IsPointerType()) { + const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName("r3", 0); + + DataExtractor data; + Status data_error; + size_t num_bytes = new_value_sp->GetData(data, data_error); + if (data_error.Fail()) { + error.SetErrorStringWithFormat( + "Couldn't convert return value to raw data: %s", + data_error.AsCString()); + return error; + } + lldb::offset_t offset = 0; + if (num_bytes <= 8) { + uint64_t raw_value = data.GetMaxU64(&offset, num_bytes); + + if (reg_ctx->WriteRegisterFromUnsigned(reg_info, raw_value)) + set_it_simple = true; + } else { + error.SetErrorString("We don't support returning longer than 64 bit " + "integer values at present."); + } + } else if (compiler_type.IsFloatingPointType(count, is_complex)) { + if (is_complex) + error.SetErrorString( + "We don't support returning complex values at present"); + else { + size_t bit_width = compiler_type.GetBitSize(frame_sp.get()); + if (bit_width <= 64) { + DataExtractor data; + Status data_error; + size_t num_bytes = new_value_sp->GetData(data, data_error); + if (data_error.Fail()) { + error.SetErrorStringWithFormat( + "Couldn't convert return value to raw data: %s", + data_error.AsCString()); + return error; + } + + unsigned char buffer[16]; + ByteOrder byte_order = data.GetByteOrder(); + + data.CopyByteOrderedData(0, num_bytes, buffer, 16, byte_order); + set_it_simple = true; + } else { + // FIXME - don't know how to do 80 bit long doubles yet. + error.SetErrorString( + "We don't support returning float values > 64 bits at present"); + } + } + } + + if (!set_it_simple) { + // Okay we've got a structure or something that doesn't fit in a simple + // register. + // We should figure out where it really goes, but we don't support this yet. + error.SetErrorString("We only support setting simple integer and float " + "return types at present."); + } + + return error; +} + +ValueObjectSP ABISysV_ppc64le::GetReturnValueObjectSimple(Thread &thread, + CompilerType &return_compiler_type) const { + ValueObjectSP return_valobj_sp; + Value value; + + if (!return_compiler_type) + return return_valobj_sp; + + // value.SetContext (Value::eContextTypeClangType, return_value_type); + 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(); + if (type_flags & eTypeIsScalar) { + value.SetValueType(Value::eValueTypeScalar); + + bool success = false; + if (type_flags & eTypeIsInteger) { + // Extract the register context so we can read arguments from registers + const size_t byte_size = return_compiler_type.GetByteSize(nullptr); + uint64_t raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned( + reg_ctx->GetRegisterInfoByName("r3", 0), 0); + const bool is_signed = (type_flags & eTypeIsSigned) != 0; + switch (byte_size) { + default: + break; + + case sizeof(uint64_t): + if (is_signed) + value.GetScalar() = (int64_t)(raw_value); + else + value.GetScalar() = (uint64_t)(raw_value); + success = true; + break; + + case sizeof(uint32_t): + if (is_signed) + value.GetScalar() = (int32_t)(raw_value & UINT32_MAX); + else + value.GetScalar() = (uint32_t)(raw_value & UINT32_MAX); + success = true; + break; + + case sizeof(uint16_t): + if (is_signed) + value.GetScalar() = (int16_t)(raw_value & UINT16_MAX); + else + value.GetScalar() = (uint16_t)(raw_value & UINT16_MAX); + success = true; + break; + + case sizeof(uint8_t): + if (is_signed) + value.GetScalar() = (int8_t)(raw_value & UINT8_MAX); + else + value.GetScalar() = (uint8_t)(raw_value & UINT8_MAX); + success = true; + break; + } + } else if (type_flags & eTypeIsFloat) { + if (type_flags & eTypeIsComplex) { + // Don't handle complex yet. + } else { + const size_t byte_size = return_compiler_type.GetByteSize(nullptr); + if (byte_size <= sizeof(long double)) { + const RegisterInfo *f1_info = reg_ctx->GetRegisterInfoByName("f1", 0); + RegisterValue f1_value; + if (reg_ctx->ReadRegister(f1_info, f1_value)) { + DataExtractor data; + if (f1_value.GetData(data)) { + lldb::offset_t offset = 0; + if (byte_size == sizeof(float)) { + value.GetScalar() = (float) data.GetFloat(&offset); + success = true; + } else if (byte_size == sizeof(double)) { + value.GetScalar() = (double) data.GetDouble(&offset); + success = true; + } + } + } + } + } + } + + if (success) + return_valobj_sp = ValueObjectConstResult::Create( + thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); + } else if (type_flags & eTypeIsPointer) { + unsigned r3_id = + reg_ctx->GetRegisterInfoByName("r3", 0)->kinds[eRegisterKindLLDB]; + value.GetScalar() = + (uint64_t) thread.GetRegisterContext()->ReadRegisterAsUnsigned(r3_id, + 0); + value.SetValueType(Value::eValueTypeScalar); + return_valobj_sp = ValueObjectConstResult::Create( + thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); + } else if (type_flags & eTypeIsVector) { + const size_t byte_size = return_compiler_type.GetByteSize(nullptr); + if (byte_size > 0) { + const RegisterInfo *altivec_reg = reg_ctx->GetRegisterInfoByName("v2", + 0); + if (altivec_reg) { + if (byte_size <= altivec_reg->byte_size) { + ProcessSP process_sp(thread.GetProcess()); + if (process_sp) { + std::unique_ptr < DataBufferHeap + > heap_data_ap(new DataBufferHeap(byte_size, 0)); + const ByteOrder byte_order = process_sp->GetByteOrder(); + RegisterValue reg_value; + if (reg_ctx->ReadRegister(altivec_reg, reg_value)) { + Status error; + if (reg_value.GetAsMemoryData(altivec_reg, + heap_data_ap->GetBytes(), heap_data_ap->GetByteSize(), + byte_order, error)) { + DataExtractor data(DataBufferSP(heap_data_ap.release()), + byte_order, + process_sp->GetTarget().GetArchitecture().GetAddressByteSize()); + return_valobj_sp = ValueObjectConstResult::Create(&thread, + return_compiler_type, ConstString(""), data); + } + } + } + } + } + } + } + + return return_valobj_sp; +} + +ValueObjectSP ABISysV_ppc64le::GetReturnValueObjectImpl(Thread &thread, + CompilerType &return_compiler_type) const { + return GetReturnValueObjectSimple(thread, return_compiler_type); +} + +bool ABISysV_ppc64le::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) { + unwind_plan.Clear(); + unwind_plan.SetRegisterKind(eRegisterKindDWARF); + + uint32_t lr_reg_num = ppc64le_dwarf::dwarf_lr_ppc64le; + uint32_t sp_reg_num = ppc64le_dwarf::dwarf_r1_ppc64le; + uint32_t pc_reg_num = ppc64le_dwarf::dwarf_pc_ppc64le; + + UnwindPlan::RowSP row(new UnwindPlan::Row); + + // Our Call Frame Address is the stack pointer value. + row->GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 0); + + // The previous PC is in the LR. + row->SetRegisterLocationToRegister(pc_reg_num, lr_reg_num, true); + unwind_plan.AppendRow(row); + + // All other registers are the same. + unwind_plan.SetSourceName("ppc64le at-func-entry default"); + unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); + + return true; +} + +bool ABISysV_ppc64le::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) { + unwind_plan.Clear(); + unwind_plan.SetRegisterKind(eRegisterKindDWARF); + + uint32_t sp_reg_num = ppc64le_dwarf::dwarf_r1_ppc64le; + uint32_t pc_reg_num = ppc64le_dwarf::dwarf_lr_ppc64le; + UnwindPlan::RowSP row(new UnwindPlan::Row); + const int32_t ptr_size = 8; + + row->GetCFAValue().SetIsRegisterDereferenced(sp_reg_num); + row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * 2, true); + row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true); + row->SetRegisterLocationToAtCFAPlusOffset(ppc64le_dwarf::dwarf_cr_ppc64le, + ptr_size, true); + + unwind_plan.AppendRow(row); + unwind_plan.SetSourceName("ppc64le default unwind plan"); + unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); + unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); + unwind_plan.SetReturnAddressRegister(ppc64le_dwarf::dwarf_lr_ppc64le); + + return true; +} + +bool ABISysV_ppc64le::RegisterIsVolatile(const RegisterInfo *reg_info) { + return !RegisterIsCalleeSaved(reg_info); +} + +// See "Register Usage" in the +// "System V Application Binary Interface" +// "64-bit PowerPC ELF Application Binary Interface Supplement" +// current version is 2 released 2015 at +// https://members.openpowerfoundation.org/document/dl/576 +bool ABISysV_ppc64le::RegisterIsCalleeSaved(const RegisterInfo *reg_info) { + if (reg_info) { + // Preserved registers are : + // r1,r2,r13-r31 + // cr2-cr4 (partially preserved) + // f14-f31 (not yet) + // v20-v31 (not yet) + // vrsave (not yet) + + const char *name = reg_info->name; + if (name[0] == 'r') { + if ((name[1] == '1' || name[1] == '2') && name[2] == '\0') + return true; + if (name[1] == '1' && name[2] > '2') + return true; + if ((name[1] == '2' || name[1] == '3') && name[2] != '\0') + return true; + } + + if (name[0] == 'f' && name[1] >= '0' && name[2] <= '9') { + if (name[2] == '\0') + return false; + if (name[1] == '1' && name[2] >= '4') + return true; + if ((name[1] == '2' || name[1] == '3') && name[2] != '\0') + return true; + } + + 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 false; + if (name[0] == 'p' && name[1] == 'c' && name[2] == '\0') // pc + return true; + } + return false; +} + +void ABISysV_ppc64le::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + "System V ABI for ppc64le targets", CreateInstance); +} + +void ABISysV_ppc64le::Terminate() { + PluginManager::UnregisterPlugin (CreateInstance); +} + +lldb_private::ConstString ABISysV_ppc64le::GetPluginNameStatic() { + static ConstString g_name("sysv-ppc64le"); + return g_name; +} + +//------------------------------------------------------------------ +// PluginInterface protocol +//------------------------------------------------------------------ + +lldb_private::ConstString ABISysV_ppc64le::GetPluginName() { + return GetPluginNameStatic(); +} + +uint32_t ABISysV_ppc64le::GetPluginVersion() { + return 1; +} Index: source/Plugins/ABI/SysV-ppc64le/CMakeLists.txt =================================================================== --- /dev/null +++ source/Plugins/ABI/SysV-ppc64le/CMakeLists.txt @@ -0,0 +1,10 @@ +add_lldb_library(lldbPluginABISysV_ppc64le PLUGIN + ABISysV_ppc64le.cpp + + LINK_LIBS + lldbCore + lldbSymbol + lldbTarget + LINK_COMPONENTS + Support + )