Path: blob/main/contrib/llvm-project/lldb/source/Plugins/ABI/ARC/ABISysV_arc.cpp
39653 views
//===-- ABISysV_arc.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//6//===----------------------------------------------------------------------===//78#include "ABISysV_arc.h"910// C Includes11// C++ Includes12#include <array>13#include <limits>14#include <type_traits>1516// Other libraries and framework includes17#include "llvm/IR/DerivedTypes.h"18#include "llvm/Support/MathExtras.h"19#include "llvm/TargetParser/Triple.h"2021#include "lldb/Core/Module.h"22#include "lldb/Core/PluginManager.h"23#include "lldb/Core/Value.h"24#include "lldb/Core/ValueObjectConstResult.h"25#include "lldb/Core/ValueObjectMemory.h"26#include "lldb/Core/ValueObjectRegister.h"27#include "lldb/Symbol/UnwindPlan.h"28#include "lldb/Target/Process.h"29#include "lldb/Target/RegisterContext.h"30#include "lldb/Target/StackFrame.h"31#include "lldb/Target/Target.h"32#include "lldb/Target/Thread.h"33#include "lldb/Utility/ConstString.h"34#include "lldb/Utility/RegisterValue.h"35#include "lldb/Utility/Status.h"3637#define DEFINE_REG_NAME(reg_num) ConstString(#reg_num).GetCString()38#define DEFINE_REG_NAME_STR(reg_name) ConstString(reg_name).GetCString()3940// The ABI is not a source of such information as size, offset, encoding, etc.41// of a register. Just provides correct dwarf and eh_frame numbers.4243#define DEFINE_GENERIC_REGISTER_STUB(dwarf_num, str_name, generic_num) \44{ \45DEFINE_REG_NAME(dwarf_num), DEFINE_REG_NAME_STR(str_name), \460, 0, eEncodingInvalid, eFormatDefault, \47{ dwarf_num, dwarf_num, generic_num, LLDB_INVALID_REGNUM, dwarf_num }, \48nullptr, nullptr, nullptr, \49}5051#define DEFINE_REGISTER_STUB(dwarf_num, str_name) \52DEFINE_GENERIC_REGISTER_STUB(dwarf_num, str_name, LLDB_INVALID_REGNUM)5354using namespace lldb;55using namespace lldb_private;5657LLDB_PLUGIN_DEFINE_ADV(ABISysV_arc, ABIARC)5859namespace {60namespace dwarf {61enum regnums {62r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16,63r17, r18, r19, r20, r21, r22, r23, r24, r25, r26,64r27, fp = r27, r28, sp = r28, r29, r30, r31, blink = r31,65r32, r33, r34, r35, r36, r37, r38, r39, r40, r41, r42, r43, r44, r45, r46,66r47, r48, r49, r50, r51, r52, r53, r54, r55, r56, r57, r58, r59, r60,67/*reserved,*/ /*limm indicator,*/ r63 = 63, pc = 70, status32 = 7468};6970static const std::array<RegisterInfo, 64> g_register_infos = { {71DEFINE_GENERIC_REGISTER_STUB(r0, nullptr, LLDB_REGNUM_GENERIC_ARG1),72DEFINE_GENERIC_REGISTER_STUB(r1, nullptr, LLDB_REGNUM_GENERIC_ARG2),73DEFINE_GENERIC_REGISTER_STUB(r2, nullptr, LLDB_REGNUM_GENERIC_ARG3),74DEFINE_GENERIC_REGISTER_STUB(r3, nullptr, LLDB_REGNUM_GENERIC_ARG4),75DEFINE_GENERIC_REGISTER_STUB(r4, nullptr, LLDB_REGNUM_GENERIC_ARG5),76DEFINE_GENERIC_REGISTER_STUB(r5, nullptr, LLDB_REGNUM_GENERIC_ARG6),77DEFINE_GENERIC_REGISTER_STUB(r6, nullptr, LLDB_REGNUM_GENERIC_ARG7),78DEFINE_GENERIC_REGISTER_STUB(r7, nullptr, LLDB_REGNUM_GENERIC_ARG8),79DEFINE_REGISTER_STUB(r8, nullptr),80DEFINE_REGISTER_STUB(r9, nullptr),81DEFINE_REGISTER_STUB(r10, nullptr),82DEFINE_REGISTER_STUB(r11, nullptr),83DEFINE_REGISTER_STUB(r12, nullptr),84DEFINE_REGISTER_STUB(r13, nullptr),85DEFINE_REGISTER_STUB(r14, nullptr),86DEFINE_REGISTER_STUB(r15, nullptr),87DEFINE_REGISTER_STUB(r16, nullptr),88DEFINE_REGISTER_STUB(r17, nullptr),89DEFINE_REGISTER_STUB(r18, nullptr),90DEFINE_REGISTER_STUB(r19, nullptr),91DEFINE_REGISTER_STUB(r20, nullptr),92DEFINE_REGISTER_STUB(r21, nullptr),93DEFINE_REGISTER_STUB(r22, nullptr),94DEFINE_REGISTER_STUB(r23, nullptr),95DEFINE_REGISTER_STUB(r24, nullptr),96DEFINE_REGISTER_STUB(r25, nullptr),97DEFINE_REGISTER_STUB(r26, "gp"),98DEFINE_GENERIC_REGISTER_STUB(r27, "fp", LLDB_REGNUM_GENERIC_FP),99DEFINE_GENERIC_REGISTER_STUB(r28, "sp", LLDB_REGNUM_GENERIC_SP),100DEFINE_REGISTER_STUB(r29, "ilink"),101DEFINE_REGISTER_STUB(r30, nullptr),102DEFINE_GENERIC_REGISTER_STUB(r31, "blink", LLDB_REGNUM_GENERIC_RA),103DEFINE_REGISTER_STUB(r32, nullptr),104DEFINE_REGISTER_STUB(r33, nullptr),105DEFINE_REGISTER_STUB(r34, nullptr),106DEFINE_REGISTER_STUB(r35, nullptr),107DEFINE_REGISTER_STUB(r36, nullptr),108DEFINE_REGISTER_STUB(r37, nullptr),109DEFINE_REGISTER_STUB(r38, nullptr),110DEFINE_REGISTER_STUB(r39, nullptr),111DEFINE_REGISTER_STUB(r40, nullptr),112DEFINE_REGISTER_STUB(r41, nullptr),113DEFINE_REGISTER_STUB(r42, nullptr),114DEFINE_REGISTER_STUB(r43, nullptr),115DEFINE_REGISTER_STUB(r44, nullptr),116DEFINE_REGISTER_STUB(r45, nullptr),117DEFINE_REGISTER_STUB(r46, nullptr),118DEFINE_REGISTER_STUB(r47, nullptr),119DEFINE_REGISTER_STUB(r48, nullptr),120DEFINE_REGISTER_STUB(r49, nullptr),121DEFINE_REGISTER_STUB(r50, nullptr),122DEFINE_REGISTER_STUB(r51, nullptr),123DEFINE_REGISTER_STUB(r52, nullptr),124DEFINE_REGISTER_STUB(r53, nullptr),125DEFINE_REGISTER_STUB(r54, nullptr),126DEFINE_REGISTER_STUB(r55, nullptr),127DEFINE_REGISTER_STUB(r56, nullptr),128DEFINE_REGISTER_STUB(r57, nullptr),129DEFINE_REGISTER_STUB(r58, "accl"),130DEFINE_REGISTER_STUB(r59, "acch"),131DEFINE_REGISTER_STUB(r60, "lp_count"),132DEFINE_REGISTER_STUB(r63, "pcl"),133DEFINE_GENERIC_REGISTER_STUB(pc, nullptr, LLDB_REGNUM_GENERIC_PC),134DEFINE_GENERIC_REGISTER_STUB(status32, nullptr, LLDB_REGNUM_GENERIC_FLAGS)} };135} // namespace dwarf136} // namespace137138const RegisterInfo *ABISysV_arc::GetRegisterInfoArray(uint32_t &count) {139count = dwarf::g_register_infos.size();140return dwarf::g_register_infos.data();141}142143size_t ABISysV_arc::GetRedZoneSize() const { return 0; }144145bool ABISysV_arc::IsRegisterFileReduced(RegisterContext ®_ctx) const {146if (!m_is_reg_file_reduced) {147const auto *const rf_build_reg = reg_ctx.GetRegisterInfoByName("rf_build");148149const auto reg_value = reg_ctx.ReadRegisterAsUnsigned(rf_build_reg,150/*fail_value*/ 0);151// RF_BUILD "Number of Entries" bit.152const uint32_t rf_entries_bit = 1U << 9U;153m_is_reg_file_reduced = (reg_value & rf_entries_bit) != 0;154}155156return m_is_reg_file_reduced.value_or(false);157}158159//------------------------------------------------------------------160// Static Functions161//------------------------------------------------------------------162163ABISP ABISysV_arc::CreateInstance(ProcessSP process_sp, const ArchSpec &arch) {164return llvm::Triple::arc == arch.GetTriple().getArch() ?165ABISP(new ABISysV_arc(std::move(process_sp), MakeMCRegisterInfo(arch))) :166ABISP();167}168169static const size_t word_size = 4U;170static const size_t reg_size = word_size;171172static inline size_t AugmentArgSize(size_t size_in_bytes) {173return llvm::alignTo(size_in_bytes, word_size);174}175176static size_t177TotalArgsSizeInWords(const llvm::ArrayRef<ABI::CallArgument> &args) {178size_t total_size = 0;179for (const auto &arg : args)180total_size +=181(ABI::CallArgument::TargetValue == arg.type ? AugmentArgSize(arg.size)182: reg_size) /183word_size;184185return total_size;186}187188bool ABISysV_arc::PrepareTrivialCall(Thread &thread, addr_t sp,189addr_t func_addr, addr_t return_addr,190llvm::ArrayRef<addr_t> args) const {191// We don't use the traditional trivial call specialized for jit.192return false;193}194195bool ABISysV_arc::PrepareTrivialCall(Thread &thread, addr_t sp, addr_t pc,196addr_t ra, llvm::Type &prototype,197llvm::ArrayRef<ABI::CallArgument> args) const {198auto reg_ctx = thread.GetRegisterContext();199if (!reg_ctx)200return false;201202uint32_t pc_reg = reg_ctx->ConvertRegisterKindToRegisterNumber(203eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);204if (pc_reg == LLDB_INVALID_REGNUM)205return false;206207uint32_t ra_reg = reg_ctx->ConvertRegisterKindToRegisterNumber(208eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA);209if (ra_reg == LLDB_INVALID_REGNUM)210return false;211212uint32_t sp_reg = reg_ctx->ConvertRegisterKindToRegisterNumber(213eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);214if (sp_reg == LLDB_INVALID_REGNUM)215return false;216217Status error;218ProcessSP process = thread.GetProcess();219if (!process)220return false;221222// Push host data onto target.223for (const auto &arg : args) {224// Skip over target values.225if (arg.type == ABI::CallArgument::TargetValue)226continue;227228// Create space on the stack for this data 4-byte aligned.229sp -= AugmentArgSize(arg.size);230231if (process->WriteMemory(sp, arg.data_up.get(), arg.size, error) < arg.size232|| error.Fail())233return false;234235// Update the argument with the target pointer.236*const_cast<addr_t *>(&arg.value) = sp;237}238239// Make sure number of parameters matches prototype.240assert(!prototype.isFunctionVarArg());241assert(prototype.getFunctionNumParams() == args.size());242243const size_t regs_for_args_count = IsRegisterFileReduced(*reg_ctx) ? 4U : 8U;244245// Number of arguments passed on stack.246auto args_size = TotalArgsSizeInWords(args);247auto on_stack =248args_size <= regs_for_args_count ? 0 : args_size - regs_for_args_count;249auto offset = on_stack * word_size;250251uint8_t reg_value[reg_size];252size_t reg_index = LLDB_REGNUM_GENERIC_ARG1;253254for (const auto &arg : args) {255auto value = reinterpret_cast<const uint8_t *>(&arg.value);256auto size =257ABI::CallArgument::TargetValue == arg.type ? arg.size : reg_size;258259// Pass arguments via registers.260while (size > 0 && reg_index < regs_for_args_count) {261size_t byte_index = 0;262auto end = size < reg_size ? size : reg_size;263264while (byte_index < end) {265reg_value[byte_index++] = *(value++);266--size;267}268269while (byte_index < reg_size) {270reg_value[byte_index++] = 0;271}272273RegisterValue reg_val_obj(llvm::ArrayRef(reg_value, reg_size),274eByteOrderLittle);275if (!reg_ctx->WriteRegister(276reg_ctx->GetRegisterInfo(eRegisterKindGeneric, reg_index),277reg_val_obj))278return false;279280// NOTE: It's unsafe to iterate through LLDB_REGNUM_GENERICs.281++reg_index;282}283284if (reg_index < regs_for_args_count || size == 0)285continue;286287// Remaining arguments are passed on the stack.288if (process->WriteMemory(sp - offset, value, size, error) < size ||289!error.Success())290return false;291292offset -= AugmentArgSize(size);293}294295// Set stack pointer immediately below arguments.296sp -= on_stack * word_size;297298// Update registers with current function call state.299reg_ctx->WriteRegisterFromUnsigned(pc_reg, pc);300reg_ctx->WriteRegisterFromUnsigned(ra_reg, ra);301reg_ctx->WriteRegisterFromUnsigned(sp_reg, sp);302303return true;304}305306bool ABISysV_arc::GetArgumentValues(Thread &thread, ValueList &values) const {307return false;308}309310Status ABISysV_arc::SetReturnValueObject(StackFrameSP &frame_sp,311ValueObjectSP &new_value_sp) {312Status result;313if (!new_value_sp) {314result.SetErrorString("Empty value object for return value.");315return result;316}317318CompilerType compiler_type = new_value_sp->GetCompilerType();319if (!compiler_type) {320result.SetErrorString("Null clang type for return value.");321return result;322}323324auto ®_ctx = *frame_sp->GetThread()->GetRegisterContext();325326bool is_signed = false;327if (!compiler_type.IsIntegerOrEnumerationType(is_signed) &&328!compiler_type.IsPointerType()) {329result.SetErrorString("We don't support returning other types at present");330return result;331}332333DataExtractor data;334size_t num_bytes = new_value_sp->GetData(data, result);335336if (result.Fail()) {337result.SetErrorStringWithFormat(338"Couldn't convert return value to raw data: %s", result.AsCString());339return result;340}341342if (num_bytes <= 2 * reg_size) {343offset_t offset = 0;344uint64_t raw_value = data.GetMaxU64(&offset, num_bytes);345346auto reg_info =347reg_ctx.GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1);348if (!reg_ctx.WriteRegisterFromUnsigned(reg_info, raw_value)) {349result.SetErrorStringWithFormat("Couldn't write value to register %s",350reg_info->name);351return result;352}353354if (num_bytes <= reg_size)355return result; // Successfully written.356357raw_value >>= 32;358reg_info =359reg_ctx.GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG2);360if (!reg_ctx.WriteRegisterFromUnsigned(reg_info, raw_value)) {361result.SetErrorStringWithFormat("Couldn't write value to register %s",362reg_info->name);363}364365return result;366}367368result.SetErrorString(369"We don't support returning large integer values at present.");370return result;371}372373template <typename T>374static void SetInteger(Scalar &scalar, uint64_t raw_value, bool is_signed) {375raw_value &= std::numeric_limits<T>::max();376if (is_signed)377scalar = static_cast<typename std::make_signed<T>::type>(raw_value);378else379scalar = static_cast<T>(raw_value);380}381382static bool SetSizedInteger(Scalar &scalar, uint64_t raw_value,383uint8_t size_in_bytes, bool is_signed) {384switch (size_in_bytes) {385default:386return false;387388case sizeof(uint64_t):389SetInteger<uint64_t>(scalar, raw_value, is_signed);390break;391392case sizeof(uint32_t):393SetInteger<uint32_t>(scalar, raw_value, is_signed);394break;395396case sizeof(uint16_t):397SetInteger<uint16_t>(scalar, raw_value, is_signed);398break;399400case sizeof(uint8_t):401SetInteger<uint8_t>(scalar, raw_value, is_signed);402break;403}404405return true;406}407408static bool SetSizedFloat(Scalar &scalar, uint64_t raw_value,409uint8_t size_in_bytes) {410switch (size_in_bytes) {411default:412return false;413414case sizeof(uint64_t):415scalar = *reinterpret_cast<double *>(&raw_value);416break;417418case sizeof(uint32_t):419scalar = *reinterpret_cast<float *>(&raw_value);420break;421}422423return true;424}425426static uint64_t ReadRawValue(const RegisterContextSP ®_ctx,427uint8_t size_in_bytes) {428auto reg_info_r0 =429reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1);430431// Extract the register context so we can read arguments from registers.432uint64_t raw_value =433reg_ctx->ReadRegisterAsUnsigned(reg_info_r0, 0) & UINT32_MAX;434435if (sizeof(uint64_t) == size_in_bytes)436raw_value |= (reg_ctx->ReadRegisterAsUnsigned(437reg_ctx->GetRegisterInfo(eRegisterKindGeneric,438LLDB_REGNUM_GENERIC_ARG2), 0) &439UINT64_MAX) << 32U;440441return raw_value;442}443444ValueObjectSP445ABISysV_arc::GetReturnValueObjectSimple(Thread &thread,446CompilerType &compiler_type) const {447if (!compiler_type)448return ValueObjectSP();449450auto reg_ctx = thread.GetRegisterContext();451if (!reg_ctx)452return ValueObjectSP();453454Value value;455value.SetCompilerType(compiler_type);456457const uint32_t type_flags = compiler_type.GetTypeInfo();458// Integer return type.459if (type_flags & eTypeIsInteger) {460const size_t byte_size = compiler_type.GetByteSize(&thread).value_or(0);461auto raw_value = ReadRawValue(reg_ctx, byte_size);462463const bool is_signed = (type_flags & eTypeIsSigned) != 0;464if (!SetSizedInteger(value.GetScalar(), raw_value, byte_size, is_signed))465return ValueObjectSP();466467value.SetValueType(Value::ValueType::Scalar);468}469// Pointer return type.470else if (type_flags & eTypeIsPointer) {471auto reg_info_r0 = reg_ctx->GetRegisterInfo(eRegisterKindGeneric,472LLDB_REGNUM_GENERIC_ARG1);473value.GetScalar() = reg_ctx->ReadRegisterAsUnsigned(reg_info_r0, 0);474475value.SetValueType(Value::ValueType::Scalar);476}477// Floating point return type.478else if (type_flags & eTypeIsFloat) {479uint32_t float_count = 0;480bool is_complex = false;481482if (compiler_type.IsFloatingPointType(float_count, is_complex) &&4831 == float_count && !is_complex) {484const size_t byte_size = compiler_type.GetByteSize(&thread).value_or(0);485auto raw_value = ReadRawValue(reg_ctx, byte_size);486487if (!SetSizedFloat(value.GetScalar(), raw_value, byte_size))488return ValueObjectSP();489}490}491// Unsupported return type.492else493return ValueObjectSP();494495return ValueObjectConstResult::Create(thread.GetStackFrameAtIndex(0).get(),496value, ConstString(""));497}498499ValueObjectSP ABISysV_arc::GetReturnValueObjectImpl(500Thread &thread, CompilerType &return_compiler_type) const {501ValueObjectSP return_valobj_sp;502503if (!return_compiler_type)504return return_valobj_sp;505506ExecutionContext exe_ctx(thread.shared_from_this());507return GetReturnValueObjectSimple(thread, return_compiler_type);508}509510ValueObjectSP ABISysV_arc::GetReturnValueObjectImpl(Thread &thread,511llvm::Type &retType) const {512auto reg_ctx = thread.GetRegisterContext();513if (!reg_ctx)514return ValueObjectSP();515516Value value;517// Void return type.518if (retType.isVoidTy()) {519value.GetScalar() = 0;520}521// Integer return type.522else if (retType.isIntegerTy()) {523size_t byte_size = retType.getPrimitiveSizeInBits();524if (1 != byte_size) // For boolean type.525byte_size /= CHAR_BIT;526527auto raw_value = ReadRawValue(reg_ctx, byte_size);528529const bool is_signed = false; // IR Type doesn't provide this info.530if (!SetSizedInteger(value.GetScalar(), raw_value, byte_size, is_signed))531return ValueObjectSP();532}533// Pointer return type.534else if (retType.isPointerTy()) {535auto reg_info_r0 = reg_ctx->GetRegisterInfo(eRegisterKindGeneric,536LLDB_REGNUM_GENERIC_ARG1);537value.GetScalar() = reg_ctx->ReadRegisterAsUnsigned(reg_info_r0, 0);538value.SetValueType(Value::ValueType::Scalar);539}540// Floating point return type.541else if (retType.isFloatingPointTy()) {542const size_t byte_size = retType.getPrimitiveSizeInBits() / CHAR_BIT;543auto raw_value = ReadRawValue(reg_ctx, byte_size);544545if (!SetSizedFloat(value.GetScalar(), raw_value, byte_size))546return ValueObjectSP();547}548// Unsupported return type.549else550return ValueObjectSP();551552return ValueObjectConstResult::Create(thread.GetStackFrameAtIndex(0).get(),553value, ConstString(""));554}555556bool ABISysV_arc::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) {557unwind_plan.Clear();558unwind_plan.SetRegisterKind(eRegisterKindDWARF);559560UnwindPlan::RowSP row(new UnwindPlan::Row);561562// Our Call Frame Address is the stack pointer value.563row->GetCFAValue().SetIsRegisterPlusOffset(dwarf::sp, 0);564565// The previous PC is in the BLINK.566row->SetRegisterLocationToRegister(dwarf::pc, dwarf::blink, true);567unwind_plan.AppendRow(row);568569// All other registers are the same.570unwind_plan.SetSourceName("arc at-func-entry default");571unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);572573return true;574}575576bool ABISysV_arc::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {577return false;578}579580bool ABISysV_arc::RegisterIsVolatile(const RegisterInfo *reg_info) {581if (nullptr == reg_info)582return false;583584// Volatile registers are: r0..r12.585uint32_t regnum = reg_info->kinds[eRegisterKindDWARF];586if (regnum <= 12)587return true;588589static const std::string ra_reg_name = "blink";590return ra_reg_name == reg_info->name;591}592593void ABISysV_arc::Initialize() {594PluginManager::RegisterPlugin(GetPluginNameStatic(),595"System V ABI for ARC targets", CreateInstance);596}597598void ABISysV_arc::Terminate() {599PluginManager::UnregisterPlugin(CreateInstance);600}601602603