text: //===-- ABISysV_ppc64.cpp ---------------------------------------*- C++ -*-===//
  //
  // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  // See https://llvm.org/LICENSE.txt for license information.
  // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  //
  //===----------------------------------------------------------------------===//
  
  #include "ABISysV_ppc64.h"
  
  #include "llvm/ADT/STLExtras.h"
  #include "llvm/ADT/Triple.h"
  
  #include "Utility/PPC64LE_DWARF_Registers.h"
  #include "Utility/PPC64_DWARF_Registers.h"
  #include "lldb/Core/Module.h"
  #include "lldb/Core/PluginManager.h"
  #include "lldb/Core/Value.h"
  #include "lldb/Core/ValueObjectConstResult.h"
  #include "lldb/Core/ValueObjectMemory.h"
  #include "lldb/Core/ValueObjectRegister.h"
  #include "lldb/Symbol/ClangASTContext.h"
  #include "lldb/Symbol/UnwindPlan.h"
  #include "lldb/Target/Process.h"
  #include "lldb/Target/RegisterContext.h"
  #include "lldb/Target/StackFrame.h"
  #include "lldb/Target/Target.h"
  #include "lldb/Target/Thread.h"
  #include "lldb/Utility/ConstString.h"
  #include "lldb/Utility/DataExtractor.h"
  #include "lldb/Utility/Log.h"
  #include "lldb/Utility/RegisterValue.h"
  #include "lldb/Utility/Status.h"
  
  #include "clang/AST/ASTContext.h"
  #include "clang/AST/Attr.h"
  #include "clang/AST/Decl.h"
  
  #define DECLARE_REGISTER_INFOS_PPC64_STRUCT
  #include "Plugins/Process/Utility/RegisterInfos_ppc64.h"
  #undef DECLARE_REGISTER_INFOS_PPC64_STRUCT
  
  #define DECLARE_REGISTER_INFOS_PPC64LE_STRUCT
  #include "Plugins/Process/Utility/RegisterInfos_ppc64le.h"
  #undef DECLARE_REGISTER_INFOS_PPC64LE_STRUCT
  
  using namespace lldb;
  using namespace lldb_private;
  
  const lldb_private::RegisterInfo *
  ABISysV_ppc64::GetRegisterInfoArray(uint32_t &count) {
    if (GetByteOrder() == lldb::eByteOrderLittle) {
      count = llvm::array_lengthof(g_register_infos_ppc64le);
      return g_register_infos_ppc64le;
    } else {
      count = llvm::array_lengthof(g_register_infos_ppc64);
      return g_register_infos_ppc64;
    }
  }
  
  size_t ABISysV_ppc64::GetRedZoneSize() const { return 224; }
  
  lldb::ByteOrder ABISysV_ppc64::GetByteOrder() const {
    return GetProcessSP()->GetByteOrder();
  }
  
  // Static Functions
  
  ABISP
  ABISysV_ppc64::CreateInstance(lldb::ProcessSP process_sp,
                                const ArchSpec &arch) {
    if (arch.GetTriple().isPPC64())
      return ABISP(
          new ABISysV_ppc64(std::move(process_sp), MakeMCRegisterInfo(arch)));
    return ABISP();
  }
  
  bool ABISysV_ppc64::PrepareTrivialCall(Thread &thread, addr_t sp,
                                         addr_t func_addr, addr_t return_addr,
                                         llvm::ArrayRef<addr_t> args) const {
    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
  
    if (log) {
      StreamString s;
      s.Printf("ABISysV_ppc64::PrepareTrivialCall (tid = 0x%" PRIx64
               ", sp = 0x%" PRIx64 ", func_addr = 0x%" PRIx64
               ", return_addr = 0x%" PRIx64,
               thread.GetID(), (uint64_t)sp, (uint64_t)func_addr,
               (uint64_t)return_addr);
  
      for (size_t i = 0; i < args.size(); ++i)
        s.Printf(", arg%" PRIu64 " = 0x%" PRIx64, static_cast<uint64_t>(i + 1),
                 args[i]);
      s.PutCString(")");
      log->PutString(s.GetString());
    }
  
    RegisterContext *reg_ctx = thread.GetRegisterContext().get();
    if (!reg_ctx)
      return false;
  
    const RegisterInfo *reg_info = nullptr;
  
    if (args.size() > 8) // TODO handle more than 8 arguments
      return false;
  
    for (size_t i = 0; i < args.size(); ++i) {
      reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric,
                                          LLDB_REGNUM_GENERIC_ARG1 + i);
      LLDB_LOGF(log, "About to write arg%" PRIu64 " (0x%" PRIx64 ") into %s",
                static_cast<uint64_t>(i + 1), args[i], reg_info->name);
      if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i]))
        return false;
    }
  
    // First, align the SP
  
    LLDB_LOGF(log, "16-byte aligning SP: 0x%" PRIx64 " to 0x%" PRIx64,
              (uint64_t)sp, (uint64_t)(sp & ~0xfull));
  
    sp &= ~(0xfull); // 16-byte alignment
  
    sp -= 544; // allocate frame to save TOC, RA and SP.
  
    Status error;
    uint64_t reg_value;
    const RegisterInfo *pc_reg_info =
        reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
    const RegisterInfo *sp_reg_info =
        reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
    ProcessSP process_sp(thread.GetProcess());
    const RegisterInfo *lr_reg_info =
        reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA);
    const RegisterInfo *r2_reg_info = reg_ctx->GetRegisterInfoAtIndex(2);
    const RegisterInfo *r12_reg_info = reg_ctx->GetRegisterInfoAtIndex(12);
  
    // Save return address onto the stack.
    LLDB_LOGF(log,
              "Pushing the return address onto the stack: 0x%" PRIx64
              "(+16): 0x%" PRIx64,
              (uint64_t)sp, (uint64_t)return_addr);
    if (!process_sp->WritePointerToMemory(sp + 16, return_addr, error))
      return false;
  
    // Write the return address to link register.
    LLDB_LOGF(log, "Writing LR: 0x%" PRIx64, (uint64_t)return_addr);
    if (!reg_ctx->WriteRegisterFromUnsigned(lr_reg_info, return_addr))
      return false;
  
    // Write target address to %r12 register.
    LLDB_LOGF(log, "Writing R12: 0x%" PRIx64, (uint64_t)func_addr);
    if (!reg_ctx->WriteRegisterFromUnsigned(r12_reg_info, func_addr))
      return false;
  
    // Read TOC pointer value.
    reg_value = reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0);
  
    // Write TOC pointer onto the stack.
    uint64_t stack_offset;
    if (GetByteOrder() == lldb::eByteOrderLittle)
      stack_offset = 24;
    else
      stack_offset = 40;
  
    LLDB_LOGF(log, "Writing R2 (TOC) at SP(0x%" PRIx64 ")+%d: 0x%" PRIx64,
              (uint64_t)(sp + stack_offset), (int)stack_offset,
              (uint64_t)reg_value);
    if (!process_sp->WritePointerToMemory(sp + stack_offset, reg_value, error))
      return false;
  
    // Read the current SP value.
    reg_value = reg_ctx->ReadRegisterAsUnsigned(sp_reg_info, 0);
  
    // Save current SP onto the stack.
    LLDB_LOGF(log, "Writing SP at SP(0x%" PRIx64 ")+0: 0x%" PRIx64, (uint64_t)sp,
              (uint64_t)reg_value);
    if (!process_sp->WritePointerToMemory(sp, reg_value, error))
      return false;
  
    // %r1 is set to the actual stack value.
    LLDB_LOGF(log, "Writing SP: 0x%" PRIx64, (uint64_t)sp);
  
    if (!reg_ctx->WriteRegisterFromUnsigned(sp_reg_info, sp))
      return false;
  
    // %pc is set to the address of the called function.
  
    LLDB_LOGF(log, "Writing IP: 0x%" PRIx64, (uint64_t)func_addr);
  
    if (!reg_ctx->WriteRegisterFromUnsigned(pc_reg_info, func_addr))
      return false;
  
    return true;
  }
  
  static bool 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) {
    if (bit_width > 64)
      return false; // Scalar can't hold large integer arguments
  
    if (current_argument_register < 6) {
      scalar = thread.GetRegisterContext()->ReadRegisterAsUnsigned(
          argument_register_ids[current_argument_register], 0);
      current_argument_register++;
      if (is_signed)
        scalar.SignExtend(bit_width);
    } else {
      uint32_t byte_size = (bit_width + (8 - 1)) / 8;
      Status error;
      if (thread.GetProcess()->ReadScalarIntegerFromMemory(
              current_stack_argument, byte_size, is_signed, scalar, error)) {
        current_stack_argument += byte_size;
        return true;
      }
      return false;
    }
    return true;
  }
  
  bool ABISysV_ppc64::GetArgumentValues(Thread &thread, ValueList &values) const {
    unsigned int num_values = values.GetSize();
    unsigned int value_index;
  
    // Extract the register context so we can read arguments from registers
  
    RegisterContext *reg_ctx = thread.GetRegisterContext().get();
  
    if (!reg_ctx)
      return false;
  
    // Get the pointer to the first stack argument so we have a place to start
    // when reading data
  
    addr_t sp = reg_ctx->GetSP(0);
  
    if (!sp)
      return false;
  
    uint64_t stack_offset;
    if (GetByteOrder() == lldb::eByteOrderLittle)
      stack_offset = 32;
    else
      stack_offset = 48;
  
    // jump over return address.
    addr_t current_stack_argument = sp + stack_offset;
    uint32_t argument_register_ids[8];
  
    for (size_t i = 0; i < 8; ++i) {
      argument_register_ids[i] =
          reg_ctx
              ->GetRegisterInfo(eRegisterKindGeneric,
                                LLDB_REGNUM_GENERIC_ARG1 + i)
              ->kinds[eRegisterKindLLDB];
    }
  
    unsigned int current_argument_register = 0;
  
    for (value_index = 0; value_index < num_values; ++value_index) {
      Value *value = values.GetValueAtIndex(value_index);
  
      if (!value)
        return false;
  
      // We currently only support extracting values with Clang QualTypes. Do we
      // care about others?
      CompilerType compiler_type = value->GetCompilerType();
      llvm::Optional<uint64_t> bit_size = compiler_type.GetBitSize(&thread);
      if (!bit_size)
        return false;
      bool is_signed;
  
      if (compiler_type.IsIntegerOrEnumerationType(is_signed)) {
        ReadIntegerArgument(value->GetScalar(), *bit_size, is_signed, thread,
                            argument_register_ids, current_argument_register,
                            current_stack_argument);
      } else if (compiler_type.IsPointerType()) {
        ReadIntegerArgument(value->GetScalar(), *bit_size, false, thread,
                            argument_register_ids, current_argument_register,
                            current_stack_argument);
      }
    }
  
    return true;
  }
  
  Status ABISysV_ppc64::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
                                             lldb::ValueObjectSP &new_value_sp) {
    Status error;
    if (!new_value_sp) {
      error.SetErrorString("Empty value object for return value.");
      return error;
    }
  
    CompilerType compiler_type = new_value_sp->GetCompilerType();
    if (!compiler_type) {
      error.SetErrorString("Null clang type for return value.");
      return error;
    }
  
    Thread *thread = frame_sp->GetThread().get();
  
    bool is_signed;
    uint32_t count;
    bool is_complex;
  
    RegisterContext *reg_ctx = thread->GetRegisterContext().get();
  
    bool set_it_simple = false;
    if (compiler_type.IsIntegerOrEnumerationType(is_signed) ||
        compiler_type.IsPointerType()) {
      const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName("r3", 0);
  
      DataExtractor data;
      Status data_error;
      size_t num_bytes = new_value_sp->GetData(data, data_error);
      if (data_error.Fail()) {
        error.SetErrorStringWithFormat(
            "Couldn't convert return value to raw data: %s",
            data_error.AsCString());
        return error;
      }
      lldb::offset_t offset = 0;
      if (num_bytes <= 8) {
        uint64_t raw_value = data.GetMaxU64(&offset, num_bytes);
  
        if (reg_ctx->WriteRegisterFromUnsigned(reg_info, raw_value))
          set_it_simple = true;
      } else {
        error.SetErrorString("We don't support returning longer than 64 bit "
                             "integer values at present.");
      }
    } else if (compiler_type.IsFloatingPointType(count, is_complex)) {
      if (is_complex)
        error.SetErrorString(
            "We don't support returning complex values at present");
      else {
        llvm::Optional<uint64_t> bit_width =
            compiler_type.GetBitSize(frame_sp.get());
        if (!bit_width) {
          error.SetErrorString("can't get size of type");
          return error;
        }
        if (*bit_width <= 64) {
          DataExtractor data;
          Status data_error;
          size_t num_bytes = new_value_sp->GetData(data, data_error);
          if (data_error.Fail()) {
            error.SetErrorStringWithFormat(
                "Couldn't convert return value to raw data: %s",
                data_error.AsCString());
            return error;
          }
  
          unsigned char buffer[16];
          ByteOrder byte_order = data.GetByteOrder();
  
          data.CopyByteOrderedData(0, num_bytes, buffer, 16, byte_order);
          set_it_simple = true;
        } else {
          // FIXME - don't know how to do 80 bit long doubles yet.
          error.SetErrorString(
              "We don't support returning float values > 64 bits at present");
        }
      }
    }
  
    if (!set_it_simple) {
      // Okay we've got a structure or something that doesn't fit in a simple
      // register. We should figure out where it really goes, but we don't
      // support this yet.
      error.SetErrorString("We only support setting simple integer and float "
                           "return types at present.");
    }
  
    return error;
  }
  
  //
  // ReturnValueExtractor
  //
  
  namespace {
  
  #define LOG_PREFIX "ReturnValueExtractor: "
  
  class ReturnValueExtractor {
    // This class represents a register, from which data may be extracted.
    //
    // It may be constructed by directly specifying its index (where 0 is the
    // first register used to return values) or by specifying the offset of a
    // given struct field, in which case the appropriated register index will be
    // calculated.
    class Register {
    public:
      enum Type {
        GPR, // General Purpose Register
        FPR  // Floating Point Register
      };
  
      // main constructor
      //
      // offs - field offset in struct
      Register(Type ty, uint32_t index, uint32_t offs, RegisterContext *reg_ctx,
               ByteOrder byte_order)
          : m_index(index), m_offs(offs % sizeof(uint64_t)),
            m_avail(sizeof(uint64_t) - m_offs), m_type(ty), m_reg_ctx(reg_ctx),
            m_byte_order(byte_order) {}
  
      // explicit index, no offset
      Register(Type ty, uint32_t index, RegisterContext *reg_ctx,
               ByteOrder byte_order)
          : Register(ty, index, 0, reg_ctx, byte_order) {}
  
      // GPR, calculate index from offs
      Register(uint32_t offs, RegisterContext *reg_ctx, ByteOrder byte_order)
          : Register(GPR, offs / sizeof(uint64_t), offs, reg_ctx, byte_order) {}
  
      uint32_t Index() const { return m_index; }
  
      // register offset where data is located
      uint32_t Offs() const { return m_offs; }
  
      // available bytes in this register
      uint32_t Avail() const { return m_avail; }
  
      bool IsValid() const {
        if (m_index > 7) {
          LLDB_LOG(m_log, LOG_PREFIX
                   "No more than 8 registers should be used to return values");
          return false;
        }
        return true;
      }
  
      std::string GetName() const {
        if (m_type == GPR)
          return ("r" + llvm::Twine(m_index + 3)).str();
        else
          return ("f" + llvm::Twine(m_index + 1)).str();
      }
  
      // get raw register data
      bool GetRawData(uint64_t &raw_data) {
        const RegisterInfo *reg_info =
            m_reg_ctx->GetRegisterInfoByName(GetName());
        if (!reg_info) {
          LLDB_LOG(m_log, LOG_PREFIX "Failed to get RegisterInfo");
          return false;
        }
  
        RegisterValue reg_val;
        if (!m_reg_ctx->ReadRegister(reg_info, reg_val)) {
          LLDB_LOG(m_log, LOG_PREFIX "ReadRegister() failed");
          return false;
        }
  
        Status error;
        uint32_t rc = reg_val.GetAsMemoryData(
            reg_info, &raw_data, sizeof(raw_data), m_byte_order, error);
        if (rc != sizeof(raw_data)) {
          LLDB_LOG(m_log, LOG_PREFIX "GetAsMemoryData() failed");
          return false;
        }
  
        return true;
      }
  
    private:
      uint32_t m_index;
      uint32_t m_offs;
      uint32_t m_avail;
      Type m_type;
      RegisterContext *m_reg_ctx;
      ByteOrder m_byte_order;
      Log *m_log =
          lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS);
    };
  
    Register GetGPR(uint32_t index) const {
      return Register(Register::GPR, index, m_reg_ctx, m_byte_order);
    }
  
    Register GetFPR(uint32_t index) const {
      return Register(Register::FPR, index, m_reg_ctx, m_byte_order);
    }
  
    Register GetGPRByOffs(uint32_t offs) const {
      return Register(offs, m_reg_ctx, m_byte_order);
    }
  
  public:
    // factory
    static llvm::Expected<ReturnValueExtractor> Create(Thread &thread,
                                                       CompilerType &type) {
      RegisterContext *reg_ctx = thread.GetRegisterContext().get();
      if (!reg_ctx)
        return llvm::make_error<llvm::StringError>(
            LOG_PREFIX "Failed to get RegisterContext",
            llvm::inconvertibleErrorCode());
  
      ProcessSP process_sp = thread.GetProcess();
      if (!process_sp)
        return llvm::make_error<llvm::StringError>(
            LOG_PREFIX "GetProcess() failed", llvm::inconvertibleErrorCode());
  
      return ReturnValueExtractor(thread, type, reg_ctx, process_sp);
    }
  
    // main method: get value of the type specified at construction time
    ValueObjectSP GetValue() {
      const uint32_t type_flags = m_type.GetTypeInfo();
  
      // call the appropriate type handler
      ValueSP value_sp;
      ValueObjectSP valobj_sp;
      if (type_flags & eTypeIsScalar) {
        if (type_flags & eTypeIsInteger) {
          value_sp = GetIntegerValue(0);
        } else if (type_flags & eTypeIsFloat) {
          if (type_flags & eTypeIsComplex) {
            LLDB_LOG(m_log, LOG_PREFIX "Complex numbers are not supported yet");
            return ValueObjectSP();
          } else {
            value_sp = GetFloatValue(m_type, 0);
          }
        }
      } else if (type_flags & eTypeIsPointer) {
        value_sp = GetPointerValue(0);
      }
  
      if (value_sp) {
        valobj_sp = ValueObjectConstResult::Create(
            m_thread.GetStackFrameAtIndex(0).get(), *value_sp, ConstString(""));
      } else if (type_flags & eTypeIsVector) {
        valobj_sp = GetVectorValueObject();
      } else if (type_flags & eTypeIsStructUnion || type_flags & eTypeIsClass) {
        valobj_sp = GetStructValueObject();
      }
  
      return valobj_sp;
    }
  
  private:
    // data
    Thread &m_thread;
    CompilerType &m_type;
    uint64_t m_byte_size;
    std::unique_ptr<DataBufferHeap> m_data_up;
    int32_t m_src_offs = 0;
    int32_t m_dst_offs = 0;
    bool m_packed = false;
    Log *m_log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS);
    RegisterContext *m_reg_ctx;
    ProcessSP m_process_sp;
    ByteOrder m_byte_order;
    uint32_t m_addr_size;
  
    // methods
  
    // constructor
    ReturnValueExtractor(Thread &thread, CompilerType &type,
                         RegisterContext *reg_ctx, ProcessSP process_sp)
        : m_thread(thread), m_type(type),
          m_byte_size(m_type.GetByteSize(nullptr).getValueOr(0)),
          m_data_up(new DataBufferHeap(m_byte_size, 0)), m_reg_ctx(reg_ctx),
          m_process_sp(process_sp), m_byte_order(process_sp->GetByteOrder()),
          m_addr_size(
              process_sp->GetTarget().GetArchitecture().GetAddressByteSize()) {}
  
    // build a new scalar value
    ValueSP NewScalarValue(CompilerType &type) {
      ValueSP value_sp(new Value);
      value_sp->SetCompilerType(type);
      value_sp->SetValueType(Value::eValueTypeScalar);
      return value_sp;
    }
  
    // get an integer value in the specified register
    ValueSP GetIntegerValue(uint32_t reg_index) {
      uint64_t raw_value;
      auto reg = GetGPR(reg_index);
      if (!reg.GetRawData(raw_value))
        return ValueSP();
  
      // build value from data
      ValueSP value_sp(NewScalarValue(m_type));
  
      uint32_t type_flags = m_type.GetTypeInfo();
      bool is_signed = (type_flags & eTypeIsSigned) != 0;
  
      switch (m_byte_size) {
      case sizeof(uint64_t):
        if (is_signed)
          value_sp->GetScalar() = (int64_t)(raw_value);
        else
          value_sp->GetScalar() = (uint64_t)(raw_value);
        break;
  
      case sizeof(uint32_t):
        if (is_signed)
          value_sp->GetScalar() = (int32_t)(raw_value & UINT32_MAX);
        else
          value_sp->GetScalar() = (uint32_t)(raw_value & UINT32_MAX);
        break;
  
      case sizeof(uint16_t):
        if (is_signed)
          value_sp->GetScalar() = (int16_t)(raw_value & UINT16_MAX);
        else
          value_sp->GetScalar() = (uint16_t)(raw_value & UINT16_MAX);
        break;
  
      case sizeof(uint8_t):
        if (is_signed)
          value_sp->GetScalar() = (int8_t)(raw_value & UINT8_MAX);
        else
          value_sp->GetScalar() = (uint8_t)(raw_value & UINT8_MAX);
        break;
  
      default:
        llvm_unreachable("Invalid integer size");
      }
  
      return value_sp;
    }
  
    // get a floating point value on the specified register
    ValueSP GetFloatValue(CompilerType &type, uint32_t reg_index) {
      uint64_t raw_data;
      auto reg = GetFPR(reg_index);
      if (!reg.GetRawData(raw_data))
        return {};
  
      // build value from data
      ValueSP value_sp(NewScalarValue(type));
  
      DataExtractor de(&raw_data, sizeof(raw_data), m_byte_order, m_addr_size);
  
      offset_t offset = 0;
      llvm::Optional<uint64_t> byte_size = type.GetByteSize(nullptr);
      if (!byte_size)
        return {};
      switch (*byte_size) {
      case sizeof(float):
        value_sp->GetScalar() = (float)de.GetDouble(&offset);
        break;
  
      case sizeof(double):
        value_sp->GetScalar() = de.GetDouble(&offset);
        break;
  
      default:
        llvm_unreachable("Invalid floating point size");
      }
  
      return value_sp;
    }
  
    // get pointer value from register
    ValueSP GetPointerValue(uint32_t reg_index) {
      uint64_t raw_data;
      auto reg = GetGPR(reg_index);
      if (!reg.GetRawData(raw_data))
        return ValueSP();
  
      // build value from raw data
      ValueSP value_sp(NewScalarValue(m_type));
      value_sp->GetScalar() = raw_data;
      return value_sp;
    }
  
    // build the ValueObject from our data buffer
    ValueObjectSP BuildValueObject() {
      DataExtractor de(DataBufferSP(m_data_up.release()), m_byte_order,
                       m_addr_size);
      return ValueObjectConstResult::Create(&m_thread, m_type, ConstString(""),
                                            de);
    }
  
    // get a vector return value
    ValueObjectSP GetVectorValueObject() {
      const uint32_t MAX_VRS = 2;
  
      // get first V register used to return values
      const RegisterInfo *vr[MAX_VRS];
      vr[0] = m_reg_ctx->GetRegisterInfoByName("vr2");
      if (!vr[0]) {
        LLDB_LOG(m_log, LOG_PREFIX "Failed to get vr2 RegisterInfo");
        return ValueObjectSP();
      }
  
      const uint32_t vr_size = vr[0]->byte_size;
      size_t vrs = 1;
      if (m_byte_size > 2 * vr_size) {
        LLDB_LOG(
            m_log, LOG_PREFIX
            "Returning vectors that don't fit in 2 VR regs is not supported");
        return ValueObjectSP();
      }
  
      // load vr3, if needed
      if (m_byte_size > vr_size) {
        vrs++;
        vr[1] = m_reg_ctx->GetRegisterInfoByName("vr3");
        if (!vr[1]) {
          LLDB_LOG(m_log, LOG_PREFIX "Failed to get vr3 RegisterInfo");
          return ValueObjectSP();
        }
      }
  
      // Get the whole contents of vector registers and let the logic here
      // arrange the data properly.
  
      RegisterValue vr_val[MAX_VRS];
      Status error;
      std::unique_ptr<DataBufferHeap> vr_data(
          new DataBufferHeap(vrs * vr_size, 0));
  
      for (uint32_t i = 0; i < vrs; i++) {
        if (!m_reg_ctx->ReadRegister(vr[i], vr_val[i])) {
          LLDB_LOG(m_log, LOG_PREFIX "Failed to read vector register contents");
          return ValueObjectSP();
        }
        if (!vr_val[i].GetAsMemoryData(vr[i], vr_data->GetBytes() + i * vr_size,
                                       vr_size, m_byte_order, error)) {
          LLDB_LOG(m_log, LOG_PREFIX "Failed to extract vector register bytes");
          return ValueObjectSP();
        }
      }
  
      // The compiler generated code seems to always put the vector elements at
      // the end of the vector register, in case they don't occupy all of it.
      // This offset variable handles this.
      uint32_t offs = 0;
      if (m_byte_size < vr_size)
        offs = vr_size - m_byte_size;
  
      // copy extracted data to our buffer
      memcpy(m_data_up->GetBytes(), vr_data->GetBytes() + offs, m_byte_size);
      return BuildValueObject();
    }
  
    // get a struct return value
    ValueObjectSP GetStructValueObject() {
      // case 1: get from stack
      if (m_byte_size > 2 * sizeof(uint64_t)) {
        uint64_t addr;
        auto reg = GetGPR(0);
        if (!reg.GetRawData(addr))
          return {};
  
        Status error;
        size_t rc = m_process_sp->ReadMemory(addr, m_data_up->GetBytes(),
                                             m_byte_size, error);
        if (rc != m_byte_size) {
          LLDB_LOG(m_log, LOG_PREFIX "Failed to read memory pointed by r3");
          return ValueObjectSP();
        }
        return BuildValueObject();
      }
  
      // get number of children
      const bool omit_empty_base_classes = true;
      uint32_t n = m_type.GetNumChildren(omit_empty_base_classes, nullptr);
      if (!n) {
        LLDB_LOG(m_log, LOG_PREFIX "No children found in struct");
        return {};
      }
  
      // case 2: homogeneous double or float aggregate
      CompilerType elem_type;
      if (m_type.IsHomogeneousAggregate(&elem_type)) {
        uint32_t type_flags = elem_type.GetTypeInfo();
        llvm::Optional<uint64_t> elem_size = elem_type.GetByteSize(nullptr);
        if (!elem_size)
          return {};
        if (type_flags & eTypeIsComplex || !(type_flags & eTypeIsFloat)) {
          LLDB_LOG(m_log,
                   LOG_PREFIX "Unexpected type found in homogeneous aggregate");
          return {};
        }
  
        for (uint32_t i = 0; i < n; i++) {
          ValueSP val_sp = GetFloatValue(elem_type, i);
          if (!val_sp)
            return {};
  
          // copy to buffer
          Status error;
          size_t rc = val_sp->GetScalar().GetAsMemoryData(
              m_data_up->GetBytes() + m_dst_offs, *elem_size, m_byte_order,
              error);
          if (rc != *elem_size) {
            LLDB_LOG(m_log, LOG_PREFIX "Failed to get float data");
            return {};
          }
          m_dst_offs += *elem_size;
        }
        return BuildValueObject();
      }
  
      // case 3: get from GPRs
  
      // first, check if this is a packed struct or not
      ClangASTContext *ast =
          llvm::dyn_cast<ClangASTContext>(m_type.GetTypeSystem());
      if (ast) {
        clang::RecordDecl *record_decl = ClangASTContext::GetAsRecordDecl(m_type);
  
        if (record_decl) {
          auto attrs = record_decl->attrs();
          for (const auto &attr : attrs) {
            if (attr->getKind() == clang::attr::Packed) {
              m_packed = true;
              break;
            }
          }
        }
      }
  
      LLDB_LOG(m_log, LOG_PREFIX "{0} struct",
               m_packed ? "packed" : "not packed");
  
      for (uint32_t i = 0; i < n; i++) {
        std::string name;
        uint32_t size;
        GetChildType(i, name, size);
        // NOTE: the offset returned by GetChildCompilerTypeAtIndex()
        //       can't be used because it never considers alignment bytes
        //       between struct fields.
        LLDB_LOG(m_log, LOG_PREFIX "field={0}, size={1}", name, size);
        if (!ExtractField(size))
          return ValueObjectSP();
      }
  
      return BuildValueObject();
    }
  
    // extract 'size' bytes at 'offs' from GPRs
    bool ExtractFromRegs(int32_t offs, uint32_t size, void *buf) {
      while (size) {
        auto reg = GetGPRByOffs(offs);
        if (!reg.IsValid())
          return false;
  
        uint32_t n = std::min(reg.Avail(), size);
        uint64_t raw_data;
  
        if (!reg.GetRawData(raw_data))
          return false;
  
        memcpy(buf, (char *)&raw_data + reg.Offs(), n);
        offs += n;
        size -= n;
        buf = (char *)buf + n;
      }
      return true;
    }
  
    // extract one field from GPRs and put it in our buffer
    bool ExtractField(uint32_t size) {
      auto reg = GetGPRByOffs(m_src_offs);
      if (!reg.IsValid())
        return false;
  
      // handle padding
      if (!m_packed) {
        uint32_t n = m_src_offs % size;
  
        // not 'size' bytes aligned
        if (n) {
          LLDB_LOG(m_log,
                   LOG_PREFIX "Extracting {0} alignment bytes at offset {1}", n,
                   m_src_offs);
          // get alignment bytes
          if (!ExtractFromRegs(m_src_offs, n, m_data_up->GetBytes() + m_dst_offs))
            return false;
          m_src_offs += n;
          m_dst_offs += n;
        }
      }
  
      // get field
      LLDB_LOG(m_log, LOG_PREFIX "Extracting {0} field bytes at offset {1}", size,
               m_src_offs);
      if (!ExtractFromRegs(m_src_offs, size, m_data_up->GetBytes() + m_dst_offs))
        return false;
      m_src_offs += size;
      m_dst_offs += size;
      return true;
    }
  
    // get child
    CompilerType GetChildType(uint32_t i, std::string &name, uint32_t &size) {
      // GetChild constant inputs
      const bool transparent_pointers = false;
      const bool omit_empty_base_classes = true;
      const bool ignore_array_bounds = false;
      // GetChild output params
      int32_t child_offs;
      uint32_t child_bitfield_bit_size;
      uint32_t child_bitfield_bit_offset;
      bool child_is_base_class;
      bool child_is_deref_of_parent;
      ValueObject *valobj = nullptr;
      uint64_t language_flags;
      ExecutionContext exe_ctx;
      m_thread.CalculateExecutionContext(exe_ctx);
  
      return m_type.GetChildCompilerTypeAtIndex(
          &exe_ctx, i, transparent_pointers, omit_empty_base_classes,
          ignore_array_bounds, name, size, child_offs, child_bitfield_bit_size,
          child_bitfield_bit_offset, child_is_base_class,
          child_is_deref_of_parent, valobj, language_flags);
    }
  };
  
  #undef LOG_PREFIX
  
  } // anonymous namespace
  
  ValueObjectSP
  ABISysV_ppc64::GetReturnValueObjectSimple(Thread &thread,
                                            CompilerType &type) const {
    if (!type)
      return ValueObjectSP();
  
    auto exp_extractor = ReturnValueExtractor::Create(thread, type);
    if (!exp_extractor) {
      Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS);
      LLDB_LOG_ERROR(log, exp_extractor.takeError(),
                     "Extracting return value failed: {0}");
      return ValueObjectSP();
    }
  
    return exp_extractor.get().GetValue();
  }
  
  ValueObjectSP ABISysV_ppc64::GetReturnValueObjectImpl(
      Thread &thread, CompilerType &return_compiler_type) const {
    return GetReturnValueObjectSimple(thread, return_compiler_type);
  }
  
  bool ABISysV_ppc64::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) {
    unwind_plan.Clear();
    unwind_plan.SetRegisterKind(eRegisterKindDWARF);
  
    uint32_t lr_reg_num;
    uint32_t sp_reg_num;
    uint32_t pc_reg_num;
  
    if (GetByteOrder() == lldb::eByteOrderLittle) {
      lr_reg_num = ppc64le_dwarf::dwarf_lr_ppc64le;
      sp_reg_num = ppc64le_dwarf::dwarf_r1_ppc64le;
      pc_reg_num = ppc64le_dwarf::dwarf_pc_ppc64le;
    } else {
      lr_reg_num = ppc64_dwarf::dwarf_lr_ppc64;
      sp_reg_num = ppc64_dwarf::dwarf_r1_ppc64;
      pc_reg_num = ppc64_dwarf::dwarf_pc_ppc64;
    }
  
    UnwindPlan::RowSP row(new UnwindPlan::Row);
  
    // Our Call Frame Address is the stack pointer value
    row->GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 0);
  
    // The previous PC is in the LR
    row->SetRegisterLocationToRegister(pc_reg_num, lr_reg_num, true);
    unwind_plan.AppendRow(row);
  
    // All other registers are the same.
  
    unwind_plan.SetSourceName("ppc64 at-func-entry default");
    unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
  
    return true;
  }
  
  bool ABISysV_ppc64::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
    unwind_plan.Clear();
    unwind_plan.SetRegisterKind(eRegisterKindDWARF);
  
    uint32_t sp_reg_num;
    uint32_t pc_reg_num;
    uint32_t cr_reg_num;
  
    if (GetByteOrder() == lldb::eByteOrderLittle) {
      sp_reg_num = ppc64le_dwarf::dwarf_r1_ppc64le;
      pc_reg_num = ppc64le_dwarf::dwarf_lr_ppc64le;
      cr_reg_num = ppc64le_dwarf::dwarf_cr_ppc64le;
    } else {
      sp_reg_num = ppc64_dwarf::dwarf_r1_ppc64;
      pc_reg_num = ppc64_dwarf::dwarf_lr_ppc64;
      cr_reg_num = ppc64_dwarf::dwarf_cr_ppc64;
    }
  
    UnwindPlan::RowSP row(new UnwindPlan::Row);
    const int32_t ptr_size = 8;
    row->GetCFAValue().SetIsRegisterDereferenced(sp_reg_num);
  
    row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * 2, true);
    row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);
    row->SetRegisterLocationToAtCFAPlusOffset(cr_reg_num, ptr_size, true);
  
    unwind_plan.AppendRow(row);
    unwind_plan.SetSourceName("ppc64 default unwind plan");
    unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
    unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
    unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
    unwind_plan.SetReturnAddressRegister(pc_reg_num);
    return true;
  }
  
  bool ABISysV_ppc64::RegisterIsVolatile(const RegisterInfo *reg_info) {
    return !RegisterIsCalleeSaved(reg_info);
  }
  
  // See "Register Usage" in the
  // "System V Application Binary Interface"
  // "64-bit PowerPC ELF Application Binary Interface Supplement" current version
  // is 2 released 2015 at
  // https://members.openpowerfoundation.org/document/dl/576
  bool ABISysV_ppc64::RegisterIsCalleeSaved(const RegisterInfo *reg_info) {
    if (reg_info) {
      // Preserved registers are :
      //    r1,r2,r13-r31
      //    cr2-cr4 (partially preserved)
      //    f14-f31 (not yet)
      //    v20-v31 (not yet)
      //    vrsave (not yet)
  
      const char *name = reg_info->name;
      if (name[0] == 'r') {
        if ((name[1] == '1' || name[1] == '2') && name[2] == '\0')
          return true;
        if (name[1] == '1' && name[2] > '2')
          return true;
        if ((name[1] == '2' || name[1] == '3') && name[2] != '\0')
          return true;
      }
  
      if (name[0] == 'f' && name[1] >= '0' && name[2] <= '9') {
        if (name[2] == '\0')
          return false;
        if (name[1] == '1' && name[2] >= '4')
          return true;
        if ((name[1] == '2' || name[1] == '3') && name[2] != '\0')
          return true;
      }
  
      if (name[0] == 's' && name[1] == 'p' && name[2] == '\0') // sp
        return true;
      if (name[0] == 'f' && name[1] == 'p' && name[2] == '\0') // fp
        return false;
      if (name[0] == 'p' && name[1] == 'c' && name[2] == '\0') // pc
        return true;
    }
    return false;
  }
  
  void ABISysV_ppc64::Initialize() {
    PluginManager::RegisterPlugin(
        GetPluginNameStatic(), "System V ABI for ppc64 targets", CreateInstance);
  }
  
  void ABISysV_ppc64::Terminate() {
    PluginManager::UnregisterPlugin(CreateInstance);
  }
  
  lldb_private::ConstString ABISysV_ppc64::GetPluginNameStatic() {
    static ConstString g_name("sysv-ppc64");
    return g_name;
  }
  
  // PluginInterface protocol
  
  lldb_private::ConstString ABISysV_ppc64::GetPluginName() {
    return GetPluginNameStatic();
  }
  
  uint32_t ABISysV_ppc64::GetPluginVersion() { return 1; }
  