Path: blob/main/contrib/llvm-project/lldb/source/Plugins/ABI/SystemZ/ABISysV_s390x.cpp
39654 views
//===-- ABISysV_s390x.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_s390x.h"910#include "llvm/ADT/STLExtras.h"11#include "llvm/TargetParser/Triple.h"1213#include "lldb/Core/Module.h"14#include "lldb/Core/PluginManager.h"15#include "lldb/Core/Value.h"16#include "lldb/Core/ValueObjectConstResult.h"17#include "lldb/Core/ValueObjectMemory.h"18#include "lldb/Core/ValueObjectRegister.h"19#include "lldb/Symbol/UnwindPlan.h"20#include "lldb/Target/Process.h"21#include "lldb/Target/RegisterContext.h"22#include "lldb/Target/StackFrame.h"23#include "lldb/Target/Target.h"24#include "lldb/Target/Thread.h"25#include "lldb/Utility/ConstString.h"26#include "lldb/Utility/DataExtractor.h"27#include "lldb/Utility/LLDBLog.h"28#include "lldb/Utility/Log.h"29#include "lldb/Utility/RegisterValue.h"30#include "lldb/Utility/Status.h"31#include <optional>3233using namespace lldb;34using namespace lldb_private;3536LLDB_PLUGIN_DEFINE_ADV(ABISysV_s390x, ABISystemZ)3738enum dwarf_regnums {39// General Purpose Registers40dwarf_r0_s390x = 0,41dwarf_r1_s390x,42dwarf_r2_s390x,43dwarf_r3_s390x,44dwarf_r4_s390x,45dwarf_r5_s390x,46dwarf_r6_s390x,47dwarf_r7_s390x,48dwarf_r8_s390x,49dwarf_r9_s390x,50dwarf_r10_s390x,51dwarf_r11_s390x,52dwarf_r12_s390x,53dwarf_r13_s390x,54dwarf_r14_s390x,55dwarf_r15_s390x,56// Floating Point Registers / Vector Registers 0-1557dwarf_f0_s390x = 16,58dwarf_f2_s390x,59dwarf_f4_s390x,60dwarf_f6_s390x,61dwarf_f1_s390x,62dwarf_f3_s390x,63dwarf_f5_s390x,64dwarf_f7_s390x,65dwarf_f8_s390x,66dwarf_f10_s390x,67dwarf_f12_s390x,68dwarf_f14_s390x,69dwarf_f9_s390x,70dwarf_f11_s390x,71dwarf_f13_s390x,72dwarf_f15_s390x,73// Access Registers74dwarf_acr0_s390x = 48,75dwarf_acr1_s390x,76dwarf_acr2_s390x,77dwarf_acr3_s390x,78dwarf_acr4_s390x,79dwarf_acr5_s390x,80dwarf_acr6_s390x,81dwarf_acr7_s390x,82dwarf_acr8_s390x,83dwarf_acr9_s390x,84dwarf_acr10_s390x,85dwarf_acr11_s390x,86dwarf_acr12_s390x,87dwarf_acr13_s390x,88dwarf_acr14_s390x,89dwarf_acr15_s390x,90// Program Status Word91dwarf_pswm_s390x = 64,92dwarf_pswa_s390x,93// Vector Registers 16-3194dwarf_v16_s390x = 68,95dwarf_v18_s390x,96dwarf_v20_s390x,97dwarf_v22_s390x,98dwarf_v17_s390x,99dwarf_v19_s390x,100dwarf_v21_s390x,101dwarf_v23_s390x,102dwarf_v24_s390x,103dwarf_v26_s390x,104dwarf_v28_s390x,105dwarf_v30_s390x,106dwarf_v25_s390x,107dwarf_v27_s390x,108dwarf_v29_s390x,109dwarf_v31_s390x,110};111112// RegisterKind: EHFrame, DWARF, Generic, Process Plugin, LLDB113114#define DEFINE_REG(name, size, alt, generic) \115{ \116#name, alt, size, 0, eEncodingUint, eFormatHex, \117{dwarf_##name##_s390x, dwarf_##name##_s390x, generic, \118LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, \119nullptr, nullptr, nullptr, \120}121122static const RegisterInfo g_register_infos[] = {123DEFINE_REG(r0, 8, nullptr, LLDB_INVALID_REGNUM),124DEFINE_REG(r1, 8, nullptr, LLDB_INVALID_REGNUM),125DEFINE_REG(r2, 8, nullptr, LLDB_REGNUM_GENERIC_ARG1),126DEFINE_REG(r3, 8, nullptr, LLDB_REGNUM_GENERIC_ARG2),127DEFINE_REG(r4, 8, nullptr, LLDB_REGNUM_GENERIC_ARG3),128DEFINE_REG(r5, 8, nullptr, LLDB_REGNUM_GENERIC_ARG4),129DEFINE_REG(r6, 8, nullptr, LLDB_REGNUM_GENERIC_ARG5),130DEFINE_REG(r7, 8, nullptr, LLDB_INVALID_REGNUM),131DEFINE_REG(r8, 8, nullptr, LLDB_INVALID_REGNUM),132DEFINE_REG(r9, 8, nullptr, LLDB_INVALID_REGNUM),133DEFINE_REG(r10, 8, nullptr, LLDB_INVALID_REGNUM),134DEFINE_REG(r11, 8, nullptr, LLDB_REGNUM_GENERIC_FP),135DEFINE_REG(r12, 8, nullptr, LLDB_INVALID_REGNUM),136DEFINE_REG(r13, 8, nullptr, LLDB_INVALID_REGNUM),137DEFINE_REG(r14, 8, nullptr, LLDB_INVALID_REGNUM),138DEFINE_REG(r15, 8, "sp", LLDB_REGNUM_GENERIC_SP),139DEFINE_REG(acr0, 4, nullptr, LLDB_INVALID_REGNUM),140DEFINE_REG(acr1, 4, nullptr, LLDB_INVALID_REGNUM),141DEFINE_REG(acr2, 4, nullptr, LLDB_INVALID_REGNUM),142DEFINE_REG(acr3, 4, nullptr, LLDB_INVALID_REGNUM),143DEFINE_REG(acr4, 4, nullptr, LLDB_INVALID_REGNUM),144DEFINE_REG(acr5, 4, nullptr, LLDB_INVALID_REGNUM),145DEFINE_REG(acr6, 4, nullptr, LLDB_INVALID_REGNUM),146DEFINE_REG(acr7, 4, nullptr, LLDB_INVALID_REGNUM),147DEFINE_REG(acr8, 4, nullptr, LLDB_INVALID_REGNUM),148DEFINE_REG(acr9, 4, nullptr, LLDB_INVALID_REGNUM),149DEFINE_REG(acr10, 4, nullptr, LLDB_INVALID_REGNUM),150DEFINE_REG(acr11, 4, nullptr, LLDB_INVALID_REGNUM),151DEFINE_REG(acr12, 4, nullptr, LLDB_INVALID_REGNUM),152DEFINE_REG(acr13, 4, nullptr, LLDB_INVALID_REGNUM),153DEFINE_REG(acr14, 4, nullptr, LLDB_INVALID_REGNUM),154DEFINE_REG(acr15, 4, nullptr, LLDB_INVALID_REGNUM),155DEFINE_REG(pswm, 8, nullptr, LLDB_REGNUM_GENERIC_FLAGS),156DEFINE_REG(pswa, 8, nullptr, LLDB_REGNUM_GENERIC_PC),157DEFINE_REG(f0, 8, nullptr, LLDB_INVALID_REGNUM),158DEFINE_REG(f1, 8, nullptr, LLDB_INVALID_REGNUM),159DEFINE_REG(f2, 8, nullptr, LLDB_INVALID_REGNUM),160DEFINE_REG(f3, 8, nullptr, LLDB_INVALID_REGNUM),161DEFINE_REG(f4, 8, nullptr, LLDB_INVALID_REGNUM),162DEFINE_REG(f5, 8, nullptr, LLDB_INVALID_REGNUM),163DEFINE_REG(f6, 8, nullptr, LLDB_INVALID_REGNUM),164DEFINE_REG(f7, 8, nullptr, LLDB_INVALID_REGNUM),165DEFINE_REG(f8, 8, nullptr, LLDB_INVALID_REGNUM),166DEFINE_REG(f9, 8, nullptr, LLDB_INVALID_REGNUM),167DEFINE_REG(f10, 8, nullptr, LLDB_INVALID_REGNUM),168DEFINE_REG(f11, 8, nullptr, LLDB_INVALID_REGNUM),169DEFINE_REG(f12, 8, nullptr, LLDB_INVALID_REGNUM),170DEFINE_REG(f13, 8, nullptr, LLDB_INVALID_REGNUM),171DEFINE_REG(f14, 8, nullptr, LLDB_INVALID_REGNUM),172DEFINE_REG(f15, 8, nullptr, LLDB_INVALID_REGNUM),173};174175static const uint32_t k_num_register_infos = std::size(g_register_infos);176177const lldb_private::RegisterInfo *178ABISysV_s390x::GetRegisterInfoArray(uint32_t &count) {179count = k_num_register_infos;180return g_register_infos;181}182183size_t ABISysV_s390x::GetRedZoneSize() const { return 0; }184185// Static Functions186187ABISP188ABISysV_s390x::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) {189if (arch.GetTriple().getArch() == llvm::Triple::systemz) {190return ABISP(new ABISysV_s390x(std::move(process_sp), MakeMCRegisterInfo(arch)));191}192return ABISP();193}194195bool ABISysV_s390x::PrepareTrivialCall(Thread &thread, addr_t sp,196addr_t func_addr, addr_t return_addr,197llvm::ArrayRef<addr_t> args) const {198Log *log = GetLog(LLDBLog::Expressions);199200if (log) {201StreamString s;202s.Printf("ABISysV_s390x::PrepareTrivialCall (tid = 0x%" PRIx64203", sp = 0x%" PRIx64 ", func_addr = 0x%" PRIx64204", return_addr = 0x%" PRIx64,205thread.GetID(), (uint64_t)sp, (uint64_t)func_addr,206(uint64_t)return_addr);207208for (size_t i = 0; i < args.size(); ++i)209s.Printf(", arg%" PRIu64 " = 0x%" PRIx64, static_cast<uint64_t>(i + 1),210args[i]);211s.PutCString(")");212log->PutString(s.GetString());213}214215RegisterContext *reg_ctx = thread.GetRegisterContext().get();216if (!reg_ctx)217return false;218219const RegisterInfo *pc_reg_info =220reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);221const RegisterInfo *sp_reg_info =222reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);223const RegisterInfo *ra_reg_info = reg_ctx->GetRegisterInfoByName("r14", 0);224ProcessSP process_sp(thread.GetProcess());225226// Allocate a new stack frame and space for stack arguments if necessary227228addr_t arg_pos = 0;229if (args.size() > 5) {230sp -= 8 * (args.size() - 5);231arg_pos = sp;232}233234sp -= 160;235236// Process arguments237238for (size_t i = 0; i < args.size(); ++i) {239if (i < 5) {240const RegisterInfo *reg_info = reg_ctx->GetRegisterInfo(241eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + i);242LLDB_LOGF(log, "About to write arg%" PRIu64 " (0x%" PRIx64 ") into %s",243static_cast<uint64_t>(i + 1), args[i], reg_info->name);244if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i]))245return false;246} else {247Status error;248LLDB_LOGF(log, "About to write arg%" PRIu64 " (0x%" PRIx64 ") onto stack",249static_cast<uint64_t>(i + 1), args[i]);250if (!process_sp->WritePointerToMemory(arg_pos, args[i], error))251return false;252arg_pos += 8;253}254}255256// %r14 is set to the return address257258LLDB_LOGF(log, "Writing RA: 0x%" PRIx64, (uint64_t)return_addr);259260if (!reg_ctx->WriteRegisterFromUnsigned(ra_reg_info, return_addr))261return false;262263// %r15 is set to the actual stack value.264265LLDB_LOGF(log, "Writing SP: 0x%" PRIx64, (uint64_t)sp);266267if (!reg_ctx->WriteRegisterFromUnsigned(sp_reg_info, sp))268return false;269270// %pc is set to the address of the called function.271272LLDB_LOGF(log, "Writing PC: 0x%" PRIx64, (uint64_t)func_addr);273274if (!reg_ctx->WriteRegisterFromUnsigned(pc_reg_info, func_addr))275return false;276277return true;278}279280static bool ReadIntegerArgument(Scalar &scalar, unsigned int bit_width,281bool is_signed, Thread &thread,282uint32_t *argument_register_ids,283unsigned int ¤t_argument_register,284addr_t ¤t_stack_argument) {285if (bit_width > 64)286return false; // Scalar can't hold large integer arguments287288if (current_argument_register < 5) {289scalar = thread.GetRegisterContext()->ReadRegisterAsUnsigned(290argument_register_ids[current_argument_register], 0);291current_argument_register++;292if (is_signed)293scalar.SignExtend(bit_width);294} else {295uint32_t byte_size = (bit_width + (8 - 1)) / 8;296Status error;297if (thread.GetProcess()->ReadScalarIntegerFromMemory(298current_stack_argument + 8 - byte_size, byte_size, is_signed,299scalar, error)) {300current_stack_argument += 8;301return true;302}303return false;304}305return true;306}307308bool ABISysV_s390x::GetArgumentValues(Thread &thread, ValueList &values) const {309unsigned int num_values = values.GetSize();310unsigned int value_index;311312// Extract the register context so we can read arguments from registers313314RegisterContext *reg_ctx = thread.GetRegisterContext().get();315316if (!reg_ctx)317return false;318319// Get the pointer to the first stack argument so we have a place to start320// when reading data321322addr_t sp = reg_ctx->GetSP(0);323324if (!sp)325return false;326327addr_t current_stack_argument = sp + 160;328329uint32_t argument_register_ids[5];330331argument_register_ids[0] =332reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1)333->kinds[eRegisterKindLLDB];334argument_register_ids[1] =335reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG2)336->kinds[eRegisterKindLLDB];337argument_register_ids[2] =338reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG3)339->kinds[eRegisterKindLLDB];340argument_register_ids[3] =341reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG4)342->kinds[eRegisterKindLLDB];343argument_register_ids[4] =344reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG5)345->kinds[eRegisterKindLLDB];346347unsigned int current_argument_register = 0;348349for (value_index = 0; value_index < num_values; ++value_index) {350Value *value = values.GetValueAtIndex(value_index);351352if (!value)353return false;354355// We currently only support extracting values with Clang QualTypes. Do we356// care about others?357CompilerType compiler_type = value->GetCompilerType();358std::optional<uint64_t> bit_size = compiler_type.GetBitSize(&thread);359if (!bit_size)360return false;361bool is_signed;362363if (compiler_type.IsIntegerOrEnumerationType(is_signed)) {364ReadIntegerArgument(value->GetScalar(), *bit_size, is_signed, thread,365argument_register_ids, current_argument_register,366current_stack_argument);367} else if (compiler_type.IsPointerType()) {368ReadIntegerArgument(value->GetScalar(), *bit_size, false, thread,369argument_register_ids, current_argument_register,370current_stack_argument);371}372}373374return true;375}376377Status ABISysV_s390x::SetReturnValueObject(lldb::StackFrameSP &frame_sp,378lldb::ValueObjectSP &new_value_sp) {379Status error;380if (!new_value_sp) {381error.SetErrorString("Empty value object for return value.");382return error;383}384385CompilerType compiler_type = new_value_sp->GetCompilerType();386if (!compiler_type) {387error.SetErrorString("Null clang type for return value.");388return error;389}390391Thread *thread = frame_sp->GetThread().get();392393bool is_signed;394uint32_t count;395bool is_complex;396397RegisterContext *reg_ctx = thread->GetRegisterContext().get();398399bool set_it_simple = false;400if (compiler_type.IsIntegerOrEnumerationType(is_signed) ||401compiler_type.IsPointerType()) {402const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName("r2", 0);403404DataExtractor data;405Status data_error;406size_t num_bytes = new_value_sp->GetData(data, data_error);407if (data_error.Fail()) {408error.SetErrorStringWithFormat(409"Couldn't convert return value to raw data: %s",410data_error.AsCString());411return error;412}413lldb::offset_t offset = 0;414if (num_bytes <= 8) {415uint64_t raw_value = data.GetMaxU64(&offset, num_bytes);416417if (reg_ctx->WriteRegisterFromUnsigned(reg_info, raw_value))418set_it_simple = true;419} else {420error.SetErrorString("We don't support returning longer than 64 bit "421"integer values at present.");422}423} else if (compiler_type.IsFloatingPointType(count, is_complex)) {424if (is_complex)425error.SetErrorString(426"We don't support returning complex values at present");427else {428std::optional<uint64_t> bit_width =429compiler_type.GetBitSize(frame_sp.get());430if (!bit_width) {431error.SetErrorString("can't get type size");432return error;433}434if (*bit_width <= 64) {435const RegisterInfo *f0_info = reg_ctx->GetRegisterInfoByName("f0", 0);436RegisterValue f0_value;437DataExtractor data;438Status data_error;439size_t num_bytes = new_value_sp->GetData(data, data_error);440if (data_error.Fail()) {441error.SetErrorStringWithFormat(442"Couldn't convert return value to raw data: %s",443data_error.AsCString());444return error;445}446447unsigned char buffer[8];448ByteOrder byte_order = data.GetByteOrder();449450data.CopyByteOrderedData(0, num_bytes, buffer, 8, byte_order);451f0_value.SetBytes(buffer, 8, byte_order);452reg_ctx->WriteRegister(f0_info, f0_value);453set_it_simple = true;454} else {455// FIXME - don't know how to do long doubles yet.456error.SetErrorString(457"We don't support returning float values > 64 bits at present");458}459}460}461462if (!set_it_simple) {463// Okay we've got a structure or something that doesn't fit in a simple464// register. We should figure out where it really goes, but we don't465// support this yet.466error.SetErrorString("We only support setting simple integer and float "467"return types at present.");468}469470return error;471}472473ValueObjectSP ABISysV_s390x::GetReturnValueObjectSimple(474Thread &thread, CompilerType &return_compiler_type) const {475ValueObjectSP return_valobj_sp;476Value value;477478if (!return_compiler_type)479return return_valobj_sp;480481// value.SetContext (Value::eContextTypeClangType, return_value_type);482value.SetCompilerType(return_compiler_type);483484RegisterContext *reg_ctx = thread.GetRegisterContext().get();485if (!reg_ctx)486return return_valobj_sp;487488const uint32_t type_flags = return_compiler_type.GetTypeInfo();489if (type_flags & eTypeIsScalar) {490value.SetValueType(Value::ValueType::Scalar);491492bool success = false;493if (type_flags & eTypeIsInteger) {494// Extract the register context so we can read arguments from registers.495std::optional<uint64_t> byte_size =496return_compiler_type.GetByteSize(&thread);497if (!byte_size)498return return_valobj_sp;499uint64_t raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned(500reg_ctx->GetRegisterInfoByName("r2", 0), 0);501const bool is_signed = (type_flags & eTypeIsSigned) != 0;502switch (*byte_size) {503default:504break;505506case sizeof(uint64_t):507if (is_signed)508value.GetScalar() = (int64_t)(raw_value);509else510value.GetScalar() = (uint64_t)(raw_value);511success = true;512break;513514case sizeof(uint32_t):515if (is_signed)516value.GetScalar() = (int32_t)(raw_value & UINT32_MAX);517else518value.GetScalar() = (uint32_t)(raw_value & UINT32_MAX);519success = true;520break;521522case sizeof(uint16_t):523if (is_signed)524value.GetScalar() = (int16_t)(raw_value & UINT16_MAX);525else526value.GetScalar() = (uint16_t)(raw_value & UINT16_MAX);527success = true;528break;529530case sizeof(uint8_t):531if (is_signed)532value.GetScalar() = (int8_t)(raw_value & UINT8_MAX);533else534value.GetScalar() = (uint8_t)(raw_value & UINT8_MAX);535success = true;536break;537}538} else if (type_flags & eTypeIsFloat) {539if (type_flags & eTypeIsComplex) {540// Don't handle complex yet.541} else {542std::optional<uint64_t> byte_size =543return_compiler_type.GetByteSize(&thread);544if (byte_size && *byte_size <= sizeof(long double)) {545const RegisterInfo *f0_info = reg_ctx->GetRegisterInfoByName("f0", 0);546RegisterValue f0_value;547if (reg_ctx->ReadRegister(f0_info, f0_value)) {548DataExtractor data;549if (f0_value.GetData(data)) {550lldb::offset_t offset = 0;551if (*byte_size == sizeof(float)) {552value.GetScalar() = (float)data.GetFloat(&offset);553success = true;554} else if (*byte_size == sizeof(double)) {555value.GetScalar() = (double)data.GetDouble(&offset);556success = true;557} else if (*byte_size == sizeof(long double)) {558// Don't handle long double yet.559}560}561}562}563}564}565566if (success)567return_valobj_sp = ValueObjectConstResult::Create(568thread.GetStackFrameAtIndex(0).get(), value, ConstString(""));569} else if (type_flags & eTypeIsPointer) {570unsigned r2_id =571reg_ctx->GetRegisterInfoByName("r2", 0)->kinds[eRegisterKindLLDB];572value.GetScalar() =573(uint64_t)thread.GetRegisterContext()->ReadRegisterAsUnsigned(r2_id, 0);574value.SetValueType(Value::ValueType::Scalar);575return_valobj_sp = ValueObjectConstResult::Create(576thread.GetStackFrameAtIndex(0).get(), value, ConstString(""));577}578579return return_valobj_sp;580}581582ValueObjectSP ABISysV_s390x::GetReturnValueObjectImpl(583Thread &thread, CompilerType &return_compiler_type) const {584ValueObjectSP return_valobj_sp;585586if (!return_compiler_type)587return return_valobj_sp;588589ExecutionContext exe_ctx(thread.shared_from_this());590return_valobj_sp = GetReturnValueObjectSimple(thread, return_compiler_type);591if (return_valobj_sp)592return return_valobj_sp;593594RegisterContextSP reg_ctx_sp = thread.GetRegisterContext();595if (!reg_ctx_sp)596return return_valobj_sp;597598if (return_compiler_type.IsAggregateType()) {599// FIXME: This is just taking a guess, r2 may very well no longer hold the600// return storage location.601// If we are going to do this right, when we make a new frame we should602// check to see if it uses a memory return, and if we are at the first603// instruction and if so stash away the return location. Then we would604// only return the memory return value if we know it is valid.605606unsigned r2_id =607reg_ctx_sp->GetRegisterInfoByName("r2", 0)->kinds[eRegisterKindLLDB];608lldb::addr_t storage_addr =609(uint64_t)thread.GetRegisterContext()->ReadRegisterAsUnsigned(r2_id, 0);610return_valobj_sp = ValueObjectMemory::Create(611&thread, "", Address(storage_addr, nullptr), return_compiler_type);612}613614return return_valobj_sp;615}616617bool ABISysV_s390x::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) {618unwind_plan.Clear();619unwind_plan.SetRegisterKind(eRegisterKindDWARF);620621UnwindPlan::RowSP row(new UnwindPlan::Row);622623// Our Call Frame Address is the stack pointer value + 160624row->GetCFAValue().SetIsRegisterPlusOffset(dwarf_r15_s390x, 160);625626// The previous PC is in r14627row->SetRegisterLocationToRegister(dwarf_pswa_s390x, dwarf_r14_s390x, true);628629// All other registers are the same.630unwind_plan.AppendRow(row);631unwind_plan.SetSourceName("s390x at-func-entry default");632unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);633return true;634}635636bool ABISysV_s390x::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {637// There's really no default way to unwind on s390x. Trust the .eh_frame CFI,638// which should always be good.639return false;640}641642bool ABISysV_s390x::GetFallbackRegisterLocation(643const RegisterInfo *reg_info,644UnwindPlan::Row::RegisterLocation &unwind_regloc) {645// If a volatile register is being requested, we don't want to forward the646// next frame's register contents up the stack -- the register is not647// retrievable at this frame.648if (RegisterIsVolatile(reg_info)) {649unwind_regloc.SetUndefined();650return true;651}652653return false;654}655656bool ABISysV_s390x::RegisterIsVolatile(const RegisterInfo *reg_info) {657return !RegisterIsCalleeSaved(reg_info);658}659660bool ABISysV_s390x::RegisterIsCalleeSaved(const RegisterInfo *reg_info) {661if (reg_info) {662// Preserved registers are :663// r6-r13, r15664// f8-f15665666const char *name = reg_info->name;667if (name[0] == 'r') {668switch (name[1]) {669case '6': // r6670case '7': // r7671case '8': // r8672case '9': // r9673return name[2] == '\0';674675case '1': // r10, r11, r12, r13, r15676if ((name[2] >= '0' && name[2] <= '3') || name[2] == '5')677return name[3] == '\0';678break;679680default:681break;682}683}684if (name[0] == 'f') {685switch (name[1]) {686case '8': // r8687case '9': // r9688return name[2] == '\0';689690case '1': // r10, r11, r12, r13, r14, r15691if (name[2] >= '0' && name[2] <= '5')692return name[3] == '\0';693break;694695default:696break;697}698}699700// Accept shorter-variant versions701if (name[0] == 's' && name[1] == 'p' && name[2] == '\0') // sp702return true;703if (name[0] == 'f' && name[1] == 'p' && name[2] == '\0') // fp704return true;705if (name[0] == 'p' && name[1] == 'c' && name[2] == '\0') // pc706return true;707}708return false;709}710711void ABISysV_s390x::Initialize() {712PluginManager::RegisterPlugin(713GetPluginNameStatic(), "System V ABI for s390x targets", CreateInstance);714}715716void ABISysV_s390x::Terminate() {717PluginManager::UnregisterPlugin(CreateInstance);718}719720721