xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1dda28197Spatrick //===-- ABISysV_ppc64.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_ppc64.h"
10dda28197Spatrick 
11dda28197Spatrick #include "llvm/ADT/STLExtras.h"
12dda28197Spatrick #include "llvm/ADT/Triple.h"
13dda28197Spatrick 
14dda28197Spatrick #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
15dda28197Spatrick #include "Utility/PPC64LE_DWARF_Registers.h"
16dda28197Spatrick #include "Utility/PPC64_DWARF_Registers.h"
17dda28197Spatrick #include "lldb/Core/Module.h"
18dda28197Spatrick #include "lldb/Core/PluginManager.h"
19dda28197Spatrick #include "lldb/Core/Value.h"
20dda28197Spatrick #include "lldb/Core/ValueObjectConstResult.h"
21dda28197Spatrick #include "lldb/Core/ValueObjectMemory.h"
22dda28197Spatrick #include "lldb/Core/ValueObjectRegister.h"
23dda28197Spatrick #include "lldb/Symbol/UnwindPlan.h"
24dda28197Spatrick #include "lldb/Target/Process.h"
25dda28197Spatrick #include "lldb/Target/RegisterContext.h"
26dda28197Spatrick #include "lldb/Target/StackFrame.h"
27dda28197Spatrick #include "lldb/Target/Target.h"
28dda28197Spatrick #include "lldb/Target/Thread.h"
29dda28197Spatrick #include "lldb/Utility/ConstString.h"
30dda28197Spatrick #include "lldb/Utility/DataExtractor.h"
31*f6aab3d8Srobert #include "lldb/Utility/LLDBLog.h"
32dda28197Spatrick #include "lldb/Utility/Log.h"
33dda28197Spatrick #include "lldb/Utility/RegisterValue.h"
34dda28197Spatrick #include "lldb/Utility/Status.h"
35dda28197Spatrick 
36dda28197Spatrick #include "clang/AST/ASTContext.h"
37dda28197Spatrick #include "clang/AST/Attr.h"
38dda28197Spatrick #include "clang/AST/Decl.h"
39dda28197Spatrick 
40dda28197Spatrick #define DECLARE_REGISTER_INFOS_PPC64_STRUCT
41dda28197Spatrick #include "Plugins/Process/Utility/RegisterInfos_ppc64.h"
42dda28197Spatrick #undef DECLARE_REGISTER_INFOS_PPC64_STRUCT
43dda28197Spatrick 
44dda28197Spatrick #define DECLARE_REGISTER_INFOS_PPC64LE_STRUCT
45dda28197Spatrick #include "Plugins/Process/Utility/RegisterInfos_ppc64le.h"
46dda28197Spatrick #undef DECLARE_REGISTER_INFOS_PPC64LE_STRUCT
47*f6aab3d8Srobert #include <optional>
48dda28197Spatrick 
49dda28197Spatrick using namespace lldb;
50dda28197Spatrick using namespace lldb_private;
51dda28197Spatrick 
LLDB_PLUGIN_DEFINE(ABISysV_ppc64) const52dda28197Spatrick LLDB_PLUGIN_DEFINE(ABISysV_ppc64)
53dda28197Spatrick 
54dda28197Spatrick const lldb_private::RegisterInfo *
55dda28197Spatrick ABISysV_ppc64::GetRegisterInfoArray(uint32_t &count) {
56dda28197Spatrick   if (GetByteOrder() == lldb::eByteOrderLittle) {
57*f6aab3d8Srobert     count = std::size(g_register_infos_ppc64le);
58dda28197Spatrick     return g_register_infos_ppc64le;
59dda28197Spatrick   } else {
60*f6aab3d8Srobert     count = std::size(g_register_infos_ppc64);
61dda28197Spatrick     return g_register_infos_ppc64;
62dda28197Spatrick   }
63dda28197Spatrick }
64dda28197Spatrick 
GetRedZoneSize() const65dda28197Spatrick size_t ABISysV_ppc64::GetRedZoneSize() const { return 224; }
66dda28197Spatrick 
GetByteOrder() const67dda28197Spatrick lldb::ByteOrder ABISysV_ppc64::GetByteOrder() const {
68dda28197Spatrick   return GetProcessSP()->GetByteOrder();
69dda28197Spatrick }
70dda28197Spatrick 
71dda28197Spatrick // Static Functions
72dda28197Spatrick 
73dda28197Spatrick ABISP
CreateInstance(lldb::ProcessSP process_sp,const ArchSpec & arch)74dda28197Spatrick ABISysV_ppc64::CreateInstance(lldb::ProcessSP process_sp,
75dda28197Spatrick                               const ArchSpec &arch) {
76dda28197Spatrick   if (arch.GetTriple().isPPC64())
77dda28197Spatrick     return ABISP(
78dda28197Spatrick         new ABISysV_ppc64(std::move(process_sp), MakeMCRegisterInfo(arch)));
79dda28197Spatrick   return ABISP();
80dda28197Spatrick }
81dda28197Spatrick 
PrepareTrivialCall(Thread & thread,addr_t sp,addr_t func_addr,addr_t return_addr,llvm::ArrayRef<addr_t> args) const82dda28197Spatrick bool ABISysV_ppc64::PrepareTrivialCall(Thread &thread, addr_t sp,
83dda28197Spatrick                                        addr_t func_addr, addr_t return_addr,
84dda28197Spatrick                                        llvm::ArrayRef<addr_t> args) const {
85*f6aab3d8Srobert   Log *log = GetLog(LLDBLog::Expressions);
86dda28197Spatrick 
87dda28197Spatrick   if (log) {
88dda28197Spatrick     StreamString s;
89dda28197Spatrick     s.Printf("ABISysV_ppc64::PrepareTrivialCall (tid = 0x%" PRIx64
90dda28197Spatrick              ", sp = 0x%" PRIx64 ", func_addr = 0x%" PRIx64
91dda28197Spatrick              ", return_addr = 0x%" PRIx64,
92dda28197Spatrick              thread.GetID(), (uint64_t)sp, (uint64_t)func_addr,
93dda28197Spatrick              (uint64_t)return_addr);
94dda28197Spatrick 
95dda28197Spatrick     for (size_t i = 0; i < args.size(); ++i)
96dda28197Spatrick       s.Printf(", arg%" PRIu64 " = 0x%" PRIx64, static_cast<uint64_t>(i + 1),
97dda28197Spatrick                args[i]);
98dda28197Spatrick     s.PutCString(")");
99dda28197Spatrick     log->PutString(s.GetString());
100dda28197Spatrick   }
101dda28197Spatrick 
102dda28197Spatrick   RegisterContext *reg_ctx = thread.GetRegisterContext().get();
103dda28197Spatrick   if (!reg_ctx)
104dda28197Spatrick     return false;
105dda28197Spatrick 
106dda28197Spatrick   const RegisterInfo *reg_info = nullptr;
107dda28197Spatrick 
108dda28197Spatrick   if (args.size() > 8) // TODO handle more than 8 arguments
109dda28197Spatrick     return false;
110dda28197Spatrick 
111dda28197Spatrick   for (size_t i = 0; i < args.size(); ++i) {
112dda28197Spatrick     reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric,
113dda28197Spatrick                                         LLDB_REGNUM_GENERIC_ARG1 + i);
114dda28197Spatrick     LLDB_LOGF(log, "About to write arg%" PRIu64 " (0x%" PRIx64 ") into %s",
115dda28197Spatrick               static_cast<uint64_t>(i + 1), args[i], reg_info->name);
116dda28197Spatrick     if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i]))
117dda28197Spatrick       return false;
118dda28197Spatrick   }
119dda28197Spatrick 
120dda28197Spatrick   // First, align the SP
121dda28197Spatrick 
122dda28197Spatrick   LLDB_LOGF(log, "16-byte aligning SP: 0x%" PRIx64 " to 0x%" PRIx64,
123dda28197Spatrick             (uint64_t)sp, (uint64_t)(sp & ~0xfull));
124dda28197Spatrick 
125dda28197Spatrick   sp &= ~(0xfull); // 16-byte alignment
126dda28197Spatrick 
127dda28197Spatrick   sp -= 544; // allocate frame to save TOC, RA and SP.
128dda28197Spatrick 
129dda28197Spatrick   Status error;
130dda28197Spatrick   uint64_t reg_value;
131dda28197Spatrick   const RegisterInfo *pc_reg_info =
132dda28197Spatrick       reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
133dda28197Spatrick   const RegisterInfo *sp_reg_info =
134dda28197Spatrick       reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
135dda28197Spatrick   ProcessSP process_sp(thread.GetProcess());
136dda28197Spatrick   const RegisterInfo *lr_reg_info =
137dda28197Spatrick       reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA);
138dda28197Spatrick   const RegisterInfo *r2_reg_info = reg_ctx->GetRegisterInfoAtIndex(2);
139dda28197Spatrick   const RegisterInfo *r12_reg_info = reg_ctx->GetRegisterInfoAtIndex(12);
140dda28197Spatrick 
141dda28197Spatrick   // Save return address onto the stack.
142dda28197Spatrick   LLDB_LOGF(log,
143dda28197Spatrick             "Pushing the return address onto the stack: 0x%" PRIx64
144dda28197Spatrick             "(+16): 0x%" PRIx64,
145dda28197Spatrick             (uint64_t)sp, (uint64_t)return_addr);
146dda28197Spatrick   if (!process_sp->WritePointerToMemory(sp + 16, return_addr, error))
147dda28197Spatrick     return false;
148dda28197Spatrick 
149dda28197Spatrick   // Write the return address to link register.
150dda28197Spatrick   LLDB_LOGF(log, "Writing LR: 0x%" PRIx64, (uint64_t)return_addr);
151dda28197Spatrick   if (!reg_ctx->WriteRegisterFromUnsigned(lr_reg_info, return_addr))
152dda28197Spatrick     return false;
153dda28197Spatrick 
154dda28197Spatrick   // Write target address to %r12 register.
155dda28197Spatrick   LLDB_LOGF(log, "Writing R12: 0x%" PRIx64, (uint64_t)func_addr);
156dda28197Spatrick   if (!reg_ctx->WriteRegisterFromUnsigned(r12_reg_info, func_addr))
157dda28197Spatrick     return false;
158dda28197Spatrick 
159dda28197Spatrick   // Read TOC pointer value.
160dda28197Spatrick   reg_value = reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0);
161dda28197Spatrick 
162dda28197Spatrick   // Write TOC pointer onto the stack.
163dda28197Spatrick   uint64_t stack_offset;
164dda28197Spatrick   if (GetByteOrder() == lldb::eByteOrderLittle)
165dda28197Spatrick     stack_offset = 24;
166dda28197Spatrick   else
167dda28197Spatrick     stack_offset = 40;
168dda28197Spatrick 
169dda28197Spatrick   LLDB_LOGF(log, "Writing R2 (TOC) at SP(0x%" PRIx64 ")+%d: 0x%" PRIx64,
170dda28197Spatrick             (uint64_t)(sp + stack_offset), (int)stack_offset,
171dda28197Spatrick             (uint64_t)reg_value);
172dda28197Spatrick   if (!process_sp->WritePointerToMemory(sp + stack_offset, reg_value, error))
173dda28197Spatrick     return false;
174dda28197Spatrick 
175dda28197Spatrick   // Read the current SP value.
176dda28197Spatrick   reg_value = reg_ctx->ReadRegisterAsUnsigned(sp_reg_info, 0);
177dda28197Spatrick 
178dda28197Spatrick   // Save current SP onto the stack.
179dda28197Spatrick   LLDB_LOGF(log, "Writing SP at SP(0x%" PRIx64 ")+0: 0x%" PRIx64, (uint64_t)sp,
180dda28197Spatrick             (uint64_t)reg_value);
181dda28197Spatrick   if (!process_sp->WritePointerToMemory(sp, reg_value, error))
182dda28197Spatrick     return false;
183dda28197Spatrick 
184dda28197Spatrick   // %r1 is set to the actual stack value.
185dda28197Spatrick   LLDB_LOGF(log, "Writing SP: 0x%" PRIx64, (uint64_t)sp);
186dda28197Spatrick 
187dda28197Spatrick   if (!reg_ctx->WriteRegisterFromUnsigned(sp_reg_info, sp))
188dda28197Spatrick     return false;
189dda28197Spatrick 
190dda28197Spatrick   // %pc is set to the address of the called function.
191dda28197Spatrick 
192dda28197Spatrick   LLDB_LOGF(log, "Writing IP: 0x%" PRIx64, (uint64_t)func_addr);
193dda28197Spatrick 
194dda28197Spatrick   if (!reg_ctx->WriteRegisterFromUnsigned(pc_reg_info, func_addr))
195dda28197Spatrick     return false;
196dda28197Spatrick 
197dda28197Spatrick   return true;
198dda28197Spatrick }
199dda28197Spatrick 
ReadIntegerArgument(Scalar & scalar,unsigned int bit_width,bool is_signed,Thread & thread,uint32_t * argument_register_ids,unsigned int & current_argument_register,addr_t & current_stack_argument)200dda28197Spatrick static bool ReadIntegerArgument(Scalar &scalar, unsigned int bit_width,
201dda28197Spatrick                                 bool is_signed, Thread &thread,
202dda28197Spatrick                                 uint32_t *argument_register_ids,
203dda28197Spatrick                                 unsigned int &current_argument_register,
204dda28197Spatrick                                 addr_t &current_stack_argument) {
205dda28197Spatrick   if (bit_width > 64)
206dda28197Spatrick     return false; // Scalar can't hold large integer arguments
207dda28197Spatrick 
208dda28197Spatrick   if (current_argument_register < 6) {
209dda28197Spatrick     scalar = thread.GetRegisterContext()->ReadRegisterAsUnsigned(
210dda28197Spatrick         argument_register_ids[current_argument_register], 0);
211dda28197Spatrick     current_argument_register++;
212dda28197Spatrick     if (is_signed)
213dda28197Spatrick       scalar.SignExtend(bit_width);
214dda28197Spatrick   } else {
215dda28197Spatrick     uint32_t byte_size = (bit_width + (8 - 1)) / 8;
216dda28197Spatrick     Status error;
217dda28197Spatrick     if (thread.GetProcess()->ReadScalarIntegerFromMemory(
218dda28197Spatrick             current_stack_argument, byte_size, is_signed, scalar, error)) {
219dda28197Spatrick       current_stack_argument += byte_size;
220dda28197Spatrick       return true;
221dda28197Spatrick     }
222dda28197Spatrick     return false;
223dda28197Spatrick   }
224dda28197Spatrick   return true;
225dda28197Spatrick }
226dda28197Spatrick 
GetArgumentValues(Thread & thread,ValueList & values) const227dda28197Spatrick bool ABISysV_ppc64::GetArgumentValues(Thread &thread, ValueList &values) const {
228dda28197Spatrick   unsigned int num_values = values.GetSize();
229dda28197Spatrick   unsigned int value_index;
230dda28197Spatrick 
231dda28197Spatrick   // Extract the register context so we can read arguments from registers
232dda28197Spatrick 
233dda28197Spatrick   RegisterContext *reg_ctx = thread.GetRegisterContext().get();
234dda28197Spatrick 
235dda28197Spatrick   if (!reg_ctx)
236dda28197Spatrick     return false;
237dda28197Spatrick 
238dda28197Spatrick   // Get the pointer to the first stack argument so we have a place to start
239dda28197Spatrick   // when reading data
240dda28197Spatrick 
241dda28197Spatrick   addr_t sp = reg_ctx->GetSP(0);
242dda28197Spatrick 
243dda28197Spatrick   if (!sp)
244dda28197Spatrick     return false;
245dda28197Spatrick 
246dda28197Spatrick   uint64_t stack_offset;
247dda28197Spatrick   if (GetByteOrder() == lldb::eByteOrderLittle)
248dda28197Spatrick     stack_offset = 32;
249dda28197Spatrick   else
250dda28197Spatrick     stack_offset = 48;
251dda28197Spatrick 
252dda28197Spatrick   // jump over return address.
253dda28197Spatrick   addr_t current_stack_argument = sp + stack_offset;
254dda28197Spatrick   uint32_t argument_register_ids[8];
255dda28197Spatrick 
256dda28197Spatrick   for (size_t i = 0; i < 8; ++i) {
257dda28197Spatrick     argument_register_ids[i] =
258dda28197Spatrick         reg_ctx
259dda28197Spatrick             ->GetRegisterInfo(eRegisterKindGeneric,
260dda28197Spatrick                               LLDB_REGNUM_GENERIC_ARG1 + i)
261dda28197Spatrick             ->kinds[eRegisterKindLLDB];
262dda28197Spatrick   }
263dda28197Spatrick 
264dda28197Spatrick   unsigned int current_argument_register = 0;
265dda28197Spatrick 
266dda28197Spatrick   for (value_index = 0; value_index < num_values; ++value_index) {
267dda28197Spatrick     Value *value = values.GetValueAtIndex(value_index);
268dda28197Spatrick 
269dda28197Spatrick     if (!value)
270dda28197Spatrick       return false;
271dda28197Spatrick 
272dda28197Spatrick     // We currently only support extracting values with Clang QualTypes. Do we
273dda28197Spatrick     // care about others?
274dda28197Spatrick     CompilerType compiler_type = value->GetCompilerType();
275*f6aab3d8Srobert     std::optional<uint64_t> bit_size = compiler_type.GetBitSize(&thread);
276dda28197Spatrick     if (!bit_size)
277dda28197Spatrick       return false;
278dda28197Spatrick     bool is_signed;
279dda28197Spatrick 
280dda28197Spatrick     if (compiler_type.IsIntegerOrEnumerationType(is_signed)) {
281dda28197Spatrick       ReadIntegerArgument(value->GetScalar(), *bit_size, is_signed, thread,
282dda28197Spatrick                           argument_register_ids, current_argument_register,
283dda28197Spatrick                           current_stack_argument);
284dda28197Spatrick     } else if (compiler_type.IsPointerType()) {
285dda28197Spatrick       ReadIntegerArgument(value->GetScalar(), *bit_size, false, thread,
286dda28197Spatrick                           argument_register_ids, current_argument_register,
287dda28197Spatrick                           current_stack_argument);
288dda28197Spatrick     }
289dda28197Spatrick   }
290dda28197Spatrick 
291dda28197Spatrick   return true;
292dda28197Spatrick }
293dda28197Spatrick 
SetReturnValueObject(lldb::StackFrameSP & frame_sp,lldb::ValueObjectSP & new_value_sp)294dda28197Spatrick Status ABISysV_ppc64::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
295dda28197Spatrick                                            lldb::ValueObjectSP &new_value_sp) {
296dda28197Spatrick   Status error;
297dda28197Spatrick   if (!new_value_sp) {
298dda28197Spatrick     error.SetErrorString("Empty value object for return value.");
299dda28197Spatrick     return error;
300dda28197Spatrick   }
301dda28197Spatrick 
302dda28197Spatrick   CompilerType compiler_type = new_value_sp->GetCompilerType();
303dda28197Spatrick   if (!compiler_type) {
304dda28197Spatrick     error.SetErrorString("Null clang type for return value.");
305dda28197Spatrick     return error;
306dda28197Spatrick   }
307dda28197Spatrick 
308dda28197Spatrick   Thread *thread = frame_sp->GetThread().get();
309dda28197Spatrick 
310dda28197Spatrick   bool is_signed;
311dda28197Spatrick   uint32_t count;
312dda28197Spatrick   bool is_complex;
313dda28197Spatrick 
314dda28197Spatrick   RegisterContext *reg_ctx = thread->GetRegisterContext().get();
315dda28197Spatrick 
316dda28197Spatrick   bool set_it_simple = false;
317dda28197Spatrick   if (compiler_type.IsIntegerOrEnumerationType(is_signed) ||
318dda28197Spatrick       compiler_type.IsPointerType()) {
319dda28197Spatrick     const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName("r3", 0);
320dda28197Spatrick 
321dda28197Spatrick     DataExtractor data;
322dda28197Spatrick     Status data_error;
323dda28197Spatrick     size_t num_bytes = new_value_sp->GetData(data, data_error);
324dda28197Spatrick     if (data_error.Fail()) {
325dda28197Spatrick       error.SetErrorStringWithFormat(
326dda28197Spatrick           "Couldn't convert return value to raw data: %s",
327dda28197Spatrick           data_error.AsCString());
328dda28197Spatrick       return error;
329dda28197Spatrick     }
330dda28197Spatrick     lldb::offset_t offset = 0;
331dda28197Spatrick     if (num_bytes <= 8) {
332dda28197Spatrick       uint64_t raw_value = data.GetMaxU64(&offset, num_bytes);
333dda28197Spatrick 
334dda28197Spatrick       if (reg_ctx->WriteRegisterFromUnsigned(reg_info, raw_value))
335dda28197Spatrick         set_it_simple = true;
336dda28197Spatrick     } else {
337dda28197Spatrick       error.SetErrorString("We don't support returning longer than 64 bit "
338dda28197Spatrick                            "integer values at present.");
339dda28197Spatrick     }
340dda28197Spatrick   } else if (compiler_type.IsFloatingPointType(count, is_complex)) {
341dda28197Spatrick     if (is_complex)
342dda28197Spatrick       error.SetErrorString(
343dda28197Spatrick           "We don't support returning complex values at present");
344dda28197Spatrick     else {
345*f6aab3d8Srobert       std::optional<uint64_t> bit_width =
346dda28197Spatrick           compiler_type.GetBitSize(frame_sp.get());
347dda28197Spatrick       if (!bit_width) {
348dda28197Spatrick         error.SetErrorString("can't get size of type");
349dda28197Spatrick         return error;
350dda28197Spatrick       }
351dda28197Spatrick       if (*bit_width <= 64) {
352dda28197Spatrick         DataExtractor data;
353dda28197Spatrick         Status data_error;
354dda28197Spatrick         size_t num_bytes = new_value_sp->GetData(data, data_error);
355dda28197Spatrick         if (data_error.Fail()) {
356dda28197Spatrick           error.SetErrorStringWithFormat(
357dda28197Spatrick               "Couldn't convert return value to raw data: %s",
358dda28197Spatrick               data_error.AsCString());
359dda28197Spatrick           return error;
360dda28197Spatrick         }
361dda28197Spatrick 
362dda28197Spatrick         unsigned char buffer[16];
363dda28197Spatrick         ByteOrder byte_order = data.GetByteOrder();
364dda28197Spatrick 
365dda28197Spatrick         data.CopyByteOrderedData(0, num_bytes, buffer, 16, byte_order);
366dda28197Spatrick         set_it_simple = true;
367dda28197Spatrick       } else {
368dda28197Spatrick         // FIXME - don't know how to do 80 bit long doubles yet.
369dda28197Spatrick         error.SetErrorString(
370dda28197Spatrick             "We don't support returning float values > 64 bits at present");
371dda28197Spatrick       }
372dda28197Spatrick     }
373dda28197Spatrick   }
374dda28197Spatrick 
375dda28197Spatrick   if (!set_it_simple) {
376dda28197Spatrick     // Okay we've got a structure or something that doesn't fit in a simple
377dda28197Spatrick     // register. We should figure out where it really goes, but we don't
378dda28197Spatrick     // support this yet.
379dda28197Spatrick     error.SetErrorString("We only support setting simple integer and float "
380dda28197Spatrick                          "return types at present.");
381dda28197Spatrick   }
382dda28197Spatrick 
383dda28197Spatrick   return error;
384dda28197Spatrick }
385dda28197Spatrick 
386dda28197Spatrick //
387dda28197Spatrick // ReturnValueExtractor
388dda28197Spatrick //
389dda28197Spatrick 
390dda28197Spatrick namespace {
391dda28197Spatrick 
392dda28197Spatrick #define LOG_PREFIX "ReturnValueExtractor: "
393dda28197Spatrick 
394dda28197Spatrick class ReturnValueExtractor {
395dda28197Spatrick   // This class represents a register, from which data may be extracted.
396dda28197Spatrick   //
397dda28197Spatrick   // It may be constructed by directly specifying its index (where 0 is the
398dda28197Spatrick   // first register used to return values) or by specifying the offset of a
399dda28197Spatrick   // given struct field, in which case the appropriated register index will be
400dda28197Spatrick   // calculated.
401dda28197Spatrick   class Register {
402dda28197Spatrick   public:
403dda28197Spatrick     enum Type {
404dda28197Spatrick       GPR, // General Purpose Register
405dda28197Spatrick       FPR  // Floating Point Register
406dda28197Spatrick     };
407dda28197Spatrick 
408dda28197Spatrick     // main constructor
409dda28197Spatrick     //
410dda28197Spatrick     // offs - field offset in struct
Register(Type ty,uint32_t index,uint32_t offs,RegisterContext * reg_ctx,ByteOrder byte_order)411dda28197Spatrick     Register(Type ty, uint32_t index, uint32_t offs, RegisterContext *reg_ctx,
412dda28197Spatrick              ByteOrder byte_order)
413dda28197Spatrick         : m_index(index), m_offs(offs % sizeof(uint64_t)),
414dda28197Spatrick           m_avail(sizeof(uint64_t) - m_offs), m_type(ty), m_reg_ctx(reg_ctx),
415dda28197Spatrick           m_byte_order(byte_order) {}
416dda28197Spatrick 
417dda28197Spatrick     // explicit index, no offset
Register(Type ty,uint32_t index,RegisterContext * reg_ctx,ByteOrder byte_order)418dda28197Spatrick     Register(Type ty, uint32_t index, RegisterContext *reg_ctx,
419dda28197Spatrick              ByteOrder byte_order)
420dda28197Spatrick         : Register(ty, index, 0, reg_ctx, byte_order) {}
421dda28197Spatrick 
422dda28197Spatrick     // GPR, calculate index from offs
Register(uint32_t offs,RegisterContext * reg_ctx,ByteOrder byte_order)423dda28197Spatrick     Register(uint32_t offs, RegisterContext *reg_ctx, ByteOrder byte_order)
424dda28197Spatrick         : Register(GPR, offs / sizeof(uint64_t), offs, reg_ctx, byte_order) {}
425dda28197Spatrick 
Index() const426dda28197Spatrick     uint32_t Index() const { return m_index; }
427dda28197Spatrick 
428dda28197Spatrick     // register offset where data is located
Offs() const429dda28197Spatrick     uint32_t Offs() const { return m_offs; }
430dda28197Spatrick 
431dda28197Spatrick     // available bytes in this register
Avail() const432dda28197Spatrick     uint32_t Avail() const { return m_avail; }
433dda28197Spatrick 
IsValid() const434dda28197Spatrick     bool IsValid() const {
435dda28197Spatrick       if (m_index > 7) {
436dda28197Spatrick         LLDB_LOG(m_log, LOG_PREFIX
437dda28197Spatrick                  "No more than 8 registers should be used to return values");
438dda28197Spatrick         return false;
439dda28197Spatrick       }
440dda28197Spatrick       return true;
441dda28197Spatrick     }
442dda28197Spatrick 
GetName() const443dda28197Spatrick     std::string GetName() const {
444dda28197Spatrick       if (m_type == GPR)
445dda28197Spatrick         return ("r" + llvm::Twine(m_index + 3)).str();
446dda28197Spatrick       else
447dda28197Spatrick         return ("f" + llvm::Twine(m_index + 1)).str();
448dda28197Spatrick     }
449dda28197Spatrick 
450dda28197Spatrick     // get raw register data
GetRawData(uint64_t & raw_data)451dda28197Spatrick     bool GetRawData(uint64_t &raw_data) {
452dda28197Spatrick       const RegisterInfo *reg_info =
453dda28197Spatrick           m_reg_ctx->GetRegisterInfoByName(GetName());
454dda28197Spatrick       if (!reg_info) {
455dda28197Spatrick         LLDB_LOG(m_log, LOG_PREFIX "Failed to get RegisterInfo");
456dda28197Spatrick         return false;
457dda28197Spatrick       }
458dda28197Spatrick 
459dda28197Spatrick       RegisterValue reg_val;
460dda28197Spatrick       if (!m_reg_ctx->ReadRegister(reg_info, reg_val)) {
461dda28197Spatrick         LLDB_LOG(m_log, LOG_PREFIX "ReadRegister() failed");
462dda28197Spatrick         return false;
463dda28197Spatrick       }
464dda28197Spatrick 
465dda28197Spatrick       Status error;
466dda28197Spatrick       uint32_t rc = reg_val.GetAsMemoryData(
467*f6aab3d8Srobert           *reg_info, &raw_data, sizeof(raw_data), m_byte_order, error);
468dda28197Spatrick       if (rc != sizeof(raw_data)) {
469dda28197Spatrick         LLDB_LOG(m_log, LOG_PREFIX "GetAsMemoryData() failed");
470dda28197Spatrick         return false;
471dda28197Spatrick       }
472dda28197Spatrick 
473dda28197Spatrick       return true;
474dda28197Spatrick     }
475dda28197Spatrick 
476dda28197Spatrick   private:
477dda28197Spatrick     uint32_t m_index;
478dda28197Spatrick     uint32_t m_offs;
479dda28197Spatrick     uint32_t m_avail;
480dda28197Spatrick     Type m_type;
481dda28197Spatrick     RegisterContext *m_reg_ctx;
482dda28197Spatrick     ByteOrder m_byte_order;
483*f6aab3d8Srobert     Log *m_log = GetLog(LLDBLog::Expressions);
484dda28197Spatrick   };
485dda28197Spatrick 
GetGPR(uint32_t index) const486dda28197Spatrick   Register GetGPR(uint32_t index) const {
487dda28197Spatrick     return Register(Register::GPR, index, m_reg_ctx, m_byte_order);
488dda28197Spatrick   }
489dda28197Spatrick 
GetFPR(uint32_t index) const490dda28197Spatrick   Register GetFPR(uint32_t index) const {
491dda28197Spatrick     return Register(Register::FPR, index, m_reg_ctx, m_byte_order);
492dda28197Spatrick   }
493dda28197Spatrick 
GetGPRByOffs(uint32_t offs) const494dda28197Spatrick   Register GetGPRByOffs(uint32_t offs) const {
495dda28197Spatrick     return Register(offs, m_reg_ctx, m_byte_order);
496dda28197Spatrick   }
497dda28197Spatrick 
498dda28197Spatrick public:
499dda28197Spatrick   // factory
Create(Thread & thread,CompilerType & type)500dda28197Spatrick   static llvm::Expected<ReturnValueExtractor> Create(Thread &thread,
501dda28197Spatrick                                                      CompilerType &type) {
502dda28197Spatrick     RegisterContext *reg_ctx = thread.GetRegisterContext().get();
503dda28197Spatrick     if (!reg_ctx)
504dda28197Spatrick       return llvm::make_error<llvm::StringError>(
505dda28197Spatrick           LOG_PREFIX "Failed to get RegisterContext",
506dda28197Spatrick           llvm::inconvertibleErrorCode());
507dda28197Spatrick 
508dda28197Spatrick     ProcessSP process_sp = thread.GetProcess();
509dda28197Spatrick     if (!process_sp)
510dda28197Spatrick       return llvm::make_error<llvm::StringError>(
511dda28197Spatrick           LOG_PREFIX "GetProcess() failed", llvm::inconvertibleErrorCode());
512dda28197Spatrick 
513dda28197Spatrick     return ReturnValueExtractor(thread, type, reg_ctx, process_sp);
514dda28197Spatrick   }
515dda28197Spatrick 
516dda28197Spatrick   // main method: get value of the type specified at construction time
GetValue()517dda28197Spatrick   ValueObjectSP GetValue() {
518dda28197Spatrick     const uint32_t type_flags = m_type.GetTypeInfo();
519dda28197Spatrick 
520dda28197Spatrick     // call the appropriate type handler
521dda28197Spatrick     ValueSP value_sp;
522dda28197Spatrick     ValueObjectSP valobj_sp;
523dda28197Spatrick     if (type_flags & eTypeIsScalar) {
524dda28197Spatrick       if (type_flags & eTypeIsInteger) {
525dda28197Spatrick         value_sp = GetIntegerValue(0);
526dda28197Spatrick       } else if (type_flags & eTypeIsFloat) {
527dda28197Spatrick         if (type_flags & eTypeIsComplex) {
528dda28197Spatrick           LLDB_LOG(m_log, LOG_PREFIX "Complex numbers are not supported yet");
529dda28197Spatrick           return ValueObjectSP();
530dda28197Spatrick         } else {
531dda28197Spatrick           value_sp = GetFloatValue(m_type, 0);
532dda28197Spatrick         }
533dda28197Spatrick       }
534dda28197Spatrick     } else if (type_flags & eTypeIsPointer) {
535dda28197Spatrick       value_sp = GetPointerValue(0);
536dda28197Spatrick     }
537dda28197Spatrick 
538dda28197Spatrick     if (value_sp) {
539dda28197Spatrick       valobj_sp = ValueObjectConstResult::Create(
540dda28197Spatrick           m_thread.GetStackFrameAtIndex(0).get(), *value_sp, ConstString(""));
541dda28197Spatrick     } else if (type_flags & eTypeIsVector) {
542dda28197Spatrick       valobj_sp = GetVectorValueObject();
543dda28197Spatrick     } else if (type_flags & eTypeIsStructUnion || type_flags & eTypeIsClass) {
544dda28197Spatrick       valobj_sp = GetStructValueObject();
545dda28197Spatrick     }
546dda28197Spatrick 
547dda28197Spatrick     return valobj_sp;
548dda28197Spatrick   }
549dda28197Spatrick 
550dda28197Spatrick private:
551dda28197Spatrick   // data
552dda28197Spatrick   Thread &m_thread;
553dda28197Spatrick   CompilerType &m_type;
554dda28197Spatrick   uint64_t m_byte_size;
555dda28197Spatrick   std::unique_ptr<DataBufferHeap> m_data_up;
556dda28197Spatrick   int32_t m_src_offs = 0;
557dda28197Spatrick   int32_t m_dst_offs = 0;
558dda28197Spatrick   bool m_packed = false;
559*f6aab3d8Srobert   Log *m_log = GetLog(LLDBLog::Expressions);
560dda28197Spatrick   RegisterContext *m_reg_ctx;
561dda28197Spatrick   ProcessSP m_process_sp;
562dda28197Spatrick   ByteOrder m_byte_order;
563dda28197Spatrick   uint32_t m_addr_size;
564dda28197Spatrick 
565dda28197Spatrick   // methods
566dda28197Spatrick 
567dda28197Spatrick   // constructor
ReturnValueExtractor(Thread & thread,CompilerType & type,RegisterContext * reg_ctx,ProcessSP process_sp)568dda28197Spatrick   ReturnValueExtractor(Thread &thread, CompilerType &type,
569dda28197Spatrick                        RegisterContext *reg_ctx, ProcessSP process_sp)
570dda28197Spatrick       : m_thread(thread), m_type(type),
571*f6aab3d8Srobert         m_byte_size(m_type.GetByteSize(&thread).value_or(0)),
572dda28197Spatrick         m_data_up(new DataBufferHeap(m_byte_size, 0)), m_reg_ctx(reg_ctx),
573dda28197Spatrick         m_process_sp(process_sp), m_byte_order(process_sp->GetByteOrder()),
574dda28197Spatrick         m_addr_size(
575dda28197Spatrick             process_sp->GetTarget().GetArchitecture().GetAddressByteSize()) {}
576dda28197Spatrick 
577dda28197Spatrick   // build a new scalar value
NewScalarValue(CompilerType & type)578dda28197Spatrick   ValueSP NewScalarValue(CompilerType &type) {
579dda28197Spatrick     ValueSP value_sp(new Value);
580dda28197Spatrick     value_sp->SetCompilerType(type);
581be691f3bSpatrick     value_sp->SetValueType(Value::ValueType::Scalar);
582dda28197Spatrick     return value_sp;
583dda28197Spatrick   }
584dda28197Spatrick 
585dda28197Spatrick   // get an integer value in the specified register
GetIntegerValue(uint32_t reg_index)586dda28197Spatrick   ValueSP GetIntegerValue(uint32_t reg_index) {
587dda28197Spatrick     uint64_t raw_value;
588dda28197Spatrick     auto reg = GetGPR(reg_index);
589dda28197Spatrick     if (!reg.GetRawData(raw_value))
590dda28197Spatrick       return ValueSP();
591dda28197Spatrick 
592dda28197Spatrick     // build value from data
593dda28197Spatrick     ValueSP value_sp(NewScalarValue(m_type));
594dda28197Spatrick 
595dda28197Spatrick     uint32_t type_flags = m_type.GetTypeInfo();
596dda28197Spatrick     bool is_signed = (type_flags & eTypeIsSigned) != 0;
597dda28197Spatrick 
598dda28197Spatrick     switch (m_byte_size) {
599dda28197Spatrick     case sizeof(uint64_t):
600dda28197Spatrick       if (is_signed)
601dda28197Spatrick         value_sp->GetScalar() = (int64_t)(raw_value);
602dda28197Spatrick       else
603dda28197Spatrick         value_sp->GetScalar() = (uint64_t)(raw_value);
604dda28197Spatrick       break;
605dda28197Spatrick 
606dda28197Spatrick     case sizeof(uint32_t):
607dda28197Spatrick       if (is_signed)
608dda28197Spatrick         value_sp->GetScalar() = (int32_t)(raw_value & UINT32_MAX);
609dda28197Spatrick       else
610dda28197Spatrick         value_sp->GetScalar() = (uint32_t)(raw_value & UINT32_MAX);
611dda28197Spatrick       break;
612dda28197Spatrick 
613dda28197Spatrick     case sizeof(uint16_t):
614dda28197Spatrick       if (is_signed)
615dda28197Spatrick         value_sp->GetScalar() = (int16_t)(raw_value & UINT16_MAX);
616dda28197Spatrick       else
617dda28197Spatrick         value_sp->GetScalar() = (uint16_t)(raw_value & UINT16_MAX);
618dda28197Spatrick       break;
619dda28197Spatrick 
620dda28197Spatrick     case sizeof(uint8_t):
621dda28197Spatrick       if (is_signed)
622dda28197Spatrick         value_sp->GetScalar() = (int8_t)(raw_value & UINT8_MAX);
623dda28197Spatrick       else
624dda28197Spatrick         value_sp->GetScalar() = (uint8_t)(raw_value & UINT8_MAX);
625dda28197Spatrick       break;
626dda28197Spatrick 
627dda28197Spatrick     default:
628dda28197Spatrick       llvm_unreachable("Invalid integer size");
629dda28197Spatrick     }
630dda28197Spatrick 
631dda28197Spatrick     return value_sp;
632dda28197Spatrick   }
633dda28197Spatrick 
634dda28197Spatrick   // get a floating point value on the specified register
GetFloatValue(CompilerType & type,uint32_t reg_index)635dda28197Spatrick   ValueSP GetFloatValue(CompilerType &type, uint32_t reg_index) {
636dda28197Spatrick     uint64_t raw_data;
637dda28197Spatrick     auto reg = GetFPR(reg_index);
638dda28197Spatrick     if (!reg.GetRawData(raw_data))
639dda28197Spatrick       return {};
640dda28197Spatrick 
641dda28197Spatrick     // build value from data
642dda28197Spatrick     ValueSP value_sp(NewScalarValue(type));
643dda28197Spatrick 
644dda28197Spatrick     DataExtractor de(&raw_data, sizeof(raw_data), m_byte_order, m_addr_size);
645dda28197Spatrick 
646dda28197Spatrick     offset_t offset = 0;
647*f6aab3d8Srobert     std::optional<uint64_t> byte_size = type.GetByteSize(m_process_sp.get());
648dda28197Spatrick     if (!byte_size)
649dda28197Spatrick       return {};
650dda28197Spatrick     switch (*byte_size) {
651dda28197Spatrick     case sizeof(float):
652dda28197Spatrick       value_sp->GetScalar() = (float)de.GetDouble(&offset);
653dda28197Spatrick       break;
654dda28197Spatrick 
655dda28197Spatrick     case sizeof(double):
656dda28197Spatrick       value_sp->GetScalar() = de.GetDouble(&offset);
657dda28197Spatrick       break;
658dda28197Spatrick 
659dda28197Spatrick     default:
660dda28197Spatrick       llvm_unreachable("Invalid floating point size");
661dda28197Spatrick     }
662dda28197Spatrick 
663dda28197Spatrick     return value_sp;
664dda28197Spatrick   }
665dda28197Spatrick 
666dda28197Spatrick   // get pointer value from register
GetPointerValue(uint32_t reg_index)667dda28197Spatrick   ValueSP GetPointerValue(uint32_t reg_index) {
668dda28197Spatrick     uint64_t raw_data;
669dda28197Spatrick     auto reg = GetGPR(reg_index);
670dda28197Spatrick     if (!reg.GetRawData(raw_data))
671dda28197Spatrick       return ValueSP();
672dda28197Spatrick 
673dda28197Spatrick     // build value from raw data
674dda28197Spatrick     ValueSP value_sp(NewScalarValue(m_type));
675dda28197Spatrick     value_sp->GetScalar() = raw_data;
676dda28197Spatrick     return value_sp;
677dda28197Spatrick   }
678dda28197Spatrick 
679dda28197Spatrick   // build the ValueObject from our data buffer
BuildValueObject()680dda28197Spatrick   ValueObjectSP BuildValueObject() {
681dda28197Spatrick     DataExtractor de(DataBufferSP(m_data_up.release()), m_byte_order,
682dda28197Spatrick                      m_addr_size);
683dda28197Spatrick     return ValueObjectConstResult::Create(&m_thread, m_type, ConstString(""),
684dda28197Spatrick                                           de);
685dda28197Spatrick   }
686dda28197Spatrick 
687dda28197Spatrick   // get a vector return value
GetVectorValueObject()688dda28197Spatrick   ValueObjectSP GetVectorValueObject() {
689dda28197Spatrick     const uint32_t MAX_VRS = 2;
690dda28197Spatrick 
691dda28197Spatrick     // get first V register used to return values
692dda28197Spatrick     const RegisterInfo *vr[MAX_VRS];
693dda28197Spatrick     vr[0] = m_reg_ctx->GetRegisterInfoByName("vr2");
694dda28197Spatrick     if (!vr[0]) {
695dda28197Spatrick       LLDB_LOG(m_log, LOG_PREFIX "Failed to get vr2 RegisterInfo");
696dda28197Spatrick       return ValueObjectSP();
697dda28197Spatrick     }
698dda28197Spatrick 
699dda28197Spatrick     const uint32_t vr_size = vr[0]->byte_size;
700dda28197Spatrick     size_t vrs = 1;
701dda28197Spatrick     if (m_byte_size > 2 * vr_size) {
702dda28197Spatrick       LLDB_LOG(
703dda28197Spatrick           m_log, LOG_PREFIX
704dda28197Spatrick           "Returning vectors that don't fit in 2 VR regs is not supported");
705dda28197Spatrick       return ValueObjectSP();
706dda28197Spatrick     }
707dda28197Spatrick 
708dda28197Spatrick     // load vr3, if needed
709dda28197Spatrick     if (m_byte_size > vr_size) {
710dda28197Spatrick       vrs++;
711dda28197Spatrick       vr[1] = m_reg_ctx->GetRegisterInfoByName("vr3");
712dda28197Spatrick       if (!vr[1]) {
713dda28197Spatrick         LLDB_LOG(m_log, LOG_PREFIX "Failed to get vr3 RegisterInfo");
714dda28197Spatrick         return ValueObjectSP();
715dda28197Spatrick       }
716dda28197Spatrick     }
717dda28197Spatrick 
718dda28197Spatrick     // Get the whole contents of vector registers and let the logic here
719dda28197Spatrick     // arrange the data properly.
720dda28197Spatrick 
721dda28197Spatrick     RegisterValue vr_val[MAX_VRS];
722dda28197Spatrick     Status error;
723dda28197Spatrick     std::unique_ptr<DataBufferHeap> vr_data(
724dda28197Spatrick         new DataBufferHeap(vrs * vr_size, 0));
725dda28197Spatrick 
726dda28197Spatrick     for (uint32_t i = 0; i < vrs; i++) {
727dda28197Spatrick       if (!m_reg_ctx->ReadRegister(vr[i], vr_val[i])) {
728dda28197Spatrick         LLDB_LOG(m_log, LOG_PREFIX "Failed to read vector register contents");
729dda28197Spatrick         return ValueObjectSP();
730dda28197Spatrick       }
731*f6aab3d8Srobert       if (!vr_val[i].GetAsMemoryData(*vr[i], vr_data->GetBytes() + i * vr_size,
732dda28197Spatrick                                      vr_size, m_byte_order, error)) {
733dda28197Spatrick         LLDB_LOG(m_log, LOG_PREFIX "Failed to extract vector register bytes");
734dda28197Spatrick         return ValueObjectSP();
735dda28197Spatrick       }
736dda28197Spatrick     }
737dda28197Spatrick 
738dda28197Spatrick     // The compiler generated code seems to always put the vector elements at
739dda28197Spatrick     // the end of the vector register, in case they don't occupy all of it.
740dda28197Spatrick     // This offset variable handles this.
741dda28197Spatrick     uint32_t offs = 0;
742dda28197Spatrick     if (m_byte_size < vr_size)
743dda28197Spatrick       offs = vr_size - m_byte_size;
744dda28197Spatrick 
745dda28197Spatrick     // copy extracted data to our buffer
746dda28197Spatrick     memcpy(m_data_up->GetBytes(), vr_data->GetBytes() + offs, m_byte_size);
747dda28197Spatrick     return BuildValueObject();
748dda28197Spatrick   }
749dda28197Spatrick 
750dda28197Spatrick   // get a struct return value
GetStructValueObject()751dda28197Spatrick   ValueObjectSP GetStructValueObject() {
752dda28197Spatrick     // case 1: get from stack
753dda28197Spatrick     if (m_byte_size > 2 * sizeof(uint64_t)) {
754dda28197Spatrick       uint64_t addr;
755dda28197Spatrick       auto reg = GetGPR(0);
756dda28197Spatrick       if (!reg.GetRawData(addr))
757dda28197Spatrick         return {};
758dda28197Spatrick 
759dda28197Spatrick       Status error;
760dda28197Spatrick       size_t rc = m_process_sp->ReadMemory(addr, m_data_up->GetBytes(),
761dda28197Spatrick                                            m_byte_size, error);
762dda28197Spatrick       if (rc != m_byte_size) {
763dda28197Spatrick         LLDB_LOG(m_log, LOG_PREFIX "Failed to read memory pointed by r3");
764dda28197Spatrick         return ValueObjectSP();
765dda28197Spatrick       }
766dda28197Spatrick       return BuildValueObject();
767dda28197Spatrick     }
768dda28197Spatrick 
769dda28197Spatrick     // get number of children
770dda28197Spatrick     const bool omit_empty_base_classes = true;
771dda28197Spatrick     uint32_t n = m_type.GetNumChildren(omit_empty_base_classes, nullptr);
772dda28197Spatrick     if (!n) {
773dda28197Spatrick       LLDB_LOG(m_log, LOG_PREFIX "No children found in struct");
774dda28197Spatrick       return {};
775dda28197Spatrick     }
776dda28197Spatrick 
777dda28197Spatrick     // case 2: homogeneous double or float aggregate
778dda28197Spatrick     CompilerType elem_type;
779dda28197Spatrick     if (m_type.IsHomogeneousAggregate(&elem_type)) {
780dda28197Spatrick       uint32_t type_flags = elem_type.GetTypeInfo();
781*f6aab3d8Srobert       std::optional<uint64_t> elem_size =
782be691f3bSpatrick           elem_type.GetByteSize(m_process_sp.get());
783dda28197Spatrick       if (!elem_size)
784dda28197Spatrick         return {};
785dda28197Spatrick       if (type_flags & eTypeIsComplex || !(type_flags & eTypeIsFloat)) {
786dda28197Spatrick         LLDB_LOG(m_log,
787dda28197Spatrick                  LOG_PREFIX "Unexpected type found in homogeneous aggregate");
788dda28197Spatrick         return {};
789dda28197Spatrick       }
790dda28197Spatrick 
791dda28197Spatrick       for (uint32_t i = 0; i < n; i++) {
792dda28197Spatrick         ValueSP val_sp = GetFloatValue(elem_type, i);
793dda28197Spatrick         if (!val_sp)
794dda28197Spatrick           return {};
795dda28197Spatrick 
796dda28197Spatrick         // copy to buffer
797dda28197Spatrick         Status error;
798dda28197Spatrick         size_t rc = val_sp->GetScalar().GetAsMemoryData(
799dda28197Spatrick             m_data_up->GetBytes() + m_dst_offs, *elem_size, m_byte_order,
800dda28197Spatrick             error);
801dda28197Spatrick         if (rc != *elem_size) {
802dda28197Spatrick           LLDB_LOG(m_log, LOG_PREFIX "Failed to get float data");
803dda28197Spatrick           return {};
804dda28197Spatrick         }
805dda28197Spatrick         m_dst_offs += *elem_size;
806dda28197Spatrick       }
807dda28197Spatrick       return BuildValueObject();
808dda28197Spatrick     }
809dda28197Spatrick 
810dda28197Spatrick     // case 3: get from GPRs
811dda28197Spatrick 
812dda28197Spatrick     // first, check if this is a packed struct or not
813*f6aab3d8Srobert     auto ast = m_type.GetTypeSystem().dyn_cast_or_null<TypeSystemClang>();
814dda28197Spatrick     if (ast) {
815dda28197Spatrick       clang::RecordDecl *record_decl = TypeSystemClang::GetAsRecordDecl(m_type);
816dda28197Spatrick 
817dda28197Spatrick       if (record_decl) {
818dda28197Spatrick         auto attrs = record_decl->attrs();
819dda28197Spatrick         for (const auto &attr : attrs) {
820dda28197Spatrick           if (attr->getKind() == clang::attr::Packed) {
821dda28197Spatrick             m_packed = true;
822dda28197Spatrick             break;
823dda28197Spatrick           }
824dda28197Spatrick         }
825dda28197Spatrick       }
826dda28197Spatrick     }
827dda28197Spatrick 
828dda28197Spatrick     LLDB_LOG(m_log, LOG_PREFIX "{0} struct",
829dda28197Spatrick              m_packed ? "packed" : "not packed");
830dda28197Spatrick 
831dda28197Spatrick     for (uint32_t i = 0; i < n; i++) {
832dda28197Spatrick       std::string name;
833dda28197Spatrick       uint32_t size;
834dda28197Spatrick       GetChildType(i, name, size);
835dda28197Spatrick       // NOTE: the offset returned by GetChildCompilerTypeAtIndex()
836dda28197Spatrick       //       can't be used because it never considers alignment bytes
837dda28197Spatrick       //       between struct fields.
838dda28197Spatrick       LLDB_LOG(m_log, LOG_PREFIX "field={0}, size={1}", name, size);
839dda28197Spatrick       if (!ExtractField(size))
840dda28197Spatrick         return ValueObjectSP();
841dda28197Spatrick     }
842dda28197Spatrick 
843dda28197Spatrick     return BuildValueObject();
844dda28197Spatrick   }
845dda28197Spatrick 
846dda28197Spatrick   // extract 'size' bytes at 'offs' from GPRs
ExtractFromRegs(int32_t offs,uint32_t size,void * buf)847dda28197Spatrick   bool ExtractFromRegs(int32_t offs, uint32_t size, void *buf) {
848dda28197Spatrick     while (size) {
849dda28197Spatrick       auto reg = GetGPRByOffs(offs);
850dda28197Spatrick       if (!reg.IsValid())
851dda28197Spatrick         return false;
852dda28197Spatrick 
853dda28197Spatrick       uint32_t n = std::min(reg.Avail(), size);
854dda28197Spatrick       uint64_t raw_data;
855dda28197Spatrick 
856dda28197Spatrick       if (!reg.GetRawData(raw_data))
857dda28197Spatrick         return false;
858dda28197Spatrick 
859dda28197Spatrick       memcpy(buf, (char *)&raw_data + reg.Offs(), n);
860dda28197Spatrick       offs += n;
861dda28197Spatrick       size -= n;
862dda28197Spatrick       buf = (char *)buf + n;
863dda28197Spatrick     }
864dda28197Spatrick     return true;
865dda28197Spatrick   }
866dda28197Spatrick 
867dda28197Spatrick   // extract one field from GPRs and put it in our buffer
ExtractField(uint32_t size)868dda28197Spatrick   bool ExtractField(uint32_t size) {
869dda28197Spatrick     auto reg = GetGPRByOffs(m_src_offs);
870dda28197Spatrick     if (!reg.IsValid())
871dda28197Spatrick       return false;
872dda28197Spatrick 
873dda28197Spatrick     // handle padding
874dda28197Spatrick     if (!m_packed) {
875dda28197Spatrick       uint32_t n = m_src_offs % size;
876dda28197Spatrick 
877dda28197Spatrick       // not 'size' bytes aligned
878dda28197Spatrick       if (n) {
879dda28197Spatrick         LLDB_LOG(m_log,
880dda28197Spatrick                  LOG_PREFIX "Extracting {0} alignment bytes at offset {1}", n,
881dda28197Spatrick                  m_src_offs);
882dda28197Spatrick         // get alignment bytes
883dda28197Spatrick         if (!ExtractFromRegs(m_src_offs, n, m_data_up->GetBytes() + m_dst_offs))
884dda28197Spatrick           return false;
885dda28197Spatrick         m_src_offs += n;
886dda28197Spatrick         m_dst_offs += n;
887dda28197Spatrick       }
888dda28197Spatrick     }
889dda28197Spatrick 
890dda28197Spatrick     // get field
891dda28197Spatrick     LLDB_LOG(m_log, LOG_PREFIX "Extracting {0} field bytes at offset {1}", size,
892dda28197Spatrick              m_src_offs);
893dda28197Spatrick     if (!ExtractFromRegs(m_src_offs, size, m_data_up->GetBytes() + m_dst_offs))
894dda28197Spatrick       return false;
895dda28197Spatrick     m_src_offs += size;
896dda28197Spatrick     m_dst_offs += size;
897dda28197Spatrick     return true;
898dda28197Spatrick   }
899dda28197Spatrick 
900dda28197Spatrick   // get child
GetChildType(uint32_t i,std::string & name,uint32_t & size)901dda28197Spatrick   CompilerType GetChildType(uint32_t i, std::string &name, uint32_t &size) {
902dda28197Spatrick     // GetChild constant inputs
903dda28197Spatrick     const bool transparent_pointers = false;
904dda28197Spatrick     const bool omit_empty_base_classes = true;
905dda28197Spatrick     const bool ignore_array_bounds = false;
906dda28197Spatrick     // GetChild output params
907dda28197Spatrick     int32_t child_offs;
908dda28197Spatrick     uint32_t child_bitfield_bit_size;
909dda28197Spatrick     uint32_t child_bitfield_bit_offset;
910dda28197Spatrick     bool child_is_base_class;
911dda28197Spatrick     bool child_is_deref_of_parent;
912dda28197Spatrick     ValueObject *valobj = nullptr;
913dda28197Spatrick     uint64_t language_flags;
914dda28197Spatrick     ExecutionContext exe_ctx;
915dda28197Spatrick     m_thread.CalculateExecutionContext(exe_ctx);
916dda28197Spatrick 
917dda28197Spatrick     return m_type.GetChildCompilerTypeAtIndex(
918dda28197Spatrick         &exe_ctx, i, transparent_pointers, omit_empty_base_classes,
919dda28197Spatrick         ignore_array_bounds, name, size, child_offs, child_bitfield_bit_size,
920dda28197Spatrick         child_bitfield_bit_offset, child_is_base_class,
921dda28197Spatrick         child_is_deref_of_parent, valobj, language_flags);
922dda28197Spatrick   }
923dda28197Spatrick };
924dda28197Spatrick 
925dda28197Spatrick #undef LOG_PREFIX
926dda28197Spatrick 
927dda28197Spatrick } // anonymous namespace
928dda28197Spatrick 
929dda28197Spatrick ValueObjectSP
GetReturnValueObjectSimple(Thread & thread,CompilerType & type) const930dda28197Spatrick ABISysV_ppc64::GetReturnValueObjectSimple(Thread &thread,
931dda28197Spatrick                                           CompilerType &type) const {
932dda28197Spatrick   if (!type)
933dda28197Spatrick     return ValueObjectSP();
934dda28197Spatrick 
935dda28197Spatrick   auto exp_extractor = ReturnValueExtractor::Create(thread, type);
936dda28197Spatrick   if (!exp_extractor) {
937*f6aab3d8Srobert     Log *log = GetLog(LLDBLog::Expressions);
938dda28197Spatrick     LLDB_LOG_ERROR(log, exp_extractor.takeError(),
939dda28197Spatrick                    "Extracting return value failed: {0}");
940dda28197Spatrick     return ValueObjectSP();
941dda28197Spatrick   }
942dda28197Spatrick 
943dda28197Spatrick   return exp_extractor.get().GetValue();
944dda28197Spatrick }
945dda28197Spatrick 
GetReturnValueObjectImpl(Thread & thread,CompilerType & return_compiler_type) const946dda28197Spatrick ValueObjectSP ABISysV_ppc64::GetReturnValueObjectImpl(
947dda28197Spatrick     Thread &thread, CompilerType &return_compiler_type) const {
948dda28197Spatrick   return GetReturnValueObjectSimple(thread, return_compiler_type);
949dda28197Spatrick }
950dda28197Spatrick 
CreateFunctionEntryUnwindPlan(UnwindPlan & unwind_plan)951dda28197Spatrick bool ABISysV_ppc64::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) {
952dda28197Spatrick   unwind_plan.Clear();
953dda28197Spatrick   unwind_plan.SetRegisterKind(eRegisterKindDWARF);
954dda28197Spatrick 
955dda28197Spatrick   uint32_t lr_reg_num;
956dda28197Spatrick   uint32_t sp_reg_num;
957dda28197Spatrick   uint32_t pc_reg_num;
958dda28197Spatrick 
959dda28197Spatrick   if (GetByteOrder() == lldb::eByteOrderLittle) {
960dda28197Spatrick     lr_reg_num = ppc64le_dwarf::dwarf_lr_ppc64le;
961dda28197Spatrick     sp_reg_num = ppc64le_dwarf::dwarf_r1_ppc64le;
962dda28197Spatrick     pc_reg_num = ppc64le_dwarf::dwarf_pc_ppc64le;
963dda28197Spatrick   } else {
964dda28197Spatrick     lr_reg_num = ppc64_dwarf::dwarf_lr_ppc64;
965dda28197Spatrick     sp_reg_num = ppc64_dwarf::dwarf_r1_ppc64;
966dda28197Spatrick     pc_reg_num = ppc64_dwarf::dwarf_pc_ppc64;
967dda28197Spatrick   }
968dda28197Spatrick 
969dda28197Spatrick   UnwindPlan::RowSP row(new UnwindPlan::Row);
970dda28197Spatrick 
971dda28197Spatrick   // Our Call Frame Address is the stack pointer value
972dda28197Spatrick   row->GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 0);
973dda28197Spatrick 
974dda28197Spatrick   // The previous PC is in the LR
975dda28197Spatrick   row->SetRegisterLocationToRegister(pc_reg_num, lr_reg_num, true);
976dda28197Spatrick   unwind_plan.AppendRow(row);
977dda28197Spatrick 
978dda28197Spatrick   // All other registers are the same.
979dda28197Spatrick 
980dda28197Spatrick   unwind_plan.SetSourceName("ppc64 at-func-entry default");
981dda28197Spatrick   unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
982dda28197Spatrick 
983dda28197Spatrick   return true;
984dda28197Spatrick }
985dda28197Spatrick 
CreateDefaultUnwindPlan(UnwindPlan & unwind_plan)986dda28197Spatrick bool ABISysV_ppc64::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
987dda28197Spatrick   unwind_plan.Clear();
988dda28197Spatrick   unwind_plan.SetRegisterKind(eRegisterKindDWARF);
989dda28197Spatrick 
990dda28197Spatrick   uint32_t sp_reg_num;
991dda28197Spatrick   uint32_t pc_reg_num;
992dda28197Spatrick   uint32_t cr_reg_num;
993dda28197Spatrick 
994dda28197Spatrick   if (GetByteOrder() == lldb::eByteOrderLittle) {
995dda28197Spatrick     sp_reg_num = ppc64le_dwarf::dwarf_r1_ppc64le;
996dda28197Spatrick     pc_reg_num = ppc64le_dwarf::dwarf_lr_ppc64le;
997dda28197Spatrick     cr_reg_num = ppc64le_dwarf::dwarf_cr_ppc64le;
998dda28197Spatrick   } else {
999dda28197Spatrick     sp_reg_num = ppc64_dwarf::dwarf_r1_ppc64;
1000dda28197Spatrick     pc_reg_num = ppc64_dwarf::dwarf_lr_ppc64;
1001dda28197Spatrick     cr_reg_num = ppc64_dwarf::dwarf_cr_ppc64;
1002dda28197Spatrick   }
1003dda28197Spatrick 
1004dda28197Spatrick   UnwindPlan::RowSP row(new UnwindPlan::Row);
1005dda28197Spatrick   const int32_t ptr_size = 8;
1006be691f3bSpatrick   row->SetUnspecifiedRegistersAreUndefined(true);
1007dda28197Spatrick   row->GetCFAValue().SetIsRegisterDereferenced(sp_reg_num);
1008dda28197Spatrick 
1009dda28197Spatrick   row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * 2, true);
1010dda28197Spatrick   row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);
1011dda28197Spatrick   row->SetRegisterLocationToAtCFAPlusOffset(cr_reg_num, ptr_size, true);
1012dda28197Spatrick 
1013dda28197Spatrick   unwind_plan.AppendRow(row);
1014dda28197Spatrick   unwind_plan.SetSourceName("ppc64 default unwind plan");
1015dda28197Spatrick   unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
1016dda28197Spatrick   unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
1017dda28197Spatrick   unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
1018dda28197Spatrick   unwind_plan.SetReturnAddressRegister(pc_reg_num);
1019dda28197Spatrick   return true;
1020dda28197Spatrick }
1021dda28197Spatrick 
RegisterIsVolatile(const RegisterInfo * reg_info)1022dda28197Spatrick bool ABISysV_ppc64::RegisterIsVolatile(const RegisterInfo *reg_info) {
1023dda28197Spatrick   return !RegisterIsCalleeSaved(reg_info);
1024dda28197Spatrick }
1025dda28197Spatrick 
1026dda28197Spatrick // See "Register Usage" in the
1027dda28197Spatrick // "System V Application Binary Interface"
1028dda28197Spatrick // "64-bit PowerPC ELF Application Binary Interface Supplement" current version
1029dda28197Spatrick // is 2 released 2015 at
1030dda28197Spatrick // https://members.openpowerfoundation.org/document/dl/576
RegisterIsCalleeSaved(const RegisterInfo * reg_info)1031dda28197Spatrick bool ABISysV_ppc64::RegisterIsCalleeSaved(const RegisterInfo *reg_info) {
1032dda28197Spatrick   if (reg_info) {
1033dda28197Spatrick     // Preserved registers are :
1034dda28197Spatrick     //    r1,r2,r13-r31
1035dda28197Spatrick     //    cr2-cr4 (partially preserved)
1036dda28197Spatrick     //    f14-f31 (not yet)
1037dda28197Spatrick     //    v20-v31 (not yet)
1038dda28197Spatrick     //    vrsave (not yet)
1039dda28197Spatrick 
1040dda28197Spatrick     const char *name = reg_info->name;
1041dda28197Spatrick     if (name[0] == 'r') {
1042dda28197Spatrick       if ((name[1] == '1' || name[1] == '2') && name[2] == '\0')
1043dda28197Spatrick         return true;
1044dda28197Spatrick       if (name[1] == '1' && name[2] > '2')
1045dda28197Spatrick         return true;
1046dda28197Spatrick       if ((name[1] == '2' || name[1] == '3') && name[2] != '\0')
1047dda28197Spatrick         return true;
1048dda28197Spatrick     }
1049dda28197Spatrick 
1050dda28197Spatrick     if (name[0] == 'f' && name[1] >= '0' && name[2] <= '9') {
1051dda28197Spatrick       if (name[2] == '\0')
1052dda28197Spatrick         return false;
1053dda28197Spatrick       if (name[1] == '1' && name[2] >= '4')
1054dda28197Spatrick         return true;
1055dda28197Spatrick       if ((name[1] == '2' || name[1] == '3') && name[2] != '\0')
1056dda28197Spatrick         return true;
1057dda28197Spatrick     }
1058dda28197Spatrick 
1059dda28197Spatrick     if (name[0] == 's' && name[1] == 'p' && name[2] == '\0') // sp
1060dda28197Spatrick       return true;
1061dda28197Spatrick     if (name[0] == 'f' && name[1] == 'p' && name[2] == '\0') // fp
1062dda28197Spatrick       return false;
1063dda28197Spatrick     if (name[0] == 'p' && name[1] == 'c' && name[2] == '\0') // pc
1064dda28197Spatrick       return true;
1065dda28197Spatrick   }
1066dda28197Spatrick   return false;
1067dda28197Spatrick }
1068dda28197Spatrick 
Initialize()1069dda28197Spatrick void ABISysV_ppc64::Initialize() {
1070dda28197Spatrick   PluginManager::RegisterPlugin(
1071dda28197Spatrick       GetPluginNameStatic(), "System V ABI for ppc64 targets", CreateInstance);
1072dda28197Spatrick }
1073dda28197Spatrick 
Terminate()1074dda28197Spatrick void ABISysV_ppc64::Terminate() {
1075dda28197Spatrick   PluginManager::UnregisterPlugin(CreateInstance);
1076dda28197Spatrick }
1077