xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/ABI/ARC/ABISysV_arc.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1dda28197Spatrick //===-- ABISysV_arc.cpp ---------------------------------------------------===//
2dda28197Spatrick //
3dda28197Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4dda28197Spatrick // See https://llvm.org/LICENSE.txt for license information.
5dda28197Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6dda28197Spatrick //
7dda28197Spatrick //===----------------------------------------------------------------------===//
8dda28197Spatrick 
9dda28197Spatrick #include "ABISysV_arc.h"
10dda28197Spatrick 
11dda28197Spatrick // C Includes
12dda28197Spatrick // C++ Includes
13dda28197Spatrick #include <array>
14dda28197Spatrick #include <limits>
15dda28197Spatrick #include <type_traits>
16dda28197Spatrick 
17dda28197Spatrick // Other libraries and framework includes
18dda28197Spatrick #include "llvm/ADT/Triple.h"
19dda28197Spatrick #include "llvm/IR/DerivedTypes.h"
20dda28197Spatrick #include "llvm/Support/MathExtras.h"
21dda28197Spatrick 
22dda28197Spatrick #include "lldb/Core/Module.h"
23dda28197Spatrick #include "lldb/Core/PluginManager.h"
24dda28197Spatrick #include "lldb/Core/Value.h"
25dda28197Spatrick #include "lldb/Core/ValueObjectConstResult.h"
26dda28197Spatrick #include "lldb/Core/ValueObjectMemory.h"
27dda28197Spatrick #include "lldb/Core/ValueObjectRegister.h"
28dda28197Spatrick #include "lldb/Symbol/UnwindPlan.h"
29dda28197Spatrick #include "lldb/Target/Process.h"
30dda28197Spatrick #include "lldb/Target/RegisterContext.h"
31dda28197Spatrick #include "lldb/Target/StackFrame.h"
32dda28197Spatrick #include "lldb/Target/Target.h"
33dda28197Spatrick #include "lldb/Target/Thread.h"
34dda28197Spatrick #include "lldb/Utility/ConstString.h"
35dda28197Spatrick #include "lldb/Utility/RegisterValue.h"
36dda28197Spatrick #include "lldb/Utility/Status.h"
37dda28197Spatrick 
38dda28197Spatrick #define DEFINE_REG_NAME(reg_num)      ConstString(#reg_num).GetCString()
39dda28197Spatrick #define DEFINE_REG_NAME_STR(reg_name) ConstString(reg_name).GetCString()
40dda28197Spatrick 
41dda28197Spatrick // The ABI is not a source of such information as size, offset, encoding, etc.
42dda28197Spatrick // of a register. Just provides correct dwarf and eh_frame numbers.
43dda28197Spatrick 
44dda28197Spatrick #define DEFINE_GENERIC_REGISTER_STUB(dwarf_num, str_name, generic_num)        \
45dda28197Spatrick   {                                                                           \
46dda28197Spatrick     DEFINE_REG_NAME(dwarf_num), DEFINE_REG_NAME_STR(str_name),                \
47dda28197Spatrick     0, 0, eEncodingInvalid, eFormatDefault,                                   \
48dda28197Spatrick     { dwarf_num, dwarf_num, generic_num, LLDB_INVALID_REGNUM, dwarf_num },    \
49*f6aab3d8Srobert     nullptr, nullptr                                                          \
50dda28197Spatrick   }
51dda28197Spatrick 
52dda28197Spatrick #define DEFINE_REGISTER_STUB(dwarf_num, str_name) \
53dda28197Spatrick   DEFINE_GENERIC_REGISTER_STUB(dwarf_num, str_name, LLDB_INVALID_REGNUM)
54dda28197Spatrick 
55dda28197Spatrick using namespace lldb;
56dda28197Spatrick using namespace lldb_private;
57dda28197Spatrick 
58dda28197Spatrick LLDB_PLUGIN_DEFINE_ADV(ABISysV_arc, ABIARC)
59dda28197Spatrick 
60dda28197Spatrick namespace {
61dda28197Spatrick namespace dwarf {
62dda28197Spatrick enum regnums {
63dda28197Spatrick   r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16,
64dda28197Spatrick   r17, r18, r19, r20, r21, r22, r23, r24, r25, r26,
65dda28197Spatrick   r27, fp = r27, r28, sp = r28, r29, r30, r31, blink = r31,
66dda28197Spatrick   r32, r33, r34, r35, r36, r37, r38, r39, r40, r41, r42, r43, r44, r45, r46,
67dda28197Spatrick   r47, r48, r49, r50, r51, r52, r53, r54, r55, r56, r57, r58, r59, r60,
68dda28197Spatrick   /*reserved,*/ /*limm indicator,*/ r63 = 63, pc = 70, status32 = 74
69dda28197Spatrick };
70dda28197Spatrick 
71dda28197Spatrick static const std::array<RegisterInfo, 64> g_register_infos = { {
72dda28197Spatrick     DEFINE_GENERIC_REGISTER_STUB(r0, nullptr, LLDB_REGNUM_GENERIC_ARG1),
73dda28197Spatrick     DEFINE_GENERIC_REGISTER_STUB(r1, nullptr, LLDB_REGNUM_GENERIC_ARG2),
74dda28197Spatrick     DEFINE_GENERIC_REGISTER_STUB(r2, nullptr, LLDB_REGNUM_GENERIC_ARG3),
75dda28197Spatrick     DEFINE_GENERIC_REGISTER_STUB(r3, nullptr, LLDB_REGNUM_GENERIC_ARG4),
76dda28197Spatrick     DEFINE_GENERIC_REGISTER_STUB(r4, nullptr, LLDB_REGNUM_GENERIC_ARG5),
77dda28197Spatrick     DEFINE_GENERIC_REGISTER_STUB(r5, nullptr, LLDB_REGNUM_GENERIC_ARG6),
78dda28197Spatrick     DEFINE_GENERIC_REGISTER_STUB(r6, nullptr, LLDB_REGNUM_GENERIC_ARG7),
79dda28197Spatrick     DEFINE_GENERIC_REGISTER_STUB(r7, nullptr, LLDB_REGNUM_GENERIC_ARG8),
80dda28197Spatrick     DEFINE_REGISTER_STUB(r8, nullptr),
81dda28197Spatrick     DEFINE_REGISTER_STUB(r9, nullptr),
82dda28197Spatrick     DEFINE_REGISTER_STUB(r10, nullptr),
83dda28197Spatrick     DEFINE_REGISTER_STUB(r11, nullptr),
84dda28197Spatrick     DEFINE_REGISTER_STUB(r12, nullptr),
85dda28197Spatrick     DEFINE_REGISTER_STUB(r13, nullptr),
86dda28197Spatrick     DEFINE_REGISTER_STUB(r14, nullptr),
87dda28197Spatrick     DEFINE_REGISTER_STUB(r15, nullptr),
88dda28197Spatrick     DEFINE_REGISTER_STUB(r16, nullptr),
89dda28197Spatrick     DEFINE_REGISTER_STUB(r17, nullptr),
90dda28197Spatrick     DEFINE_REGISTER_STUB(r18, nullptr),
91dda28197Spatrick     DEFINE_REGISTER_STUB(r19, nullptr),
92dda28197Spatrick     DEFINE_REGISTER_STUB(r20, nullptr),
93dda28197Spatrick     DEFINE_REGISTER_STUB(r21, nullptr),
94dda28197Spatrick     DEFINE_REGISTER_STUB(r22, nullptr),
95dda28197Spatrick     DEFINE_REGISTER_STUB(r23, nullptr),
96dda28197Spatrick     DEFINE_REGISTER_STUB(r24, nullptr),
97dda28197Spatrick     DEFINE_REGISTER_STUB(r25, nullptr),
98dda28197Spatrick     DEFINE_REGISTER_STUB(r26, "gp"),
99dda28197Spatrick     DEFINE_GENERIC_REGISTER_STUB(r27, "fp", LLDB_REGNUM_GENERIC_FP),
100dda28197Spatrick     DEFINE_GENERIC_REGISTER_STUB(r28, "sp", LLDB_REGNUM_GENERIC_SP),
101dda28197Spatrick     DEFINE_REGISTER_STUB(r29, "ilink"),
102dda28197Spatrick     DEFINE_REGISTER_STUB(r30, nullptr),
103dda28197Spatrick     DEFINE_GENERIC_REGISTER_STUB(r31, "blink", LLDB_REGNUM_GENERIC_RA),
104dda28197Spatrick     DEFINE_REGISTER_STUB(r32, nullptr),
105dda28197Spatrick     DEFINE_REGISTER_STUB(r33, nullptr),
106dda28197Spatrick     DEFINE_REGISTER_STUB(r34, nullptr),
107dda28197Spatrick     DEFINE_REGISTER_STUB(r35, nullptr),
108dda28197Spatrick     DEFINE_REGISTER_STUB(r36, nullptr),
109dda28197Spatrick     DEFINE_REGISTER_STUB(r37, nullptr),
110dda28197Spatrick     DEFINE_REGISTER_STUB(r38, nullptr),
111dda28197Spatrick     DEFINE_REGISTER_STUB(r39, nullptr),
112dda28197Spatrick     DEFINE_REGISTER_STUB(r40, nullptr),
113dda28197Spatrick     DEFINE_REGISTER_STUB(r41, nullptr),
114dda28197Spatrick     DEFINE_REGISTER_STUB(r42, nullptr),
115dda28197Spatrick     DEFINE_REGISTER_STUB(r43, nullptr),
116dda28197Spatrick     DEFINE_REGISTER_STUB(r44, nullptr),
117dda28197Spatrick     DEFINE_REGISTER_STUB(r45, nullptr),
118dda28197Spatrick     DEFINE_REGISTER_STUB(r46, nullptr),
119dda28197Spatrick     DEFINE_REGISTER_STUB(r47, nullptr),
120dda28197Spatrick     DEFINE_REGISTER_STUB(r48, nullptr),
121dda28197Spatrick     DEFINE_REGISTER_STUB(r49, nullptr),
122dda28197Spatrick     DEFINE_REGISTER_STUB(r50, nullptr),
123dda28197Spatrick     DEFINE_REGISTER_STUB(r51, nullptr),
124dda28197Spatrick     DEFINE_REGISTER_STUB(r52, nullptr),
125dda28197Spatrick     DEFINE_REGISTER_STUB(r53, nullptr),
126dda28197Spatrick     DEFINE_REGISTER_STUB(r54, nullptr),
127dda28197Spatrick     DEFINE_REGISTER_STUB(r55, nullptr),
128dda28197Spatrick     DEFINE_REGISTER_STUB(r56, nullptr),
129dda28197Spatrick     DEFINE_REGISTER_STUB(r57, nullptr),
130dda28197Spatrick     DEFINE_REGISTER_STUB(r58, "accl"),
131dda28197Spatrick     DEFINE_REGISTER_STUB(r59, "acch"),
132dda28197Spatrick     DEFINE_REGISTER_STUB(r60, "lp_count"),
133dda28197Spatrick     DEFINE_REGISTER_STUB(r63, "pcl"),
134dda28197Spatrick     DEFINE_GENERIC_REGISTER_STUB(pc, nullptr, LLDB_REGNUM_GENERIC_PC),
135dda28197Spatrick     DEFINE_GENERIC_REGISTER_STUB(status32, nullptr, LLDB_REGNUM_GENERIC_FLAGS)} };
136dda28197Spatrick } // namespace dwarf
137dda28197Spatrick } // namespace
138dda28197Spatrick 
GetRegisterInfoArray(uint32_t & count)139dda28197Spatrick const RegisterInfo *ABISysV_arc::GetRegisterInfoArray(uint32_t &count) {
140dda28197Spatrick   count = dwarf::g_register_infos.size();
141dda28197Spatrick   return dwarf::g_register_infos.data();
142dda28197Spatrick }
143dda28197Spatrick 
GetRedZoneSize() const144dda28197Spatrick size_t ABISysV_arc::GetRedZoneSize() const { return 0; }
145dda28197Spatrick 
IsRegisterFileReduced(RegisterContext & reg_ctx) const146dda28197Spatrick bool ABISysV_arc::IsRegisterFileReduced(RegisterContext &reg_ctx) const {
147dda28197Spatrick   if (!m_is_reg_file_reduced) {
148dda28197Spatrick     const auto *const rf_build_reg = reg_ctx.GetRegisterInfoByName("rf_build");
149dda28197Spatrick 
150dda28197Spatrick     const auto reg_value = reg_ctx.ReadRegisterAsUnsigned(rf_build_reg,
151dda28197Spatrick                                                           /*fail_value*/ 0);
152dda28197Spatrick     // RF_BUILD "Number of Entries" bit.
153dda28197Spatrick     const uint32_t rf_entries_bit = 1U << 9U;
154*f6aab3d8Srobert     m_is_reg_file_reduced = (reg_value & rf_entries_bit) != 0;
155dda28197Spatrick   }
156dda28197Spatrick 
157*f6aab3d8Srobert   return m_is_reg_file_reduced.value_or(false);
158dda28197Spatrick }
159dda28197Spatrick 
160dda28197Spatrick //------------------------------------------------------------------
161dda28197Spatrick // Static Functions
162dda28197Spatrick //------------------------------------------------------------------
163dda28197Spatrick 
CreateInstance(ProcessSP process_sp,const ArchSpec & arch)164dda28197Spatrick ABISP ABISysV_arc::CreateInstance(ProcessSP process_sp, const ArchSpec &arch) {
165dda28197Spatrick   return llvm::Triple::arc == arch.GetTriple().getArch() ?
166dda28197Spatrick       ABISP(new ABISysV_arc(std::move(process_sp), MakeMCRegisterInfo(arch))) :
167dda28197Spatrick       ABISP();
168dda28197Spatrick }
169dda28197Spatrick 
170*f6aab3d8Srobert static const size_t word_size = 4U;
171*f6aab3d8Srobert static const size_t reg_size = word_size;
172dda28197Spatrick 
AugmentArgSize(size_t size_in_bytes)173*f6aab3d8Srobert static inline size_t AugmentArgSize(size_t size_in_bytes) {
174dda28197Spatrick   return llvm::alignTo(size_in_bytes, word_size);
175dda28197Spatrick }
176dda28197Spatrick 
177*f6aab3d8Srobert static size_t
TotalArgsSizeInWords(const llvm::ArrayRef<ABI::CallArgument> & args)178*f6aab3d8Srobert TotalArgsSizeInWords(const llvm::ArrayRef<ABI::CallArgument> &args) {
179dda28197Spatrick   size_t total_size = 0;
180dda28197Spatrick   for (const auto &arg : args)
181dda28197Spatrick     total_size +=
182dda28197Spatrick         (ABI::CallArgument::TargetValue == arg.type ? AugmentArgSize(arg.size)
183dda28197Spatrick                                                     : reg_size) /
184dda28197Spatrick         word_size;
185dda28197Spatrick 
186dda28197Spatrick   return total_size;
187dda28197Spatrick }
188dda28197Spatrick 
PrepareTrivialCall(Thread & thread,addr_t sp,addr_t func_addr,addr_t return_addr,llvm::ArrayRef<addr_t> args) const189dda28197Spatrick bool ABISysV_arc::PrepareTrivialCall(Thread &thread, addr_t sp,
190dda28197Spatrick                                      addr_t func_addr, addr_t return_addr,
191dda28197Spatrick                                      llvm::ArrayRef<addr_t> args) const {
192dda28197Spatrick   // We don't use the traditional trivial call specialized for jit.
193dda28197Spatrick   return false;
194dda28197Spatrick }
195dda28197Spatrick 
PrepareTrivialCall(Thread & thread,addr_t sp,addr_t pc,addr_t ra,llvm::Type & prototype,llvm::ArrayRef<ABI::CallArgument> args) const196dda28197Spatrick bool ABISysV_arc::PrepareTrivialCall(Thread &thread, addr_t sp, addr_t pc,
197dda28197Spatrick     addr_t ra, llvm::Type &prototype,
198dda28197Spatrick     llvm::ArrayRef<ABI::CallArgument> args) const {
199dda28197Spatrick   auto reg_ctx = thread.GetRegisterContext();
200dda28197Spatrick   if (!reg_ctx)
201dda28197Spatrick     return false;
202dda28197Spatrick 
203dda28197Spatrick   uint32_t pc_reg = reg_ctx->ConvertRegisterKindToRegisterNumber(
204dda28197Spatrick       eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
205dda28197Spatrick   if (pc_reg == LLDB_INVALID_REGNUM)
206dda28197Spatrick     return false;
207dda28197Spatrick 
208dda28197Spatrick   uint32_t ra_reg = reg_ctx->ConvertRegisterKindToRegisterNumber(
209dda28197Spatrick       eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA);
210dda28197Spatrick   if (ra_reg == LLDB_INVALID_REGNUM)
211dda28197Spatrick     return false;
212dda28197Spatrick 
213dda28197Spatrick   uint32_t sp_reg = reg_ctx->ConvertRegisterKindToRegisterNumber(
214dda28197Spatrick       eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
215dda28197Spatrick   if (sp_reg == LLDB_INVALID_REGNUM)
216dda28197Spatrick     return false;
217dda28197Spatrick 
218dda28197Spatrick   Status error;
219dda28197Spatrick   ProcessSP process = thread.GetProcess();
220dda28197Spatrick   if (!process)
221dda28197Spatrick     return false;
222dda28197Spatrick 
223dda28197Spatrick   // Push host data onto target.
224dda28197Spatrick   for (const auto &arg : args) {
225dda28197Spatrick     // Skip over target values.
226dda28197Spatrick     if (arg.type == ABI::CallArgument::TargetValue)
227dda28197Spatrick       continue;
228dda28197Spatrick 
229dda28197Spatrick     // Create space on the stack for this data 4-byte aligned.
230dda28197Spatrick     sp -= AugmentArgSize(arg.size);
231dda28197Spatrick 
232dda28197Spatrick     if (process->WriteMemory(sp, arg.data_up.get(), arg.size, error) < arg.size
233dda28197Spatrick         || error.Fail())
234dda28197Spatrick       return false;
235dda28197Spatrick 
236dda28197Spatrick     // Update the argument with the target pointer.
237dda28197Spatrick     *const_cast<addr_t *>(&arg.value) = sp;
238dda28197Spatrick   }
239dda28197Spatrick 
240dda28197Spatrick   // Make sure number of parameters matches prototype.
241dda28197Spatrick   assert(!prototype.isFunctionVarArg());
242dda28197Spatrick   assert(prototype.getFunctionNumParams() == args.size());
243dda28197Spatrick 
244dda28197Spatrick   const size_t regs_for_args_count = IsRegisterFileReduced(*reg_ctx) ? 4U : 8U;
245dda28197Spatrick 
246dda28197Spatrick   // Number of arguments passed on stack.
247dda28197Spatrick   auto args_size = TotalArgsSizeInWords(args);
248dda28197Spatrick   auto on_stack =
249dda28197Spatrick       args_size <= regs_for_args_count ? 0 : args_size - regs_for_args_count;
250dda28197Spatrick   auto offset = on_stack * word_size;
251dda28197Spatrick 
252dda28197Spatrick   uint8_t reg_value[reg_size];
253dda28197Spatrick   size_t reg_index = LLDB_REGNUM_GENERIC_ARG1;
254dda28197Spatrick 
255dda28197Spatrick   for (const auto &arg : args) {
256dda28197Spatrick     auto value = reinterpret_cast<const uint8_t *>(&arg.value);
257dda28197Spatrick     auto size =
258dda28197Spatrick         ABI::CallArgument::TargetValue == arg.type ? arg.size : reg_size;
259dda28197Spatrick 
260dda28197Spatrick     // Pass arguments via registers.
261dda28197Spatrick     while (size > 0 && reg_index < regs_for_args_count) {
262dda28197Spatrick       size_t byte_index = 0;
263dda28197Spatrick       auto end = size < reg_size ? size : reg_size;
264dda28197Spatrick 
265dda28197Spatrick       while (byte_index < end) {
266dda28197Spatrick         reg_value[byte_index++] = *(value++);
267dda28197Spatrick         --size;
268dda28197Spatrick       }
269dda28197Spatrick 
270dda28197Spatrick       while (byte_index < reg_size) {
271dda28197Spatrick         reg_value[byte_index++] = 0;
272dda28197Spatrick       }
273dda28197Spatrick 
274*f6aab3d8Srobert       RegisterValue reg_val_obj(llvm::ArrayRef(reg_value, reg_size),
275be691f3bSpatrick                                 eByteOrderLittle);
276dda28197Spatrick       if (!reg_ctx->WriteRegister(
277dda28197Spatrick             reg_ctx->GetRegisterInfo(eRegisterKindGeneric, reg_index),
278dda28197Spatrick             reg_val_obj))
279dda28197Spatrick         return false;
280dda28197Spatrick 
281dda28197Spatrick       // NOTE: It's unsafe to iterate through LLDB_REGNUM_GENERICs.
282dda28197Spatrick       ++reg_index;
283dda28197Spatrick     }
284dda28197Spatrick 
285dda28197Spatrick     if (reg_index < regs_for_args_count || size == 0)
286dda28197Spatrick       continue;
287dda28197Spatrick 
288dda28197Spatrick     // Remaining arguments are passed on the stack.
289dda28197Spatrick     if (process->WriteMemory(sp - offset, value, size, error) < size ||
290dda28197Spatrick         !error.Success())
291dda28197Spatrick       return false;
292dda28197Spatrick 
293dda28197Spatrick     offset -= AugmentArgSize(size);
294dda28197Spatrick   }
295dda28197Spatrick 
296dda28197Spatrick   // Set stack pointer immediately below arguments.
297dda28197Spatrick   sp -= on_stack * word_size;
298dda28197Spatrick 
299dda28197Spatrick   // Update registers with current function call state.
300dda28197Spatrick   reg_ctx->WriteRegisterFromUnsigned(pc_reg, pc);
301dda28197Spatrick   reg_ctx->WriteRegisterFromUnsigned(ra_reg, ra);
302dda28197Spatrick   reg_ctx->WriteRegisterFromUnsigned(sp_reg, sp);
303dda28197Spatrick 
304dda28197Spatrick   return true;
305dda28197Spatrick }
306dda28197Spatrick 
GetArgumentValues(Thread & thread,ValueList & values) const307dda28197Spatrick bool ABISysV_arc::GetArgumentValues(Thread &thread, ValueList &values) const {
308dda28197Spatrick   return false;
309dda28197Spatrick }
310dda28197Spatrick 
SetReturnValueObject(StackFrameSP & frame_sp,ValueObjectSP & new_value_sp)311dda28197Spatrick Status ABISysV_arc::SetReturnValueObject(StackFrameSP &frame_sp,
312dda28197Spatrick                                          ValueObjectSP &new_value_sp) {
313dda28197Spatrick   Status result;
314dda28197Spatrick   if (!new_value_sp) {
315dda28197Spatrick     result.SetErrorString("Empty value object for return value.");
316dda28197Spatrick     return result;
317dda28197Spatrick   }
318dda28197Spatrick 
319dda28197Spatrick   CompilerType compiler_type = new_value_sp->GetCompilerType();
320dda28197Spatrick   if (!compiler_type) {
321dda28197Spatrick     result.SetErrorString("Null clang type for return value.");
322dda28197Spatrick     return result;
323dda28197Spatrick   }
324dda28197Spatrick 
325dda28197Spatrick   auto &reg_ctx = *frame_sp->GetThread()->GetRegisterContext();
326dda28197Spatrick 
327dda28197Spatrick   bool is_signed = false;
328dda28197Spatrick   if (!compiler_type.IsIntegerOrEnumerationType(is_signed) &&
329dda28197Spatrick       !compiler_type.IsPointerType()) {
330dda28197Spatrick     result.SetErrorString("We don't support returning other types at present");
331dda28197Spatrick     return result;
332dda28197Spatrick   }
333dda28197Spatrick 
334dda28197Spatrick   DataExtractor data;
335dda28197Spatrick   size_t num_bytes = new_value_sp->GetData(data, result);
336dda28197Spatrick 
337dda28197Spatrick   if (result.Fail()) {
338dda28197Spatrick     result.SetErrorStringWithFormat(
339dda28197Spatrick         "Couldn't convert return value to raw data: %s", result.AsCString());
340dda28197Spatrick     return result;
341dda28197Spatrick   }
342dda28197Spatrick 
343dda28197Spatrick   if (num_bytes <= 2 * reg_size) {
344dda28197Spatrick     offset_t offset = 0;
345dda28197Spatrick     uint64_t raw_value = data.GetMaxU64(&offset, num_bytes);
346dda28197Spatrick 
347dda28197Spatrick     auto reg_info =
348dda28197Spatrick         reg_ctx.GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1);
349dda28197Spatrick     if (!reg_ctx.WriteRegisterFromUnsigned(reg_info, raw_value)) {
350dda28197Spatrick       result.SetErrorStringWithFormat("Couldn't write value to register %s",
351dda28197Spatrick                                       reg_info->name);
352dda28197Spatrick       return result;
353dda28197Spatrick     }
354dda28197Spatrick 
355dda28197Spatrick     if (num_bytes <= reg_size)
356dda28197Spatrick       return result; // Successfully written.
357dda28197Spatrick 
358dda28197Spatrick     raw_value >>= 32;
359dda28197Spatrick     reg_info =
360dda28197Spatrick         reg_ctx.GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG2);
361dda28197Spatrick     if (!reg_ctx.WriteRegisterFromUnsigned(reg_info, raw_value)) {
362dda28197Spatrick       result.SetErrorStringWithFormat("Couldn't write value to register %s",
363dda28197Spatrick                                       reg_info->name);
364dda28197Spatrick     }
365dda28197Spatrick 
366dda28197Spatrick     return result;
367dda28197Spatrick   }
368dda28197Spatrick 
369dda28197Spatrick   result.SetErrorString(
370dda28197Spatrick       "We don't support returning large integer values at present.");
371dda28197Spatrick   return result;
372dda28197Spatrick }
373dda28197Spatrick 
374dda28197Spatrick template <typename T>
SetInteger(Scalar & scalar,uint64_t raw_value,bool is_signed)375*f6aab3d8Srobert static void SetInteger(Scalar &scalar, uint64_t raw_value, bool is_signed) {
376dda28197Spatrick   raw_value &= std::numeric_limits<T>::max();
377dda28197Spatrick   if (is_signed)
378dda28197Spatrick     scalar = static_cast<typename std::make_signed<T>::type>(raw_value);
379dda28197Spatrick   else
380dda28197Spatrick     scalar = static_cast<T>(raw_value);
381dda28197Spatrick }
382dda28197Spatrick 
SetSizedInteger(Scalar & scalar,uint64_t raw_value,uint8_t size_in_bytes,bool is_signed)383*f6aab3d8Srobert static bool SetSizedInteger(Scalar &scalar, uint64_t raw_value,
384*f6aab3d8Srobert                             uint8_t size_in_bytes, bool is_signed) {
385dda28197Spatrick   switch (size_in_bytes) {
386dda28197Spatrick   default:
387dda28197Spatrick     return false;
388dda28197Spatrick 
389dda28197Spatrick   case sizeof(uint64_t):
390dda28197Spatrick     SetInteger<uint64_t>(scalar, raw_value, is_signed);
391dda28197Spatrick     break;
392dda28197Spatrick 
393dda28197Spatrick   case sizeof(uint32_t):
394dda28197Spatrick     SetInteger<uint32_t>(scalar, raw_value, is_signed);
395dda28197Spatrick     break;
396dda28197Spatrick 
397dda28197Spatrick   case sizeof(uint16_t):
398dda28197Spatrick     SetInteger<uint16_t>(scalar, raw_value, is_signed);
399dda28197Spatrick     break;
400dda28197Spatrick 
401dda28197Spatrick   case sizeof(uint8_t):
402dda28197Spatrick     SetInteger<uint8_t>(scalar, raw_value, is_signed);
403dda28197Spatrick     break;
404dda28197Spatrick   }
405dda28197Spatrick 
406dda28197Spatrick   return true;
407dda28197Spatrick }
408dda28197Spatrick 
SetSizedFloat(Scalar & scalar,uint64_t raw_value,uint8_t size_in_bytes)409*f6aab3d8Srobert static bool SetSizedFloat(Scalar &scalar, uint64_t raw_value,
410*f6aab3d8Srobert                           uint8_t size_in_bytes) {
411dda28197Spatrick   switch (size_in_bytes) {
412dda28197Spatrick   default:
413dda28197Spatrick     return false;
414dda28197Spatrick 
415dda28197Spatrick   case sizeof(uint64_t):
416dda28197Spatrick     scalar = *reinterpret_cast<double *>(&raw_value);
417dda28197Spatrick     break;
418dda28197Spatrick 
419dda28197Spatrick   case sizeof(uint32_t):
420dda28197Spatrick     scalar = *reinterpret_cast<float *>(&raw_value);
421dda28197Spatrick     break;
422dda28197Spatrick   }
423dda28197Spatrick 
424dda28197Spatrick   return true;
425dda28197Spatrick }
426dda28197Spatrick 
ReadRawValue(const RegisterContextSP & reg_ctx,uint8_t size_in_bytes)427*f6aab3d8Srobert static uint64_t ReadRawValue(const RegisterContextSP &reg_ctx,
428*f6aab3d8Srobert                              uint8_t size_in_bytes) {
429dda28197Spatrick   auto reg_info_r0 =
430dda28197Spatrick       reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1);
431dda28197Spatrick 
432dda28197Spatrick   // Extract the register context so we can read arguments from registers.
433dda28197Spatrick   uint64_t raw_value =
434dda28197Spatrick       reg_ctx->ReadRegisterAsUnsigned(reg_info_r0, 0) & UINT32_MAX;
435dda28197Spatrick 
436dda28197Spatrick   if (sizeof(uint64_t) == size_in_bytes)
437dda28197Spatrick     raw_value |= (reg_ctx->ReadRegisterAsUnsigned(
438dda28197Spatrick                       reg_ctx->GetRegisterInfo(eRegisterKindGeneric,
439dda28197Spatrick                                                LLDB_REGNUM_GENERIC_ARG2), 0) &
440dda28197Spatrick                   UINT64_MAX) << 32U;
441dda28197Spatrick 
442dda28197Spatrick   return raw_value;
443dda28197Spatrick }
444dda28197Spatrick 
445dda28197Spatrick ValueObjectSP
GetReturnValueObjectSimple(Thread & thread,CompilerType & compiler_type) const446dda28197Spatrick ABISysV_arc::GetReturnValueObjectSimple(Thread &thread,
447dda28197Spatrick                                         CompilerType &compiler_type) const {
448dda28197Spatrick   if (!compiler_type)
449dda28197Spatrick     return ValueObjectSP();
450dda28197Spatrick 
451dda28197Spatrick   auto reg_ctx = thread.GetRegisterContext();
452dda28197Spatrick   if (!reg_ctx)
453dda28197Spatrick     return ValueObjectSP();
454dda28197Spatrick 
455dda28197Spatrick   Value value;
456dda28197Spatrick   value.SetCompilerType(compiler_type);
457dda28197Spatrick 
458dda28197Spatrick   const uint32_t type_flags = compiler_type.GetTypeInfo();
459dda28197Spatrick   // Integer return type.
460dda28197Spatrick   if (type_flags & eTypeIsInteger) {
461*f6aab3d8Srobert     const size_t byte_size = compiler_type.GetByteSize(&thread).value_or(0);
462dda28197Spatrick     auto raw_value = ReadRawValue(reg_ctx, byte_size);
463dda28197Spatrick 
464dda28197Spatrick     const bool is_signed = (type_flags & eTypeIsSigned) != 0;
465dda28197Spatrick     if (!SetSizedInteger(value.GetScalar(), raw_value, byte_size, is_signed))
466dda28197Spatrick       return ValueObjectSP();
467dda28197Spatrick 
468be691f3bSpatrick     value.SetValueType(Value::ValueType::Scalar);
469dda28197Spatrick   }
470dda28197Spatrick   // Pointer return type.
471dda28197Spatrick   else if (type_flags & eTypeIsPointer) {
472dda28197Spatrick     auto reg_info_r0 = reg_ctx->GetRegisterInfo(eRegisterKindGeneric,
473dda28197Spatrick                                                 LLDB_REGNUM_GENERIC_ARG1);
474dda28197Spatrick     value.GetScalar() = reg_ctx->ReadRegisterAsUnsigned(reg_info_r0, 0);
475dda28197Spatrick 
476be691f3bSpatrick     value.SetValueType(Value::ValueType::Scalar);
477dda28197Spatrick   }
478dda28197Spatrick   // Floating point return type.
479dda28197Spatrick   else if (type_flags & eTypeIsFloat) {
480dda28197Spatrick     uint32_t float_count = 0;
481dda28197Spatrick     bool is_complex = false;
482dda28197Spatrick 
483dda28197Spatrick     if (compiler_type.IsFloatingPointType(float_count, is_complex) &&
484dda28197Spatrick         1 == float_count && !is_complex) {
485*f6aab3d8Srobert       const size_t byte_size = compiler_type.GetByteSize(&thread).value_or(0);
486dda28197Spatrick       auto raw_value = ReadRawValue(reg_ctx, byte_size);
487dda28197Spatrick 
488dda28197Spatrick       if (!SetSizedFloat(value.GetScalar(), raw_value, byte_size))
489dda28197Spatrick         return ValueObjectSP();
490dda28197Spatrick     }
491dda28197Spatrick   }
492dda28197Spatrick   // Unsupported return type.
493dda28197Spatrick   else
494dda28197Spatrick     return ValueObjectSP();
495dda28197Spatrick 
496dda28197Spatrick   return ValueObjectConstResult::Create(thread.GetStackFrameAtIndex(0).get(),
497dda28197Spatrick                                         value, ConstString(""));
498dda28197Spatrick }
499dda28197Spatrick 
GetReturnValueObjectImpl(Thread & thread,CompilerType & return_compiler_type) const500dda28197Spatrick ValueObjectSP ABISysV_arc::GetReturnValueObjectImpl(
501dda28197Spatrick     Thread &thread, CompilerType &return_compiler_type) const {
502dda28197Spatrick   ValueObjectSP return_valobj_sp;
503dda28197Spatrick 
504dda28197Spatrick   if (!return_compiler_type)
505dda28197Spatrick     return return_valobj_sp;
506dda28197Spatrick 
507dda28197Spatrick   ExecutionContext exe_ctx(thread.shared_from_this());
508dda28197Spatrick   return GetReturnValueObjectSimple(thread, return_compiler_type);
509dda28197Spatrick }
510dda28197Spatrick 
GetReturnValueObjectImpl(Thread & thread,llvm::Type & retType) const511dda28197Spatrick ValueObjectSP ABISysV_arc::GetReturnValueObjectImpl(Thread &thread,
512dda28197Spatrick                                                     llvm::Type &retType) const {
513dda28197Spatrick   auto reg_ctx = thread.GetRegisterContext();
514dda28197Spatrick   if (!reg_ctx)
515dda28197Spatrick     return ValueObjectSP();
516dda28197Spatrick 
517dda28197Spatrick   Value value;
518dda28197Spatrick   // Void return type.
519dda28197Spatrick   if (retType.isVoidTy()) {
520dda28197Spatrick     value.GetScalar() = 0;
521dda28197Spatrick   }
522dda28197Spatrick   // Integer return type.
523dda28197Spatrick   else if (retType.isIntegerTy()) {
524dda28197Spatrick     size_t byte_size = retType.getPrimitiveSizeInBits();
525dda28197Spatrick     if (1 != byte_size) // For boolean type.
526dda28197Spatrick       byte_size /= CHAR_BIT;
527dda28197Spatrick 
528dda28197Spatrick     auto raw_value = ReadRawValue(reg_ctx, byte_size);
529dda28197Spatrick 
530dda28197Spatrick     const bool is_signed = false; // IR Type doesn't provide this info.
531dda28197Spatrick     if (!SetSizedInteger(value.GetScalar(), raw_value, byte_size, is_signed))
532dda28197Spatrick       return ValueObjectSP();
533dda28197Spatrick   }
534dda28197Spatrick   // Pointer return type.
535dda28197Spatrick   else if (retType.isPointerTy()) {
536dda28197Spatrick     auto reg_info_r0 = reg_ctx->GetRegisterInfo(eRegisterKindGeneric,
537dda28197Spatrick                                                 LLDB_REGNUM_GENERIC_ARG1);
538dda28197Spatrick     value.GetScalar() = reg_ctx->ReadRegisterAsUnsigned(reg_info_r0, 0);
539be691f3bSpatrick     value.SetValueType(Value::ValueType::Scalar);
540dda28197Spatrick   }
541dda28197Spatrick   // Floating point return type.
542dda28197Spatrick   else if (retType.isFloatingPointTy()) {
543dda28197Spatrick     const size_t byte_size = retType.getPrimitiveSizeInBits() / CHAR_BIT;
544dda28197Spatrick     auto raw_value = ReadRawValue(reg_ctx, byte_size);
545dda28197Spatrick 
546dda28197Spatrick     if (!SetSizedFloat(value.GetScalar(), raw_value, byte_size))
547dda28197Spatrick       return ValueObjectSP();
548dda28197Spatrick   }
549dda28197Spatrick   // Unsupported return type.
550dda28197Spatrick   else
551dda28197Spatrick     return ValueObjectSP();
552dda28197Spatrick 
553dda28197Spatrick   return ValueObjectConstResult::Create(thread.GetStackFrameAtIndex(0).get(),
554dda28197Spatrick                                         value, ConstString(""));
555dda28197Spatrick }
556dda28197Spatrick 
CreateFunctionEntryUnwindPlan(UnwindPlan & unwind_plan)557dda28197Spatrick bool ABISysV_arc::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) {
558dda28197Spatrick   unwind_plan.Clear();
559dda28197Spatrick   unwind_plan.SetRegisterKind(eRegisterKindDWARF);
560dda28197Spatrick 
561dda28197Spatrick   UnwindPlan::RowSP row(new UnwindPlan::Row);
562dda28197Spatrick 
563dda28197Spatrick   // Our Call Frame Address is the stack pointer value.
564dda28197Spatrick   row->GetCFAValue().SetIsRegisterPlusOffset(dwarf::sp, 0);
565dda28197Spatrick 
566dda28197Spatrick   // The previous PC is in the BLINK.
567dda28197Spatrick   row->SetRegisterLocationToRegister(dwarf::pc, dwarf::blink, true);
568dda28197Spatrick   unwind_plan.AppendRow(row);
569dda28197Spatrick 
570dda28197Spatrick   // All other registers are the same.
571dda28197Spatrick   unwind_plan.SetSourceName("arc at-func-entry default");
572dda28197Spatrick   unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
573dda28197Spatrick 
574dda28197Spatrick   return true;
575dda28197Spatrick }
576dda28197Spatrick 
CreateDefaultUnwindPlan(UnwindPlan & unwind_plan)577dda28197Spatrick bool ABISysV_arc::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
578dda28197Spatrick   return false;
579dda28197Spatrick }
580dda28197Spatrick 
RegisterIsVolatile(const RegisterInfo * reg_info)581dda28197Spatrick bool ABISysV_arc::RegisterIsVolatile(const RegisterInfo *reg_info) {
582dda28197Spatrick   if (nullptr == reg_info)
583dda28197Spatrick     return false;
584dda28197Spatrick 
585dda28197Spatrick   // Volatile registers are: r0..r12.
586dda28197Spatrick   uint32_t regnum = reg_info->kinds[eRegisterKindDWARF];
587dda28197Spatrick   if (regnum <= 12)
588dda28197Spatrick     return true;
589dda28197Spatrick 
590dda28197Spatrick   static const std::string ra_reg_name = "blink";
591dda28197Spatrick   return ra_reg_name == reg_info->name;
592dda28197Spatrick }
593dda28197Spatrick 
Initialize()594dda28197Spatrick void ABISysV_arc::Initialize() {
595dda28197Spatrick   PluginManager::RegisterPlugin(GetPluginNameStatic(),
596dda28197Spatrick                                 "System V ABI for ARC targets", CreateInstance);
597dda28197Spatrick }
598dda28197Spatrick 
Terminate()599dda28197Spatrick void ABISysV_arc::Terminate() {
600dda28197Spatrick   PluginManager::UnregisterPlugin(CreateInstance);
601dda28197Spatrick }
602