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"
13*5e391985SPavel Labath #include "Plugins/Process/Utility/RegisterContextLinux_s390x.h"
14bb00d0b6SUlrich Weigand #include "lldb/Host/HostInfo.h"
15666cc0b2SZachary Turner #include "lldb/Utility/DataBufferHeap.h"
166f9e6901SZachary Turner #include "lldb/Utility/Log.h"
17d821c997SPavel Labath #include "lldb/Utility/RegisterValue.h"
1897206d57SZachary Turner #include "lldb/Utility/Status.h"
19bb00d0b6SUlrich Weigand #include <sys/ptrace.h>
20*5e391985SPavel Labath #include <sys/uio.h>
21bb00d0b6SUlrich Weigand 
22bb00d0b6SUlrich Weigand using namespace lldb_private;
23bb00d0b6SUlrich Weigand using namespace lldb_private::process_linux;
24bb00d0b6SUlrich Weigand 
25bb00d0b6SUlrich Weigand // Private namespace.
26bb00d0b6SUlrich Weigand 
27b9c1b51eSKate Stone namespace {
28bb00d0b6SUlrich Weigand // s390x 64-bit general purpose registers.
29b9c1b51eSKate Stone static const uint32_t g_gpr_regnums_s390x[] = {
30b9c1b51eSKate Stone     lldb_r0_s390x,      lldb_r1_s390x,    lldb_r2_s390x,    lldb_r3_s390x,
31b9c1b51eSKate Stone     lldb_r4_s390x,      lldb_r5_s390x,    lldb_r6_s390x,    lldb_r7_s390x,
32b9c1b51eSKate Stone     lldb_r8_s390x,      lldb_r9_s390x,    lldb_r10_s390x,   lldb_r11_s390x,
33b9c1b51eSKate Stone     lldb_r12_s390x,     lldb_r13_s390x,   lldb_r14_s390x,   lldb_r15_s390x,
34b9c1b51eSKate Stone     lldb_acr0_s390x,    lldb_acr1_s390x,  lldb_acr2_s390x,  lldb_acr3_s390x,
35b9c1b51eSKate Stone     lldb_acr4_s390x,    lldb_acr5_s390x,  lldb_acr6_s390x,  lldb_acr7_s390x,
36b9c1b51eSKate Stone     lldb_acr8_s390x,    lldb_acr9_s390x,  lldb_acr10_s390x, lldb_acr11_s390x,
37b9c1b51eSKate Stone     lldb_acr12_s390x,   lldb_acr13_s390x, lldb_acr14_s390x, lldb_acr15_s390x,
38b9c1b51eSKate Stone     lldb_pswm_s390x,    lldb_pswa_s390x,
39bb00d0b6SUlrich Weigand     LLDB_INVALID_REGNUM // register sets need to end with this flag
40bb00d0b6SUlrich Weigand };
41b9c1b51eSKate Stone static_assert((sizeof(g_gpr_regnums_s390x) / sizeof(g_gpr_regnums_s390x[0])) -
42b9c1b51eSKate Stone                       1 ==
43b9c1b51eSKate Stone                   k_num_gpr_registers_s390x,
44bb00d0b6SUlrich Weigand               "g_gpr_regnums_s390x has wrong number of register infos");
45bb00d0b6SUlrich Weigand 
46bb00d0b6SUlrich Weigand // s390x 64-bit floating point registers.
47b9c1b51eSKate Stone static const uint32_t g_fpu_regnums_s390x[] = {
48b9c1b51eSKate Stone     lldb_f0_s390x,      lldb_f1_s390x,  lldb_f2_s390x,  lldb_f3_s390x,
49b9c1b51eSKate Stone     lldb_f4_s390x,      lldb_f5_s390x,  lldb_f6_s390x,  lldb_f7_s390x,
50b9c1b51eSKate Stone     lldb_f8_s390x,      lldb_f9_s390x,  lldb_f10_s390x, lldb_f11_s390x,
51b9c1b51eSKate Stone     lldb_f12_s390x,     lldb_f13_s390x, lldb_f14_s390x, lldb_f15_s390x,
52bb00d0b6SUlrich Weigand     lldb_fpc_s390x,
53bb00d0b6SUlrich Weigand     LLDB_INVALID_REGNUM // register sets need to end with this flag
54bb00d0b6SUlrich Weigand };
55b9c1b51eSKate Stone static_assert((sizeof(g_fpu_regnums_s390x) / sizeof(g_fpu_regnums_s390x[0])) -
56b9c1b51eSKate Stone                       1 ==
57b9c1b51eSKate Stone                   k_num_fpr_registers_s390x,
58bb00d0b6SUlrich Weigand               "g_fpu_regnums_s390x has wrong number of register infos");
59bb00d0b6SUlrich Weigand 
60bb00d0b6SUlrich Weigand // s390x Linux operating-system information.
61b9c1b51eSKate Stone static const uint32_t g_linux_regnums_s390x[] = {
62b9c1b51eSKate Stone     lldb_orig_r2_s390x, lldb_last_break_s390x, lldb_system_call_s390x,
63bb00d0b6SUlrich Weigand     LLDB_INVALID_REGNUM // register sets need to end with this flag
64bb00d0b6SUlrich Weigand };
65b9c1b51eSKate Stone static_assert((sizeof(g_linux_regnums_s390x) /
66b9c1b51eSKate Stone                sizeof(g_linux_regnums_s390x[0])) -
67b9c1b51eSKate Stone                       1 ==
68b9c1b51eSKate Stone                   k_num_linux_registers_s390x,
69bb00d0b6SUlrich Weigand               "g_linux_regnums_s390x has wrong number of register infos");
70bb00d0b6SUlrich Weigand 
71bb00d0b6SUlrich Weigand // Number of register sets provided by this context.
72b9c1b51eSKate Stone enum { k_num_register_sets = 3 };
73bb00d0b6SUlrich Weigand 
74bb00d0b6SUlrich Weigand // Register sets for s390x 64-bit.
75b9c1b51eSKate Stone static const RegisterSet g_reg_sets_s390x[k_num_register_sets] = {
76b9c1b51eSKate Stone     {"General Purpose Registers", "gpr", k_num_gpr_registers_s390x,
77b9c1b51eSKate Stone      g_gpr_regnums_s390x},
78b9c1b51eSKate Stone     {"Floating Point Registers", "fpr", k_num_fpr_registers_s390x,
79b9c1b51eSKate Stone      g_fpu_regnums_s390x},
80b9c1b51eSKate Stone     {"Linux Operating System Data", "linux", k_num_linux_registers_s390x,
81b9c1b51eSKate Stone      g_linux_regnums_s390x},
82bb00d0b6SUlrich Weigand };
83bb00d0b6SUlrich Weigand }
84bb00d0b6SUlrich Weigand 
85bb00d0b6SUlrich Weigand #define REG_CONTEXT_SIZE (sizeof(s390_regs) + sizeof(s390_fp_regs) + 4)
86bb00d0b6SUlrich Weigand 
87bb00d0b6SUlrich Weigand // Required ptrace defines.
88bb00d0b6SUlrich Weigand 
89bb00d0b6SUlrich Weigand #define NT_S390_LAST_BREAK 0x306  /* s390 breaking event address */
90bb00d0b6SUlrich Weigand #define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */
91bb00d0b6SUlrich Weigand 
92d37349f3SPavel Labath std::unique_ptr<NativeRegisterContextLinux>
CreateHostNativeRegisterContextLinux(const ArchSpec & target_arch,NativeThreadLinux & native_thread)93b9c1b51eSKate Stone NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(
94d1486e65SPavel Labath     const ArchSpec &target_arch, NativeThreadLinux &native_thread) {
95a8f3ae7cSJonas Devlieghere   return std::make_unique<NativeRegisterContextLinux_s390x>(target_arch,
96d37349f3SPavel Labath                                                              native_thread);
97bb00d0b6SUlrich Weigand }
98bb00d0b6SUlrich Weigand 
99bb00d0b6SUlrich Weigand // NativeRegisterContextLinux_s390x members.
100bb00d0b6SUlrich Weigand 
101bb00d0b6SUlrich Weigand static RegisterInfoInterface *
CreateRegisterInfoInterface(const ArchSpec & target_arch)102b9c1b51eSKate Stone CreateRegisterInfoInterface(const ArchSpec &target_arch) {
103bb00d0b6SUlrich Weigand   assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) &&
104bb00d0b6SUlrich Weigand          "Register setting path assumes this is a 64-bit host");
105bb00d0b6SUlrich Weigand   return new RegisterContextLinux_s390x(target_arch);
106bb00d0b6SUlrich Weigand }
107bb00d0b6SUlrich Weigand 
NativeRegisterContextLinux_s390x(const ArchSpec & target_arch,NativeThreadProtocol & native_thread)108b9c1b51eSKate Stone NativeRegisterContextLinux_s390x::NativeRegisterContextLinux_s390x(
109d37349f3SPavel Labath     const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
110f5ca2756SMichał Górny     : NativeRegisterContextRegisterInfo(
111e1d4fb1eSPavel Labath           native_thread, CreateRegisterInfoInterface(target_arch)),
112e1d4fb1eSPavel Labath       NativeRegisterContextLinux(native_thread) {
113bb00d0b6SUlrich Weigand   // Set up data about ranges of valid registers.
114b9c1b51eSKate Stone   switch (target_arch.GetMachine()) {
115bb00d0b6SUlrich Weigand   case llvm::Triple::systemz:
116bb00d0b6SUlrich Weigand     m_reg_info.num_registers = k_num_registers_s390x;
117bb00d0b6SUlrich Weigand     m_reg_info.num_gpr_registers = k_num_gpr_registers_s390x;
118bb00d0b6SUlrich Weigand     m_reg_info.num_fpr_registers = k_num_fpr_registers_s390x;
119bb00d0b6SUlrich Weigand     m_reg_info.last_gpr = k_last_gpr_s390x;
120bb00d0b6SUlrich Weigand     m_reg_info.first_fpr = k_first_fpr_s390x;
121bb00d0b6SUlrich Weigand     m_reg_info.last_fpr = k_last_fpr_s390x;
122bb00d0b6SUlrich Weigand     break;
123bb00d0b6SUlrich Weigand   default:
124bb00d0b6SUlrich Weigand     assert(false && "Unhandled target architecture.");
125bb00d0b6SUlrich Weigand     break;
126bb00d0b6SUlrich Weigand   }
127bb00d0b6SUlrich Weigand 
128bb00d0b6SUlrich Weigand   // Clear out the watchpoint state.
129bb00d0b6SUlrich Weigand   m_watchpoint_addr = LLDB_INVALID_ADDRESS;
130bb00d0b6SUlrich Weigand }
131bb00d0b6SUlrich Weigand 
GetRegisterSetCount() const132b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_s390x::GetRegisterSetCount() const {
133bb00d0b6SUlrich Weigand   uint32_t sets = 0;
134b9c1b51eSKate Stone   for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) {
135bb00d0b6SUlrich Weigand     if (IsRegisterSetAvailable(set_index))
136bb00d0b6SUlrich Weigand       ++sets;
137bb00d0b6SUlrich Weigand   }
138bb00d0b6SUlrich Weigand 
139bb00d0b6SUlrich Weigand   return sets;
140bb00d0b6SUlrich Weigand }
141bb00d0b6SUlrich Weigand 
GetUserRegisterCount() const142b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_s390x::GetUserRegisterCount() const {
143bb00d0b6SUlrich Weigand   uint32_t count = 0;
144b9c1b51eSKate Stone   for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) {
145bb00d0b6SUlrich Weigand     const RegisterSet *set = GetRegisterSet(set_index);
146bb00d0b6SUlrich Weigand     if (set)
147bb00d0b6SUlrich Weigand       count += set->num_registers;
148bb00d0b6SUlrich Weigand   }
149bb00d0b6SUlrich Weigand   return count;
150bb00d0b6SUlrich Weigand }
151bb00d0b6SUlrich Weigand 
152bb00d0b6SUlrich Weigand const RegisterSet *
GetRegisterSet(uint32_t set_index) const153b9c1b51eSKate Stone NativeRegisterContextLinux_s390x::GetRegisterSet(uint32_t set_index) const {
154bb00d0b6SUlrich Weigand   if (!IsRegisterSetAvailable(set_index))
155bb00d0b6SUlrich Weigand     return nullptr;
156bb00d0b6SUlrich Weigand 
157b9c1b51eSKate Stone   switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
158bb00d0b6SUlrich Weigand   case llvm::Triple::systemz:
159bb00d0b6SUlrich Weigand     return &g_reg_sets_s390x[set_index];
160bb00d0b6SUlrich Weigand   default:
161bb00d0b6SUlrich Weigand     assert(false && "Unhandled target architecture.");
162bb00d0b6SUlrich Weigand     return nullptr;
163bb00d0b6SUlrich Weigand   }
164bb00d0b6SUlrich Weigand 
165bb00d0b6SUlrich Weigand   return nullptr;
166bb00d0b6SUlrich Weigand }
167bb00d0b6SUlrich Weigand 
IsRegisterSetAvailable(uint32_t set_index) const168b9c1b51eSKate Stone bool NativeRegisterContextLinux_s390x::IsRegisterSetAvailable(
169b9c1b51eSKate Stone     uint32_t set_index) const {
170bb00d0b6SUlrich Weigand   return set_index < k_num_register_sets;
171bb00d0b6SUlrich Weigand }
172bb00d0b6SUlrich Weigand 
IsGPR(uint32_t reg_index) const173b9c1b51eSKate Stone bool NativeRegisterContextLinux_s390x::IsGPR(uint32_t reg_index) const {
174b9c1b51eSKate Stone   // GPRs come first.  "orig_r2" counts as GPR since it is part of the GPR
175b9c1b51eSKate Stone   // register area.
176bb00d0b6SUlrich Weigand   return reg_index <= m_reg_info.last_gpr || reg_index == lldb_orig_r2_s390x;
177bb00d0b6SUlrich Weigand }
178bb00d0b6SUlrich Weigand 
IsFPR(uint32_t reg_index) const179b9c1b51eSKate Stone bool NativeRegisterContextLinux_s390x::IsFPR(uint32_t reg_index) const {
180b9c1b51eSKate Stone   return (m_reg_info.first_fpr <= reg_index &&
181b9c1b51eSKate Stone           reg_index <= m_reg_info.last_fpr);
182bb00d0b6SUlrich Weigand }
183bb00d0b6SUlrich Weigand 
18497206d57SZachary Turner Status
ReadRegister(const RegisterInfo * reg_info,RegisterValue & reg_value)18597206d57SZachary Turner NativeRegisterContextLinux_s390x::ReadRegister(const RegisterInfo *reg_info,
18697206d57SZachary Turner                                                RegisterValue &reg_value) {
187bb00d0b6SUlrich Weigand   if (!reg_info)
18897206d57SZachary Turner     return Status("reg_info NULL");
189bb00d0b6SUlrich Weigand 
190bb00d0b6SUlrich Weigand   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
191bb00d0b6SUlrich Weigand   if (reg == LLDB_INVALID_REGNUM)
19297206d57SZachary Turner     return Status("register \"%s\" is an internal-only lldb register, cannot "
193b9c1b51eSKate Stone                   "read directly",
194b9c1b51eSKate Stone                   reg_info->name);
195bb00d0b6SUlrich Weigand 
196b9c1b51eSKate Stone   if (IsGPR(reg)) {
1973f3673eaSPavel Labath     Status error = ReadGPR();
198bb00d0b6SUlrich Weigand     if (error.Fail())
199bb00d0b6SUlrich Weigand       return error;
200bb00d0b6SUlrich Weigand 
2013f3673eaSPavel Labath     uint8_t *src = (uint8_t *)&m_regs + reg_info->byte_offset;
2023f3673eaSPavel Labath     assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(m_regs));
203b9c1b51eSKate Stone     switch (reg_info->byte_size) {
204bb00d0b6SUlrich Weigand     case 4:
205bb00d0b6SUlrich Weigand       reg_value.SetUInt32(*(uint32_t *)src);
206bb00d0b6SUlrich Weigand       break;
207bb00d0b6SUlrich Weigand     case 8:
208bb00d0b6SUlrich Weigand       reg_value.SetUInt64(*(uint64_t *)src);
209bb00d0b6SUlrich Weigand       break;
210bb00d0b6SUlrich Weigand     default:
211bb00d0b6SUlrich Weigand       assert(false && "Unhandled data size.");
21297206d57SZachary Turner       return Status("unhandled byte size: %" PRIu32, reg_info->byte_size);
213bb00d0b6SUlrich Weigand     }
21497206d57SZachary Turner     return Status();
215bb00d0b6SUlrich Weigand   }
216bb00d0b6SUlrich Weigand 
217b9c1b51eSKate Stone   if (IsFPR(reg)) {
2183f3673eaSPavel Labath     Status error = ReadFPR();
219bb00d0b6SUlrich Weigand     if (error.Fail())
220bb00d0b6SUlrich Weigand       return error;
221bb00d0b6SUlrich Weigand 
222bb00d0b6SUlrich Weigand     // byte_offset is just the offset within FPR, not the whole user area.
2233f3673eaSPavel Labath     uint8_t *src = (uint8_t *)&m_fp_regs + reg_info->byte_offset;
2243f3673eaSPavel Labath     assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(m_fp_regs));
225b9c1b51eSKate Stone     switch (reg_info->byte_size) {
226bb00d0b6SUlrich Weigand     case 4:
227bb00d0b6SUlrich Weigand       reg_value.SetUInt32(*(uint32_t *)src);
228bb00d0b6SUlrich Weigand       break;
229bb00d0b6SUlrich Weigand     case 8:
230bb00d0b6SUlrich Weigand       reg_value.SetUInt64(*(uint64_t *)src);
231bb00d0b6SUlrich Weigand       break;
232bb00d0b6SUlrich Weigand     default:
233bb00d0b6SUlrich Weigand       assert(false && "Unhandled data size.");
23497206d57SZachary Turner       return Status("unhandled byte size: %" PRIu32, reg_info->byte_size);
235bb00d0b6SUlrich Weigand     }
23697206d57SZachary Turner     return Status();
237bb00d0b6SUlrich Weigand   }
238bb00d0b6SUlrich Weigand 
239b9c1b51eSKate Stone   if (reg == lldb_last_break_s390x) {
240bb00d0b6SUlrich Weigand     uint64_t last_break;
24197206d57SZachary Turner     Status error = DoReadRegisterSet(NT_S390_LAST_BREAK, &last_break, 8);
242bb00d0b6SUlrich Weigand     if (error.Fail())
243bb00d0b6SUlrich Weigand       return error;
244bb00d0b6SUlrich Weigand 
245bb00d0b6SUlrich Weigand     reg_value.SetUInt64(last_break);
24697206d57SZachary Turner     return Status();
247bb00d0b6SUlrich Weigand   }
248bb00d0b6SUlrich Weigand 
249b9c1b51eSKate Stone   if (reg == lldb_system_call_s390x) {
250bb00d0b6SUlrich Weigand     uint32_t system_call;
25197206d57SZachary Turner     Status error = DoReadRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4);
252bb00d0b6SUlrich Weigand     if (error.Fail())
253bb00d0b6SUlrich Weigand       return error;
254bb00d0b6SUlrich Weigand 
255bb00d0b6SUlrich Weigand     reg_value.SetUInt32(system_call);
25697206d57SZachary Turner     return Status();
257bb00d0b6SUlrich Weigand   }
258bb00d0b6SUlrich Weigand 
25997206d57SZachary Turner   return Status("failed - register wasn't recognized");
260bb00d0b6SUlrich Weigand }
261bb00d0b6SUlrich Weigand 
WriteRegister(const RegisterInfo * reg_info,const RegisterValue & reg_value)26297206d57SZachary Turner Status NativeRegisterContextLinux_s390x::WriteRegister(
263b9c1b51eSKate Stone     const RegisterInfo *reg_info, const RegisterValue &reg_value) {
264bb00d0b6SUlrich Weigand   if (!reg_info)
26597206d57SZachary Turner     return Status("reg_info NULL");
266bb00d0b6SUlrich Weigand 
267bb00d0b6SUlrich Weigand   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
268bb00d0b6SUlrich Weigand   if (reg == LLDB_INVALID_REGNUM)
26997206d57SZachary Turner     return Status("register \"%s\" is an internal-only lldb register, cannot "
270b9c1b51eSKate Stone                   "write directly",
271b9c1b51eSKate Stone                   reg_info->name);
272bb00d0b6SUlrich Weigand 
273b9c1b51eSKate Stone   if (IsGPR(reg)) {
2743f3673eaSPavel Labath     Status error = ReadGPR();
275bb00d0b6SUlrich Weigand     if (error.Fail())
276bb00d0b6SUlrich Weigand       return error;
277bb00d0b6SUlrich Weigand 
2783f3673eaSPavel Labath     uint8_t *dst = (uint8_t *)&m_regs + reg_info->byte_offset;
2793f3673eaSPavel Labath     assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(m_regs));
280b9c1b51eSKate Stone     switch (reg_info->byte_size) {
281bb00d0b6SUlrich Weigand     case 4:
282bb00d0b6SUlrich Weigand       *(uint32_t *)dst = reg_value.GetAsUInt32();
283bb00d0b6SUlrich Weigand       break;
284bb00d0b6SUlrich Weigand     case 8:
285bb00d0b6SUlrich Weigand       *(uint64_t *)dst = reg_value.GetAsUInt64();
286bb00d0b6SUlrich Weigand       break;
287bb00d0b6SUlrich Weigand     default:
288bb00d0b6SUlrich Weigand       assert(false && "Unhandled data size.");
28997206d57SZachary Turner       return Status("unhandled byte size: %" PRIu32, reg_info->byte_size);
290bb00d0b6SUlrich Weigand     }
2913f3673eaSPavel Labath     return WriteGPR();
292bb00d0b6SUlrich Weigand   }
293bb00d0b6SUlrich Weigand 
294b9c1b51eSKate Stone   if (IsFPR(reg)) {
2953f3673eaSPavel Labath     Status error = ReadFPR();
296bb00d0b6SUlrich Weigand     if (error.Fail())
297bb00d0b6SUlrich Weigand       return error;
298bb00d0b6SUlrich Weigand 
299bb00d0b6SUlrich Weigand     // byte_offset is just the offset within fp_regs, not the whole user area.
3003f3673eaSPavel Labath     uint8_t *dst = (uint8_t *)&m_fp_regs + reg_info->byte_offset;
3013f3673eaSPavel Labath     assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(m_fp_regs));
302b9c1b51eSKate Stone     switch (reg_info->byte_size) {
303bb00d0b6SUlrich Weigand     case 4:
304bb00d0b6SUlrich Weigand       *(uint32_t *)dst = reg_value.GetAsUInt32();
305bb00d0b6SUlrich Weigand       break;
306bb00d0b6SUlrich Weigand     case 8:
307bb00d0b6SUlrich Weigand       *(uint64_t *)dst = reg_value.GetAsUInt64();
308bb00d0b6SUlrich Weigand       break;
309bb00d0b6SUlrich Weigand     default:
310bb00d0b6SUlrich Weigand       assert(false && "Unhandled data size.");
31197206d57SZachary Turner       return Status("unhandled byte size: %" PRIu32, reg_info->byte_size);
312bb00d0b6SUlrich Weigand     }
3133f3673eaSPavel Labath     return WriteFPR();
314bb00d0b6SUlrich Weigand   }
315bb00d0b6SUlrich Weigand 
316b9c1b51eSKate Stone   if (reg == lldb_last_break_s390x) {
31797206d57SZachary Turner     return Status("The last break address is read-only");
318bb00d0b6SUlrich Weigand   }
319bb00d0b6SUlrich Weigand 
320b9c1b51eSKate Stone   if (reg == lldb_system_call_s390x) {
321bb00d0b6SUlrich Weigand     uint32_t system_call = reg_value.GetAsUInt32();
322bb00d0b6SUlrich Weigand     return DoWriteRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4);
323bb00d0b6SUlrich Weigand   }
324bb00d0b6SUlrich Weigand 
32597206d57SZachary Turner   return Status("failed - register wasn't recognized");
326bb00d0b6SUlrich Weigand }
327bb00d0b6SUlrich Weigand 
ReadAllRegisterValues(lldb::WritableDataBufferSP & data_sp)32897206d57SZachary Turner Status NativeRegisterContextLinux_s390x::ReadAllRegisterValues(
329c2f64601SJonas Devlieghere     lldb::WritableDataBufferSP &data_sp) {
33097206d57SZachary Turner   Status error;
331bb00d0b6SUlrich Weigand 
332bb00d0b6SUlrich Weigand   data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
333bb00d0b6SUlrich Weigand   uint8_t *dst = data_sp->GetBytes();
3343f3673eaSPavel Labath   error = ReadGPR();
335bb00d0b6SUlrich Weigand   if (error.Fail())
336bb00d0b6SUlrich Weigand     return error;
3373f3673eaSPavel Labath   memcpy(dst, GetGPRBuffer(), GetGPRSize());
3383f3673eaSPavel Labath   dst += GetGPRSize();
339bb00d0b6SUlrich Weigand 
3403f3673eaSPavel Labath   error = ReadFPR();
341bb00d0b6SUlrich Weigand   if (error.Fail())
342bb00d0b6SUlrich Weigand     return error;
3433f3673eaSPavel Labath   memcpy(dst, GetFPRBuffer(), GetFPRSize());
3443f3673eaSPavel Labath   dst += GetFPRSize();
345bb00d0b6SUlrich Weigand 
346bb00d0b6SUlrich Weigand   // Ignore errors if the regset is unsupported (happens on older kernels).
347bb00d0b6SUlrich Weigand   DoReadRegisterSet(NT_S390_SYSTEM_CALL, dst, 4);
348bb00d0b6SUlrich Weigand   dst += 4;
349bb00d0b6SUlrich Weigand 
35005097246SAdrian Prantl   // To enable inferior function calls while the process is stopped in an
35105097246SAdrian Prantl   // interrupted system call, we need to clear the system call flag. It will be
35205097246SAdrian Prantl   // restored to its original value by WriteAllRegisterValues. Again we ignore
35305097246SAdrian Prantl   // error if the regset is unsupported.
354bb00d0b6SUlrich Weigand   uint32_t system_call = 0;
355bb00d0b6SUlrich Weigand   DoWriteRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4);
356bb00d0b6SUlrich Weigand 
357bb00d0b6SUlrich Weigand   return error;
358bb00d0b6SUlrich Weigand }
359bb00d0b6SUlrich Weigand 
WriteAllRegisterValues(const lldb::DataBufferSP & data_sp)36097206d57SZachary Turner Status NativeRegisterContextLinux_s390x::WriteAllRegisterValues(
361b9c1b51eSKate Stone     const lldb::DataBufferSP &data_sp) {
36297206d57SZachary Turner   Status error;
363bb00d0b6SUlrich Weigand 
364b9c1b51eSKate Stone   if (!data_sp) {
365b9c1b51eSKate Stone     error.SetErrorStringWithFormat(
366b9c1b51eSKate Stone         "NativeRegisterContextLinux_s390x::%s invalid data_sp provided",
367b9c1b51eSKate Stone         __FUNCTION__);
368bb00d0b6SUlrich Weigand     return error;
369bb00d0b6SUlrich Weigand   }
370bb00d0b6SUlrich Weigand 
371b9c1b51eSKate Stone   if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
372bb00d0b6SUlrich Weigand     error.SetErrorStringWithFormat(
373b9c1b51eSKate Stone         "NativeRegisterContextLinux_s390x::%s data_sp contained mismatched "
374b9c1b51eSKate Stone         "data size, expected %" PRIu64 ", actual %" PRIu64,
375bb00d0b6SUlrich Weigand         __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
376bb00d0b6SUlrich Weigand     return error;
377bb00d0b6SUlrich Weigand   }
378bb00d0b6SUlrich Weigand 
3793f3673eaSPavel Labath   const uint8_t *src = data_sp->GetBytes();
380b9c1b51eSKate Stone   if (src == nullptr) {
381b9c1b51eSKate Stone     error.SetErrorStringWithFormat("NativeRegisterContextLinux_s390x::%s "
382b9c1b51eSKate Stone                                    "DataBuffer::GetBytes() returned a null "
383b9c1b51eSKate Stone                                    "pointer",
384b9c1b51eSKate Stone                                    __FUNCTION__);
385bb00d0b6SUlrich Weigand     return error;
386bb00d0b6SUlrich Weigand   }
387bb00d0b6SUlrich Weigand 
3883f3673eaSPavel Labath   memcpy(GetGPRBuffer(), src, GetGPRSize());
3893f3673eaSPavel Labath   src += GetGPRSize();
3903f3673eaSPavel Labath   error = WriteGPR();
391bb00d0b6SUlrich Weigand   if (error.Fail())
392bb00d0b6SUlrich Weigand     return error;
393bb00d0b6SUlrich Weigand 
3943f3673eaSPavel Labath   memcpy(GetFPRBuffer(), src, GetFPRSize());
3953f3673eaSPavel Labath   src += GetFPRSize();
3963f3673eaSPavel Labath   error = WriteFPR();
397bb00d0b6SUlrich Weigand   if (error.Fail())
398bb00d0b6SUlrich Weigand     return error;
399bb00d0b6SUlrich Weigand 
400bb00d0b6SUlrich Weigand   // Ignore errors if the regset is unsupported (happens on older kernels).
401bb00d0b6SUlrich Weigand   DoWriteRegisterSet(NT_S390_SYSTEM_CALL, src, 4);
402bb00d0b6SUlrich Weigand   src += 4;
403bb00d0b6SUlrich Weigand 
404bb00d0b6SUlrich Weigand   return error;
405bb00d0b6SUlrich Weigand }
406bb00d0b6SUlrich Weigand 
DoReadRegisterValue(uint32_t offset,const char * reg_name,uint32_t size,RegisterValue & value)40797206d57SZachary Turner Status NativeRegisterContextLinux_s390x::DoReadRegisterValue(
408b9c1b51eSKate Stone     uint32_t offset, const char *reg_name, uint32_t size,
409b9c1b51eSKate Stone     RegisterValue &value) {
41097206d57SZachary Turner   return Status("DoReadRegisterValue unsupported");
411bb00d0b6SUlrich Weigand }
412bb00d0b6SUlrich Weigand 
DoWriteRegisterValue(uint32_t offset,const char * reg_name,const RegisterValue & value)41397206d57SZachary Turner Status NativeRegisterContextLinux_s390x::DoWriteRegisterValue(
414b9c1b51eSKate Stone     uint32_t offset, const char *reg_name, const RegisterValue &value) {
41597206d57SZachary Turner   return Status("DoWriteRegisterValue unsupported");
416bb00d0b6SUlrich Weigand }
417bb00d0b6SUlrich Weigand 
PeekUserArea(uint32_t offset,void * buf,size_t buf_size)41897206d57SZachary Turner Status NativeRegisterContextLinux_s390x::PeekUserArea(uint32_t offset,
41997206d57SZachary Turner                                                       void *buf,
420b9c1b51eSKate Stone                                                       size_t buf_size) {
421bb00d0b6SUlrich Weigand   ptrace_area parea;
422bb00d0b6SUlrich Weigand   parea.len = buf_size;
423bb00d0b6SUlrich Weigand   parea.process_addr = (addr_t)buf;
424bb00d0b6SUlrich Weigand   parea.kernel_addr = offset;
425bb00d0b6SUlrich Weigand 
426b9c1b51eSKate Stone   return NativeProcessLinux::PtraceWrapper(PTRACE_PEEKUSR_AREA,
427b9c1b51eSKate Stone                                            m_thread.GetID(), &parea);
428bb00d0b6SUlrich Weigand }
429bb00d0b6SUlrich Weigand 
PokeUserArea(uint32_t offset,const void * buf,size_t buf_size)43097206d57SZachary Turner Status NativeRegisterContextLinux_s390x::PokeUserArea(uint32_t offset,
431b9c1b51eSKate Stone                                                       const void *buf,
432b9c1b51eSKate Stone                                                       size_t buf_size) {
433bb00d0b6SUlrich Weigand   ptrace_area parea;
434bb00d0b6SUlrich Weigand   parea.len = buf_size;
435bb00d0b6SUlrich Weigand   parea.process_addr = (addr_t)buf;
436bb00d0b6SUlrich Weigand   parea.kernel_addr = offset;
437bb00d0b6SUlrich Weigand 
438b9c1b51eSKate Stone   return NativeProcessLinux::PtraceWrapper(PTRACE_POKEUSR_AREA,
439b9c1b51eSKate Stone                                            m_thread.GetID(), &parea);
440bb00d0b6SUlrich Weigand }
441bb00d0b6SUlrich Weigand 
ReadGPR()4423f3673eaSPavel Labath Status NativeRegisterContextLinux_s390x::ReadGPR() {
4433f3673eaSPavel Labath   return PeekUserArea(offsetof(user_regs_struct, psw), GetGPRBuffer(),
4443f3673eaSPavel Labath                       GetGPRSize());
445bb00d0b6SUlrich Weigand }
446bb00d0b6SUlrich Weigand 
WriteGPR()4473f3673eaSPavel Labath Status NativeRegisterContextLinux_s390x::WriteGPR() {
4483f3673eaSPavel Labath   return PokeUserArea(offsetof(user_regs_struct, psw), GetGPRBuffer(),
4493f3673eaSPavel Labath                       GetGPRSize());
450bb00d0b6SUlrich Weigand }
451bb00d0b6SUlrich Weigand 
ReadFPR()4523f3673eaSPavel Labath Status NativeRegisterContextLinux_s390x::ReadFPR() {
4533f3673eaSPavel Labath   return PeekUserArea(offsetof(user_regs_struct, fp_regs), GetGPRBuffer(),
4543f3673eaSPavel Labath                       GetGPRSize());
455bb00d0b6SUlrich Weigand }
456bb00d0b6SUlrich Weigand 
WriteFPR()4573f3673eaSPavel Labath Status NativeRegisterContextLinux_s390x::WriteFPR() {
4583f3673eaSPavel Labath   return PokeUserArea(offsetof(user_regs_struct, fp_regs), GetGPRBuffer(),
4593f3673eaSPavel Labath                       GetGPRSize());
460bb00d0b6SUlrich Weigand }
461bb00d0b6SUlrich Weigand 
DoReadRegisterSet(uint32_t regset,void * buf,size_t buf_size)46297206d57SZachary Turner Status NativeRegisterContextLinux_s390x::DoReadRegisterSet(uint32_t regset,
463b9c1b51eSKate Stone                                                            void *buf,
464b9c1b51eSKate Stone                                                            size_t buf_size) {
465bb00d0b6SUlrich Weigand   struct iovec iov;
466bb00d0b6SUlrich Weigand   iov.iov_base = buf;
467bb00d0b6SUlrich Weigand   iov.iov_len = buf_size;
468bb00d0b6SUlrich Weigand 
469bb00d0b6SUlrich Weigand   return ReadRegisterSet(&iov, buf_size, regset);
470bb00d0b6SUlrich Weigand }
471bb00d0b6SUlrich Weigand 
DoWriteRegisterSet(uint32_t regset,const void * buf,size_t buf_size)47297206d57SZachary Turner Status NativeRegisterContextLinux_s390x::DoWriteRegisterSet(uint32_t regset,
473b9c1b51eSKate Stone                                                             const void *buf,
474b9c1b51eSKate Stone                                                             size_t buf_size) {
475bb00d0b6SUlrich Weigand   struct iovec iov;
476bb00d0b6SUlrich Weigand   iov.iov_base = const_cast<void *>(buf);
477bb00d0b6SUlrich Weigand   iov.iov_len = buf_size;
478bb00d0b6SUlrich Weigand 
479bb00d0b6SUlrich Weigand   return WriteRegisterSet(&iov, buf_size, regset);
480bb00d0b6SUlrich Weigand }
481bb00d0b6SUlrich Weigand 
IsWatchpointHit(uint32_t wp_index,bool & is_hit)48297206d57SZachary Turner Status NativeRegisterContextLinux_s390x::IsWatchpointHit(uint32_t wp_index,
483b9c1b51eSKate Stone                                                          bool &is_hit) {
484bb00d0b6SUlrich Weigand   per_lowcore_bits per_lowcore;
485bb00d0b6SUlrich Weigand 
486bb00d0b6SUlrich Weigand   if (wp_index >= NumSupportedHardwareWatchpoints())
48797206d57SZachary Turner     return Status("Watchpoint index out of range");
488bb00d0b6SUlrich Weigand 
489b9c1b51eSKate Stone   if (m_watchpoint_addr == LLDB_INVALID_ADDRESS) {
490bb00d0b6SUlrich Weigand     is_hit = false;
49197206d57SZachary Turner     return Status();
492bb00d0b6SUlrich Weigand   }
493bb00d0b6SUlrich Weigand 
49497206d57SZachary Turner   Status error = PeekUserArea(offsetof(user_regs_struct, per_info.lowcore),
495b9c1b51eSKate Stone                               &per_lowcore, sizeof(per_lowcore));
496b9c1b51eSKate Stone   if (error.Fail()) {
497bb00d0b6SUlrich Weigand     is_hit = false;
498bb00d0b6SUlrich Weigand     return error;
499bb00d0b6SUlrich Weigand   }
500bb00d0b6SUlrich Weigand 
501b9c1b51eSKate Stone   is_hit = (per_lowcore.perc_storage_alteration == 1 &&
502b9c1b51eSKate Stone             per_lowcore.perc_store_real_address == 0);
503bb00d0b6SUlrich Weigand 
504b9c1b51eSKate Stone   if (is_hit) {
505bb00d0b6SUlrich Weigand     // Do not report this watchpoint again.
506bb00d0b6SUlrich Weigand     memset(&per_lowcore, 0, sizeof(per_lowcore));
507b9c1b51eSKate Stone     PokeUserArea(offsetof(user_regs_struct, per_info.lowcore), &per_lowcore,
508b9c1b51eSKate Stone                  sizeof(per_lowcore));
509bb00d0b6SUlrich Weigand   }
510bb00d0b6SUlrich Weigand 
51197206d57SZachary Turner   return Status();
512bb00d0b6SUlrich Weigand }
513bb00d0b6SUlrich Weigand 
GetWatchpointHitIndex(uint32_t & wp_index,lldb::addr_t trap_addr)51497206d57SZachary Turner Status NativeRegisterContextLinux_s390x::GetWatchpointHitIndex(
515b9c1b51eSKate Stone     uint32_t &wp_index, lldb::addr_t trap_addr) {
516bb00d0b6SUlrich Weigand   uint32_t num_hw_wps = NumSupportedHardwareWatchpoints();
517b9c1b51eSKate Stone   for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) {
518bb00d0b6SUlrich Weigand     bool is_hit;
51997206d57SZachary Turner     Status error = IsWatchpointHit(wp_index, is_hit);
520b9c1b51eSKate Stone     if (error.Fail()) {
521bb00d0b6SUlrich Weigand       wp_index = LLDB_INVALID_INDEX32;
522bb00d0b6SUlrich Weigand       return error;
523b9c1b51eSKate Stone     } else if (is_hit) {
524bb00d0b6SUlrich Weigand       return error;
525bb00d0b6SUlrich Weigand     }
526bb00d0b6SUlrich Weigand   }
527bb00d0b6SUlrich Weigand   wp_index = LLDB_INVALID_INDEX32;
52897206d57SZachary Turner   return Status();
529bb00d0b6SUlrich Weigand }
530bb00d0b6SUlrich Weigand 
IsWatchpointVacant(uint32_t wp_index,bool & is_vacant)53197206d57SZachary Turner Status NativeRegisterContextLinux_s390x::IsWatchpointVacant(uint32_t wp_index,
532b9c1b51eSKate Stone                                                             bool &is_vacant) {
533bb00d0b6SUlrich Weigand   if (wp_index >= NumSupportedHardwareWatchpoints())
53497206d57SZachary Turner     return Status("Watchpoint index out of range");
535bb00d0b6SUlrich Weigand 
536bb00d0b6SUlrich Weigand   is_vacant = m_watchpoint_addr == LLDB_INVALID_ADDRESS;
537bb00d0b6SUlrich Weigand 
53897206d57SZachary Turner   return Status();
539bb00d0b6SUlrich Weigand }
540bb00d0b6SUlrich Weigand 
ClearHardwareWatchpoint(uint32_t wp_index)541b9c1b51eSKate Stone bool NativeRegisterContextLinux_s390x::ClearHardwareWatchpoint(
542b9c1b51eSKate Stone     uint32_t wp_index) {
543bb00d0b6SUlrich Weigand   per_struct per_info;
544bb00d0b6SUlrich Weigand 
545bb00d0b6SUlrich Weigand   if (wp_index >= NumSupportedHardwareWatchpoints())
546bb00d0b6SUlrich Weigand     return false;
547bb00d0b6SUlrich Weigand 
54897206d57SZachary Turner   Status error = PeekUserArea(offsetof(user_regs_struct, per_info), &per_info,
549b9c1b51eSKate Stone                               sizeof(per_info));
550bb00d0b6SUlrich Weigand   if (error.Fail())
551bb00d0b6SUlrich Weigand     return false;
552bb00d0b6SUlrich Weigand 
553bb00d0b6SUlrich Weigand   per_info.control_regs.bits.em_storage_alteration = 0;
554bb00d0b6SUlrich Weigand   per_info.control_regs.bits.storage_alt_space_ctl = 0;
555bb00d0b6SUlrich Weigand   per_info.starting_addr = 0;
556bb00d0b6SUlrich Weigand   per_info.ending_addr = 0;
557bb00d0b6SUlrich Weigand 
558b9c1b51eSKate Stone   error = PokeUserArea(offsetof(user_regs_struct, per_info), &per_info,
559b9c1b51eSKate Stone                        sizeof(per_info));
560bb00d0b6SUlrich Weigand   if (error.Fail())
561bb00d0b6SUlrich Weigand     return false;
562bb00d0b6SUlrich Weigand 
563bb00d0b6SUlrich Weigand   m_watchpoint_addr = LLDB_INVALID_ADDRESS;
564bb00d0b6SUlrich Weigand   return true;
565bb00d0b6SUlrich Weigand }
566bb00d0b6SUlrich Weigand 
ClearAllHardwareWatchpoints()56797206d57SZachary Turner Status NativeRegisterContextLinux_s390x::ClearAllHardwareWatchpoints() {
568bb00d0b6SUlrich Weigand   if (ClearHardwareWatchpoint(0))
56997206d57SZachary Turner     return Status();
57097206d57SZachary Turner   return Status("Clearing all hardware watchpoints failed.");
571bb00d0b6SUlrich Weigand }
572bb00d0b6SUlrich Weigand 
SetHardwareWatchpoint(lldb::addr_t addr,size_t size,uint32_t watch_flags)573b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_s390x::SetHardwareWatchpoint(
574b9c1b51eSKate Stone     lldb::addr_t addr, size_t size, uint32_t watch_flags) {
575bb00d0b6SUlrich Weigand   per_struct per_info;
576bb00d0b6SUlrich Weigand 
577bb00d0b6SUlrich Weigand   if (watch_flags != 0x1)
578bb00d0b6SUlrich Weigand     return LLDB_INVALID_INDEX32;
579bb00d0b6SUlrich Weigand 
580bb00d0b6SUlrich Weigand   if (m_watchpoint_addr != LLDB_INVALID_ADDRESS)
581bb00d0b6SUlrich Weigand     return LLDB_INVALID_INDEX32;
582bb00d0b6SUlrich Weigand 
58397206d57SZachary Turner   Status error = PeekUserArea(offsetof(user_regs_struct, per_info), &per_info,
584b9c1b51eSKate Stone                               sizeof(per_info));
585bb00d0b6SUlrich Weigand   if (error.Fail())
586bb00d0b6SUlrich Weigand     return LLDB_INVALID_INDEX32;
587bb00d0b6SUlrich Weigand 
588bb00d0b6SUlrich Weigand   per_info.control_regs.bits.em_storage_alteration = 1;
589bb00d0b6SUlrich Weigand   per_info.control_regs.bits.storage_alt_space_ctl = 1;
590bb00d0b6SUlrich Weigand   per_info.starting_addr = addr;
591bb00d0b6SUlrich Weigand   per_info.ending_addr = addr + size - 1;
592bb00d0b6SUlrich Weigand 
593b9c1b51eSKate Stone   error = PokeUserArea(offsetof(user_regs_struct, per_info), &per_info,
594b9c1b51eSKate Stone                        sizeof(per_info));
595bb00d0b6SUlrich Weigand   if (error.Fail())
596bb00d0b6SUlrich Weigand     return LLDB_INVALID_INDEX32;
597bb00d0b6SUlrich Weigand 
598bb00d0b6SUlrich Weigand   m_watchpoint_addr = addr;
599bb00d0b6SUlrich Weigand   return 0;
600bb00d0b6SUlrich Weigand }
601bb00d0b6SUlrich Weigand 
602bb00d0b6SUlrich Weigand lldb::addr_t
GetWatchpointAddress(uint32_t wp_index)603b9c1b51eSKate Stone NativeRegisterContextLinux_s390x::GetWatchpointAddress(uint32_t wp_index) {
604bb00d0b6SUlrich Weigand   if (wp_index >= NumSupportedHardwareWatchpoints())
605bb00d0b6SUlrich Weigand     return LLDB_INVALID_ADDRESS;
606bb00d0b6SUlrich Weigand   return m_watchpoint_addr;
607bb00d0b6SUlrich Weigand }
608bb00d0b6SUlrich Weigand 
NumSupportedHardwareWatchpoints()609b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_s390x::NumSupportedHardwareWatchpoints() {
610bb00d0b6SUlrich Weigand   return 1;
611bb00d0b6SUlrich Weigand }
612bb00d0b6SUlrich Weigand 
613bb00d0b6SUlrich Weigand #endif // defined(__s390x__) && defined(__linux__)
614