15f757f3fSDimitry Andric //===-- ABISysV_riscv.cpp ------------------------------------------------===// 25f757f3fSDimitry Andric // 35f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 55f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65f757f3fSDimitry Andric // 75f757f3fSDimitry Andric //===---------------------------------------------------------------------===// 85f757f3fSDimitry Andric 95f757f3fSDimitry Andric #include "ABISysV_riscv.h" 105f757f3fSDimitry Andric 115f757f3fSDimitry Andric #include <array> 125f757f3fSDimitry Andric #include <limits> 135f757f3fSDimitry Andric 145f757f3fSDimitry Andric #include "llvm/IR/DerivedTypes.h" 155f757f3fSDimitry Andric 16*0fca6ea1SDimitry Andric #include "Utility/RISCV_DWARF_Registers.h" 175f757f3fSDimitry Andric #include "lldb/Core/PluginManager.h" 185f757f3fSDimitry Andric #include "lldb/Core/Value.h" 195f757f3fSDimitry Andric #include "lldb/Core/ValueObjectConstResult.h" 205f757f3fSDimitry Andric #include "lldb/Target/RegisterContext.h" 215f757f3fSDimitry Andric #include "lldb/Target/StackFrame.h" 225f757f3fSDimitry Andric #include "lldb/Target/Thread.h" 235f757f3fSDimitry Andric #include "lldb/Utility/RegisterValue.h" 245f757f3fSDimitry Andric 255f757f3fSDimitry Andric #define DEFINE_REG_NAME(reg_num) ConstString(#reg_num).GetCString() 265f757f3fSDimitry Andric #define DEFINE_REG_NAME_STR(reg_name) ConstString(reg_name).GetCString() 275f757f3fSDimitry Andric 285f757f3fSDimitry Andric // The ABI is not a source of such information as size, offset, encoding, etc. 295f757f3fSDimitry Andric // of a register. Just provides correct dwarf and eh_frame numbers. 305f757f3fSDimitry Andric 315f757f3fSDimitry Andric #define DEFINE_GENERIC_REGISTER_STUB(dwarf_num, str_name, generic_num) \ 325f757f3fSDimitry Andric { \ 335f757f3fSDimitry Andric DEFINE_REG_NAME(dwarf_num), DEFINE_REG_NAME_STR(str_name), 0, 0, \ 345f757f3fSDimitry Andric eEncodingInvalid, eFormatDefault, \ 355f757f3fSDimitry Andric {dwarf_num, dwarf_num, generic_num, LLDB_INVALID_REGNUM, dwarf_num}, \ 365f757f3fSDimitry Andric nullptr, nullptr, nullptr, \ 375f757f3fSDimitry Andric } 385f757f3fSDimitry Andric 395f757f3fSDimitry Andric #define DEFINE_REGISTER_STUB(dwarf_num, str_name) \ 405f757f3fSDimitry Andric DEFINE_GENERIC_REGISTER_STUB(dwarf_num, str_name, LLDB_INVALID_REGNUM) 415f757f3fSDimitry Andric 425f757f3fSDimitry Andric using namespace lldb; 435f757f3fSDimitry Andric using namespace lldb_private; 445f757f3fSDimitry Andric 455f757f3fSDimitry Andric LLDB_PLUGIN_DEFINE_ADV(ABISysV_riscv, ABIRISCV) 465f757f3fSDimitry Andric 475f757f3fSDimitry Andric namespace { 485f757f3fSDimitry Andric namespace dwarf { 495f757f3fSDimitry Andric enum regnums { 505f757f3fSDimitry Andric zero, 515f757f3fSDimitry Andric ra, 525f757f3fSDimitry Andric sp, 535f757f3fSDimitry Andric gp, 545f757f3fSDimitry Andric tp, 555f757f3fSDimitry Andric t0, 565f757f3fSDimitry Andric t1, 575f757f3fSDimitry Andric t2, 585f757f3fSDimitry Andric fp, 595f757f3fSDimitry Andric s0 = fp, 605f757f3fSDimitry Andric s1, 615f757f3fSDimitry Andric a0, 625f757f3fSDimitry Andric a1, 635f757f3fSDimitry Andric a2, 645f757f3fSDimitry Andric a3, 655f757f3fSDimitry Andric a4, 665f757f3fSDimitry Andric a5, 675f757f3fSDimitry Andric a6, 685f757f3fSDimitry Andric a7, 695f757f3fSDimitry Andric s2, 705f757f3fSDimitry Andric s3, 715f757f3fSDimitry Andric s4, 725f757f3fSDimitry Andric s5, 735f757f3fSDimitry Andric s6, 745f757f3fSDimitry Andric s7, 755f757f3fSDimitry Andric s8, 765f757f3fSDimitry Andric s9, 775f757f3fSDimitry Andric s10, 785f757f3fSDimitry Andric s11, 795f757f3fSDimitry Andric t3, 805f757f3fSDimitry Andric t4, 815f757f3fSDimitry Andric t5, 825f757f3fSDimitry Andric t6, 835f757f3fSDimitry Andric pc 845f757f3fSDimitry Andric }; 855f757f3fSDimitry Andric 865f757f3fSDimitry Andric static const std::array<RegisterInfo, 33> g_register_infos = { 875f757f3fSDimitry Andric {DEFINE_REGISTER_STUB(zero, nullptr), 885f757f3fSDimitry Andric DEFINE_GENERIC_REGISTER_STUB(ra, nullptr, LLDB_REGNUM_GENERIC_RA), 895f757f3fSDimitry Andric DEFINE_GENERIC_REGISTER_STUB(sp, nullptr, LLDB_REGNUM_GENERIC_SP), 905f757f3fSDimitry Andric DEFINE_REGISTER_STUB(gp, nullptr), 915f757f3fSDimitry Andric DEFINE_REGISTER_STUB(tp, nullptr), 925f757f3fSDimitry Andric DEFINE_REGISTER_STUB(t0, nullptr), 935f757f3fSDimitry Andric DEFINE_REGISTER_STUB(t1, nullptr), 945f757f3fSDimitry Andric DEFINE_REGISTER_STUB(t2, nullptr), 955f757f3fSDimitry Andric DEFINE_GENERIC_REGISTER_STUB(fp, nullptr, LLDB_REGNUM_GENERIC_FP), 965f757f3fSDimitry Andric DEFINE_REGISTER_STUB(s1, nullptr), 975f757f3fSDimitry Andric DEFINE_GENERIC_REGISTER_STUB(a0, nullptr, LLDB_REGNUM_GENERIC_ARG1), 985f757f3fSDimitry Andric DEFINE_GENERIC_REGISTER_STUB(a1, nullptr, LLDB_REGNUM_GENERIC_ARG2), 995f757f3fSDimitry Andric DEFINE_GENERIC_REGISTER_STUB(a2, nullptr, LLDB_REGNUM_GENERIC_ARG3), 1005f757f3fSDimitry Andric DEFINE_GENERIC_REGISTER_STUB(a3, nullptr, LLDB_REGNUM_GENERIC_ARG4), 1015f757f3fSDimitry Andric DEFINE_GENERIC_REGISTER_STUB(a4, nullptr, LLDB_REGNUM_GENERIC_ARG5), 1025f757f3fSDimitry Andric DEFINE_GENERIC_REGISTER_STUB(a5, nullptr, LLDB_REGNUM_GENERIC_ARG6), 1035f757f3fSDimitry Andric DEFINE_GENERIC_REGISTER_STUB(a6, nullptr, LLDB_REGNUM_GENERIC_ARG7), 1045f757f3fSDimitry Andric DEFINE_GENERIC_REGISTER_STUB(a7, nullptr, LLDB_REGNUM_GENERIC_ARG8), 1055f757f3fSDimitry Andric DEFINE_REGISTER_STUB(s2, nullptr), 1065f757f3fSDimitry Andric DEFINE_REGISTER_STUB(s3, nullptr), 1075f757f3fSDimitry Andric DEFINE_REGISTER_STUB(s4, nullptr), 1085f757f3fSDimitry Andric DEFINE_REGISTER_STUB(s5, nullptr), 1095f757f3fSDimitry Andric DEFINE_REGISTER_STUB(s6, nullptr), 1105f757f3fSDimitry Andric DEFINE_REGISTER_STUB(s7, nullptr), 1115f757f3fSDimitry Andric DEFINE_REGISTER_STUB(s8, nullptr), 1125f757f3fSDimitry Andric DEFINE_REGISTER_STUB(s9, nullptr), 1135f757f3fSDimitry Andric DEFINE_REGISTER_STUB(s10, nullptr), 1145f757f3fSDimitry Andric DEFINE_REGISTER_STUB(s11, nullptr), 1155f757f3fSDimitry Andric DEFINE_REGISTER_STUB(t3, nullptr), 1165f757f3fSDimitry Andric DEFINE_REGISTER_STUB(t4, nullptr), 1175f757f3fSDimitry Andric DEFINE_REGISTER_STUB(t5, nullptr), 1185f757f3fSDimitry Andric DEFINE_REGISTER_STUB(t6, nullptr), 1195f757f3fSDimitry Andric DEFINE_GENERIC_REGISTER_STUB(pc, nullptr, LLDB_REGNUM_GENERIC_PC)}}; 1205f757f3fSDimitry Andric } // namespace dwarf 1215f757f3fSDimitry Andric } // namespace 1225f757f3fSDimitry Andric 1235f757f3fSDimitry Andric const RegisterInfo *ABISysV_riscv::GetRegisterInfoArray(uint32_t &count) { 1245f757f3fSDimitry Andric count = dwarf::g_register_infos.size(); 1255f757f3fSDimitry Andric return dwarf::g_register_infos.data(); 1265f757f3fSDimitry Andric } 1275f757f3fSDimitry Andric 1285f757f3fSDimitry Andric //------------------------------------------------------------------ 1295f757f3fSDimitry Andric // Static Functions 1305f757f3fSDimitry Andric //------------------------------------------------------------------ 1315f757f3fSDimitry Andric 1325f757f3fSDimitry Andric ABISP 1335f757f3fSDimitry Andric ABISysV_riscv::CreateInstance(ProcessSP process_sp, const ArchSpec &arch) { 1345f757f3fSDimitry Andric llvm::Triple::ArchType machine = arch.GetTriple().getArch(); 1355f757f3fSDimitry Andric 1365f757f3fSDimitry Andric if (llvm::Triple::riscv32 != machine && llvm::Triple::riscv64 != machine) 1375f757f3fSDimitry Andric return ABISP(); 1385f757f3fSDimitry Andric 1395f757f3fSDimitry Andric ABISysV_riscv *abi = new ABISysV_riscv(std::move(process_sp), 1405f757f3fSDimitry Andric MakeMCRegisterInfo(arch)); 1415f757f3fSDimitry Andric if (abi) 1425f757f3fSDimitry Andric abi->SetIsRV64((llvm::Triple::riscv64 == machine) ? true : false); 1435f757f3fSDimitry Andric return ABISP(abi); 1445f757f3fSDimitry Andric } 1455f757f3fSDimitry Andric 1465f757f3fSDimitry Andric static inline size_t AugmentArgSize(bool is_rv64, size_t size_in_bytes) { 1475f757f3fSDimitry Andric size_t word_size = is_rv64 ? 8 : 4; 1485f757f3fSDimitry Andric return llvm::alignTo(size_in_bytes, word_size); 1495f757f3fSDimitry Andric } 1505f757f3fSDimitry Andric 1515f757f3fSDimitry Andric static size_t 1525f757f3fSDimitry Andric TotalArgsSizeInWords(bool is_rv64, 1535f757f3fSDimitry Andric const llvm::ArrayRef<ABI::CallArgument> &args) { 1545f757f3fSDimitry Andric size_t reg_size = is_rv64 ? 8 : 4; 1555f757f3fSDimitry Andric size_t word_size = reg_size; 1565f757f3fSDimitry Andric size_t total_size = 0; 1575f757f3fSDimitry Andric for (const auto &arg : args) 1585f757f3fSDimitry Andric total_size += 1595f757f3fSDimitry Andric (ABI::CallArgument::TargetValue == arg.type ? AugmentArgSize(is_rv64, 1605f757f3fSDimitry Andric arg.size) 1615f757f3fSDimitry Andric : reg_size) / 1625f757f3fSDimitry Andric word_size; 1635f757f3fSDimitry Andric 1645f757f3fSDimitry Andric return total_size; 1655f757f3fSDimitry Andric } 1665f757f3fSDimitry Andric 1675f757f3fSDimitry Andric bool ABISysV_riscv::PrepareTrivialCall(Thread &thread, addr_t sp, 1685f757f3fSDimitry Andric addr_t func_addr, addr_t return_addr, 1695f757f3fSDimitry Andric llvm::ArrayRef<addr_t> args) const { 1705f757f3fSDimitry Andric // TODO: Implement 1715f757f3fSDimitry Andric return false; 1725f757f3fSDimitry Andric } 1735f757f3fSDimitry Andric 1745f757f3fSDimitry Andric bool ABISysV_riscv::PrepareTrivialCall( 1755f757f3fSDimitry Andric Thread &thread, addr_t sp, addr_t pc, addr_t ra, llvm::Type &prototype, 1765f757f3fSDimitry Andric llvm::ArrayRef<ABI::CallArgument> args) const { 1775f757f3fSDimitry Andric auto reg_ctx = thread.GetRegisterContext(); 1785f757f3fSDimitry Andric if (!reg_ctx) 1795f757f3fSDimitry Andric return false; 1805f757f3fSDimitry Andric 1815f757f3fSDimitry Andric uint32_t pc_reg = reg_ctx->ConvertRegisterKindToRegisterNumber( 1825f757f3fSDimitry Andric eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); 1835f757f3fSDimitry Andric if (pc_reg == LLDB_INVALID_REGNUM) 1845f757f3fSDimitry Andric return false; 1855f757f3fSDimitry Andric 1865f757f3fSDimitry Andric uint32_t ra_reg = reg_ctx->ConvertRegisterKindToRegisterNumber( 1875f757f3fSDimitry Andric eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA); 1885f757f3fSDimitry Andric if (ra_reg == LLDB_INVALID_REGNUM) 1895f757f3fSDimitry Andric return false; 1905f757f3fSDimitry Andric 1915f757f3fSDimitry Andric uint32_t sp_reg = reg_ctx->ConvertRegisterKindToRegisterNumber( 1925f757f3fSDimitry Andric eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); 1935f757f3fSDimitry Andric if (sp_reg == LLDB_INVALID_REGNUM) 1945f757f3fSDimitry Andric return false; 1955f757f3fSDimitry Andric 1965f757f3fSDimitry Andric Status error; 1975f757f3fSDimitry Andric ProcessSP process = thread.GetProcess(); 1985f757f3fSDimitry Andric if (!process) 1995f757f3fSDimitry Andric return false; 2005f757f3fSDimitry Andric 2015f757f3fSDimitry Andric size_t reg_size = m_is_rv64 ? 8 : 4; 2025f757f3fSDimitry Andric size_t word_size = reg_size; 2035f757f3fSDimitry Andric // Push host data onto target. 2045f757f3fSDimitry Andric for (const auto &arg : args) { 2055f757f3fSDimitry Andric // Skip over target values. 2065f757f3fSDimitry Andric if (arg.type == ABI::CallArgument::TargetValue) 2075f757f3fSDimitry Andric continue; 2085f757f3fSDimitry Andric 2095f757f3fSDimitry Andric // Create space on the host stack for this data 4-byte aligned. 2105f757f3fSDimitry Andric sp -= AugmentArgSize(m_is_rv64, arg.size); 2115f757f3fSDimitry Andric 2125f757f3fSDimitry Andric if (process->WriteMemory(sp, arg.data_up.get(), arg.size, error) < 2135f757f3fSDimitry Andric arg.size || 2145f757f3fSDimitry Andric error.Fail()) 2155f757f3fSDimitry Andric return false; 2165f757f3fSDimitry Andric 2175f757f3fSDimitry Andric // Update the argument with the target pointer. 2185f757f3fSDimitry Andric *const_cast<addr_t *>(&arg.value) = sp; 2195f757f3fSDimitry Andric } 2205f757f3fSDimitry Andric 2215f757f3fSDimitry Andric // Make sure number of parameters matches prototype. 2225f757f3fSDimitry Andric assert(prototype.getFunctionNumParams() == args.size()); 2235f757f3fSDimitry Andric 2245f757f3fSDimitry Andric const size_t num_args = args.size(); 2255f757f3fSDimitry Andric const size_t regs_for_args_count = 8U; 2265f757f3fSDimitry Andric const size_t num_args_in_regs = 2275f757f3fSDimitry Andric num_args > regs_for_args_count ? regs_for_args_count : num_args; 2285f757f3fSDimitry Andric 2295f757f3fSDimitry Andric // Number of arguments passed on stack. 2305f757f3fSDimitry Andric size_t args_size = TotalArgsSizeInWords(m_is_rv64, args); 2315f757f3fSDimitry Andric auto on_stack = 2325f757f3fSDimitry Andric args_size <= regs_for_args_count ? 0 : args_size - regs_for_args_count; 2335f757f3fSDimitry Andric auto offset = on_stack * word_size; 2345f757f3fSDimitry Andric 2355f757f3fSDimitry Andric uint8_t reg_value[8]; 2365f757f3fSDimitry Andric size_t reg_index = LLDB_REGNUM_GENERIC_ARG1; 2375f757f3fSDimitry Andric 2385f757f3fSDimitry Andric for (size_t i = 0; i < args_size; ++i) { 2395f757f3fSDimitry Andric auto value = reinterpret_cast<const uint8_t *>(&args[i].value); 2405f757f3fSDimitry Andric auto size = 2415f757f3fSDimitry Andric ABI::CallArgument::TargetValue == args[i].type ? args[i].size : reg_size; 2425f757f3fSDimitry Andric 2435f757f3fSDimitry Andric // Pass arguments via registers. 2445f757f3fSDimitry Andric if (i < num_args_in_regs) { 2455f757f3fSDimitry Andric // copy value to register, padding if arg is smaller than register 2465f757f3fSDimitry Andric auto end = size < reg_size ? size : reg_size; 2475f757f3fSDimitry Andric memcpy(reg_value, value, end); 2485f757f3fSDimitry Andric if (reg_size > end) 2495f757f3fSDimitry Andric memset(reg_value + end, 0, reg_size - end); 2505f757f3fSDimitry Andric 2515f757f3fSDimitry Andric RegisterValue reg_val_obj(llvm::ArrayRef(reg_value, reg_size), 2525f757f3fSDimitry Andric eByteOrderLittle); 2535f757f3fSDimitry Andric if (!reg_ctx->WriteRegister( 2545f757f3fSDimitry Andric reg_ctx->GetRegisterInfo(eRegisterKindGeneric, reg_index), 2555f757f3fSDimitry Andric reg_val_obj)) 2565f757f3fSDimitry Andric return false; 2575f757f3fSDimitry Andric 2585f757f3fSDimitry Andric // NOTE: It's unsafe to iterate through LLDB_REGNUM_GENERICs 2595f757f3fSDimitry Andric // But the "a" registers are sequential in the RISC-V register space 2605f757f3fSDimitry Andric ++reg_index; 2615f757f3fSDimitry Andric } 2625f757f3fSDimitry Andric 2635f757f3fSDimitry Andric if (reg_index < regs_for_args_count || size == 0) 2645f757f3fSDimitry Andric continue; 2655f757f3fSDimitry Andric 2665f757f3fSDimitry Andric // Remaining arguments are passed on the stack. 2675f757f3fSDimitry Andric if (process->WriteMemory(sp - offset, value, size, error) < size || 2685f757f3fSDimitry Andric !error.Success()) 2695f757f3fSDimitry Andric return false; 2705f757f3fSDimitry Andric 2715f757f3fSDimitry Andric offset -= AugmentArgSize(m_is_rv64, size); 2725f757f3fSDimitry Andric } 2735f757f3fSDimitry Andric 2745f757f3fSDimitry Andric // Set stack pointer immediately below arguments. 2755f757f3fSDimitry Andric sp -= on_stack * word_size; 2765f757f3fSDimitry Andric 2775f757f3fSDimitry Andric // Update registers with current function call state. 2785f757f3fSDimitry Andric reg_ctx->WriteRegisterFromUnsigned(pc_reg, pc); 2795f757f3fSDimitry Andric reg_ctx->WriteRegisterFromUnsigned(ra_reg, ra); 2805f757f3fSDimitry Andric reg_ctx->WriteRegisterFromUnsigned(sp_reg, sp); 2815f757f3fSDimitry Andric 2825f757f3fSDimitry Andric return true; 2835f757f3fSDimitry Andric } 2845f757f3fSDimitry Andric 2855f757f3fSDimitry Andric bool ABISysV_riscv::GetArgumentValues(Thread &thread, ValueList &values) const { 2865f757f3fSDimitry Andric // TODO: Implement 2875f757f3fSDimitry Andric return false; 2885f757f3fSDimitry Andric } 2895f757f3fSDimitry Andric 2905f757f3fSDimitry Andric Status ABISysV_riscv::SetReturnValueObject(StackFrameSP &frame_sp, 2915f757f3fSDimitry Andric ValueObjectSP &new_value_sp) { 2925f757f3fSDimitry Andric Status result; 2935f757f3fSDimitry Andric if (!new_value_sp) { 2945f757f3fSDimitry Andric result.SetErrorString("Empty value object for return value."); 2955f757f3fSDimitry Andric return result; 2965f757f3fSDimitry Andric } 2975f757f3fSDimitry Andric 2985f757f3fSDimitry Andric CompilerType compiler_type = new_value_sp->GetCompilerType(); 2995f757f3fSDimitry Andric if (!compiler_type) { 3005f757f3fSDimitry Andric result.SetErrorString("Null clang type for return value."); 3015f757f3fSDimitry Andric return result; 3025f757f3fSDimitry Andric } 3035f757f3fSDimitry Andric 3045f757f3fSDimitry Andric auto ®_ctx = *frame_sp->GetThread()->GetRegisterContext(); 3055f757f3fSDimitry Andric 3065f757f3fSDimitry Andric bool is_signed = false; 3075f757f3fSDimitry Andric if (!compiler_type.IsIntegerOrEnumerationType(is_signed) && 3085f757f3fSDimitry Andric !compiler_type.IsPointerType()) { 3095f757f3fSDimitry Andric result.SetErrorString("We don't support returning other types at present"); 3105f757f3fSDimitry Andric return result; 3115f757f3fSDimitry Andric } 3125f757f3fSDimitry Andric 3135f757f3fSDimitry Andric DataExtractor data; 3145f757f3fSDimitry Andric size_t num_bytes = new_value_sp->GetData(data, result); 3155f757f3fSDimitry Andric 3165f757f3fSDimitry Andric if (result.Fail()) { 3175f757f3fSDimitry Andric result.SetErrorStringWithFormat( 3185f757f3fSDimitry Andric "Couldn't convert return value to raw data: %s", result.AsCString()); 3195f757f3fSDimitry Andric return result; 3205f757f3fSDimitry Andric } 3215f757f3fSDimitry Andric 3225f757f3fSDimitry Andric size_t reg_size = m_is_rv64 ? 8 : 4; 3235f757f3fSDimitry Andric if (num_bytes <= 2 * reg_size) { 3245f757f3fSDimitry Andric offset_t offset = 0; 3255f757f3fSDimitry Andric uint64_t raw_value = data.GetMaxU64(&offset, num_bytes); 3265f757f3fSDimitry Andric 3275f757f3fSDimitry Andric auto reg_info = 3285f757f3fSDimitry Andric reg_ctx.GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1); 3295f757f3fSDimitry Andric if (!reg_ctx.WriteRegisterFromUnsigned(reg_info, raw_value)) { 3305f757f3fSDimitry Andric result.SetErrorStringWithFormat("Couldn't write value to register %s", 3315f757f3fSDimitry Andric reg_info->name); 3325f757f3fSDimitry Andric return result; 3335f757f3fSDimitry Andric } 3345f757f3fSDimitry Andric 3355f757f3fSDimitry Andric if (num_bytes <= reg_size) 3365f757f3fSDimitry Andric return result; // Successfully written. 3375f757f3fSDimitry Andric 3385f757f3fSDimitry Andric // for riscv32, get the upper 32 bits from raw_value and write them 3395f757f3fSDimitry Andric // for riscv64, get the next 64 bits from data and write them 3405f757f3fSDimitry Andric if (4 == reg_size) 3415f757f3fSDimitry Andric raw_value >>= 32; 3425f757f3fSDimitry Andric else 3435f757f3fSDimitry Andric raw_value = data.GetMaxU64(&offset, num_bytes - reg_size); 3445f757f3fSDimitry Andric reg_info = 3455f757f3fSDimitry Andric reg_ctx.GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG2); 3465f757f3fSDimitry Andric if (!reg_ctx.WriteRegisterFromUnsigned(reg_info, raw_value)) { 3475f757f3fSDimitry Andric result.SetErrorStringWithFormat("Couldn't write value to register %s", 3485f757f3fSDimitry Andric reg_info->name); 3495f757f3fSDimitry Andric } 3505f757f3fSDimitry Andric 3515f757f3fSDimitry Andric return result; 3525f757f3fSDimitry Andric } 3535f757f3fSDimitry Andric 3545f757f3fSDimitry Andric result.SetErrorString( 3555f757f3fSDimitry Andric "We don't support returning large integer values at present."); 3565f757f3fSDimitry Andric return result; 3575f757f3fSDimitry Andric } 3585f757f3fSDimitry Andric 3595f757f3fSDimitry Andric template <typename T> 3605f757f3fSDimitry Andric static void SetInteger(Scalar &scalar, uint64_t raw_value, bool is_signed) { 3615f757f3fSDimitry Andric raw_value &= std::numeric_limits<T>::max(); 3625f757f3fSDimitry Andric if (is_signed) 3635f757f3fSDimitry Andric scalar = static_cast<typename std::make_signed<T>::type>(raw_value); 3645f757f3fSDimitry Andric else 3655f757f3fSDimitry Andric scalar = static_cast<T>(raw_value); 3665f757f3fSDimitry Andric } 3675f757f3fSDimitry Andric 3685f757f3fSDimitry Andric static bool SetSizedInteger(Scalar &scalar, uint64_t raw_value, 3695f757f3fSDimitry Andric uint8_t size_in_bytes, bool is_signed) { 3705f757f3fSDimitry Andric switch (size_in_bytes) { 3715f757f3fSDimitry Andric default: 3725f757f3fSDimitry Andric return false; 3735f757f3fSDimitry Andric 3745f757f3fSDimitry Andric case sizeof(uint64_t): 3755f757f3fSDimitry Andric SetInteger<uint64_t>(scalar, raw_value, is_signed); 3765f757f3fSDimitry Andric break; 3775f757f3fSDimitry Andric 3785f757f3fSDimitry Andric case sizeof(uint32_t): 3795f757f3fSDimitry Andric SetInteger<uint32_t>(scalar, raw_value, is_signed); 3805f757f3fSDimitry Andric break; 3815f757f3fSDimitry Andric 3825f757f3fSDimitry Andric case sizeof(uint16_t): 3835f757f3fSDimitry Andric SetInteger<uint16_t>(scalar, raw_value, is_signed); 3845f757f3fSDimitry Andric break; 3855f757f3fSDimitry Andric 3865f757f3fSDimitry Andric case sizeof(uint8_t): 3875f757f3fSDimitry Andric SetInteger<uint8_t>(scalar, raw_value, is_signed); 3885f757f3fSDimitry Andric break; 3895f757f3fSDimitry Andric } 3905f757f3fSDimitry Andric 3915f757f3fSDimitry Andric return true; 3925f757f3fSDimitry Andric } 3935f757f3fSDimitry Andric 3945f757f3fSDimitry Andric static bool SetSizedFloat(Scalar &scalar, uint64_t raw_value, 3955f757f3fSDimitry Andric uint8_t size_in_bytes) { 3965f757f3fSDimitry Andric switch (size_in_bytes) { 3975f757f3fSDimitry Andric default: 3985f757f3fSDimitry Andric return false; 3995f757f3fSDimitry Andric 4005f757f3fSDimitry Andric case sizeof(uint64_t): 4015f757f3fSDimitry Andric scalar = *reinterpret_cast<double *>(&raw_value); 4025f757f3fSDimitry Andric break; 4035f757f3fSDimitry Andric 4045f757f3fSDimitry Andric case sizeof(uint32_t): 4055f757f3fSDimitry Andric scalar = *reinterpret_cast<float *>(&raw_value); 4065f757f3fSDimitry Andric break; 4075f757f3fSDimitry Andric } 4085f757f3fSDimitry Andric 4095f757f3fSDimitry Andric return true; 4105f757f3fSDimitry Andric } 4115f757f3fSDimitry Andric 4125f757f3fSDimitry Andric static ValueObjectSP GetValObjFromIntRegs(Thread &thread, 4135f757f3fSDimitry Andric const RegisterContextSP ®_ctx, 4145f757f3fSDimitry Andric llvm::Triple::ArchType machine, 4155f757f3fSDimitry Andric uint32_t type_flags, 4165f757f3fSDimitry Andric uint32_t byte_size) { 4175f757f3fSDimitry Andric Value value; 4185f757f3fSDimitry Andric ValueObjectSP return_valobj_sp; 4195f757f3fSDimitry Andric auto reg_info_a0 = 4205f757f3fSDimitry Andric reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1); 4215f757f3fSDimitry Andric auto reg_info_a1 = 4225f757f3fSDimitry Andric reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG2); 4235f757f3fSDimitry Andric uint64_t raw_value; 4245f757f3fSDimitry Andric 4255f757f3fSDimitry Andric switch (byte_size) { 4265f757f3fSDimitry Andric case sizeof(uint32_t): 4275f757f3fSDimitry Andric // Read a0 to get the arg 4285f757f3fSDimitry Andric raw_value = reg_ctx->ReadRegisterAsUnsigned(reg_info_a0, 0) & UINT32_MAX; 4295f757f3fSDimitry Andric break; 4305f757f3fSDimitry Andric case sizeof(uint64_t): 4315f757f3fSDimitry Andric // Read a0 to get the arg on riscv64, a0 and a1 on riscv32 4325f757f3fSDimitry Andric if (llvm::Triple::riscv32 == machine) { 4335f757f3fSDimitry Andric raw_value = reg_ctx->ReadRegisterAsUnsigned(reg_info_a0, 0) & UINT32_MAX; 4345f757f3fSDimitry Andric raw_value |= 4355f757f3fSDimitry Andric (reg_ctx->ReadRegisterAsUnsigned(reg_info_a1, 0) & UINT32_MAX) << 32U; 4365f757f3fSDimitry Andric } else { 4375f757f3fSDimitry Andric raw_value = reg_ctx->ReadRegisterAsUnsigned(reg_info_a0, 0); 4385f757f3fSDimitry Andric } 4395f757f3fSDimitry Andric break; 4405f757f3fSDimitry Andric case 16: { 4415f757f3fSDimitry Andric // Read a0 and a1 to get the arg on riscv64, not supported on riscv32 4425f757f3fSDimitry Andric if (llvm::Triple::riscv32 == machine) 4435f757f3fSDimitry Andric return return_valobj_sp; 4445f757f3fSDimitry Andric 4455f757f3fSDimitry Andric // Create the ValueObjectSP here and return 4465f757f3fSDimitry Andric std::unique_ptr<DataBufferHeap> heap_data_up( 4475f757f3fSDimitry Andric new DataBufferHeap(byte_size, 0)); 4485f757f3fSDimitry Andric const ByteOrder byte_order = thread.GetProcess()->GetByteOrder(); 4495f757f3fSDimitry Andric RegisterValue reg_value_a0, reg_value_a1; 4505f757f3fSDimitry Andric if (reg_ctx->ReadRegister(reg_info_a0, reg_value_a0) && 4515f757f3fSDimitry Andric reg_ctx->ReadRegister(reg_info_a1, reg_value_a1)) { 4525f757f3fSDimitry Andric Status error; 4535f757f3fSDimitry Andric if (reg_value_a0.GetAsMemoryData(*reg_info_a0, 4545f757f3fSDimitry Andric heap_data_up->GetBytes() + 0, 8, 4555f757f3fSDimitry Andric byte_order, error) && 4565f757f3fSDimitry Andric reg_value_a1.GetAsMemoryData(*reg_info_a1, 4575f757f3fSDimitry Andric heap_data_up->GetBytes() + 8, 8, 4585f757f3fSDimitry Andric byte_order, error)) { 4595f757f3fSDimitry Andric value.SetBytes(heap_data_up.release(), byte_size); 4605f757f3fSDimitry Andric return ValueObjectConstResult::Create( 4615f757f3fSDimitry Andric thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); 4625f757f3fSDimitry Andric } 4635f757f3fSDimitry Andric } 4645f757f3fSDimitry Andric break; 4655f757f3fSDimitry Andric } 4665f757f3fSDimitry Andric default: 4675f757f3fSDimitry Andric return return_valobj_sp; 4685f757f3fSDimitry Andric } 4695f757f3fSDimitry Andric 4705f757f3fSDimitry Andric if (type_flags & eTypeIsInteger) { 4715f757f3fSDimitry Andric const bool is_signed = (type_flags & eTypeIsSigned) != 0; 4725f757f3fSDimitry Andric if (!SetSizedInteger(value.GetScalar(), raw_value, byte_size, is_signed)) 4735f757f3fSDimitry Andric return return_valobj_sp; 4745f757f3fSDimitry Andric } else if (type_flags & eTypeIsFloat) { 4755f757f3fSDimitry Andric if (!SetSizedFloat(value.GetScalar(), raw_value, byte_size)) 4765f757f3fSDimitry Andric return return_valobj_sp; 4775f757f3fSDimitry Andric } else 4785f757f3fSDimitry Andric return return_valobj_sp; 4795f757f3fSDimitry Andric 4805f757f3fSDimitry Andric value.SetValueType(Value::ValueType::Scalar); 4815f757f3fSDimitry Andric return_valobj_sp = ValueObjectConstResult::Create( 4825f757f3fSDimitry Andric thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); 4835f757f3fSDimitry Andric return return_valobj_sp; 4845f757f3fSDimitry Andric } 4855f757f3fSDimitry Andric 4865f757f3fSDimitry Andric static ValueObjectSP 4875f757f3fSDimitry Andric GetValObjFromFPRegs(Thread &thread, const RegisterContextSP ®_ctx, 4885f757f3fSDimitry Andric llvm::Triple::ArchType machine, uint32_t arch_fp_flags, 4895f757f3fSDimitry Andric uint32_t type_flags, uint32_t byte_size) { 4905f757f3fSDimitry Andric auto reg_info_fa0 = reg_ctx->GetRegisterInfoByName("fa0"); 4915f757f3fSDimitry Andric bool use_fp_regs = false; 4925f757f3fSDimitry Andric ValueObjectSP return_valobj_sp; 4935f757f3fSDimitry Andric 4945f757f3fSDimitry Andric switch (arch_fp_flags) { 4955f757f3fSDimitry Andric // fp return value in integer registers a0 and possibly a1 4965f757f3fSDimitry Andric case ArchSpec::eRISCV_float_abi_soft: 4975f757f3fSDimitry Andric return_valobj_sp = 4985f757f3fSDimitry Andric GetValObjFromIntRegs(thread, reg_ctx, machine, type_flags, byte_size); 4995f757f3fSDimitry Andric return return_valobj_sp; 5005f757f3fSDimitry Andric // fp return value in fp register fa0 (only float) 5015f757f3fSDimitry Andric case ArchSpec::eRISCV_float_abi_single: 5025f757f3fSDimitry Andric if (byte_size <= 4) 5035f757f3fSDimitry Andric use_fp_regs = true; 5045f757f3fSDimitry Andric break; 5055f757f3fSDimitry Andric // fp return value in fp registers fa0 (float, double) 5065f757f3fSDimitry Andric case ArchSpec::eRISCV_float_abi_double: 5075f757f3fSDimitry Andric [[fallthrough]]; 5085f757f3fSDimitry Andric // fp return value in fp registers fa0 (float, double, quad) 5095f757f3fSDimitry Andric // not implemented; act like they're doubles 5105f757f3fSDimitry Andric case ArchSpec::eRISCV_float_abi_quad: 5115f757f3fSDimitry Andric if (byte_size <= 8) 5125f757f3fSDimitry Andric use_fp_regs = true; 5135f757f3fSDimitry Andric break; 5145f757f3fSDimitry Andric } 5155f757f3fSDimitry Andric 5165f757f3fSDimitry Andric if (use_fp_regs) { 5175f757f3fSDimitry Andric uint64_t raw_value; 5185f757f3fSDimitry Andric Value value; 5195f757f3fSDimitry Andric raw_value = reg_ctx->ReadRegisterAsUnsigned(reg_info_fa0, 0); 5205f757f3fSDimitry Andric if (!SetSizedFloat(value.GetScalar(), raw_value, byte_size)) 5215f757f3fSDimitry Andric return return_valobj_sp; 5225f757f3fSDimitry Andric value.SetValueType(Value::ValueType::Scalar); 5235f757f3fSDimitry Andric return ValueObjectConstResult::Create(thread.GetStackFrameAtIndex(0).get(), 5245f757f3fSDimitry Andric value, ConstString("")); 5255f757f3fSDimitry Andric } 5265f757f3fSDimitry Andric // we should never reach this, but if we do, use the integer registers 5275f757f3fSDimitry Andric return GetValObjFromIntRegs(thread, reg_ctx, machine, type_flags, byte_size); 5285f757f3fSDimitry Andric } 5295f757f3fSDimitry Andric 5305f757f3fSDimitry Andric ValueObjectSP 5315f757f3fSDimitry Andric ABISysV_riscv::GetReturnValueObjectSimple(Thread &thread, 5325f757f3fSDimitry Andric CompilerType &compiler_type) const { 5335f757f3fSDimitry Andric ValueObjectSP return_valobj_sp; 5345f757f3fSDimitry Andric 5355f757f3fSDimitry Andric if (!compiler_type) 5365f757f3fSDimitry Andric return return_valobj_sp; 5375f757f3fSDimitry Andric 5385f757f3fSDimitry Andric auto reg_ctx = thread.GetRegisterContext(); 5395f757f3fSDimitry Andric if (!reg_ctx) 5405f757f3fSDimitry Andric return return_valobj_sp; 5415f757f3fSDimitry Andric 5425f757f3fSDimitry Andric Value value; 5435f757f3fSDimitry Andric value.SetCompilerType(compiler_type); 5445f757f3fSDimitry Andric 5455f757f3fSDimitry Andric const uint32_t type_flags = compiler_type.GetTypeInfo(); 5465f757f3fSDimitry Andric const size_t byte_size = compiler_type.GetByteSize(&thread).value_or(0); 5475f757f3fSDimitry Andric const ArchSpec arch = thread.GetProcess()->GetTarget().GetArchitecture(); 5485f757f3fSDimitry Andric const llvm::Triple::ArchType machine = arch.GetMachine(); 5495f757f3fSDimitry Andric 5505f757f3fSDimitry Andric // Integer return type. 5515f757f3fSDimitry Andric if (type_flags & eTypeIsInteger) { 5525f757f3fSDimitry Andric return_valobj_sp = 5535f757f3fSDimitry Andric GetValObjFromIntRegs(thread, reg_ctx, machine, type_flags, byte_size); 5545f757f3fSDimitry Andric return return_valobj_sp; 5555f757f3fSDimitry Andric } 5565f757f3fSDimitry Andric // Pointer return type. 5575f757f3fSDimitry Andric else if (type_flags & eTypeIsPointer) { 5585f757f3fSDimitry Andric auto reg_info_a0 = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, 5595f757f3fSDimitry Andric LLDB_REGNUM_GENERIC_ARG1); 5605f757f3fSDimitry Andric value.GetScalar() = reg_ctx->ReadRegisterAsUnsigned(reg_info_a0, 0); 5615f757f3fSDimitry Andric value.SetValueType(Value::ValueType::Scalar); 5625f757f3fSDimitry Andric return ValueObjectConstResult::Create(thread.GetStackFrameAtIndex(0).get(), 5635f757f3fSDimitry Andric value, ConstString("")); 5645f757f3fSDimitry Andric } 5655f757f3fSDimitry Andric // Floating point return type. 5665f757f3fSDimitry Andric else if (type_flags & eTypeIsFloat) { 5675f757f3fSDimitry Andric uint32_t float_count = 0; 5685f757f3fSDimitry Andric bool is_complex = false; 5695f757f3fSDimitry Andric 5705f757f3fSDimitry Andric if (compiler_type.IsFloatingPointType(float_count, is_complex) && 5715f757f3fSDimitry Andric float_count == 1 && !is_complex) { 5725f757f3fSDimitry Andric const uint32_t arch_fp_flags = 5735f757f3fSDimitry Andric arch.GetFlags() & ArchSpec::eRISCV_float_abi_mask; 5745f757f3fSDimitry Andric return_valobj_sp = GetValObjFromFPRegs( 5755f757f3fSDimitry Andric thread, reg_ctx, machine, arch_fp_flags, type_flags, byte_size); 5765f757f3fSDimitry Andric return return_valobj_sp; 5775f757f3fSDimitry Andric } 5785f757f3fSDimitry Andric } 5795f757f3fSDimitry Andric // Unsupported return type. 5805f757f3fSDimitry Andric return return_valobj_sp; 5815f757f3fSDimitry Andric } 5825f757f3fSDimitry Andric 5835f757f3fSDimitry Andric ValueObjectSP 5845f757f3fSDimitry Andric ABISysV_riscv::GetReturnValueObjectImpl(lldb_private::Thread &thread, 5855f757f3fSDimitry Andric llvm::Type &type) const { 5865f757f3fSDimitry Andric Value value; 5875f757f3fSDimitry Andric ValueObjectSP return_valobj_sp; 5885f757f3fSDimitry Andric 5895f757f3fSDimitry Andric auto reg_ctx = thread.GetRegisterContext(); 5905f757f3fSDimitry Andric if (!reg_ctx) 5915f757f3fSDimitry Andric return return_valobj_sp; 5925f757f3fSDimitry Andric 5935f757f3fSDimitry Andric uint32_t type_flags = 0; 5945f757f3fSDimitry Andric if (type.isIntegerTy()) 5955f757f3fSDimitry Andric type_flags = eTypeIsInteger; 5965f757f3fSDimitry Andric else if (type.isVoidTy()) 5975f757f3fSDimitry Andric type_flags = eTypeIsPointer; 5985f757f3fSDimitry Andric else if (type.isFloatTy()) 5995f757f3fSDimitry Andric type_flags = eTypeIsFloat; 6005f757f3fSDimitry Andric 6015f757f3fSDimitry Andric const uint32_t byte_size = type.getPrimitiveSizeInBits() / CHAR_BIT; 6025f757f3fSDimitry Andric const ArchSpec arch = thread.GetProcess()->GetTarget().GetArchitecture(); 6035f757f3fSDimitry Andric const llvm::Triple::ArchType machine = arch.GetMachine(); 6045f757f3fSDimitry Andric 6055f757f3fSDimitry Andric // Integer return type. 6065f757f3fSDimitry Andric if (type_flags & eTypeIsInteger) { 6075f757f3fSDimitry Andric return_valobj_sp = 6085f757f3fSDimitry Andric GetValObjFromIntRegs(thread, reg_ctx, machine, type_flags, byte_size); 6095f757f3fSDimitry Andric return return_valobj_sp; 6105f757f3fSDimitry Andric } 6115f757f3fSDimitry Andric // Pointer return type. 6125f757f3fSDimitry Andric else if (type_flags & eTypeIsPointer) { 6135f757f3fSDimitry Andric auto reg_info_a0 = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, 6145f757f3fSDimitry Andric LLDB_REGNUM_GENERIC_ARG1); 6155f757f3fSDimitry Andric value.GetScalar() = reg_ctx->ReadRegisterAsUnsigned(reg_info_a0, 0); 6165f757f3fSDimitry Andric value.SetValueType(Value::ValueType::Scalar); 6175f757f3fSDimitry Andric return ValueObjectConstResult::Create(thread.GetStackFrameAtIndex(0).get(), 6185f757f3fSDimitry Andric value, ConstString("")); 6195f757f3fSDimitry Andric } 6205f757f3fSDimitry Andric // Floating point return type. 6215f757f3fSDimitry Andric else if (type_flags & eTypeIsFloat) { 6225f757f3fSDimitry Andric const uint32_t arch_fp_flags = 6235f757f3fSDimitry Andric arch.GetFlags() & ArchSpec::eRISCV_float_abi_mask; 6245f757f3fSDimitry Andric return_valobj_sp = GetValObjFromFPRegs( 6255f757f3fSDimitry Andric thread, reg_ctx, machine, arch_fp_flags, type_flags, byte_size); 6265f757f3fSDimitry Andric return return_valobj_sp; 6275f757f3fSDimitry Andric } 6285f757f3fSDimitry Andric // Unsupported return type. 6295f757f3fSDimitry Andric return return_valobj_sp; 6305f757f3fSDimitry Andric } 6315f757f3fSDimitry Andric 6325f757f3fSDimitry Andric ValueObjectSP ABISysV_riscv::GetReturnValueObjectImpl( 6335f757f3fSDimitry Andric Thread &thread, CompilerType &return_compiler_type) const { 6345f757f3fSDimitry Andric ValueObjectSP return_valobj_sp; 6355f757f3fSDimitry Andric 6365f757f3fSDimitry Andric if (!return_compiler_type) 6375f757f3fSDimitry Andric return return_valobj_sp; 6385f757f3fSDimitry Andric 6395f757f3fSDimitry Andric ExecutionContext exe_ctx(thread.shared_from_this()); 6405f757f3fSDimitry Andric return GetReturnValueObjectSimple(thread, return_compiler_type); 6415f757f3fSDimitry Andric } 6425f757f3fSDimitry Andric 6435f757f3fSDimitry Andric bool ABISysV_riscv::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) { 6445f757f3fSDimitry Andric unwind_plan.Clear(); 6455f757f3fSDimitry Andric unwind_plan.SetRegisterKind(eRegisterKindDWARF); 6465f757f3fSDimitry Andric 647*0fca6ea1SDimitry Andric uint32_t pc_reg_num = riscv_dwarf::dwarf_gpr_pc; 648*0fca6ea1SDimitry Andric uint32_t sp_reg_num = riscv_dwarf::dwarf_gpr_sp; 649*0fca6ea1SDimitry Andric uint32_t ra_reg_num = riscv_dwarf::dwarf_gpr_ra; 6505f757f3fSDimitry Andric 6515f757f3fSDimitry Andric UnwindPlan::RowSP row(new UnwindPlan::Row); 6525f757f3fSDimitry Andric 6535f757f3fSDimitry Andric // Define CFA as the stack pointer 6545f757f3fSDimitry Andric row->GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 0); 6555f757f3fSDimitry Andric 6565f757f3fSDimitry Andric // Previous frame's pc is in ra 6575f757f3fSDimitry Andric 6585f757f3fSDimitry Andric row->SetRegisterLocationToRegister(pc_reg_num, ra_reg_num, true); 6595f757f3fSDimitry Andric unwind_plan.AppendRow(row); 6605f757f3fSDimitry Andric unwind_plan.SetSourceName("riscv function-entry unwind plan"); 6615f757f3fSDimitry Andric unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); 6625f757f3fSDimitry Andric 6635f757f3fSDimitry Andric return true; 6645f757f3fSDimitry Andric } 6655f757f3fSDimitry Andric 6665f757f3fSDimitry Andric bool ABISysV_riscv::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) { 6675f757f3fSDimitry Andric unwind_plan.Clear(); 6685f757f3fSDimitry Andric unwind_plan.SetRegisterKind(eRegisterKindGeneric); 6695f757f3fSDimitry Andric 6705f757f3fSDimitry Andric uint32_t pc_reg_num = LLDB_REGNUM_GENERIC_PC; 6715f757f3fSDimitry Andric uint32_t fp_reg_num = LLDB_REGNUM_GENERIC_FP; 6725f757f3fSDimitry Andric 6735f757f3fSDimitry Andric UnwindPlan::RowSP row(new UnwindPlan::Row); 6745f757f3fSDimitry Andric 6755f757f3fSDimitry Andric // Define the CFA as the current frame pointer value. 6765f757f3fSDimitry Andric row->GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 0); 6775f757f3fSDimitry Andric row->SetOffset(0); 6785f757f3fSDimitry Andric 6795f757f3fSDimitry Andric int reg_size = 4; 6805f757f3fSDimitry Andric if (m_is_rv64) 6815f757f3fSDimitry Andric reg_size = 8; 6825f757f3fSDimitry Andric 6835f757f3fSDimitry Andric // Assume the ra reg (return pc) and caller's frame pointer 6845f757f3fSDimitry Andric // have been spilled to stack already. 6855f757f3fSDimitry Andric row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, reg_size * -2, true); 6865f757f3fSDimitry Andric row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, reg_size * -1, true); 6875f757f3fSDimitry Andric 6885f757f3fSDimitry Andric unwind_plan.AppendRow(row); 6895f757f3fSDimitry Andric unwind_plan.SetSourceName("riscv default unwind plan"); 6905f757f3fSDimitry Andric unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); 6915f757f3fSDimitry Andric unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); 6925f757f3fSDimitry Andric return true; 6935f757f3fSDimitry Andric } 6945f757f3fSDimitry Andric 6955f757f3fSDimitry Andric bool ABISysV_riscv::RegisterIsVolatile(const RegisterInfo *reg_info) { 6965f757f3fSDimitry Andric return !RegisterIsCalleeSaved(reg_info); 6975f757f3fSDimitry Andric } 6985f757f3fSDimitry Andric 6995f757f3fSDimitry Andric bool ABISysV_riscv::RegisterIsCalleeSaved(const RegisterInfo *reg_info) { 7005f757f3fSDimitry Andric if (!reg_info) 7015f757f3fSDimitry Andric return false; 7025f757f3fSDimitry Andric 7035f757f3fSDimitry Andric const char *name = reg_info->name; 7045f757f3fSDimitry Andric ArchSpec arch = GetProcessSP()->GetTarget().GetArchitecture(); 7055f757f3fSDimitry Andric uint32_t arch_flags = arch.GetFlags(); 7065f757f3fSDimitry Andric // floating point registers are only callee saved when using 7075f757f3fSDimitry Andric // F, D or Q hardware floating point ABIs 7085f757f3fSDimitry Andric bool is_hw_fp = (arch_flags & ArchSpec::eRISCV_float_abi_mask) != 0; 7095f757f3fSDimitry Andric 7105f757f3fSDimitry Andric bool is_callee_saved = 7115f757f3fSDimitry Andric llvm::StringSwitch<bool>(name) 7125f757f3fSDimitry Andric // integer ABI names 7135f757f3fSDimitry Andric .Cases("ra", "sp", "fp", true) 7145f757f3fSDimitry Andric .Cases("s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", 7155f757f3fSDimitry Andric true) 7165f757f3fSDimitry Andric .Cases("s10", "s11", true) 7175f757f3fSDimitry Andric // integer hardware names 7185f757f3fSDimitry Andric .Cases("x1", "x2", "x8", "x9", "x18", "x19", "x20", "x21", "x22", 7195f757f3fSDimitry Andric true) 7205f757f3fSDimitry Andric .Cases("x23", "x24", "x25", "x26", "x27", true) 7215f757f3fSDimitry Andric // floating point ABI names 7225f757f3fSDimitry Andric .Cases("fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7", 7235f757f3fSDimitry Andric is_hw_fp) 7245f757f3fSDimitry Andric .Cases("fs8", "fs9", "fs10", "fs11", is_hw_fp) 7255f757f3fSDimitry Andric // floating point hardware names 7265f757f3fSDimitry Andric .Cases("f8", "f9", "f18", "f19", "f20", "f21", "f22", "f23", is_hw_fp) 7275f757f3fSDimitry Andric .Cases("f24", "f25", "f26", "f27", is_hw_fp) 7285f757f3fSDimitry Andric .Default(false); 7295f757f3fSDimitry Andric 7305f757f3fSDimitry Andric return is_callee_saved; 7315f757f3fSDimitry Andric } 7325f757f3fSDimitry Andric 7335f757f3fSDimitry Andric void ABISysV_riscv::Initialize() { 7345f757f3fSDimitry Andric PluginManager::RegisterPlugin( 7355f757f3fSDimitry Andric GetPluginNameStatic(), "System V ABI for RISCV targets", CreateInstance); 7365f757f3fSDimitry Andric } 7375f757f3fSDimitry Andric 7385f757f3fSDimitry Andric void ABISysV_riscv::Terminate() { 7395f757f3fSDimitry Andric PluginManager::UnregisterPlugin(CreateInstance); 7405f757f3fSDimitry Andric } 7415f757f3fSDimitry Andric 7425f757f3fSDimitry Andric static uint32_t GetGenericNum(llvm::StringRef name) { 7435f757f3fSDimitry Andric return llvm::StringSwitch<uint32_t>(name) 7445f757f3fSDimitry Andric .Case("pc", LLDB_REGNUM_GENERIC_PC) 7455f757f3fSDimitry Andric .Cases("ra", "x1", LLDB_REGNUM_GENERIC_RA) 7465f757f3fSDimitry Andric .Cases("sp", "x2", LLDB_REGNUM_GENERIC_SP) 7475f757f3fSDimitry Andric .Cases("fp", "s0", LLDB_REGNUM_GENERIC_FP) 7485f757f3fSDimitry Andric .Case("a0", LLDB_REGNUM_GENERIC_ARG1) 7495f757f3fSDimitry Andric .Case("a1", LLDB_REGNUM_GENERIC_ARG2) 7505f757f3fSDimitry Andric .Case("a2", LLDB_REGNUM_GENERIC_ARG3) 7515f757f3fSDimitry Andric .Case("a3", LLDB_REGNUM_GENERIC_ARG4) 7525f757f3fSDimitry Andric .Case("a4", LLDB_REGNUM_GENERIC_ARG5) 7535f757f3fSDimitry Andric .Case("a5", LLDB_REGNUM_GENERIC_ARG6) 7545f757f3fSDimitry Andric .Case("a6", LLDB_REGNUM_GENERIC_ARG7) 7555f757f3fSDimitry Andric .Case("a7", LLDB_REGNUM_GENERIC_ARG8) 7565f757f3fSDimitry Andric .Default(LLDB_INVALID_REGNUM); 7575f757f3fSDimitry Andric } 7585f757f3fSDimitry Andric 7595f757f3fSDimitry Andric void ABISysV_riscv::AugmentRegisterInfo( 7605f757f3fSDimitry Andric std::vector<lldb_private::DynamicRegisterInfo::Register> ®s) { 7615f757f3fSDimitry Andric lldb_private::RegInfoBasedABI::AugmentRegisterInfo(regs); 7625f757f3fSDimitry Andric 7635f757f3fSDimitry Andric for (auto it : llvm::enumerate(regs)) { 7645f757f3fSDimitry Andric // Set alt name for certain registers for convenience 7655f757f3fSDimitry Andric if (it.value().name == "zero") 7665f757f3fSDimitry Andric it.value().alt_name.SetCString("x0"); 7675f757f3fSDimitry Andric else if (it.value().name == "ra") 7685f757f3fSDimitry Andric it.value().alt_name.SetCString("x1"); 7695f757f3fSDimitry Andric else if (it.value().name == "sp") 7705f757f3fSDimitry Andric it.value().alt_name.SetCString("x2"); 7715f757f3fSDimitry Andric else if (it.value().name == "gp") 7725f757f3fSDimitry Andric it.value().alt_name.SetCString("x3"); 7735f757f3fSDimitry Andric else if (it.value().name == "fp") 7745f757f3fSDimitry Andric it.value().alt_name.SetCString("s0"); 7755f757f3fSDimitry Andric else if (it.value().name == "s0") 7765f757f3fSDimitry Andric it.value().alt_name.SetCString("x8"); 7775f757f3fSDimitry Andric 7785f757f3fSDimitry Andric // Set generic regnum so lldb knows what the PC, etc is 7795f757f3fSDimitry Andric it.value().regnum_generic = GetGenericNum(it.value().name.GetStringRef()); 7805f757f3fSDimitry Andric } 7815f757f3fSDimitry Andric } 782