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 ®_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 ®_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 ®_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