diff --git a/lldb/source/API/SystemInitializerFull.cpp b/lldb/source/API/SystemInitializerFull.cpp --- a/lldb/source/API/SystemInitializerFull.cpp +++ b/lldb/source/API/SystemInitializerFull.cpp @@ -24,6 +24,7 @@ #include "Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h" #include "Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h" #include "Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h" +#include "Plugins/ABI/SysV-arc/ABISysV_arc.h" #include "Plugins/ABI/SysV-arm/ABISysV_arm.h" #include "Plugins/ABI/SysV-arm64/ABISysV_arm64.h" #include "Plugins/ABI/SysV-hexagon/ABISysV_hexagon.h" @@ -137,6 +138,8 @@ #define LLDB_PROCESS_ARM(op) \ ABIMacOSX_arm::op(); \ ABISysV_arm::op(); +#define LLDB_PROCESS_ARC(op) \ + ABISysV_arc::op(); #define LLDB_PROCESS_Hexagon(op) ABISysV_hexagon::op(); #define LLDB_PROCESS_Mips(op) \ ABISysV_mips::op(); \ @@ -152,7 +155,6 @@ ABIWindows_x86_64::op(); #define LLDB_PROCESS_AMDGPU(op) -#define LLDB_PROCESS_ARC(op) #define LLDB_PROCESS_AVR(op) #define LLDB_PROCESS_BPF(op) #define LLDB_PROCESS_Lanai(op) diff --git a/lldb/source/Plugins/ABI/CMakeLists.txt b/lldb/source/Plugins/ABI/CMakeLists.txt --- a/lldb/source/Plugins/ABI/CMakeLists.txt +++ b/lldb/source/Plugins/ABI/CMakeLists.txt @@ -6,6 +6,9 @@ add_subdirectory(MacOSX-arm) add_subdirectory(SysV-arm) endif() +if ("ARC" IN_LIST LLVM_TARGETS_TO_BUILD) + add_subdirectory(SysV-arc) +endif() if ("Hexagon" IN_LIST LLVM_TARGETS_TO_BUILD) add_subdirectory(SysV-hexagon) endif() diff --git a/lldb/source/Plugins/ABI/SysV-arc/ABISysV_arc.h b/lldb/source/Plugins/ABI/SysV-arc/ABISysV_arc.h new file mode 100644 --- /dev/null +++ b/lldb/source/Plugins/ABI/SysV-arc/ABISysV_arc.h @@ -0,0 +1,106 @@ +//===-- ArchitectureArc.h ---------------------------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ABISysV_arc_h_ +#define liblldb_ABISysV_arc_h_ + +// Other libraries and framework includes +#include + +// Project includes +#include "lldb/Target/ABI.h" +#include "lldb/lldb-private.h" + +class ABISysV_arc : public lldb_private::ABI { +public: + ~ABISysV_arc() 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; + + // Special thread plan for GDB style non-jit function calls. + bool + PrepareTrivialCall(lldb_private::Thread &thread, lldb::addr_t sp, + lldb::addr_t functionAddress, lldb::addr_t returnAddress, + llvm::Type &prototype, + 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; + + // Specialized to work with llvm IR types. + lldb::ValueObjectSP GetReturnValueObjectImpl(lldb_private::Thread &thread, + llvm::Type &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; + + bool CallFrameAddressIsValid(lldb::addr_t cfa) override { + // Stack call frame address must be 4 byte aligned. + return (cfa & 0x3ull) == 0; + } + + bool CodeAddressIsValid(lldb::addr_t pc) override { + // Code addresse must be 2 byte aligned. + return (pc & 1ull) == 0; + } + + 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; + +private: + lldb::ValueObjectSP + GetReturnValueObjectSimple(lldb_private::Thread &thread, + lldb_private::CompilerType &ast_type) const; + + bool IsRegisterFileReduced(lldb_private::RegisterContext ®_ctx) const; + + using lldb_private::ABI::ABI; // Call CreateInstance instead. + + using RegisterFileFlag = llvm::Optional; + mutable RegisterFileFlag m_is_reg_file_reduced; +}; + +#endif // liblldb_ABISysV_arc_h_ diff --git a/lldb/source/Plugins/ABI/SysV-arc/ABISysV_arc.cpp b/lldb/source/Plugins/ABI/SysV-arc/ABISysV_arc.cpp new file mode 100644 --- /dev/null +++ b/lldb/source/Plugins/ABI/SysV-arc/ABISysV_arc.cpp @@ -0,0 +1,614 @@ +//===-- ABISysV_arc.cpp ---------------------------------------*- C++ -*-===// +// +// 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_arc.h" + +// C Includes +// C++ Includes +#include +#include +#include + +// Other libraries and framework includes +#include "llvm/ADT/Triple.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/Support/MathExtras.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/RegisterValue.h" +#include "lldb/Utility/Status.h" + +#define DEFINE_REG_NAME(reg_num) ConstString(#reg_num).GetCString() +#define DEFINE_REG_NAME_STR(reg_name) ConstString(reg_name).GetCString() + +// The ABI is not a source of such information as size, offset, encoding, etc. +// of a register. Just provides correct dwarf and eh_frame numbers. + +#define DEFINE_GENERIC_REGISTER_STUB(dwarf_num, str_name, generic_num) \ + { \ + DEFINE_REG_NAME(dwarf_num), DEFINE_REG_NAME_STR(str_name), \ + 0, 0, eEncodingInvalid, eFormatDefault, \ + { dwarf_num, dwarf_num, generic_num, LLDB_INVALID_REGNUM, dwarf_num }, \ + nullptr, nullptr, nullptr, 0 \ + } + +#define DEFINE_REGISTER_STUB(dwarf_num, str_name) \ + DEFINE_GENERIC_REGISTER_STUB(dwarf_num, str_name, LLDB_INVALID_REGNUM) + +using namespace lldb; +using namespace lldb_private; + +namespace { +namespace dwarf { +enum regnums { + r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16, + r17, r18, r19, r20, r21, r22, r23, r24, r25, r26, + r27, fp = r27, r28, sp = r28, r29, r30, r31, blink = r31, + r32, r33, r34, r35, r36, r37, r38, r39, r40, r41, r42, r43, r44, r45, r46, + r47, r48, r49, r50, r51, r52, r53, r54, r55, r56, r57, r58, r59, r60, + /*reserved,*/ /*limm indicator,*/ r63 = 63, pc = 70, status32 = 74 +}; + +static const std::array g_register_infos = { { + DEFINE_GENERIC_REGISTER_STUB(r0, nullptr, LLDB_REGNUM_GENERIC_ARG1), + DEFINE_GENERIC_REGISTER_STUB(r1, nullptr, LLDB_REGNUM_GENERIC_ARG2), + DEFINE_GENERIC_REGISTER_STUB(r2, nullptr, LLDB_REGNUM_GENERIC_ARG3), + DEFINE_GENERIC_REGISTER_STUB(r3, nullptr, LLDB_REGNUM_GENERIC_ARG4), + DEFINE_GENERIC_REGISTER_STUB(r4, nullptr, LLDB_REGNUM_GENERIC_ARG5), + DEFINE_GENERIC_REGISTER_STUB(r5, nullptr, LLDB_REGNUM_GENERIC_ARG6), + DEFINE_GENERIC_REGISTER_STUB(r6, nullptr, LLDB_REGNUM_GENERIC_ARG7), + DEFINE_GENERIC_REGISTER_STUB(r7, nullptr, LLDB_REGNUM_GENERIC_ARG8), + DEFINE_REGISTER_STUB(r8, nullptr), + DEFINE_REGISTER_STUB(r9, nullptr), + DEFINE_REGISTER_STUB(r10, nullptr), + DEFINE_REGISTER_STUB(r11, nullptr), + DEFINE_REGISTER_STUB(r12, nullptr), + DEFINE_REGISTER_STUB(r13, nullptr), + DEFINE_REGISTER_STUB(r14, nullptr), + DEFINE_REGISTER_STUB(r15, nullptr), + DEFINE_REGISTER_STUB(r16, nullptr), + DEFINE_REGISTER_STUB(r17, nullptr), + DEFINE_REGISTER_STUB(r18, nullptr), + DEFINE_REGISTER_STUB(r19, nullptr), + DEFINE_REGISTER_STUB(r20, nullptr), + DEFINE_REGISTER_STUB(r21, nullptr), + DEFINE_REGISTER_STUB(r22, nullptr), + DEFINE_REGISTER_STUB(r23, nullptr), + DEFINE_REGISTER_STUB(r24, nullptr), + DEFINE_REGISTER_STUB(r25, nullptr), + DEFINE_REGISTER_STUB(r26, "gp"), + DEFINE_GENERIC_REGISTER_STUB(r27, "fp", LLDB_REGNUM_GENERIC_FP), + DEFINE_GENERIC_REGISTER_STUB(r28, "sp", LLDB_REGNUM_GENERIC_SP), + DEFINE_REGISTER_STUB(r29, "ilink"), + DEFINE_REGISTER_STUB(r30, nullptr), + DEFINE_GENERIC_REGISTER_STUB(r31, "blink", LLDB_REGNUM_GENERIC_RA), + DEFINE_REGISTER_STUB(r32, nullptr), + DEFINE_REGISTER_STUB(r33, nullptr), + DEFINE_REGISTER_STUB(r34, nullptr), + DEFINE_REGISTER_STUB(r35, nullptr), + DEFINE_REGISTER_STUB(r36, nullptr), + DEFINE_REGISTER_STUB(r37, nullptr), + DEFINE_REGISTER_STUB(r38, nullptr), + DEFINE_REGISTER_STUB(r39, nullptr), + DEFINE_REGISTER_STUB(r40, nullptr), + DEFINE_REGISTER_STUB(r41, nullptr), + DEFINE_REGISTER_STUB(r42, nullptr), + DEFINE_REGISTER_STUB(r43, nullptr), + DEFINE_REGISTER_STUB(r44, nullptr), + DEFINE_REGISTER_STUB(r45, nullptr), + DEFINE_REGISTER_STUB(r46, nullptr), + DEFINE_REGISTER_STUB(r47, nullptr), + DEFINE_REGISTER_STUB(r48, nullptr), + DEFINE_REGISTER_STUB(r49, nullptr), + DEFINE_REGISTER_STUB(r50, nullptr), + DEFINE_REGISTER_STUB(r51, nullptr), + DEFINE_REGISTER_STUB(r52, nullptr), + DEFINE_REGISTER_STUB(r53, nullptr), + DEFINE_REGISTER_STUB(r54, nullptr), + DEFINE_REGISTER_STUB(r55, nullptr), + DEFINE_REGISTER_STUB(r56, nullptr), + DEFINE_REGISTER_STUB(r57, nullptr), + DEFINE_REGISTER_STUB(r58, "accl"), + DEFINE_REGISTER_STUB(r59, "acch"), + DEFINE_REGISTER_STUB(r60, "lp_count"), + DEFINE_REGISTER_STUB(r63, "pcl"), + DEFINE_GENERIC_REGISTER_STUB(pc, nullptr, LLDB_REGNUM_GENERIC_PC), + DEFINE_GENERIC_REGISTER_STUB(status32, nullptr, LLDB_REGNUM_GENERIC_FLAGS)} }; +} // namespace dwarf +} // namespace + +const RegisterInfo *ABISysV_arc::GetRegisterInfoArray(uint32_t &count) { + count = dwarf::g_register_infos.size(); + return dwarf::g_register_infos.data(); +} + +size_t ABISysV_arc::GetRedZoneSize() const { return 0; } + +bool ABISysV_arc::IsRegisterFileReduced(RegisterContext ®_ctx) const { + if (!m_is_reg_file_reduced) { + const auto *const rf_build_reg = reg_ctx.GetRegisterInfoByName("rf_build"); + + const auto reg_value = reg_ctx.ReadRegisterAsUnsigned(rf_build_reg, + /*fail_value*/ 0); + // RF_BUILD "Number of Entries" bit. + const uint32_t rf_entries_bit = 1U << 9U; + m_is_reg_file_reduced = (reg_value | rf_entries_bit) != 0; + } + + return m_is_reg_file_reduced.getValueOr(false); +} + +//------------------------------------------------------------------ +// Static Functions +//------------------------------------------------------------------ + +ABISP ABISysV_arc::CreateInstance(ProcessSP process_sp, const ArchSpec &arch) { + return llvm::Triple::arc == arch.GetTriple().getArch() ? + ABISP(new ABISysV_arc(std::move(process_sp), MakeMCRegisterInfo(arch))) : + ABISP(); +} + +namespace { +const size_t word_size = 4U; +const size_t reg_size = word_size; + +inline size_t AugmentArgSize(size_t size_in_bytes) { + return llvm::alignTo(size_in_bytes, word_size); +} + +size_t TotalArgsSizeInWords(const llvm::ArrayRef &args) { + size_t total_size = 0; + for (const auto &arg : args) + total_size += + (ABI::CallArgument::TargetValue == arg.type ? AugmentArgSize(arg.size) + : reg_size) / + word_size; + + return total_size; +} +} // namespace + +bool ABISysV_arc::PrepareTrivialCall(Thread &thread, addr_t sp, + addr_t func_addr, addr_t return_addr, + llvm::ArrayRef args) const { + // We don't use the traditional trivial call specialized for jit. + return false; +} + +bool ABISysV_arc::PrepareTrivialCall(Thread &thread, addr_t sp, addr_t pc, + addr_t ra, llvm::Type &prototype, + llvm::ArrayRef args) const { + auto reg_ctx = thread.GetRegisterContext(); + if (!reg_ctx) + return false; + + uint32_t pc_reg = reg_ctx->ConvertRegisterKindToRegisterNumber( + eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); + if (pc_reg == LLDB_INVALID_REGNUM) + return false; + + uint32_t ra_reg = reg_ctx->ConvertRegisterKindToRegisterNumber( + eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA); + if (ra_reg == LLDB_INVALID_REGNUM) + return false; + + uint32_t sp_reg = reg_ctx->ConvertRegisterKindToRegisterNumber( + eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); + if (sp_reg == LLDB_INVALID_REGNUM) + return false; + + Status error; + ProcessSP process = thread.GetProcess(); + if (!process) + return false; + + // Push host data onto target. + for (const auto &arg : args) { + // Skip over target values. + if (arg.type == ABI::CallArgument::TargetValue) + continue; + + // Create space on the stack for this data 4-byte aligned. + sp -= AugmentArgSize(arg.size); + + if (process->WriteMemory(sp, arg.data_up.get(), arg.size, error) < arg.size + || error.Fail()) + return false; + + // Update the argument with the target pointer. + *const_cast(&arg.value) = sp; + } + + // Make sure number of parameters matches prototype. + assert(!prototype.isFunctionVarArg()); + assert(prototype.getFunctionNumParams() == args.size()); + + const size_t regs_for_args_count = IsRegisterFileReduced(*reg_ctx) ? 4U : 8U; + + // Number of arguments passed on stack. + auto args_size = TotalArgsSizeInWords(args); + auto on_stack = + args_size <= regs_for_args_count ? 0 : args_size - regs_for_args_count; + auto offset = on_stack * word_size; + + uint8_t reg_value[reg_size]; + size_t reg_index = LLDB_REGNUM_GENERIC_ARG1; + + for (const auto &arg : args) { + auto value = reinterpret_cast(&arg.value); + auto size = + ABI::CallArgument::TargetValue == arg.type ? arg.size : reg_size; + + // Pass arguments via registers. + while (size > 0 && reg_index < regs_for_args_count) { + size_t byte_index = 0; + auto end = size < reg_size ? size : reg_size; + + while (byte_index < end) { + reg_value[byte_index++] = *(value++); + --size; + } + + while (byte_index < reg_size) { + reg_value[byte_index++] = 0; + } + + RegisterValue reg_val_obj(reg_value, reg_size, eByteOrderLittle); + if (!reg_ctx->WriteRegister( + reg_ctx->GetRegisterInfo(eRegisterKindGeneric, reg_index), + reg_val_obj)) + return false; + + // NOTE: It's unsafe to iterate through LLDB_REGNUM_GENERICs. + ++reg_index; + } + + if (reg_index < regs_for_args_count || size == 0) + continue; + + // Remaining arguments are passed on the stack. + if (process->WriteMemory(sp - offset, value, size, error) < size || + !error.Success()) + return false; + + offset -= AugmentArgSize(size); + } + + // Set stack pointer immediately below arguments. + sp -= on_stack * word_size; + + // Update registers with current function call state. + reg_ctx->WriteRegisterFromUnsigned(pc_reg, pc); + reg_ctx->WriteRegisterFromUnsigned(ra_reg, ra); + reg_ctx->WriteRegisterFromUnsigned(sp_reg, sp); + + return true; +} + +bool ABISysV_arc::GetArgumentValues(Thread &thread, ValueList &values) const { + return false; +} + +Status ABISysV_arc::SetReturnValueObject(StackFrameSP &frame_sp, + ValueObjectSP &new_value_sp) { + Status result; + if (!new_value_sp) { + result.SetErrorString("Empty value object for return value."); + return result; + } + + CompilerType compiler_type = new_value_sp->GetCompilerType(); + if (!compiler_type) { + result.SetErrorString("Null clang type for return value."); + return result; + } + + auto ®_ctx = *frame_sp->GetThread()->GetRegisterContext(); + + bool is_signed = false; + if (!compiler_type.IsIntegerOrEnumerationType(is_signed) && + !compiler_type.IsPointerType()) { + result.SetErrorString("We don't support returning other types at present"); + return result; + } + + DataExtractor data; + size_t num_bytes = new_value_sp->GetData(data, result); + + if (result.Fail()) { + result.SetErrorStringWithFormat( + "Couldn't convert return value to raw data: %s", result.AsCString()); + return result; + } + + if (num_bytes <= 2 * reg_size) { + offset_t offset = 0; + uint64_t raw_value = data.GetMaxU64(&offset, num_bytes); + + auto reg_info = + reg_ctx.GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1); + if (!reg_ctx.WriteRegisterFromUnsigned(reg_info, raw_value)) { + result.SetErrorStringWithFormat("Couldn't write value to register %s", + reg_info->name); + return result; + } + + if (num_bytes <= reg_size) + return result; // Successfully written. + + raw_value >>= 32; + reg_info = + reg_ctx.GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG2); + if (!reg_ctx.WriteRegisterFromUnsigned(reg_info, raw_value)) { + result.SetErrorStringWithFormat("Couldn't write value to register %s", + reg_info->name); + } + + return result; + } + + result.SetErrorString( + "We don't support returning large integer values at present."); + return result; +} + +namespace { +template +void SetInteger(Scalar &scalar, uint64_t raw_value, bool is_signed) { + raw_value &= std::numeric_limits::max(); + if (is_signed) + scalar = static_cast::type>(raw_value); + else + scalar = static_cast(raw_value); +} + +bool SetSizedInteger(Scalar &scalar, uint64_t raw_value, uint8_t size_in_bytes, + bool is_signed) { + switch (size_in_bytes) { + default: + return false; + + case sizeof(uint64_t): + SetInteger(scalar, raw_value, is_signed); + break; + + case sizeof(uint32_t): + SetInteger(scalar, raw_value, is_signed); + break; + + case sizeof(uint16_t): + SetInteger(scalar, raw_value, is_signed); + break; + + case sizeof(uint8_t): + SetInteger(scalar, raw_value, is_signed); + break; + } + + return true; +} + +bool SetSizedFloat(Scalar &scalar, uint64_t raw_value, uint8_t size_in_bytes) { + switch (size_in_bytes) { + default: + return false; + + case sizeof(uint64_t): + scalar = *reinterpret_cast(&raw_value); + break; + + case sizeof(uint32_t): + scalar = *reinterpret_cast(&raw_value); + break; + } + + return true; +} + +uint64_t ReadRawValue(const RegisterContextSP ®_ctx, uint8_t size_in_bytes) { + auto reg_info_r0 = + reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1); + + // Extract the register context so we can read arguments from registers. + uint64_t raw_value = + reg_ctx->ReadRegisterAsUnsigned(reg_info_r0, 0) & UINT32_MAX; + + if (sizeof(uint64_t) == size_in_bytes) + raw_value |= (reg_ctx->ReadRegisterAsUnsigned( + reg_ctx->GetRegisterInfo(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_ARG2), 0) & + UINT64_MAX) << 32U; + + return raw_value; +} +} // namespace + +ValueObjectSP +ABISysV_arc::GetReturnValueObjectSimple(Thread &thread, + CompilerType &compiler_type) const { + if (!compiler_type) + return ValueObjectSP(); + + auto reg_ctx = thread.GetRegisterContext(); + if (!reg_ctx) + return ValueObjectSP(); + + Value value; + value.SetCompilerType(compiler_type); + + const uint32_t type_flags = compiler_type.GetTypeInfo(); + // Integer return type. + if (type_flags & eTypeIsInteger) { + const size_t byte_size = compiler_type.GetByteSize(nullptr).getValueOr(0); + auto raw_value = ReadRawValue(reg_ctx, byte_size); + + const bool is_signed = (type_flags & eTypeIsSigned) != 0; + if (!SetSizedInteger(value.GetScalar(), raw_value, byte_size, is_signed)) + return ValueObjectSP(); + + value.SetValueType(Value::eValueTypeScalar); + } + // Pointer return type. + else if (type_flags & eTypeIsPointer) { + auto reg_info_r0 = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_ARG1); + value.GetScalar() = reg_ctx->ReadRegisterAsUnsigned(reg_info_r0, 0); + + value.SetValueType(Value::eValueTypeScalar); + } + // Floating point return type. + else if (type_flags & eTypeIsFloat) { + uint32_t float_count = 0; + bool is_complex = false; + + if (compiler_type.IsFloatingPointType(float_count, is_complex) && + 1 == float_count && !is_complex) { + const size_t byte_size = compiler_type.GetByteSize(nullptr).getValueOr(0); + auto raw_value = ReadRawValue(reg_ctx, byte_size); + + if (!SetSizedFloat(value.GetScalar(), raw_value, byte_size)) + return ValueObjectSP(); + } + } + // Unsupported return type. + else + return ValueObjectSP(); + + return ValueObjectConstResult::Create(thread.GetStackFrameAtIndex(0).get(), + value, ConstString("")); +} + +ValueObjectSP ABISysV_arc::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 GetReturnValueObjectSimple(thread, return_compiler_type); +} + +ValueObjectSP ABISysV_arc::GetReturnValueObjectImpl(Thread &thread, + llvm::Type &retType) const { + auto reg_ctx = thread.GetRegisterContext(); + if (!reg_ctx) + return ValueObjectSP(); + + Value value; + // Void return type. + if (retType.isVoidTy()) { + value.GetScalar() = 0; + } + // Integer return type. + else if (retType.isIntegerTy()) { + size_t byte_size = retType.getPrimitiveSizeInBits(); + if (1 != byte_size) // For boolian type. + byte_size /= CHAR_BIT; + + auto raw_value = ReadRawValue(reg_ctx, byte_size); + + const bool is_signed = false; // IR Type doesn't provide this info. + if (!SetSizedInteger(value.GetScalar(), raw_value, byte_size, is_signed)) + return ValueObjectSP(); + } + // Pointer return type. + else if (retType.isPointerTy()) { + auto reg_info_r0 = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_ARG1); + value.GetScalar() = reg_ctx->ReadRegisterAsUnsigned(reg_info_r0, 0); + value.SetValueType(Value::eValueTypeScalar); + } + // Floating point return type. + else if (retType.isFloatingPointTy()) { + const size_t byte_size = retType.getPrimitiveSizeInBits() / CHAR_BIT; + auto raw_value = ReadRawValue(reg_ctx, byte_size); + + if (!SetSizedFloat(value.GetScalar(), raw_value, byte_size)) + return ValueObjectSP(); + } + // Unsupported return type. + else + return ValueObjectSP(); + + return ValueObjectConstResult::Create(thread.GetStackFrameAtIndex(0).get(), + value, ConstString("")); +} + +bool ABISysV_arc::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) { + unwind_plan.Clear(); + unwind_plan.SetRegisterKind(eRegisterKindDWARF); + + UnwindPlan::RowSP row(new UnwindPlan::Row); + + // Our Call Frame Address is the stack pointer value. + row->GetCFAValue().SetIsRegisterPlusOffset(dwarf::sp, 0); + + // The previous PC is in the BLINK. + row->SetRegisterLocationToRegister(dwarf::pc, dwarf::blink, true); + unwind_plan.AppendRow(row); + + // All other registers are the same. + unwind_plan.SetSourceName("arc at-func-entry default"); + unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); + + return true; +} + +bool ABISysV_arc::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) { + return false; +} + +bool ABISysV_arc::RegisterIsVolatile(const RegisterInfo *reg_info) { + if (nullptr == reg_info) + return false; + + // Volatile registers are: r0..r12. + uint32_t regnum = reg_info->kinds[eRegisterKindDWARF]; + if (regnum <= 12) + return true; + + static const std::string ra_reg_name = "blink"; + return ra_reg_name == reg_info->name; +} + +void ABISysV_arc::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + "System V ABI for ARC targets", CreateInstance); +} + +void ABISysV_arc::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +ConstString ABISysV_arc::GetPluginNameStatic() { + static ConstString g_name("sysv-arc"); + return g_name; +} + +//------------------------------------------------------------------ +// PluginInterface protocol +//------------------------------------------------------------------ + +ConstString ABISysV_arc::GetPluginName() { + return GetPluginNameStatic(); +} + +uint32_t ABISysV_arc::GetPluginVersion() { return 1; } diff --git a/lldb/source/Plugins/ABI/SysV-arc/CMakeLists.txt b/lldb/source/Plugins/ABI/SysV-arc/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/lldb/source/Plugins/ABI/SysV-arc/CMakeLists.txt @@ -0,0 +1,11 @@ +add_lldb_library(lldbPluginABISysV_arc PLUGIN + ABISysV_arc.cpp + + LINK_LIBS + lldbCore + lldbSymbol + lldbTarget + lldbPluginProcessUtility + LINK_COMPONENTS + Support + )