xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 &reg_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 &reg_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 &reg_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> &regs) {
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