180814287SRaphael Isemann //===-- NativeRegisterContextLinux_s390x.cpp ------------------------------===// 2bb00d0b6SUlrich Weigand // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6bb00d0b6SUlrich Weigand // 7bb00d0b6SUlrich Weigand //===----------------------------------------------------------------------===// 8bb00d0b6SUlrich Weigand 9bb00d0b6SUlrich Weigand #if defined(__s390x__) && defined(__linux__) 10bb00d0b6SUlrich Weigand 11bb00d0b6SUlrich Weigand #include "NativeRegisterContextLinux_s390x.h" 1201961c4bSPavel Labath #include "Plugins/Process/Linux/NativeProcessLinux.h" 13bb00d0b6SUlrich Weigand #include "lldb/Host/HostInfo.h" 14666cc0b2SZachary Turner #include "lldb/Utility/DataBufferHeap.h" 156f9e6901SZachary Turner #include "lldb/Utility/Log.h" 16d821c997SPavel Labath #include "lldb/Utility/RegisterValue.h" 1797206d57SZachary Turner #include "lldb/Utility/Status.h" 18bb00d0b6SUlrich Weigand 19bb00d0b6SUlrich Weigand #include "Plugins/Process/Utility/RegisterContextLinux_s390x.h" 20bb00d0b6SUlrich Weigand 21bb00d0b6SUlrich Weigand #include <linux/uio.h> 22bb00d0b6SUlrich Weigand #include <sys/ptrace.h> 23bb00d0b6SUlrich Weigand 24bb00d0b6SUlrich Weigand using namespace lldb_private; 25bb00d0b6SUlrich Weigand using namespace lldb_private::process_linux; 26bb00d0b6SUlrich Weigand 27bb00d0b6SUlrich Weigand // Private namespace. 28bb00d0b6SUlrich Weigand 29b9c1b51eSKate Stone namespace { 30bb00d0b6SUlrich Weigand // s390x 64-bit general purpose registers. 31b9c1b51eSKate Stone static const uint32_t g_gpr_regnums_s390x[] = { 32b9c1b51eSKate Stone lldb_r0_s390x, lldb_r1_s390x, lldb_r2_s390x, lldb_r3_s390x, 33b9c1b51eSKate Stone lldb_r4_s390x, lldb_r5_s390x, lldb_r6_s390x, lldb_r7_s390x, 34b9c1b51eSKate Stone lldb_r8_s390x, lldb_r9_s390x, lldb_r10_s390x, lldb_r11_s390x, 35b9c1b51eSKate Stone lldb_r12_s390x, lldb_r13_s390x, lldb_r14_s390x, lldb_r15_s390x, 36b9c1b51eSKate Stone lldb_acr0_s390x, lldb_acr1_s390x, lldb_acr2_s390x, lldb_acr3_s390x, 37b9c1b51eSKate Stone lldb_acr4_s390x, lldb_acr5_s390x, lldb_acr6_s390x, lldb_acr7_s390x, 38b9c1b51eSKate Stone lldb_acr8_s390x, lldb_acr9_s390x, lldb_acr10_s390x, lldb_acr11_s390x, 39b9c1b51eSKate Stone lldb_acr12_s390x, lldb_acr13_s390x, lldb_acr14_s390x, lldb_acr15_s390x, 40b9c1b51eSKate Stone lldb_pswm_s390x, lldb_pswa_s390x, 41bb00d0b6SUlrich Weigand LLDB_INVALID_REGNUM // register sets need to end with this flag 42bb00d0b6SUlrich Weigand }; 43b9c1b51eSKate Stone static_assert((sizeof(g_gpr_regnums_s390x) / sizeof(g_gpr_regnums_s390x[0])) - 44b9c1b51eSKate Stone 1 == 45b9c1b51eSKate Stone k_num_gpr_registers_s390x, 46bb00d0b6SUlrich Weigand "g_gpr_regnums_s390x has wrong number of register infos"); 47bb00d0b6SUlrich Weigand 48bb00d0b6SUlrich Weigand // s390x 64-bit floating point registers. 49b9c1b51eSKate Stone static const uint32_t g_fpu_regnums_s390x[] = { 50b9c1b51eSKate Stone lldb_f0_s390x, lldb_f1_s390x, lldb_f2_s390x, lldb_f3_s390x, 51b9c1b51eSKate Stone lldb_f4_s390x, lldb_f5_s390x, lldb_f6_s390x, lldb_f7_s390x, 52b9c1b51eSKate Stone lldb_f8_s390x, lldb_f9_s390x, lldb_f10_s390x, lldb_f11_s390x, 53b9c1b51eSKate Stone lldb_f12_s390x, lldb_f13_s390x, lldb_f14_s390x, lldb_f15_s390x, 54bb00d0b6SUlrich Weigand lldb_fpc_s390x, 55bb00d0b6SUlrich Weigand LLDB_INVALID_REGNUM // register sets need to end with this flag 56bb00d0b6SUlrich Weigand }; 57b9c1b51eSKate Stone static_assert((sizeof(g_fpu_regnums_s390x) / sizeof(g_fpu_regnums_s390x[0])) - 58b9c1b51eSKate Stone 1 == 59b9c1b51eSKate Stone k_num_fpr_registers_s390x, 60bb00d0b6SUlrich Weigand "g_fpu_regnums_s390x has wrong number of register infos"); 61bb00d0b6SUlrich Weigand 62bb00d0b6SUlrich Weigand // s390x Linux operating-system information. 63b9c1b51eSKate Stone static const uint32_t g_linux_regnums_s390x[] = { 64b9c1b51eSKate Stone lldb_orig_r2_s390x, lldb_last_break_s390x, lldb_system_call_s390x, 65bb00d0b6SUlrich Weigand LLDB_INVALID_REGNUM // register sets need to end with this flag 66bb00d0b6SUlrich Weigand }; 67b9c1b51eSKate Stone static_assert((sizeof(g_linux_regnums_s390x) / 68b9c1b51eSKate Stone sizeof(g_linux_regnums_s390x[0])) - 69b9c1b51eSKate Stone 1 == 70b9c1b51eSKate Stone k_num_linux_registers_s390x, 71bb00d0b6SUlrich Weigand "g_linux_regnums_s390x has wrong number of register infos"); 72bb00d0b6SUlrich Weigand 73bb00d0b6SUlrich Weigand // Number of register sets provided by this context. 74b9c1b51eSKate Stone enum { k_num_register_sets = 3 }; 75bb00d0b6SUlrich Weigand 76bb00d0b6SUlrich Weigand // Register sets for s390x 64-bit. 77b9c1b51eSKate Stone static const RegisterSet g_reg_sets_s390x[k_num_register_sets] = { 78b9c1b51eSKate Stone {"General Purpose Registers", "gpr", k_num_gpr_registers_s390x, 79b9c1b51eSKate Stone g_gpr_regnums_s390x}, 80b9c1b51eSKate Stone {"Floating Point Registers", "fpr", k_num_fpr_registers_s390x, 81b9c1b51eSKate Stone g_fpu_regnums_s390x}, 82b9c1b51eSKate Stone {"Linux Operating System Data", "linux", k_num_linux_registers_s390x, 83b9c1b51eSKate Stone g_linux_regnums_s390x}, 84bb00d0b6SUlrich Weigand }; 85bb00d0b6SUlrich Weigand } 86bb00d0b6SUlrich Weigand 87bb00d0b6SUlrich Weigand #define REG_CONTEXT_SIZE (sizeof(s390_regs) + sizeof(s390_fp_regs) + 4) 88bb00d0b6SUlrich Weigand 89bb00d0b6SUlrich Weigand // Required ptrace defines. 90bb00d0b6SUlrich Weigand 91bb00d0b6SUlrich Weigand #define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */ 92bb00d0b6SUlrich Weigand #define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */ 93bb00d0b6SUlrich Weigand 94d37349f3SPavel Labath std::unique_ptr<NativeRegisterContextLinux> 95b9c1b51eSKate Stone NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( 96d1486e65SPavel Labath const ArchSpec &target_arch, NativeThreadLinux &native_thread) { 97a8f3ae7cSJonas Devlieghere return std::make_unique<NativeRegisterContextLinux_s390x>(target_arch, 98d37349f3SPavel Labath native_thread); 99bb00d0b6SUlrich Weigand } 100bb00d0b6SUlrich Weigand 101bb00d0b6SUlrich Weigand // NativeRegisterContextLinux_s390x members. 102bb00d0b6SUlrich Weigand 103bb00d0b6SUlrich Weigand static RegisterInfoInterface * 104b9c1b51eSKate Stone CreateRegisterInfoInterface(const ArchSpec &target_arch) { 105bb00d0b6SUlrich Weigand assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && 106bb00d0b6SUlrich Weigand "Register setting path assumes this is a 64-bit host"); 107bb00d0b6SUlrich Weigand return new RegisterContextLinux_s390x(target_arch); 108bb00d0b6SUlrich Weigand } 109bb00d0b6SUlrich Weigand 110b9c1b51eSKate Stone NativeRegisterContextLinux_s390x::NativeRegisterContextLinux_s390x( 111d37349f3SPavel Labath const ArchSpec &target_arch, NativeThreadProtocol &native_thread) 112f5ca2756SMichał Górny : NativeRegisterContextRegisterInfo( 113*e1d4fb1eSPavel Labath native_thread, CreateRegisterInfoInterface(target_arch)), 114*e1d4fb1eSPavel Labath NativeRegisterContextLinux(native_thread) { 115bb00d0b6SUlrich Weigand // Set up data about ranges of valid registers. 116b9c1b51eSKate Stone switch (target_arch.GetMachine()) { 117bb00d0b6SUlrich Weigand case llvm::Triple::systemz: 118bb00d0b6SUlrich Weigand m_reg_info.num_registers = k_num_registers_s390x; 119bb00d0b6SUlrich Weigand m_reg_info.num_gpr_registers = k_num_gpr_registers_s390x; 120bb00d0b6SUlrich Weigand m_reg_info.num_fpr_registers = k_num_fpr_registers_s390x; 121bb00d0b6SUlrich Weigand m_reg_info.last_gpr = k_last_gpr_s390x; 122bb00d0b6SUlrich Weigand m_reg_info.first_fpr = k_first_fpr_s390x; 123bb00d0b6SUlrich Weigand m_reg_info.last_fpr = k_last_fpr_s390x; 124bb00d0b6SUlrich Weigand break; 125bb00d0b6SUlrich Weigand default: 126bb00d0b6SUlrich Weigand assert(false && "Unhandled target architecture."); 127bb00d0b6SUlrich Weigand break; 128bb00d0b6SUlrich Weigand } 129bb00d0b6SUlrich Weigand 130bb00d0b6SUlrich Weigand // Clear out the watchpoint state. 131bb00d0b6SUlrich Weigand m_watchpoint_addr = LLDB_INVALID_ADDRESS; 132bb00d0b6SUlrich Weigand } 133bb00d0b6SUlrich Weigand 134b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_s390x::GetRegisterSetCount() const { 135bb00d0b6SUlrich Weigand uint32_t sets = 0; 136b9c1b51eSKate Stone for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) { 137bb00d0b6SUlrich Weigand if (IsRegisterSetAvailable(set_index)) 138bb00d0b6SUlrich Weigand ++sets; 139bb00d0b6SUlrich Weigand } 140bb00d0b6SUlrich Weigand 141bb00d0b6SUlrich Weigand return sets; 142bb00d0b6SUlrich Weigand } 143bb00d0b6SUlrich Weigand 144b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_s390x::GetUserRegisterCount() const { 145bb00d0b6SUlrich Weigand uint32_t count = 0; 146b9c1b51eSKate Stone for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) { 147bb00d0b6SUlrich Weigand const RegisterSet *set = GetRegisterSet(set_index); 148bb00d0b6SUlrich Weigand if (set) 149bb00d0b6SUlrich Weigand count += set->num_registers; 150bb00d0b6SUlrich Weigand } 151bb00d0b6SUlrich Weigand return count; 152bb00d0b6SUlrich Weigand } 153bb00d0b6SUlrich Weigand 154bb00d0b6SUlrich Weigand const RegisterSet * 155b9c1b51eSKate Stone NativeRegisterContextLinux_s390x::GetRegisterSet(uint32_t set_index) const { 156bb00d0b6SUlrich Weigand if (!IsRegisterSetAvailable(set_index)) 157bb00d0b6SUlrich Weigand return nullptr; 158bb00d0b6SUlrich Weigand 159b9c1b51eSKate Stone switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { 160bb00d0b6SUlrich Weigand case llvm::Triple::systemz: 161bb00d0b6SUlrich Weigand return &g_reg_sets_s390x[set_index]; 162bb00d0b6SUlrich Weigand default: 163bb00d0b6SUlrich Weigand assert(false && "Unhandled target architecture."); 164bb00d0b6SUlrich Weigand return nullptr; 165bb00d0b6SUlrich Weigand } 166bb00d0b6SUlrich Weigand 167bb00d0b6SUlrich Weigand return nullptr; 168bb00d0b6SUlrich Weigand } 169bb00d0b6SUlrich Weigand 170b9c1b51eSKate Stone bool NativeRegisterContextLinux_s390x::IsRegisterSetAvailable( 171b9c1b51eSKate Stone uint32_t set_index) const { 172bb00d0b6SUlrich Weigand return set_index < k_num_register_sets; 173bb00d0b6SUlrich Weigand } 174bb00d0b6SUlrich Weigand 175b9c1b51eSKate Stone bool NativeRegisterContextLinux_s390x::IsGPR(uint32_t reg_index) const { 176b9c1b51eSKate Stone // GPRs come first. "orig_r2" counts as GPR since it is part of the GPR 177b9c1b51eSKate Stone // register area. 178bb00d0b6SUlrich Weigand return reg_index <= m_reg_info.last_gpr || reg_index == lldb_orig_r2_s390x; 179bb00d0b6SUlrich Weigand } 180bb00d0b6SUlrich Weigand 181b9c1b51eSKate Stone bool NativeRegisterContextLinux_s390x::IsFPR(uint32_t reg_index) const { 182b9c1b51eSKate Stone return (m_reg_info.first_fpr <= reg_index && 183b9c1b51eSKate Stone reg_index <= m_reg_info.last_fpr); 184bb00d0b6SUlrich Weigand } 185bb00d0b6SUlrich Weigand 18697206d57SZachary Turner Status 18797206d57SZachary Turner NativeRegisterContextLinux_s390x::ReadRegister(const RegisterInfo *reg_info, 18897206d57SZachary Turner RegisterValue ®_value) { 189bb00d0b6SUlrich Weigand if (!reg_info) 19097206d57SZachary Turner return Status("reg_info NULL"); 191bb00d0b6SUlrich Weigand 192bb00d0b6SUlrich Weigand const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 193bb00d0b6SUlrich Weigand if (reg == LLDB_INVALID_REGNUM) 19497206d57SZachary Turner return Status("register \"%s\" is an internal-only lldb register, cannot " 195b9c1b51eSKate Stone "read directly", 196b9c1b51eSKate Stone reg_info->name); 197bb00d0b6SUlrich Weigand 198b9c1b51eSKate Stone if (IsGPR(reg)) { 1993f3673eaSPavel Labath Status error = ReadGPR(); 200bb00d0b6SUlrich Weigand if (error.Fail()) 201bb00d0b6SUlrich Weigand return error; 202bb00d0b6SUlrich Weigand 2033f3673eaSPavel Labath uint8_t *src = (uint8_t *)&m_regs + reg_info->byte_offset; 2043f3673eaSPavel Labath assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(m_regs)); 205b9c1b51eSKate Stone switch (reg_info->byte_size) { 206bb00d0b6SUlrich Weigand case 4: 207bb00d0b6SUlrich Weigand reg_value.SetUInt32(*(uint32_t *)src); 208bb00d0b6SUlrich Weigand break; 209bb00d0b6SUlrich Weigand case 8: 210bb00d0b6SUlrich Weigand reg_value.SetUInt64(*(uint64_t *)src); 211bb00d0b6SUlrich Weigand break; 212bb00d0b6SUlrich Weigand default: 213bb00d0b6SUlrich Weigand assert(false && "Unhandled data size."); 21497206d57SZachary Turner return Status("unhandled byte size: %" PRIu32, reg_info->byte_size); 215bb00d0b6SUlrich Weigand } 21697206d57SZachary Turner return Status(); 217bb00d0b6SUlrich Weigand } 218bb00d0b6SUlrich Weigand 219b9c1b51eSKate Stone if (IsFPR(reg)) { 2203f3673eaSPavel Labath Status error = ReadFPR(); 221bb00d0b6SUlrich Weigand if (error.Fail()) 222bb00d0b6SUlrich Weigand return error; 223bb00d0b6SUlrich Weigand 224bb00d0b6SUlrich Weigand // byte_offset is just the offset within FPR, not the whole user area. 2253f3673eaSPavel Labath uint8_t *src = (uint8_t *)&m_fp_regs + reg_info->byte_offset; 2263f3673eaSPavel Labath assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(m_fp_regs)); 227b9c1b51eSKate Stone switch (reg_info->byte_size) { 228bb00d0b6SUlrich Weigand case 4: 229bb00d0b6SUlrich Weigand reg_value.SetUInt32(*(uint32_t *)src); 230bb00d0b6SUlrich Weigand break; 231bb00d0b6SUlrich Weigand case 8: 232bb00d0b6SUlrich Weigand reg_value.SetUInt64(*(uint64_t *)src); 233bb00d0b6SUlrich Weigand break; 234bb00d0b6SUlrich Weigand default: 235bb00d0b6SUlrich Weigand assert(false && "Unhandled data size."); 23697206d57SZachary Turner return Status("unhandled byte size: %" PRIu32, reg_info->byte_size); 237bb00d0b6SUlrich Weigand } 23897206d57SZachary Turner return Status(); 239bb00d0b6SUlrich Weigand } 240bb00d0b6SUlrich Weigand 241b9c1b51eSKate Stone if (reg == lldb_last_break_s390x) { 242bb00d0b6SUlrich Weigand uint64_t last_break; 24397206d57SZachary Turner Status error = DoReadRegisterSet(NT_S390_LAST_BREAK, &last_break, 8); 244bb00d0b6SUlrich Weigand if (error.Fail()) 245bb00d0b6SUlrich Weigand return error; 246bb00d0b6SUlrich Weigand 247bb00d0b6SUlrich Weigand reg_value.SetUInt64(last_break); 24897206d57SZachary Turner return Status(); 249bb00d0b6SUlrich Weigand } 250bb00d0b6SUlrich Weigand 251b9c1b51eSKate Stone if (reg == lldb_system_call_s390x) { 252bb00d0b6SUlrich Weigand uint32_t system_call; 25397206d57SZachary Turner Status error = DoReadRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4); 254bb00d0b6SUlrich Weigand if (error.Fail()) 255bb00d0b6SUlrich Weigand return error; 256bb00d0b6SUlrich Weigand 257bb00d0b6SUlrich Weigand reg_value.SetUInt32(system_call); 25897206d57SZachary Turner return Status(); 259bb00d0b6SUlrich Weigand } 260bb00d0b6SUlrich Weigand 26197206d57SZachary Turner return Status("failed - register wasn't recognized"); 262bb00d0b6SUlrich Weigand } 263bb00d0b6SUlrich Weigand 26497206d57SZachary Turner Status NativeRegisterContextLinux_s390x::WriteRegister( 265b9c1b51eSKate Stone const RegisterInfo *reg_info, const RegisterValue ®_value) { 266bb00d0b6SUlrich Weigand if (!reg_info) 26797206d57SZachary Turner return Status("reg_info NULL"); 268bb00d0b6SUlrich Weigand 269bb00d0b6SUlrich Weigand const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 270bb00d0b6SUlrich Weigand if (reg == LLDB_INVALID_REGNUM) 27197206d57SZachary Turner return Status("register \"%s\" is an internal-only lldb register, cannot " 272b9c1b51eSKate Stone "write directly", 273b9c1b51eSKate Stone reg_info->name); 274bb00d0b6SUlrich Weigand 275b9c1b51eSKate Stone if (IsGPR(reg)) { 2763f3673eaSPavel Labath Status error = ReadGPR(); 277bb00d0b6SUlrich Weigand if (error.Fail()) 278bb00d0b6SUlrich Weigand return error; 279bb00d0b6SUlrich Weigand 2803f3673eaSPavel Labath uint8_t *dst = (uint8_t *)&m_regs + reg_info->byte_offset; 2813f3673eaSPavel Labath assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(m_regs)); 282b9c1b51eSKate Stone switch (reg_info->byte_size) { 283bb00d0b6SUlrich Weigand case 4: 284bb00d0b6SUlrich Weigand *(uint32_t *)dst = reg_value.GetAsUInt32(); 285bb00d0b6SUlrich Weigand break; 286bb00d0b6SUlrich Weigand case 8: 287bb00d0b6SUlrich Weigand *(uint64_t *)dst = reg_value.GetAsUInt64(); 288bb00d0b6SUlrich Weigand break; 289bb00d0b6SUlrich Weigand default: 290bb00d0b6SUlrich Weigand assert(false && "Unhandled data size."); 29197206d57SZachary Turner return Status("unhandled byte size: %" PRIu32, reg_info->byte_size); 292bb00d0b6SUlrich Weigand } 2933f3673eaSPavel Labath return WriteGPR(); 294bb00d0b6SUlrich Weigand } 295bb00d0b6SUlrich Weigand 296b9c1b51eSKate Stone if (IsFPR(reg)) { 2973f3673eaSPavel Labath Status error = ReadFPR(); 298bb00d0b6SUlrich Weigand if (error.Fail()) 299bb00d0b6SUlrich Weigand return error; 300bb00d0b6SUlrich Weigand 301bb00d0b6SUlrich Weigand // byte_offset is just the offset within fp_regs, not the whole user area. 3023f3673eaSPavel Labath uint8_t *dst = (uint8_t *)&m_fp_regs + reg_info->byte_offset; 3033f3673eaSPavel Labath assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(m_fp_regs)); 304b9c1b51eSKate Stone switch (reg_info->byte_size) { 305bb00d0b6SUlrich Weigand case 4: 306bb00d0b6SUlrich Weigand *(uint32_t *)dst = reg_value.GetAsUInt32(); 307bb00d0b6SUlrich Weigand break; 308bb00d0b6SUlrich Weigand case 8: 309bb00d0b6SUlrich Weigand *(uint64_t *)dst = reg_value.GetAsUInt64(); 310bb00d0b6SUlrich Weigand break; 311bb00d0b6SUlrich Weigand default: 312bb00d0b6SUlrich Weigand assert(false && "Unhandled data size."); 31397206d57SZachary Turner return Status("unhandled byte size: %" PRIu32, reg_info->byte_size); 314bb00d0b6SUlrich Weigand } 3153f3673eaSPavel Labath return WriteFPR(); 316bb00d0b6SUlrich Weigand } 317bb00d0b6SUlrich Weigand 318b9c1b51eSKate Stone if (reg == lldb_last_break_s390x) { 31997206d57SZachary Turner return Status("The last break address is read-only"); 320bb00d0b6SUlrich Weigand } 321bb00d0b6SUlrich Weigand 322b9c1b51eSKate Stone if (reg == lldb_system_call_s390x) { 323bb00d0b6SUlrich Weigand uint32_t system_call = reg_value.GetAsUInt32(); 324bb00d0b6SUlrich Weigand return DoWriteRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4); 325bb00d0b6SUlrich Weigand } 326bb00d0b6SUlrich Weigand 32797206d57SZachary Turner return Status("failed - register wasn't recognized"); 328bb00d0b6SUlrich Weigand } 329bb00d0b6SUlrich Weigand 33097206d57SZachary Turner Status NativeRegisterContextLinux_s390x::ReadAllRegisterValues( 331b9c1b51eSKate Stone lldb::DataBufferSP &data_sp) { 33297206d57SZachary Turner Status error; 333bb00d0b6SUlrich Weigand 334bb00d0b6SUlrich Weigand data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); 335bb00d0b6SUlrich Weigand uint8_t *dst = data_sp->GetBytes(); 3363f3673eaSPavel Labath error = ReadGPR(); 337bb00d0b6SUlrich Weigand if (error.Fail()) 338bb00d0b6SUlrich Weigand return error; 3393f3673eaSPavel Labath memcpy(dst, GetGPRBuffer(), GetGPRSize()); 3403f3673eaSPavel Labath dst += GetGPRSize(); 341bb00d0b6SUlrich Weigand 3423f3673eaSPavel Labath error = ReadFPR(); 343bb00d0b6SUlrich Weigand if (error.Fail()) 344bb00d0b6SUlrich Weigand return error; 3453f3673eaSPavel Labath memcpy(dst, GetFPRBuffer(), GetFPRSize()); 3463f3673eaSPavel Labath dst += GetFPRSize(); 347bb00d0b6SUlrich Weigand 348bb00d0b6SUlrich Weigand // Ignore errors if the regset is unsupported (happens on older kernels). 349bb00d0b6SUlrich Weigand DoReadRegisterSet(NT_S390_SYSTEM_CALL, dst, 4); 350bb00d0b6SUlrich Weigand dst += 4; 351bb00d0b6SUlrich Weigand 35205097246SAdrian Prantl // To enable inferior function calls while the process is stopped in an 35305097246SAdrian Prantl // interrupted system call, we need to clear the system call flag. It will be 35405097246SAdrian Prantl // restored to its original value by WriteAllRegisterValues. Again we ignore 35505097246SAdrian Prantl // error if the regset is unsupported. 356bb00d0b6SUlrich Weigand uint32_t system_call = 0; 357bb00d0b6SUlrich Weigand DoWriteRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4); 358bb00d0b6SUlrich Weigand 359bb00d0b6SUlrich Weigand return error; 360bb00d0b6SUlrich Weigand } 361bb00d0b6SUlrich Weigand 36297206d57SZachary Turner Status NativeRegisterContextLinux_s390x::WriteAllRegisterValues( 363b9c1b51eSKate Stone const lldb::DataBufferSP &data_sp) { 36497206d57SZachary Turner Status error; 365bb00d0b6SUlrich Weigand 366b9c1b51eSKate Stone if (!data_sp) { 367b9c1b51eSKate Stone error.SetErrorStringWithFormat( 368b9c1b51eSKate Stone "NativeRegisterContextLinux_s390x::%s invalid data_sp provided", 369b9c1b51eSKate Stone __FUNCTION__); 370bb00d0b6SUlrich Weigand return error; 371bb00d0b6SUlrich Weigand } 372bb00d0b6SUlrich Weigand 373b9c1b51eSKate Stone if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { 374bb00d0b6SUlrich Weigand error.SetErrorStringWithFormat( 375b9c1b51eSKate Stone "NativeRegisterContextLinux_s390x::%s data_sp contained mismatched " 376b9c1b51eSKate Stone "data size, expected %" PRIu64 ", actual %" PRIu64, 377bb00d0b6SUlrich Weigand __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); 378bb00d0b6SUlrich Weigand return error; 379bb00d0b6SUlrich Weigand } 380bb00d0b6SUlrich Weigand 3813f3673eaSPavel Labath const uint8_t *src = data_sp->GetBytes(); 382b9c1b51eSKate Stone if (src == nullptr) { 383b9c1b51eSKate Stone error.SetErrorStringWithFormat("NativeRegisterContextLinux_s390x::%s " 384b9c1b51eSKate Stone "DataBuffer::GetBytes() returned a null " 385b9c1b51eSKate Stone "pointer", 386b9c1b51eSKate Stone __FUNCTION__); 387bb00d0b6SUlrich Weigand return error; 388bb00d0b6SUlrich Weigand } 389bb00d0b6SUlrich Weigand 3903f3673eaSPavel Labath memcpy(GetGPRBuffer(), src, GetGPRSize()); 3913f3673eaSPavel Labath src += GetGPRSize(); 3923f3673eaSPavel Labath error = WriteGPR(); 393bb00d0b6SUlrich Weigand if (error.Fail()) 394bb00d0b6SUlrich Weigand return error; 395bb00d0b6SUlrich Weigand 3963f3673eaSPavel Labath memcpy(GetFPRBuffer(), src, GetFPRSize()); 3973f3673eaSPavel Labath src += GetFPRSize(); 3983f3673eaSPavel Labath error = WriteFPR(); 399bb00d0b6SUlrich Weigand if (error.Fail()) 400bb00d0b6SUlrich Weigand return error; 401bb00d0b6SUlrich Weigand 402bb00d0b6SUlrich Weigand // Ignore errors if the regset is unsupported (happens on older kernels). 403bb00d0b6SUlrich Weigand DoWriteRegisterSet(NT_S390_SYSTEM_CALL, src, 4); 404bb00d0b6SUlrich Weigand src += 4; 405bb00d0b6SUlrich Weigand 406bb00d0b6SUlrich Weigand return error; 407bb00d0b6SUlrich Weigand } 408bb00d0b6SUlrich Weigand 40997206d57SZachary Turner Status NativeRegisterContextLinux_s390x::DoReadRegisterValue( 410b9c1b51eSKate Stone uint32_t offset, const char *reg_name, uint32_t size, 411b9c1b51eSKate Stone RegisterValue &value) { 41297206d57SZachary Turner return Status("DoReadRegisterValue unsupported"); 413bb00d0b6SUlrich Weigand } 414bb00d0b6SUlrich Weigand 41597206d57SZachary Turner Status NativeRegisterContextLinux_s390x::DoWriteRegisterValue( 416b9c1b51eSKate Stone uint32_t offset, const char *reg_name, const RegisterValue &value) { 41797206d57SZachary Turner return Status("DoWriteRegisterValue unsupported"); 418bb00d0b6SUlrich Weigand } 419bb00d0b6SUlrich Weigand 42097206d57SZachary Turner Status NativeRegisterContextLinux_s390x::PeekUserArea(uint32_t offset, 42197206d57SZachary Turner void *buf, 422b9c1b51eSKate Stone size_t buf_size) { 423bb00d0b6SUlrich Weigand ptrace_area parea; 424bb00d0b6SUlrich Weigand parea.len = buf_size; 425bb00d0b6SUlrich Weigand parea.process_addr = (addr_t)buf; 426bb00d0b6SUlrich Weigand parea.kernel_addr = offset; 427bb00d0b6SUlrich Weigand 428b9c1b51eSKate Stone return NativeProcessLinux::PtraceWrapper(PTRACE_PEEKUSR_AREA, 429b9c1b51eSKate Stone m_thread.GetID(), &parea); 430bb00d0b6SUlrich Weigand } 431bb00d0b6SUlrich Weigand 43297206d57SZachary Turner Status NativeRegisterContextLinux_s390x::PokeUserArea(uint32_t offset, 433b9c1b51eSKate Stone const void *buf, 434b9c1b51eSKate Stone size_t buf_size) { 435bb00d0b6SUlrich Weigand ptrace_area parea; 436bb00d0b6SUlrich Weigand parea.len = buf_size; 437bb00d0b6SUlrich Weigand parea.process_addr = (addr_t)buf; 438bb00d0b6SUlrich Weigand parea.kernel_addr = offset; 439bb00d0b6SUlrich Weigand 440b9c1b51eSKate Stone return NativeProcessLinux::PtraceWrapper(PTRACE_POKEUSR_AREA, 441b9c1b51eSKate Stone m_thread.GetID(), &parea); 442bb00d0b6SUlrich Weigand } 443bb00d0b6SUlrich Weigand 4443f3673eaSPavel Labath Status NativeRegisterContextLinux_s390x::ReadGPR() { 4453f3673eaSPavel Labath return PeekUserArea(offsetof(user_regs_struct, psw), GetGPRBuffer(), 4463f3673eaSPavel Labath GetGPRSize()); 447bb00d0b6SUlrich Weigand } 448bb00d0b6SUlrich Weigand 4493f3673eaSPavel Labath Status NativeRegisterContextLinux_s390x::WriteGPR() { 4503f3673eaSPavel Labath return PokeUserArea(offsetof(user_regs_struct, psw), GetGPRBuffer(), 4513f3673eaSPavel Labath GetGPRSize()); 452bb00d0b6SUlrich Weigand } 453bb00d0b6SUlrich Weigand 4543f3673eaSPavel Labath Status NativeRegisterContextLinux_s390x::ReadFPR() { 4553f3673eaSPavel Labath return PeekUserArea(offsetof(user_regs_struct, fp_regs), GetGPRBuffer(), 4563f3673eaSPavel Labath GetGPRSize()); 457bb00d0b6SUlrich Weigand } 458bb00d0b6SUlrich Weigand 4593f3673eaSPavel Labath Status NativeRegisterContextLinux_s390x::WriteFPR() { 4603f3673eaSPavel Labath return PokeUserArea(offsetof(user_regs_struct, fp_regs), GetGPRBuffer(), 4613f3673eaSPavel Labath GetGPRSize()); 462bb00d0b6SUlrich Weigand } 463bb00d0b6SUlrich Weigand 46497206d57SZachary Turner Status NativeRegisterContextLinux_s390x::DoReadRegisterSet(uint32_t regset, 465b9c1b51eSKate Stone void *buf, 466b9c1b51eSKate Stone size_t buf_size) { 467bb00d0b6SUlrich Weigand struct iovec iov; 468bb00d0b6SUlrich Weigand iov.iov_base = buf; 469bb00d0b6SUlrich Weigand iov.iov_len = buf_size; 470bb00d0b6SUlrich Weigand 471bb00d0b6SUlrich Weigand return ReadRegisterSet(&iov, buf_size, regset); 472bb00d0b6SUlrich Weigand } 473bb00d0b6SUlrich Weigand 47497206d57SZachary Turner Status NativeRegisterContextLinux_s390x::DoWriteRegisterSet(uint32_t regset, 475b9c1b51eSKate Stone const void *buf, 476b9c1b51eSKate Stone size_t buf_size) { 477bb00d0b6SUlrich Weigand struct iovec iov; 478bb00d0b6SUlrich Weigand iov.iov_base = const_cast<void *>(buf); 479bb00d0b6SUlrich Weigand iov.iov_len = buf_size; 480bb00d0b6SUlrich Weigand 481bb00d0b6SUlrich Weigand return WriteRegisterSet(&iov, buf_size, regset); 482bb00d0b6SUlrich Weigand } 483bb00d0b6SUlrich Weigand 48497206d57SZachary Turner Status NativeRegisterContextLinux_s390x::IsWatchpointHit(uint32_t wp_index, 485b9c1b51eSKate Stone bool &is_hit) { 486bb00d0b6SUlrich Weigand per_lowcore_bits per_lowcore; 487bb00d0b6SUlrich Weigand 488bb00d0b6SUlrich Weigand if (wp_index >= NumSupportedHardwareWatchpoints()) 48997206d57SZachary Turner return Status("Watchpoint index out of range"); 490bb00d0b6SUlrich Weigand 491b9c1b51eSKate Stone if (m_watchpoint_addr == LLDB_INVALID_ADDRESS) { 492bb00d0b6SUlrich Weigand is_hit = false; 49397206d57SZachary Turner return Status(); 494bb00d0b6SUlrich Weigand } 495bb00d0b6SUlrich Weigand 49697206d57SZachary Turner Status error = PeekUserArea(offsetof(user_regs_struct, per_info.lowcore), 497b9c1b51eSKate Stone &per_lowcore, sizeof(per_lowcore)); 498b9c1b51eSKate Stone if (error.Fail()) { 499bb00d0b6SUlrich Weigand is_hit = false; 500bb00d0b6SUlrich Weigand return error; 501bb00d0b6SUlrich Weigand } 502bb00d0b6SUlrich Weigand 503b9c1b51eSKate Stone is_hit = (per_lowcore.perc_storage_alteration == 1 && 504b9c1b51eSKate Stone per_lowcore.perc_store_real_address == 0); 505bb00d0b6SUlrich Weigand 506b9c1b51eSKate Stone if (is_hit) { 507bb00d0b6SUlrich Weigand // Do not report this watchpoint again. 508bb00d0b6SUlrich Weigand memset(&per_lowcore, 0, sizeof(per_lowcore)); 509b9c1b51eSKate Stone PokeUserArea(offsetof(user_regs_struct, per_info.lowcore), &per_lowcore, 510b9c1b51eSKate Stone sizeof(per_lowcore)); 511bb00d0b6SUlrich Weigand } 512bb00d0b6SUlrich Weigand 51397206d57SZachary Turner return Status(); 514bb00d0b6SUlrich Weigand } 515bb00d0b6SUlrich Weigand 51697206d57SZachary Turner Status NativeRegisterContextLinux_s390x::GetWatchpointHitIndex( 517b9c1b51eSKate Stone uint32_t &wp_index, lldb::addr_t trap_addr) { 518bb00d0b6SUlrich Weigand uint32_t num_hw_wps = NumSupportedHardwareWatchpoints(); 519b9c1b51eSKate Stone for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) { 520bb00d0b6SUlrich Weigand bool is_hit; 52197206d57SZachary Turner Status error = IsWatchpointHit(wp_index, is_hit); 522b9c1b51eSKate Stone if (error.Fail()) { 523bb00d0b6SUlrich Weigand wp_index = LLDB_INVALID_INDEX32; 524bb00d0b6SUlrich Weigand return error; 525b9c1b51eSKate Stone } else if (is_hit) { 526bb00d0b6SUlrich Weigand return error; 527bb00d0b6SUlrich Weigand } 528bb00d0b6SUlrich Weigand } 529bb00d0b6SUlrich Weigand wp_index = LLDB_INVALID_INDEX32; 53097206d57SZachary Turner return Status(); 531bb00d0b6SUlrich Weigand } 532bb00d0b6SUlrich Weigand 53397206d57SZachary Turner Status NativeRegisterContextLinux_s390x::IsWatchpointVacant(uint32_t wp_index, 534b9c1b51eSKate Stone bool &is_vacant) { 535bb00d0b6SUlrich Weigand if (wp_index >= NumSupportedHardwareWatchpoints()) 53697206d57SZachary Turner return Status("Watchpoint index out of range"); 537bb00d0b6SUlrich Weigand 538bb00d0b6SUlrich Weigand is_vacant = m_watchpoint_addr == LLDB_INVALID_ADDRESS; 539bb00d0b6SUlrich Weigand 54097206d57SZachary Turner return Status(); 541bb00d0b6SUlrich Weigand } 542bb00d0b6SUlrich Weigand 543b9c1b51eSKate Stone bool NativeRegisterContextLinux_s390x::ClearHardwareWatchpoint( 544b9c1b51eSKate Stone uint32_t wp_index) { 545bb00d0b6SUlrich Weigand per_struct per_info; 546bb00d0b6SUlrich Weigand 547bb00d0b6SUlrich Weigand if (wp_index >= NumSupportedHardwareWatchpoints()) 548bb00d0b6SUlrich Weigand return false; 549bb00d0b6SUlrich Weigand 55097206d57SZachary Turner Status error = PeekUserArea(offsetof(user_regs_struct, per_info), &per_info, 551b9c1b51eSKate Stone sizeof(per_info)); 552bb00d0b6SUlrich Weigand if (error.Fail()) 553bb00d0b6SUlrich Weigand return false; 554bb00d0b6SUlrich Weigand 555bb00d0b6SUlrich Weigand per_info.control_regs.bits.em_storage_alteration = 0; 556bb00d0b6SUlrich Weigand per_info.control_regs.bits.storage_alt_space_ctl = 0; 557bb00d0b6SUlrich Weigand per_info.starting_addr = 0; 558bb00d0b6SUlrich Weigand per_info.ending_addr = 0; 559bb00d0b6SUlrich Weigand 560b9c1b51eSKate Stone error = PokeUserArea(offsetof(user_regs_struct, per_info), &per_info, 561b9c1b51eSKate Stone sizeof(per_info)); 562bb00d0b6SUlrich Weigand if (error.Fail()) 563bb00d0b6SUlrich Weigand return false; 564bb00d0b6SUlrich Weigand 565bb00d0b6SUlrich Weigand m_watchpoint_addr = LLDB_INVALID_ADDRESS; 566bb00d0b6SUlrich Weigand return true; 567bb00d0b6SUlrich Weigand } 568bb00d0b6SUlrich Weigand 56997206d57SZachary Turner Status NativeRegisterContextLinux_s390x::ClearAllHardwareWatchpoints() { 570bb00d0b6SUlrich Weigand if (ClearHardwareWatchpoint(0)) 57197206d57SZachary Turner return Status(); 57297206d57SZachary Turner return Status("Clearing all hardware watchpoints failed."); 573bb00d0b6SUlrich Weigand } 574bb00d0b6SUlrich Weigand 575b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_s390x::SetHardwareWatchpoint( 576b9c1b51eSKate Stone lldb::addr_t addr, size_t size, uint32_t watch_flags) { 577bb00d0b6SUlrich Weigand per_struct per_info; 578bb00d0b6SUlrich Weigand 579bb00d0b6SUlrich Weigand if (watch_flags != 0x1) 580bb00d0b6SUlrich Weigand return LLDB_INVALID_INDEX32; 581bb00d0b6SUlrich Weigand 582bb00d0b6SUlrich Weigand if (m_watchpoint_addr != LLDB_INVALID_ADDRESS) 583bb00d0b6SUlrich Weigand return LLDB_INVALID_INDEX32; 584bb00d0b6SUlrich Weigand 58597206d57SZachary Turner Status error = PeekUserArea(offsetof(user_regs_struct, per_info), &per_info, 586b9c1b51eSKate Stone sizeof(per_info)); 587bb00d0b6SUlrich Weigand if (error.Fail()) 588bb00d0b6SUlrich Weigand return LLDB_INVALID_INDEX32; 589bb00d0b6SUlrich Weigand 590bb00d0b6SUlrich Weigand per_info.control_regs.bits.em_storage_alteration = 1; 591bb00d0b6SUlrich Weigand per_info.control_regs.bits.storage_alt_space_ctl = 1; 592bb00d0b6SUlrich Weigand per_info.starting_addr = addr; 593bb00d0b6SUlrich Weigand per_info.ending_addr = addr + size - 1; 594bb00d0b6SUlrich Weigand 595b9c1b51eSKate Stone error = PokeUserArea(offsetof(user_regs_struct, per_info), &per_info, 596b9c1b51eSKate Stone sizeof(per_info)); 597bb00d0b6SUlrich Weigand if (error.Fail()) 598bb00d0b6SUlrich Weigand return LLDB_INVALID_INDEX32; 599bb00d0b6SUlrich Weigand 600bb00d0b6SUlrich Weigand m_watchpoint_addr = addr; 601bb00d0b6SUlrich Weigand return 0; 602bb00d0b6SUlrich Weigand } 603bb00d0b6SUlrich Weigand 604bb00d0b6SUlrich Weigand lldb::addr_t 605b9c1b51eSKate Stone NativeRegisterContextLinux_s390x::GetWatchpointAddress(uint32_t wp_index) { 606bb00d0b6SUlrich Weigand if (wp_index >= NumSupportedHardwareWatchpoints()) 607bb00d0b6SUlrich Weigand return LLDB_INVALID_ADDRESS; 608bb00d0b6SUlrich Weigand return m_watchpoint_addr; 609bb00d0b6SUlrich Weigand } 610bb00d0b6SUlrich Weigand 611b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_s390x::NumSupportedHardwareWatchpoints() { 612bb00d0b6SUlrich Weigand return 1; 613bb00d0b6SUlrich Weigand } 614bb00d0b6SUlrich Weigand 615bb00d0b6SUlrich Weigand #endif // defined(__s390x__) && defined(__linux__) 616