Path: blob/main/contrib/llvm-project/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp
39645 views
//===-- ABISysV_ppc64.cpp -------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "ABISysV_ppc64.h"910#include "llvm/ADT/STLExtras.h"11#include "llvm/TargetParser/Triple.h"1213#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"14#include "Utility/PPC64LE_DWARF_Registers.h"15#include "Utility/PPC64_DWARF_Registers.h"16#include "lldb/Core/Module.h"17#include "lldb/Core/PluginManager.h"18#include "lldb/Core/Value.h"19#include "lldb/Core/ValueObjectConstResult.h"20#include "lldb/Core/ValueObjectMemory.h"21#include "lldb/Core/ValueObjectRegister.h"22#include "lldb/Symbol/UnwindPlan.h"23#include "lldb/Target/Process.h"24#include "lldb/Target/RegisterContext.h"25#include "lldb/Target/StackFrame.h"26#include "lldb/Target/Target.h"27#include "lldb/Target/Thread.h"28#include "lldb/Utility/ConstString.h"29#include "lldb/Utility/DataExtractor.h"30#include "lldb/Utility/LLDBLog.h"31#include "lldb/Utility/Log.h"32#include "lldb/Utility/RegisterValue.h"33#include "lldb/Utility/Status.h"3435#include "clang/AST/ASTContext.h"36#include "clang/AST/Attr.h"37#include "clang/AST/Decl.h"3839#define DECLARE_REGISTER_INFOS_PPC64_STRUCT40#include "Plugins/Process/Utility/RegisterInfos_ppc64.h"41#undef DECLARE_REGISTER_INFOS_PPC64_STRUCT4243#define DECLARE_REGISTER_INFOS_PPC64LE_STRUCT44#include "Plugins/Process/Utility/RegisterInfos_ppc64le.h"45#undef DECLARE_REGISTER_INFOS_PPC64LE_STRUCT46#include <optional>4748using namespace lldb;49using namespace lldb_private;5051LLDB_PLUGIN_DEFINE(ABISysV_ppc64)5253const lldb_private::RegisterInfo *54ABISysV_ppc64::GetRegisterInfoArray(uint32_t &count) {55if (GetByteOrder() == lldb::eByteOrderLittle) {56count = std::size(g_register_infos_ppc64le);57return g_register_infos_ppc64le;58} else {59count = std::size(g_register_infos_ppc64);60return g_register_infos_ppc64;61}62}6364size_t ABISysV_ppc64::GetRedZoneSize() const { return 224; }6566lldb::ByteOrder ABISysV_ppc64::GetByteOrder() const {67return GetProcessSP()->GetByteOrder();68}6970// Static Functions7172ABISP73ABISysV_ppc64::CreateInstance(lldb::ProcessSP process_sp,74const ArchSpec &arch) {75if (arch.GetTriple().isPPC64())76return ABISP(77new ABISysV_ppc64(std::move(process_sp), MakeMCRegisterInfo(arch)));78return ABISP();79}8081bool ABISysV_ppc64::PrepareTrivialCall(Thread &thread, addr_t sp,82addr_t func_addr, addr_t return_addr,83llvm::ArrayRef<addr_t> args) const {84Log *log = GetLog(LLDBLog::Expressions);8586if (log) {87StreamString s;88s.Printf("ABISysV_ppc64::PrepareTrivialCall (tid = 0x%" PRIx6489", sp = 0x%" PRIx64 ", func_addr = 0x%" PRIx6490", return_addr = 0x%" PRIx64,91thread.GetID(), (uint64_t)sp, (uint64_t)func_addr,92(uint64_t)return_addr);9394for (size_t i = 0; i < args.size(); ++i)95s.Printf(", arg%" PRIu64 " = 0x%" PRIx64, static_cast<uint64_t>(i + 1),96args[i]);97s.PutCString(")");98log->PutString(s.GetString());99}100101RegisterContext *reg_ctx = thread.GetRegisterContext().get();102if (!reg_ctx)103return false;104105const RegisterInfo *reg_info = nullptr;106107if (args.size() > 8) // TODO handle more than 8 arguments108return false;109110for (size_t i = 0; i < args.size(); ++i) {111reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric,112LLDB_REGNUM_GENERIC_ARG1 + i);113LLDB_LOGF(log, "About to write arg%" PRIu64 " (0x%" PRIx64 ") into %s",114static_cast<uint64_t>(i + 1), args[i], reg_info->name);115if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i]))116return false;117}118119// First, align the SP120121LLDB_LOGF(log, "16-byte aligning SP: 0x%" PRIx64 " to 0x%" PRIx64,122(uint64_t)sp, (uint64_t)(sp & ~0xfull));123124sp &= ~(0xfull); // 16-byte alignment125126sp -= 544; // allocate frame to save TOC, RA and SP.127128Status error;129uint64_t reg_value;130const RegisterInfo *pc_reg_info =131reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);132const RegisterInfo *sp_reg_info =133reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);134ProcessSP process_sp(thread.GetProcess());135const RegisterInfo *lr_reg_info =136reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA);137const RegisterInfo *r2_reg_info = reg_ctx->GetRegisterInfoAtIndex(2);138const RegisterInfo *r12_reg_info = reg_ctx->GetRegisterInfoAtIndex(12);139140// Save return address onto the stack.141LLDB_LOGF(log,142"Pushing the return address onto the stack: 0x%" PRIx64143"(+16): 0x%" PRIx64,144(uint64_t)sp, (uint64_t)return_addr);145if (!process_sp->WritePointerToMemory(sp + 16, return_addr, error))146return false;147148// Write the return address to link register.149LLDB_LOGF(log, "Writing LR: 0x%" PRIx64, (uint64_t)return_addr);150if (!reg_ctx->WriteRegisterFromUnsigned(lr_reg_info, return_addr))151return false;152153// Write target address to %r12 register.154LLDB_LOGF(log, "Writing R12: 0x%" PRIx64, (uint64_t)func_addr);155if (!reg_ctx->WriteRegisterFromUnsigned(r12_reg_info, func_addr))156return false;157158// Read TOC pointer value.159reg_value = reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0);160161// Write TOC pointer onto the stack.162uint64_t stack_offset;163if (GetByteOrder() == lldb::eByteOrderLittle)164stack_offset = 24;165else166stack_offset = 40;167168LLDB_LOGF(log, "Writing R2 (TOC) at SP(0x%" PRIx64 ")+%d: 0x%" PRIx64,169(uint64_t)(sp + stack_offset), (int)stack_offset,170(uint64_t)reg_value);171if (!process_sp->WritePointerToMemory(sp + stack_offset, reg_value, error))172return false;173174// Read the current SP value.175reg_value = reg_ctx->ReadRegisterAsUnsigned(sp_reg_info, 0);176177// Save current SP onto the stack.178LLDB_LOGF(log, "Writing SP at SP(0x%" PRIx64 ")+0: 0x%" PRIx64, (uint64_t)sp,179(uint64_t)reg_value);180if (!process_sp->WritePointerToMemory(sp, reg_value, error))181return false;182183// %r1 is set to the actual stack value.184LLDB_LOGF(log, "Writing SP: 0x%" PRIx64, (uint64_t)sp);185186if (!reg_ctx->WriteRegisterFromUnsigned(sp_reg_info, sp))187return false;188189// %pc is set to the address of the called function.190191LLDB_LOGF(log, "Writing IP: 0x%" PRIx64, (uint64_t)func_addr);192193if (!reg_ctx->WriteRegisterFromUnsigned(pc_reg_info, func_addr))194return false;195196return true;197}198199static bool ReadIntegerArgument(Scalar &scalar, unsigned int bit_width,200bool is_signed, Thread &thread,201uint32_t *argument_register_ids,202unsigned int ¤t_argument_register,203addr_t ¤t_stack_argument) {204if (bit_width > 64)205return false; // Scalar can't hold large integer arguments206207if (current_argument_register < 6) {208scalar = thread.GetRegisterContext()->ReadRegisterAsUnsigned(209argument_register_ids[current_argument_register], 0);210current_argument_register++;211if (is_signed)212scalar.SignExtend(bit_width);213} else {214uint32_t byte_size = (bit_width + (8 - 1)) / 8;215Status error;216if (thread.GetProcess()->ReadScalarIntegerFromMemory(217current_stack_argument, byte_size, is_signed, scalar, error)) {218current_stack_argument += byte_size;219return true;220}221return false;222}223return true;224}225226bool ABISysV_ppc64::GetArgumentValues(Thread &thread, ValueList &values) const {227unsigned int num_values = values.GetSize();228unsigned int value_index;229230// Extract the register context so we can read arguments from registers231232RegisterContext *reg_ctx = thread.GetRegisterContext().get();233234if (!reg_ctx)235return false;236237// Get the pointer to the first stack argument so we have a place to start238// when reading data239240addr_t sp = reg_ctx->GetSP(0);241242if (!sp)243return false;244245uint64_t stack_offset;246if (GetByteOrder() == lldb::eByteOrderLittle)247stack_offset = 32;248else249stack_offset = 48;250251// jump over return address.252addr_t current_stack_argument = sp + stack_offset;253uint32_t argument_register_ids[8];254255for (size_t i = 0; i < 8; ++i) {256argument_register_ids[i] =257reg_ctx258->GetRegisterInfo(eRegisterKindGeneric,259LLDB_REGNUM_GENERIC_ARG1 + i)260->kinds[eRegisterKindLLDB];261}262263unsigned int current_argument_register = 0;264265for (value_index = 0; value_index < num_values; ++value_index) {266Value *value = values.GetValueAtIndex(value_index);267268if (!value)269return false;270271// We currently only support extracting values with Clang QualTypes. Do we272// care about others?273CompilerType compiler_type = value->GetCompilerType();274std::optional<uint64_t> bit_size = compiler_type.GetBitSize(&thread);275if (!bit_size)276return false;277bool is_signed;278279if (compiler_type.IsIntegerOrEnumerationType(is_signed)) {280ReadIntegerArgument(value->GetScalar(), *bit_size, is_signed, thread,281argument_register_ids, current_argument_register,282current_stack_argument);283} else if (compiler_type.IsPointerType()) {284ReadIntegerArgument(value->GetScalar(), *bit_size, false, thread,285argument_register_ids, current_argument_register,286current_stack_argument);287}288}289290return true;291}292293Status ABISysV_ppc64::SetReturnValueObject(lldb::StackFrameSP &frame_sp,294lldb::ValueObjectSP &new_value_sp) {295Status error;296if (!new_value_sp) {297error.SetErrorString("Empty value object for return value.");298return error;299}300301CompilerType compiler_type = new_value_sp->GetCompilerType();302if (!compiler_type) {303error.SetErrorString("Null clang type for return value.");304return error;305}306307Thread *thread = frame_sp->GetThread().get();308309bool is_signed;310uint32_t count;311bool is_complex;312313RegisterContext *reg_ctx = thread->GetRegisterContext().get();314315bool set_it_simple = false;316if (compiler_type.IsIntegerOrEnumerationType(is_signed) ||317compiler_type.IsPointerType()) {318const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName("r3", 0);319320DataExtractor data;321Status data_error;322size_t num_bytes = new_value_sp->GetData(data, data_error);323if (data_error.Fail()) {324error.SetErrorStringWithFormat(325"Couldn't convert return value to raw data: %s",326data_error.AsCString());327return error;328}329lldb::offset_t offset = 0;330if (num_bytes <= 8) {331uint64_t raw_value = data.GetMaxU64(&offset, num_bytes);332333if (reg_ctx->WriteRegisterFromUnsigned(reg_info, raw_value))334set_it_simple = true;335} else {336error.SetErrorString("We don't support returning longer than 64 bit "337"integer values at present.");338}339} else if (compiler_type.IsFloatingPointType(count, is_complex)) {340if (is_complex)341error.SetErrorString(342"We don't support returning complex values at present");343else {344std::optional<uint64_t> bit_width =345compiler_type.GetBitSize(frame_sp.get());346if (!bit_width) {347error.SetErrorString("can't get size of type");348return error;349}350if (*bit_width <= 64) {351DataExtractor data;352Status data_error;353size_t num_bytes = new_value_sp->GetData(data, data_error);354if (data_error.Fail()) {355error.SetErrorStringWithFormat(356"Couldn't convert return value to raw data: %s",357data_error.AsCString());358return error;359}360361unsigned char buffer[16];362ByteOrder byte_order = data.GetByteOrder();363364data.CopyByteOrderedData(0, num_bytes, buffer, 16, byte_order);365set_it_simple = true;366} else {367// FIXME - don't know how to do 80 bit long doubles yet.368error.SetErrorString(369"We don't support returning float values > 64 bits at present");370}371}372}373374if (!set_it_simple) {375// Okay we've got a structure or something that doesn't fit in a simple376// register. We should figure out where it really goes, but we don't377// support this yet.378error.SetErrorString("We only support setting simple integer and float "379"return types at present.");380}381382return error;383}384385//386// ReturnValueExtractor387//388389namespace {390391#define LOG_PREFIX "ReturnValueExtractor: "392393class ReturnValueExtractor {394// This class represents a register, from which data may be extracted.395//396// It may be constructed by directly specifying its index (where 0 is the397// first register used to return values) or by specifying the offset of a398// given struct field, in which case the appropriated register index will be399// calculated.400class Register {401public:402enum Type {403GPR, // General Purpose Register404FPR // Floating Point Register405};406407// main constructor408//409// offs - field offset in struct410Register(Type ty, uint32_t index, uint32_t offs, RegisterContext *reg_ctx,411ByteOrder byte_order)412: m_index(index), m_offs(offs % sizeof(uint64_t)),413m_avail(sizeof(uint64_t) - m_offs), m_type(ty), m_reg_ctx(reg_ctx),414m_byte_order(byte_order) {}415416// explicit index, no offset417Register(Type ty, uint32_t index, RegisterContext *reg_ctx,418ByteOrder byte_order)419: Register(ty, index, 0, reg_ctx, byte_order) {}420421// GPR, calculate index from offs422Register(uint32_t offs, RegisterContext *reg_ctx, ByteOrder byte_order)423: Register(GPR, offs / sizeof(uint64_t), offs, reg_ctx, byte_order) {}424425uint32_t Index() const { return m_index; }426427// register offset where data is located428uint32_t Offs() const { return m_offs; }429430// available bytes in this register431uint32_t Avail() const { return m_avail; }432433bool IsValid() const {434if (m_index > 7) {435LLDB_LOG(m_log, LOG_PREFIX436"No more than 8 registers should be used to return values");437return false;438}439return true;440}441442std::string GetName() const {443if (m_type == GPR)444return ("r" + llvm::Twine(m_index + 3)).str();445else446return ("f" + llvm::Twine(m_index + 1)).str();447}448449// get raw register data450bool GetRawData(uint64_t &raw_data) {451const RegisterInfo *reg_info =452m_reg_ctx->GetRegisterInfoByName(GetName());453if (!reg_info) {454LLDB_LOG(m_log, LOG_PREFIX "Failed to get RegisterInfo");455return false;456}457458RegisterValue reg_val;459if (!m_reg_ctx->ReadRegister(reg_info, reg_val)) {460LLDB_LOG(m_log, LOG_PREFIX "ReadRegister() failed");461return false;462}463464Status error;465uint32_t rc = reg_val.GetAsMemoryData(466*reg_info, &raw_data, sizeof(raw_data), m_byte_order, error);467if (rc != sizeof(raw_data)) {468LLDB_LOG(m_log, LOG_PREFIX "GetAsMemoryData() failed");469return false;470}471472return true;473}474475private:476uint32_t m_index;477uint32_t m_offs;478uint32_t m_avail;479Type m_type;480RegisterContext *m_reg_ctx;481ByteOrder m_byte_order;482Log *m_log = GetLog(LLDBLog::Expressions);483};484485Register GetGPR(uint32_t index) const {486return Register(Register::GPR, index, m_reg_ctx, m_byte_order);487}488489Register GetFPR(uint32_t index) const {490return Register(Register::FPR, index, m_reg_ctx, m_byte_order);491}492493Register GetGPRByOffs(uint32_t offs) const {494return Register(offs, m_reg_ctx, m_byte_order);495}496497public:498// factory499static llvm::Expected<ReturnValueExtractor> Create(Thread &thread,500CompilerType &type) {501RegisterContext *reg_ctx = thread.GetRegisterContext().get();502if (!reg_ctx)503return llvm::createStringError(LOG_PREFIX504"Failed to get RegisterContext");505506ProcessSP process_sp = thread.GetProcess();507if (!process_sp)508return llvm::createStringError(LOG_PREFIX "GetProcess() failed");509510return ReturnValueExtractor(thread, type, reg_ctx, process_sp);511}512513// main method: get value of the type specified at construction time514ValueObjectSP GetValue() {515const uint32_t type_flags = m_type.GetTypeInfo();516517// call the appropriate type handler518ValueSP value_sp;519ValueObjectSP valobj_sp;520if (type_flags & eTypeIsScalar) {521if (type_flags & eTypeIsInteger) {522value_sp = GetIntegerValue(0);523} else if (type_flags & eTypeIsFloat) {524if (type_flags & eTypeIsComplex) {525LLDB_LOG(m_log, LOG_PREFIX "Complex numbers are not supported yet");526return ValueObjectSP();527} else {528value_sp = GetFloatValue(m_type, 0);529}530}531} else if (type_flags & eTypeIsPointer) {532value_sp = GetPointerValue(0);533}534535if (value_sp) {536valobj_sp = ValueObjectConstResult::Create(537m_thread.GetStackFrameAtIndex(0).get(), *value_sp, ConstString(""));538} else if (type_flags & eTypeIsVector) {539valobj_sp = GetVectorValueObject();540} else if (type_flags & eTypeIsStructUnion || type_flags & eTypeIsClass) {541valobj_sp = GetStructValueObject();542}543544return valobj_sp;545}546547private:548// data549Thread &m_thread;550CompilerType &m_type;551uint64_t m_byte_size;552std::unique_ptr<DataBufferHeap> m_data_up;553int32_t m_src_offs = 0;554int32_t m_dst_offs = 0;555bool m_packed = false;556Log *m_log = GetLog(LLDBLog::Expressions);557RegisterContext *m_reg_ctx;558ProcessSP m_process_sp;559ByteOrder m_byte_order;560uint32_t m_addr_size;561562// methods563564// constructor565ReturnValueExtractor(Thread &thread, CompilerType &type,566RegisterContext *reg_ctx, ProcessSP process_sp)567: m_thread(thread), m_type(type),568m_byte_size(m_type.GetByteSize(&thread).value_or(0)),569m_data_up(new DataBufferHeap(m_byte_size, 0)), m_reg_ctx(reg_ctx),570m_process_sp(process_sp), m_byte_order(process_sp->GetByteOrder()),571m_addr_size(572process_sp->GetTarget().GetArchitecture().GetAddressByteSize()) {}573574// build a new scalar value575ValueSP NewScalarValue(CompilerType &type) {576ValueSP value_sp(new Value);577value_sp->SetCompilerType(type);578value_sp->SetValueType(Value::ValueType::Scalar);579return value_sp;580}581582// get an integer value in the specified register583ValueSP GetIntegerValue(uint32_t reg_index) {584uint64_t raw_value;585auto reg = GetGPR(reg_index);586if (!reg.GetRawData(raw_value))587return ValueSP();588589// build value from data590ValueSP value_sp(NewScalarValue(m_type));591592uint32_t type_flags = m_type.GetTypeInfo();593bool is_signed = (type_flags & eTypeIsSigned) != 0;594595switch (m_byte_size) {596case sizeof(uint64_t):597if (is_signed)598value_sp->GetScalar() = (int64_t)(raw_value);599else600value_sp->GetScalar() = (uint64_t)(raw_value);601break;602603case sizeof(uint32_t):604if (is_signed)605value_sp->GetScalar() = (int32_t)(raw_value & UINT32_MAX);606else607value_sp->GetScalar() = (uint32_t)(raw_value & UINT32_MAX);608break;609610case sizeof(uint16_t):611if (is_signed)612value_sp->GetScalar() = (int16_t)(raw_value & UINT16_MAX);613else614value_sp->GetScalar() = (uint16_t)(raw_value & UINT16_MAX);615break;616617case sizeof(uint8_t):618if (is_signed)619value_sp->GetScalar() = (int8_t)(raw_value & UINT8_MAX);620else621value_sp->GetScalar() = (uint8_t)(raw_value & UINT8_MAX);622break;623624default:625llvm_unreachable("Invalid integer size");626}627628return value_sp;629}630631// get a floating point value on the specified register632ValueSP GetFloatValue(CompilerType &type, uint32_t reg_index) {633uint64_t raw_data;634auto reg = GetFPR(reg_index);635if (!reg.GetRawData(raw_data))636return {};637638// build value from data639ValueSP value_sp(NewScalarValue(type));640641DataExtractor de(&raw_data, sizeof(raw_data), m_byte_order, m_addr_size);642643offset_t offset = 0;644std::optional<uint64_t> byte_size = type.GetByteSize(m_process_sp.get());645if (!byte_size)646return {};647switch (*byte_size) {648case sizeof(float):649value_sp->GetScalar() = (float)de.GetDouble(&offset);650break;651652case sizeof(double):653value_sp->GetScalar() = de.GetDouble(&offset);654break;655656default:657llvm_unreachable("Invalid floating point size");658}659660return value_sp;661}662663// get pointer value from register664ValueSP GetPointerValue(uint32_t reg_index) {665uint64_t raw_data;666auto reg = GetGPR(reg_index);667if (!reg.GetRawData(raw_data))668return ValueSP();669670// build value from raw data671ValueSP value_sp(NewScalarValue(m_type));672value_sp->GetScalar() = raw_data;673return value_sp;674}675676// build the ValueObject from our data buffer677ValueObjectSP BuildValueObject() {678DataExtractor de(DataBufferSP(m_data_up.release()), m_byte_order,679m_addr_size);680return ValueObjectConstResult::Create(&m_thread, m_type, ConstString(""),681de);682}683684// get a vector return value685ValueObjectSP GetVectorValueObject() {686const uint32_t MAX_VRS = 2;687688// get first V register used to return values689const RegisterInfo *vr[MAX_VRS];690vr[0] = m_reg_ctx->GetRegisterInfoByName("vr2");691if (!vr[0]) {692LLDB_LOG(m_log, LOG_PREFIX "Failed to get vr2 RegisterInfo");693return ValueObjectSP();694}695696const uint32_t vr_size = vr[0]->byte_size;697size_t vrs = 1;698if (m_byte_size > 2 * vr_size) {699LLDB_LOG(700m_log, LOG_PREFIX701"Returning vectors that don't fit in 2 VR regs is not supported");702return ValueObjectSP();703}704705// load vr3, if needed706if (m_byte_size > vr_size) {707vrs++;708vr[1] = m_reg_ctx->GetRegisterInfoByName("vr3");709if (!vr[1]) {710LLDB_LOG(m_log, LOG_PREFIX "Failed to get vr3 RegisterInfo");711return ValueObjectSP();712}713}714715// Get the whole contents of vector registers and let the logic here716// arrange the data properly.717718RegisterValue vr_val[MAX_VRS];719Status error;720std::unique_ptr<DataBufferHeap> vr_data(721new DataBufferHeap(vrs * vr_size, 0));722723for (uint32_t i = 0; i < vrs; i++) {724if (!m_reg_ctx->ReadRegister(vr[i], vr_val[i])) {725LLDB_LOG(m_log, LOG_PREFIX "Failed to read vector register contents");726return ValueObjectSP();727}728if (!vr_val[i].GetAsMemoryData(*vr[i], vr_data->GetBytes() + i * vr_size,729vr_size, m_byte_order, error)) {730LLDB_LOG(m_log, LOG_PREFIX "Failed to extract vector register bytes");731return ValueObjectSP();732}733}734735// The compiler generated code seems to always put the vector elements at736// the end of the vector register, in case they don't occupy all of it.737// This offset variable handles this.738uint32_t offs = 0;739if (m_byte_size < vr_size)740offs = vr_size - m_byte_size;741742// copy extracted data to our buffer743memcpy(m_data_up->GetBytes(), vr_data->GetBytes() + offs, m_byte_size);744return BuildValueObject();745}746747// get a struct return value748ValueObjectSP GetStructValueObject() {749// case 1: get from stack750if (m_byte_size > 2 * sizeof(uint64_t)) {751uint64_t addr;752auto reg = GetGPR(0);753if (!reg.GetRawData(addr))754return {};755756Status error;757size_t rc = m_process_sp->ReadMemory(addr, m_data_up->GetBytes(),758m_byte_size, error);759if (rc != m_byte_size) {760LLDB_LOG(m_log, LOG_PREFIX "Failed to read memory pointed by r3");761return ValueObjectSP();762}763return BuildValueObject();764}765766// get number of children767const bool omit_empty_base_classes = true;768auto n_or_err = m_type.GetNumChildren(omit_empty_base_classes, nullptr);769if (!n_or_err) {770LLDB_LOG_ERROR(m_log, n_or_err.takeError(), LOG_PREFIX "{0}");771return {};772}773uint32_t n = *n_or_err;774if (!n) {775LLDB_LOG(m_log, LOG_PREFIX "No children found in struct");776return {};777}778779// case 2: homogeneous double or float aggregate780CompilerType elem_type;781if (m_type.IsHomogeneousAggregate(&elem_type)) {782uint32_t type_flags = elem_type.GetTypeInfo();783std::optional<uint64_t> elem_size =784elem_type.GetByteSize(m_process_sp.get());785if (!elem_size)786return {};787if (type_flags & eTypeIsComplex || !(type_flags & eTypeIsFloat)) {788LLDB_LOG(m_log,789LOG_PREFIX "Unexpected type found in homogeneous aggregate");790return {};791}792793for (uint32_t i = 0; i < n; i++) {794ValueSP val_sp = GetFloatValue(elem_type, i);795if (!val_sp)796return {};797798// copy to buffer799Status error;800size_t rc = val_sp->GetScalar().GetAsMemoryData(801m_data_up->GetBytes() + m_dst_offs, *elem_size, m_byte_order,802error);803if (rc != *elem_size) {804LLDB_LOG(m_log, LOG_PREFIX "Failed to get float data");805return {};806}807m_dst_offs += *elem_size;808}809return BuildValueObject();810}811812// case 3: get from GPRs813814// first, check if this is a packed struct or not815auto ast = m_type.GetTypeSystem().dyn_cast_or_null<TypeSystemClang>();816if (ast) {817clang::RecordDecl *record_decl = TypeSystemClang::GetAsRecordDecl(m_type);818819if (record_decl) {820auto attrs = record_decl->attrs();821for (const auto &attr : attrs) {822if (attr->getKind() == clang::attr::Packed) {823m_packed = true;824break;825}826}827}828}829830LLDB_LOG(m_log, LOG_PREFIX "{0} struct",831m_packed ? "packed" : "not packed");832833for (uint32_t i = 0; i < n; i++) {834std::string name;835uint32_t size;836(void)GetChildType(i, name, size);837// NOTE: the offset returned by GetChildCompilerTypeAtIndex()838// can't be used because it never considers alignment bytes839// between struct fields.840LLDB_LOG(m_log, LOG_PREFIX "field={0}, size={1}", name, size);841if (!ExtractField(size))842return ValueObjectSP();843}844845return BuildValueObject();846}847848// extract 'size' bytes at 'offs' from GPRs849bool ExtractFromRegs(int32_t offs, uint32_t size, void *buf) {850while (size) {851auto reg = GetGPRByOffs(offs);852if (!reg.IsValid())853return false;854855uint32_t n = std::min(reg.Avail(), size);856uint64_t raw_data;857858if (!reg.GetRawData(raw_data))859return false;860861memcpy(buf, (char *)&raw_data + reg.Offs(), n);862offs += n;863size -= n;864buf = (char *)buf + n;865}866return true;867}868869// extract one field from GPRs and put it in our buffer870bool ExtractField(uint32_t size) {871auto reg = GetGPRByOffs(m_src_offs);872if (!reg.IsValid())873return false;874875// handle padding876if (!m_packed) {877uint32_t n = m_src_offs % size;878879// not 'size' bytes aligned880if (n) {881LLDB_LOG(m_log,882LOG_PREFIX "Extracting {0} alignment bytes at offset {1}", n,883m_src_offs);884// get alignment bytes885if (!ExtractFromRegs(m_src_offs, n, m_data_up->GetBytes() + m_dst_offs))886return false;887m_src_offs += n;888m_dst_offs += n;889}890}891892// get field893LLDB_LOG(m_log, LOG_PREFIX "Extracting {0} field bytes at offset {1}", size,894m_src_offs);895if (!ExtractFromRegs(m_src_offs, size, m_data_up->GetBytes() + m_dst_offs))896return false;897m_src_offs += size;898m_dst_offs += size;899return true;900}901902// get child903llvm::Expected<CompilerType> GetChildType(uint32_t i, std::string &name,904uint32_t &size) {905// GetChild constant inputs906const bool transparent_pointers = false;907const bool omit_empty_base_classes = true;908const bool ignore_array_bounds = false;909// GetChild output params910int32_t child_offs;911uint32_t child_bitfield_bit_size;912uint32_t child_bitfield_bit_offset;913bool child_is_base_class;914bool child_is_deref_of_parent;915ValueObject *valobj = nullptr;916uint64_t language_flags;917ExecutionContext exe_ctx;918m_thread.CalculateExecutionContext(exe_ctx);919920return m_type.GetChildCompilerTypeAtIndex(921&exe_ctx, i, transparent_pointers, omit_empty_base_classes,922ignore_array_bounds, name, size, child_offs, child_bitfield_bit_size,923child_bitfield_bit_offset, child_is_base_class,924child_is_deref_of_parent, valobj, language_flags);925}926};927928#undef LOG_PREFIX929930} // anonymous namespace931932ValueObjectSP933ABISysV_ppc64::GetReturnValueObjectSimple(Thread &thread,934CompilerType &type) const {935if (!type)936return ValueObjectSP();937938auto exp_extractor = ReturnValueExtractor::Create(thread, type);939if (!exp_extractor) {940Log *log = GetLog(LLDBLog::Expressions);941LLDB_LOG_ERROR(log, exp_extractor.takeError(),942"Extracting return value failed: {0}");943return ValueObjectSP();944}945946return exp_extractor.get().GetValue();947}948949ValueObjectSP ABISysV_ppc64::GetReturnValueObjectImpl(950Thread &thread, CompilerType &return_compiler_type) const {951return GetReturnValueObjectSimple(thread, return_compiler_type);952}953954bool ABISysV_ppc64::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) {955unwind_plan.Clear();956unwind_plan.SetRegisterKind(eRegisterKindDWARF);957958uint32_t lr_reg_num;959uint32_t sp_reg_num;960uint32_t pc_reg_num;961962if (GetByteOrder() == lldb::eByteOrderLittle) {963lr_reg_num = ppc64le_dwarf::dwarf_lr_ppc64le;964sp_reg_num = ppc64le_dwarf::dwarf_r1_ppc64le;965pc_reg_num = ppc64le_dwarf::dwarf_pc_ppc64le;966} else {967lr_reg_num = ppc64_dwarf::dwarf_lr_ppc64;968sp_reg_num = ppc64_dwarf::dwarf_r1_ppc64;969pc_reg_num = ppc64_dwarf::dwarf_pc_ppc64;970}971972UnwindPlan::RowSP row(new UnwindPlan::Row);973974// Our Call Frame Address is the stack pointer value975row->GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 0);976977// The previous PC is in the LR978row->SetRegisterLocationToRegister(pc_reg_num, lr_reg_num, true);979unwind_plan.AppendRow(row);980981// All other registers are the same.982983unwind_plan.SetSourceName("ppc64 at-func-entry default");984unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);985986return true;987}988989bool ABISysV_ppc64::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {990unwind_plan.Clear();991unwind_plan.SetRegisterKind(eRegisterKindDWARF);992993uint32_t sp_reg_num;994uint32_t pc_reg_num;995uint32_t cr_reg_num;996997if (GetByteOrder() == lldb::eByteOrderLittle) {998sp_reg_num = ppc64le_dwarf::dwarf_r1_ppc64le;999pc_reg_num = ppc64le_dwarf::dwarf_lr_ppc64le;1000cr_reg_num = ppc64le_dwarf::dwarf_cr_ppc64le;1001} else {1002sp_reg_num = ppc64_dwarf::dwarf_r1_ppc64;1003pc_reg_num = ppc64_dwarf::dwarf_lr_ppc64;1004cr_reg_num = ppc64_dwarf::dwarf_cr_ppc64;1005}10061007UnwindPlan::RowSP row(new UnwindPlan::Row);1008const int32_t ptr_size = 8;1009row->SetUnspecifiedRegistersAreUndefined(true);1010row->GetCFAValue().SetIsRegisterDereferenced(sp_reg_num);10111012row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * 2, true);1013row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);1014row->SetRegisterLocationToAtCFAPlusOffset(cr_reg_num, ptr_size, true);10151016unwind_plan.AppendRow(row);1017unwind_plan.SetSourceName("ppc64 default unwind plan");1018unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);1019unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);1020unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);1021unwind_plan.SetReturnAddressRegister(pc_reg_num);1022return true;1023}10241025bool ABISysV_ppc64::RegisterIsVolatile(const RegisterInfo *reg_info) {1026return !RegisterIsCalleeSaved(reg_info);1027}10281029// See "Register Usage" in the1030// "System V Application Binary Interface"1031// "64-bit PowerPC ELF Application Binary Interface Supplement" current version1032// is 2 released 2015 at1033// https://members.openpowerfoundation.org/document/dl/5761034bool ABISysV_ppc64::RegisterIsCalleeSaved(const RegisterInfo *reg_info) {1035if (reg_info) {1036// Preserved registers are :1037// r1,r2,r13-r311038// cr2-cr4 (partially preserved)1039// f14-f31 (not yet)1040// v20-v31 (not yet)1041// vrsave (not yet)10421043const char *name = reg_info->name;1044if (name[0] == 'r') {1045if ((name[1] == '1' || name[1] == '2') && name[2] == '\0')1046return true;1047if (name[1] == '1' && name[2] > '2')1048return true;1049if ((name[1] == '2' || name[1] == '3') && name[2] != '\0')1050return true;1051}10521053if (name[0] == 'f' && name[1] >= '0' && name[2] <= '9') {1054if (name[2] == '\0')1055return false;1056if (name[1] == '1' && name[2] >= '4')1057return true;1058if ((name[1] == '2' || name[1] == '3') && name[2] != '\0')1059return true;1060}10611062if (name[0] == 's' && name[1] == 'p' && name[2] == '\0') // sp1063return true;1064if (name[0] == 'f' && name[1] == 'p' && name[2] == '\0') // fp1065return false;1066if (name[0] == 'p' && name[1] == 'c' && name[2] == '\0') // pc1067return true;1068}1069return false;1070}10711072void ABISysV_ppc64::Initialize() {1073PluginManager::RegisterPlugin(1074GetPluginNameStatic(), "System V ABI for ppc64 targets", CreateInstance);1075}10761077void ABISysV_ppc64::Terminate() {1078PluginManager::UnregisterPlugin(CreateInstance);1079}108010811082