1bb00d0b6SUlrich Weigand //===-- NativeRegisterContextLinux_s390x.cpp --------------------*- C++ -*-===//
2bb00d0b6SUlrich Weigand //
3bb00d0b6SUlrich Weigand //                     The LLVM Compiler Infrastructure
4bb00d0b6SUlrich Weigand //
5bb00d0b6SUlrich Weigand // This file is distributed under the University of Illinois Open Source
6bb00d0b6SUlrich Weigand // License. See LICENSE.TXT for details.
7bb00d0b6SUlrich Weigand //
8bb00d0b6SUlrich Weigand //===----------------------------------------------------------------------===//
9bb00d0b6SUlrich Weigand 
10bb00d0b6SUlrich Weigand #if defined(__s390x__) && defined(__linux__)
11bb00d0b6SUlrich Weigand 
12bb00d0b6SUlrich Weigand #include "NativeRegisterContextLinux_s390x.h"
13bb00d0b6SUlrich Weigand 
14bb00d0b6SUlrich Weigand #include "lldb/Core/RegisterValue.h"
15bb00d0b6SUlrich Weigand #include "lldb/Host/HostInfo.h"
16*666cc0b2SZachary Turner #include "lldb/Utility/DataBufferHeap.h"
17bf9a7730SZachary Turner #include "lldb/Utility/Error.h"
186f9e6901SZachary Turner #include "lldb/Utility/Log.h"
19bb00d0b6SUlrich Weigand 
20bb00d0b6SUlrich Weigand #include "Plugins/Process/Utility/RegisterContextLinux_s390x.h"
21bb00d0b6SUlrich Weigand 
22bb00d0b6SUlrich Weigand #include <asm/ptrace.h>
23bb00d0b6SUlrich Weigand #include <linux/uio.h>
24bb00d0b6SUlrich Weigand #include <sys/ptrace.h>
25bb00d0b6SUlrich Weigand 
26bb00d0b6SUlrich Weigand using namespace lldb_private;
27bb00d0b6SUlrich Weigand using namespace lldb_private::process_linux;
28bb00d0b6SUlrich Weigand 
29bb00d0b6SUlrich Weigand // ----------------------------------------------------------------------------
30bb00d0b6SUlrich Weigand // Private namespace.
31bb00d0b6SUlrich Weigand // ----------------------------------------------------------------------------
32bb00d0b6SUlrich Weigand 
33b9c1b51eSKate Stone namespace {
34bb00d0b6SUlrich Weigand // s390x 64-bit general purpose registers.
35b9c1b51eSKate Stone static const uint32_t g_gpr_regnums_s390x[] = {
36b9c1b51eSKate Stone     lldb_r0_s390x,      lldb_r1_s390x,    lldb_r2_s390x,    lldb_r3_s390x,
37b9c1b51eSKate Stone     lldb_r4_s390x,      lldb_r5_s390x,    lldb_r6_s390x,    lldb_r7_s390x,
38b9c1b51eSKate Stone     lldb_r8_s390x,      lldb_r9_s390x,    lldb_r10_s390x,   lldb_r11_s390x,
39b9c1b51eSKate Stone     lldb_r12_s390x,     lldb_r13_s390x,   lldb_r14_s390x,   lldb_r15_s390x,
40b9c1b51eSKate Stone     lldb_acr0_s390x,    lldb_acr1_s390x,  lldb_acr2_s390x,  lldb_acr3_s390x,
41b9c1b51eSKate Stone     lldb_acr4_s390x,    lldb_acr5_s390x,  lldb_acr6_s390x,  lldb_acr7_s390x,
42b9c1b51eSKate Stone     lldb_acr8_s390x,    lldb_acr9_s390x,  lldb_acr10_s390x, lldb_acr11_s390x,
43b9c1b51eSKate Stone     lldb_acr12_s390x,   lldb_acr13_s390x, lldb_acr14_s390x, lldb_acr15_s390x,
44b9c1b51eSKate Stone     lldb_pswm_s390x,    lldb_pswa_s390x,
45bb00d0b6SUlrich Weigand     LLDB_INVALID_REGNUM // register sets need to end with this flag
46bb00d0b6SUlrich Weigand };
47b9c1b51eSKate Stone static_assert((sizeof(g_gpr_regnums_s390x) / sizeof(g_gpr_regnums_s390x[0])) -
48b9c1b51eSKate Stone                       1 ==
49b9c1b51eSKate Stone                   k_num_gpr_registers_s390x,
50bb00d0b6SUlrich Weigand               "g_gpr_regnums_s390x has wrong number of register infos");
51bb00d0b6SUlrich Weigand 
52bb00d0b6SUlrich Weigand // s390x 64-bit floating point registers.
53b9c1b51eSKate Stone static const uint32_t g_fpu_regnums_s390x[] = {
54b9c1b51eSKate Stone     lldb_f0_s390x,      lldb_f1_s390x,  lldb_f2_s390x,  lldb_f3_s390x,
55b9c1b51eSKate Stone     lldb_f4_s390x,      lldb_f5_s390x,  lldb_f6_s390x,  lldb_f7_s390x,
56b9c1b51eSKate Stone     lldb_f8_s390x,      lldb_f9_s390x,  lldb_f10_s390x, lldb_f11_s390x,
57b9c1b51eSKate Stone     lldb_f12_s390x,     lldb_f13_s390x, lldb_f14_s390x, lldb_f15_s390x,
58bb00d0b6SUlrich Weigand     lldb_fpc_s390x,
59bb00d0b6SUlrich Weigand     LLDB_INVALID_REGNUM // register sets need to end with this flag
60bb00d0b6SUlrich Weigand };
61b9c1b51eSKate Stone static_assert((sizeof(g_fpu_regnums_s390x) / sizeof(g_fpu_regnums_s390x[0])) -
62b9c1b51eSKate Stone                       1 ==
63b9c1b51eSKate Stone                   k_num_fpr_registers_s390x,
64bb00d0b6SUlrich Weigand               "g_fpu_regnums_s390x has wrong number of register infos");
65bb00d0b6SUlrich Weigand 
66bb00d0b6SUlrich Weigand // s390x Linux operating-system information.
67b9c1b51eSKate Stone static const uint32_t g_linux_regnums_s390x[] = {
68b9c1b51eSKate Stone     lldb_orig_r2_s390x, lldb_last_break_s390x, lldb_system_call_s390x,
69bb00d0b6SUlrich Weigand     LLDB_INVALID_REGNUM // register sets need to end with this flag
70bb00d0b6SUlrich Weigand };
71b9c1b51eSKate Stone static_assert((sizeof(g_linux_regnums_s390x) /
72b9c1b51eSKate Stone                sizeof(g_linux_regnums_s390x[0])) -
73b9c1b51eSKate Stone                       1 ==
74b9c1b51eSKate Stone                   k_num_linux_registers_s390x,
75bb00d0b6SUlrich Weigand               "g_linux_regnums_s390x has wrong number of register infos");
76bb00d0b6SUlrich Weigand 
77bb00d0b6SUlrich Weigand // Number of register sets provided by this context.
78b9c1b51eSKate Stone enum { k_num_register_sets = 3 };
79bb00d0b6SUlrich Weigand 
80bb00d0b6SUlrich Weigand // Register sets for s390x 64-bit.
81b9c1b51eSKate Stone static const RegisterSet g_reg_sets_s390x[k_num_register_sets] = {
82b9c1b51eSKate Stone     {"General Purpose Registers", "gpr", k_num_gpr_registers_s390x,
83b9c1b51eSKate Stone      g_gpr_regnums_s390x},
84b9c1b51eSKate Stone     {"Floating Point Registers", "fpr", k_num_fpr_registers_s390x,
85b9c1b51eSKate Stone      g_fpu_regnums_s390x},
86b9c1b51eSKate Stone     {"Linux Operating System Data", "linux", k_num_linux_registers_s390x,
87b9c1b51eSKate Stone      g_linux_regnums_s390x},
88bb00d0b6SUlrich Weigand };
89bb00d0b6SUlrich Weigand }
90bb00d0b6SUlrich Weigand 
91bb00d0b6SUlrich Weigand #define REG_CONTEXT_SIZE (sizeof(s390_regs) + sizeof(s390_fp_regs) + 4)
92bb00d0b6SUlrich Weigand 
93bb00d0b6SUlrich Weigand // ----------------------------------------------------------------------------
94bb00d0b6SUlrich Weigand // Required ptrace defines.
95bb00d0b6SUlrich Weigand // ----------------------------------------------------------------------------
96bb00d0b6SUlrich Weigand 
97bb00d0b6SUlrich Weigand #define NT_S390_LAST_BREAK 0x306  /* s390 breaking event address */
98bb00d0b6SUlrich Weigand #define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */
99bb00d0b6SUlrich Weigand 
100bb00d0b6SUlrich Weigand NativeRegisterContextLinux *
101b9c1b51eSKate Stone NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(
102b9c1b51eSKate Stone     const ArchSpec &target_arch, NativeThreadProtocol &native_thread,
103b9c1b51eSKate Stone     uint32_t concrete_frame_idx) {
104b9c1b51eSKate Stone   return new NativeRegisterContextLinux_s390x(target_arch, native_thread,
105b9c1b51eSKate Stone                                               concrete_frame_idx);
106bb00d0b6SUlrich Weigand }
107bb00d0b6SUlrich Weigand 
108bb00d0b6SUlrich Weigand // ----------------------------------------------------------------------------
109bb00d0b6SUlrich Weigand // NativeRegisterContextLinux_s390x members.
110bb00d0b6SUlrich Weigand // ----------------------------------------------------------------------------
111bb00d0b6SUlrich Weigand 
112bb00d0b6SUlrich Weigand static RegisterInfoInterface *
113b9c1b51eSKate Stone CreateRegisterInfoInterface(const ArchSpec &target_arch) {
114bb00d0b6SUlrich Weigand   assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) &&
115bb00d0b6SUlrich Weigand          "Register setting path assumes this is a 64-bit host");
116bb00d0b6SUlrich Weigand   return new RegisterContextLinux_s390x(target_arch);
117bb00d0b6SUlrich Weigand }
118bb00d0b6SUlrich Weigand 
119b9c1b51eSKate Stone NativeRegisterContextLinux_s390x::NativeRegisterContextLinux_s390x(
120b9c1b51eSKate Stone     const ArchSpec &target_arch, NativeThreadProtocol &native_thread,
121bb00d0b6SUlrich Weigand     uint32_t concrete_frame_idx)
122b9c1b51eSKate Stone     : NativeRegisterContextLinux(native_thread, concrete_frame_idx,
123b9c1b51eSKate Stone                                  CreateRegisterInfoInterface(target_arch)) {
124bb00d0b6SUlrich Weigand   // Set up data about ranges of valid registers.
125b9c1b51eSKate Stone   switch (target_arch.GetMachine()) {
126bb00d0b6SUlrich Weigand   case llvm::Triple::systemz:
127bb00d0b6SUlrich Weigand     m_reg_info.num_registers = k_num_registers_s390x;
128bb00d0b6SUlrich Weigand     m_reg_info.num_gpr_registers = k_num_gpr_registers_s390x;
129bb00d0b6SUlrich Weigand     m_reg_info.num_fpr_registers = k_num_fpr_registers_s390x;
130bb00d0b6SUlrich Weigand     m_reg_info.last_gpr = k_last_gpr_s390x;
131bb00d0b6SUlrich Weigand     m_reg_info.first_fpr = k_first_fpr_s390x;
132bb00d0b6SUlrich Weigand     m_reg_info.last_fpr = k_last_fpr_s390x;
133bb00d0b6SUlrich Weigand     break;
134bb00d0b6SUlrich Weigand   default:
135bb00d0b6SUlrich Weigand     assert(false && "Unhandled target architecture.");
136bb00d0b6SUlrich Weigand     break;
137bb00d0b6SUlrich Weigand   }
138bb00d0b6SUlrich Weigand 
139bb00d0b6SUlrich Weigand   // Clear out the watchpoint state.
140bb00d0b6SUlrich Weigand   m_watchpoint_addr = LLDB_INVALID_ADDRESS;
141bb00d0b6SUlrich Weigand }
142bb00d0b6SUlrich Weigand 
143b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_s390x::GetRegisterSetCount() const {
144bb00d0b6SUlrich Weigand   uint32_t sets = 0;
145b9c1b51eSKate Stone   for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) {
146bb00d0b6SUlrich Weigand     if (IsRegisterSetAvailable(set_index))
147bb00d0b6SUlrich Weigand       ++sets;
148bb00d0b6SUlrich Weigand   }
149bb00d0b6SUlrich Weigand 
150bb00d0b6SUlrich Weigand   return sets;
151bb00d0b6SUlrich Weigand }
152bb00d0b6SUlrich Weigand 
153b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_s390x::GetUserRegisterCount() const {
154bb00d0b6SUlrich Weigand   uint32_t count = 0;
155b9c1b51eSKate Stone   for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) {
156bb00d0b6SUlrich Weigand     const RegisterSet *set = GetRegisterSet(set_index);
157bb00d0b6SUlrich Weigand     if (set)
158bb00d0b6SUlrich Weigand       count += set->num_registers;
159bb00d0b6SUlrich Weigand   }
160bb00d0b6SUlrich Weigand   return count;
161bb00d0b6SUlrich Weigand }
162bb00d0b6SUlrich Weigand 
163bb00d0b6SUlrich Weigand const RegisterSet *
164b9c1b51eSKate Stone NativeRegisterContextLinux_s390x::GetRegisterSet(uint32_t set_index) const {
165bb00d0b6SUlrich Weigand   if (!IsRegisterSetAvailable(set_index))
166bb00d0b6SUlrich Weigand     return nullptr;
167bb00d0b6SUlrich Weigand 
168b9c1b51eSKate Stone   switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
169bb00d0b6SUlrich Weigand   case llvm::Triple::systemz:
170bb00d0b6SUlrich Weigand     return &g_reg_sets_s390x[set_index];
171bb00d0b6SUlrich Weigand   default:
172bb00d0b6SUlrich Weigand     assert(false && "Unhandled target architecture.");
173bb00d0b6SUlrich Weigand     return nullptr;
174bb00d0b6SUlrich Weigand   }
175bb00d0b6SUlrich Weigand 
176bb00d0b6SUlrich Weigand   return nullptr;
177bb00d0b6SUlrich Weigand }
178bb00d0b6SUlrich Weigand 
179b9c1b51eSKate Stone bool NativeRegisterContextLinux_s390x::IsRegisterSetAvailable(
180b9c1b51eSKate Stone     uint32_t set_index) const {
181bb00d0b6SUlrich Weigand   return set_index < k_num_register_sets;
182bb00d0b6SUlrich Weigand }
183bb00d0b6SUlrich Weigand 
184b9c1b51eSKate Stone bool NativeRegisterContextLinux_s390x::IsGPR(uint32_t reg_index) const {
185b9c1b51eSKate Stone   // GPRs come first.  "orig_r2" counts as GPR since it is part of the GPR
186b9c1b51eSKate Stone   // register area.
187bb00d0b6SUlrich Weigand   return reg_index <= m_reg_info.last_gpr || reg_index == lldb_orig_r2_s390x;
188bb00d0b6SUlrich Weigand }
189bb00d0b6SUlrich Weigand 
190b9c1b51eSKate Stone bool NativeRegisterContextLinux_s390x::IsFPR(uint32_t reg_index) const {
191b9c1b51eSKate Stone   return (m_reg_info.first_fpr <= reg_index &&
192b9c1b51eSKate Stone           reg_index <= m_reg_info.last_fpr);
193bb00d0b6SUlrich Weigand }
194bb00d0b6SUlrich Weigand 
195b9c1b51eSKate Stone Error NativeRegisterContextLinux_s390x::ReadRegister(
196b9c1b51eSKate Stone     const RegisterInfo *reg_info, RegisterValue &reg_value) {
197bb00d0b6SUlrich Weigand   if (!reg_info)
198bb00d0b6SUlrich Weigand     return Error("reg_info NULL");
199bb00d0b6SUlrich Weigand 
200bb00d0b6SUlrich Weigand   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
201bb00d0b6SUlrich Weigand   if (reg == LLDB_INVALID_REGNUM)
202b9c1b51eSKate Stone     return Error("register \"%s\" is an internal-only lldb register, cannot "
203b9c1b51eSKate Stone                  "read directly",
204b9c1b51eSKate Stone                  reg_info->name);
205bb00d0b6SUlrich Weigand 
206b9c1b51eSKate Stone   if (IsGPR(reg)) {
207bb00d0b6SUlrich Weigand     s390_regs regs;
208bb00d0b6SUlrich Weigand     Error error = DoReadGPR(&regs, sizeof(regs));
209bb00d0b6SUlrich Weigand     if (error.Fail())
210bb00d0b6SUlrich Weigand       return error;
211bb00d0b6SUlrich Weigand 
212bb00d0b6SUlrich Weigand     uint8_t *src = (uint8_t *)&regs + reg_info->byte_offset;
213bb00d0b6SUlrich Weigand     assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(regs));
214b9c1b51eSKate Stone     switch (reg_info->byte_size) {
215bb00d0b6SUlrich Weigand     case 4:
216bb00d0b6SUlrich Weigand       reg_value.SetUInt32(*(uint32_t *)src);
217bb00d0b6SUlrich Weigand       break;
218bb00d0b6SUlrich Weigand     case 8:
219bb00d0b6SUlrich Weigand       reg_value.SetUInt64(*(uint64_t *)src);
220bb00d0b6SUlrich Weigand       break;
221bb00d0b6SUlrich Weigand     default:
222bb00d0b6SUlrich Weigand       assert(false && "Unhandled data size.");
223bb00d0b6SUlrich Weigand       return Error("unhandled byte size: %" PRIu32, reg_info->byte_size);
224bb00d0b6SUlrich Weigand     }
225665be50eSMehdi Amini     return Error();
226bb00d0b6SUlrich Weigand   }
227bb00d0b6SUlrich Weigand 
228b9c1b51eSKate Stone   if (IsFPR(reg)) {
229bb00d0b6SUlrich Weigand     s390_fp_regs fp_regs;
230bb00d0b6SUlrich Weigand     Error error = DoReadFPR(&fp_regs, sizeof(fp_regs));
231bb00d0b6SUlrich Weigand     if (error.Fail())
232bb00d0b6SUlrich Weigand       return error;
233bb00d0b6SUlrich Weigand 
234bb00d0b6SUlrich Weigand     // byte_offset is just the offset within FPR, not the whole user area.
235bb00d0b6SUlrich Weigand     uint8_t *src = (uint8_t *)&fp_regs + reg_info->byte_offset;
236bb00d0b6SUlrich Weigand     assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(fp_regs));
237b9c1b51eSKate Stone     switch (reg_info->byte_size) {
238bb00d0b6SUlrich Weigand     case 4:
239bb00d0b6SUlrich Weigand       reg_value.SetUInt32(*(uint32_t *)src);
240bb00d0b6SUlrich Weigand       break;
241bb00d0b6SUlrich Weigand     case 8:
242bb00d0b6SUlrich Weigand       reg_value.SetUInt64(*(uint64_t *)src);
243bb00d0b6SUlrich Weigand       break;
244bb00d0b6SUlrich Weigand     default:
245bb00d0b6SUlrich Weigand       assert(false && "Unhandled data size.");
246bb00d0b6SUlrich Weigand       return Error("unhandled byte size: %" PRIu32, reg_info->byte_size);
247bb00d0b6SUlrich Weigand     }
248665be50eSMehdi Amini     return Error();
249bb00d0b6SUlrich Weigand   }
250bb00d0b6SUlrich Weigand 
251b9c1b51eSKate Stone   if (reg == lldb_last_break_s390x) {
252bb00d0b6SUlrich Weigand     uint64_t last_break;
253bb00d0b6SUlrich Weigand     Error error = DoReadRegisterSet(NT_S390_LAST_BREAK, &last_break, 8);
254bb00d0b6SUlrich Weigand     if (error.Fail())
255bb00d0b6SUlrich Weigand       return error;
256bb00d0b6SUlrich Weigand 
257bb00d0b6SUlrich Weigand     reg_value.SetUInt64(last_break);
258665be50eSMehdi Amini     return Error();
259bb00d0b6SUlrich Weigand   }
260bb00d0b6SUlrich Weigand 
261b9c1b51eSKate Stone   if (reg == lldb_system_call_s390x) {
262bb00d0b6SUlrich Weigand     uint32_t system_call;
263bb00d0b6SUlrich Weigand     Error error = DoReadRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4);
264bb00d0b6SUlrich Weigand     if (error.Fail())
265bb00d0b6SUlrich Weigand       return error;
266bb00d0b6SUlrich Weigand 
267bb00d0b6SUlrich Weigand     reg_value.SetUInt32(system_call);
268665be50eSMehdi Amini     return Error();
269bb00d0b6SUlrich Weigand   }
270bb00d0b6SUlrich Weigand 
271bb00d0b6SUlrich Weigand   return Error("failed - register wasn't recognized");
272bb00d0b6SUlrich Weigand }
273bb00d0b6SUlrich Weigand 
274b9c1b51eSKate Stone Error NativeRegisterContextLinux_s390x::WriteRegister(
275b9c1b51eSKate Stone     const RegisterInfo *reg_info, const RegisterValue &reg_value) {
276bb00d0b6SUlrich Weigand   if (!reg_info)
277bb00d0b6SUlrich Weigand     return Error("reg_info NULL");
278bb00d0b6SUlrich Weigand 
279bb00d0b6SUlrich Weigand   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
280bb00d0b6SUlrich Weigand   if (reg == LLDB_INVALID_REGNUM)
281b9c1b51eSKate Stone     return Error("register \"%s\" is an internal-only lldb register, cannot "
282b9c1b51eSKate Stone                  "write directly",
283b9c1b51eSKate Stone                  reg_info->name);
284bb00d0b6SUlrich Weigand 
285b9c1b51eSKate Stone   if (IsGPR(reg)) {
286bb00d0b6SUlrich Weigand     s390_regs regs;
287bb00d0b6SUlrich Weigand     Error error = DoReadGPR(&regs, sizeof(regs));
288bb00d0b6SUlrich Weigand     if (error.Fail())
289bb00d0b6SUlrich Weigand       return error;
290bb00d0b6SUlrich Weigand 
291bb00d0b6SUlrich Weigand     uint8_t *dst = (uint8_t *)&regs + reg_info->byte_offset;
292bb00d0b6SUlrich Weigand     assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(regs));
293b9c1b51eSKate Stone     switch (reg_info->byte_size) {
294bb00d0b6SUlrich Weigand     case 4:
295bb00d0b6SUlrich Weigand       *(uint32_t *)dst = reg_value.GetAsUInt32();
296bb00d0b6SUlrich Weigand       break;
297bb00d0b6SUlrich Weigand     case 8:
298bb00d0b6SUlrich Weigand       *(uint64_t *)dst = reg_value.GetAsUInt64();
299bb00d0b6SUlrich Weigand       break;
300bb00d0b6SUlrich Weigand     default:
301bb00d0b6SUlrich Weigand       assert(false && "Unhandled data size.");
302bb00d0b6SUlrich Weigand       return Error("unhandled byte size: %" PRIu32, reg_info->byte_size);
303bb00d0b6SUlrich Weigand     }
304bb00d0b6SUlrich Weigand     return DoWriteGPR(&regs, sizeof(regs));
305bb00d0b6SUlrich Weigand   }
306bb00d0b6SUlrich Weigand 
307b9c1b51eSKate Stone   if (IsFPR(reg)) {
308bb00d0b6SUlrich Weigand     s390_fp_regs fp_regs;
309bb00d0b6SUlrich Weigand     Error error = DoReadFPR(&fp_regs, sizeof(fp_regs));
310bb00d0b6SUlrich Weigand     if (error.Fail())
311bb00d0b6SUlrich Weigand       return error;
312bb00d0b6SUlrich Weigand 
313bb00d0b6SUlrich Weigand     // byte_offset is just the offset within fp_regs, not the whole user area.
314bb00d0b6SUlrich Weigand     uint8_t *dst = (uint8_t *)&fp_regs + reg_info->byte_offset;
315bb00d0b6SUlrich Weigand     assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(fp_regs));
316b9c1b51eSKate Stone     switch (reg_info->byte_size) {
317bb00d0b6SUlrich Weigand     case 4:
318bb00d0b6SUlrich Weigand       *(uint32_t *)dst = reg_value.GetAsUInt32();
319bb00d0b6SUlrich Weigand       break;
320bb00d0b6SUlrich Weigand     case 8:
321bb00d0b6SUlrich Weigand       *(uint64_t *)dst = reg_value.GetAsUInt64();
322bb00d0b6SUlrich Weigand       break;
323bb00d0b6SUlrich Weigand     default:
324bb00d0b6SUlrich Weigand       assert(false && "Unhandled data size.");
325bb00d0b6SUlrich Weigand       return Error("unhandled byte size: %" PRIu32, reg_info->byte_size);
326bb00d0b6SUlrich Weigand     }
327bb00d0b6SUlrich Weigand     return DoWriteFPR(&fp_regs, sizeof(fp_regs));
328bb00d0b6SUlrich Weigand   }
329bb00d0b6SUlrich Weigand 
330b9c1b51eSKate Stone   if (reg == lldb_last_break_s390x) {
331bb00d0b6SUlrich Weigand     return Error("The last break address is read-only");
332bb00d0b6SUlrich Weigand   }
333bb00d0b6SUlrich Weigand 
334b9c1b51eSKate Stone   if (reg == lldb_system_call_s390x) {
335bb00d0b6SUlrich Weigand     uint32_t system_call = reg_value.GetAsUInt32();
336bb00d0b6SUlrich Weigand     return DoWriteRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4);
337bb00d0b6SUlrich Weigand   }
338bb00d0b6SUlrich Weigand 
339bb00d0b6SUlrich Weigand   return Error("failed - register wasn't recognized");
340bb00d0b6SUlrich Weigand }
341bb00d0b6SUlrich Weigand 
342b9c1b51eSKate Stone Error NativeRegisterContextLinux_s390x::ReadAllRegisterValues(
343b9c1b51eSKate Stone     lldb::DataBufferSP &data_sp) {
344bb00d0b6SUlrich Weigand   Error error;
345bb00d0b6SUlrich Weigand 
346bb00d0b6SUlrich Weigand   data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
347b9c1b51eSKate Stone   if (!data_sp) {
348b9c1b51eSKate Stone     error.SetErrorStringWithFormat(
349b9c1b51eSKate Stone         "failed to allocate DataBufferHeap instance of size %" PRIu64,
350b9c1b51eSKate Stone         REG_CONTEXT_SIZE);
351bb00d0b6SUlrich Weigand     return error;
352bb00d0b6SUlrich Weigand   }
353bb00d0b6SUlrich Weigand 
354bb00d0b6SUlrich Weigand   uint8_t *dst = data_sp->GetBytes();
355b9c1b51eSKate Stone   if (dst == nullptr) {
356b9c1b51eSKate Stone     error.SetErrorStringWithFormat("DataBufferHeap instance of size %" PRIu64
357b9c1b51eSKate Stone                                    " returned a null pointer",
358bb00d0b6SUlrich Weigand                                    REG_CONTEXT_SIZE);
359bb00d0b6SUlrich Weigand     return error;
360bb00d0b6SUlrich Weigand   }
361bb00d0b6SUlrich Weigand 
362bb00d0b6SUlrich Weigand   error = DoReadGPR(dst, sizeof(s390_regs));
363bb00d0b6SUlrich Weigand   dst += sizeof(s390_regs);
364bb00d0b6SUlrich Weigand   if (error.Fail())
365bb00d0b6SUlrich Weigand     return error;
366bb00d0b6SUlrich Weigand 
367bb00d0b6SUlrich Weigand   error = DoReadFPR(dst, sizeof(s390_fp_regs));
368bb00d0b6SUlrich Weigand   dst += sizeof(s390_fp_regs);
369bb00d0b6SUlrich Weigand   if (error.Fail())
370bb00d0b6SUlrich Weigand     return error;
371bb00d0b6SUlrich Weigand 
372bb00d0b6SUlrich Weigand   // Ignore errors if the regset is unsupported (happens on older kernels).
373bb00d0b6SUlrich Weigand   DoReadRegisterSet(NT_S390_SYSTEM_CALL, dst, 4);
374bb00d0b6SUlrich Weigand   dst += 4;
375bb00d0b6SUlrich Weigand 
376bb00d0b6SUlrich Weigand   // To enable inferior function calls while the process is stopped in
377bb00d0b6SUlrich Weigand   // an interrupted system call, we need to clear the system call flag.
378bb00d0b6SUlrich Weigand   // It will be restored to its original value by WriteAllRegisterValues.
379bb00d0b6SUlrich Weigand   // Again we ignore error if the regset is unsupported.
380bb00d0b6SUlrich Weigand   uint32_t system_call = 0;
381bb00d0b6SUlrich Weigand   DoWriteRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4);
382bb00d0b6SUlrich Weigand 
383bb00d0b6SUlrich Weigand   return error;
384bb00d0b6SUlrich Weigand }
385bb00d0b6SUlrich Weigand 
386b9c1b51eSKate Stone Error NativeRegisterContextLinux_s390x::WriteAllRegisterValues(
387b9c1b51eSKate Stone     const lldb::DataBufferSP &data_sp) {
388bb00d0b6SUlrich Weigand   Error error;
389bb00d0b6SUlrich Weigand 
390b9c1b51eSKate Stone   if (!data_sp) {
391b9c1b51eSKate Stone     error.SetErrorStringWithFormat(
392b9c1b51eSKate Stone         "NativeRegisterContextLinux_s390x::%s invalid data_sp provided",
393b9c1b51eSKate Stone         __FUNCTION__);
394bb00d0b6SUlrich Weigand     return error;
395bb00d0b6SUlrich Weigand   }
396bb00d0b6SUlrich Weigand 
397b9c1b51eSKate Stone   if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
398bb00d0b6SUlrich Weigand     error.SetErrorStringWithFormat(
399b9c1b51eSKate Stone         "NativeRegisterContextLinux_s390x::%s data_sp contained mismatched "
400b9c1b51eSKate Stone         "data size, expected %" PRIu64 ", actual %" PRIu64,
401bb00d0b6SUlrich Weigand         __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
402bb00d0b6SUlrich Weigand     return error;
403bb00d0b6SUlrich Weigand   }
404bb00d0b6SUlrich Weigand 
405bb00d0b6SUlrich Weigand   uint8_t *src = data_sp->GetBytes();
406b9c1b51eSKate Stone   if (src == nullptr) {
407b9c1b51eSKate Stone     error.SetErrorStringWithFormat("NativeRegisterContextLinux_s390x::%s "
408b9c1b51eSKate Stone                                    "DataBuffer::GetBytes() returned a null "
409b9c1b51eSKate Stone                                    "pointer",
410b9c1b51eSKate Stone                                    __FUNCTION__);
411bb00d0b6SUlrich Weigand     return error;
412bb00d0b6SUlrich Weigand   }
413bb00d0b6SUlrich Weigand 
414bb00d0b6SUlrich Weigand   error = DoWriteGPR(src, sizeof(s390_regs));
415bb00d0b6SUlrich Weigand   src += sizeof(s390_regs);
416bb00d0b6SUlrich Weigand   if (error.Fail())
417bb00d0b6SUlrich Weigand     return error;
418bb00d0b6SUlrich Weigand 
419bb00d0b6SUlrich Weigand   error = DoWriteFPR(src, sizeof(s390_fp_regs));
420bb00d0b6SUlrich Weigand   src += sizeof(s390_fp_regs);
421bb00d0b6SUlrich Weigand   if (error.Fail())
422bb00d0b6SUlrich Weigand     return error;
423bb00d0b6SUlrich Weigand 
424bb00d0b6SUlrich Weigand   // Ignore errors if the regset is unsupported (happens on older kernels).
425bb00d0b6SUlrich Weigand   DoWriteRegisterSet(NT_S390_SYSTEM_CALL, src, 4);
426bb00d0b6SUlrich Weigand   src += 4;
427bb00d0b6SUlrich Weigand 
428bb00d0b6SUlrich Weigand   return error;
429bb00d0b6SUlrich Weigand }
430bb00d0b6SUlrich Weigand 
431b9c1b51eSKate Stone Error NativeRegisterContextLinux_s390x::DoReadRegisterValue(
432b9c1b51eSKate Stone     uint32_t offset, const char *reg_name, uint32_t size,
433b9c1b51eSKate Stone     RegisterValue &value) {
434bb00d0b6SUlrich Weigand   return Error("DoReadRegisterValue unsupported");
435bb00d0b6SUlrich Weigand }
436bb00d0b6SUlrich Weigand 
437b9c1b51eSKate Stone Error NativeRegisterContextLinux_s390x::DoWriteRegisterValue(
438b9c1b51eSKate Stone     uint32_t offset, const char *reg_name, const RegisterValue &value) {
439bb00d0b6SUlrich Weigand   return Error("DoWriteRegisterValue unsupported");
440bb00d0b6SUlrich Weigand }
441bb00d0b6SUlrich Weigand 
442b9c1b51eSKate Stone Error NativeRegisterContextLinux_s390x::PeekUserArea(uint32_t offset, void *buf,
443b9c1b51eSKate Stone                                                      size_t buf_size) {
444bb00d0b6SUlrich Weigand   ptrace_area parea;
445bb00d0b6SUlrich Weigand   parea.len = buf_size;
446bb00d0b6SUlrich Weigand   parea.process_addr = (addr_t)buf;
447bb00d0b6SUlrich Weigand   parea.kernel_addr = offset;
448bb00d0b6SUlrich Weigand 
449b9c1b51eSKate Stone   return NativeProcessLinux::PtraceWrapper(PTRACE_PEEKUSR_AREA,
450b9c1b51eSKate Stone                                            m_thread.GetID(), &parea);
451bb00d0b6SUlrich Weigand }
452bb00d0b6SUlrich Weigand 
453b9c1b51eSKate Stone Error NativeRegisterContextLinux_s390x::PokeUserArea(uint32_t offset,
454b9c1b51eSKate Stone                                                      const void *buf,
455b9c1b51eSKate Stone                                                      size_t buf_size) {
456bb00d0b6SUlrich Weigand   ptrace_area parea;
457bb00d0b6SUlrich Weigand   parea.len = buf_size;
458bb00d0b6SUlrich Weigand   parea.process_addr = (addr_t)buf;
459bb00d0b6SUlrich Weigand   parea.kernel_addr = offset;
460bb00d0b6SUlrich Weigand 
461b9c1b51eSKate Stone   return NativeProcessLinux::PtraceWrapper(PTRACE_POKEUSR_AREA,
462b9c1b51eSKate Stone                                            m_thread.GetID(), &parea);
463bb00d0b6SUlrich Weigand }
464bb00d0b6SUlrich Weigand 
465b9c1b51eSKate Stone Error NativeRegisterContextLinux_s390x::DoReadGPR(void *buf, size_t buf_size) {
466bb00d0b6SUlrich Weigand   assert(buf_size == sizeof(s390_regs));
467bb00d0b6SUlrich Weigand   return PeekUserArea(offsetof(user_regs_struct, psw), buf, buf_size);
468bb00d0b6SUlrich Weigand }
469bb00d0b6SUlrich Weigand 
470b9c1b51eSKate Stone Error NativeRegisterContextLinux_s390x::DoWriteGPR(void *buf, size_t buf_size) {
471bb00d0b6SUlrich Weigand   assert(buf_size == sizeof(s390_regs));
472bb00d0b6SUlrich Weigand   return PokeUserArea(offsetof(user_regs_struct, psw), buf, buf_size);
473bb00d0b6SUlrich Weigand }
474bb00d0b6SUlrich Weigand 
475b9c1b51eSKate Stone Error NativeRegisterContextLinux_s390x::DoReadFPR(void *buf, size_t buf_size) {
476bb00d0b6SUlrich Weigand   assert(buf_size == sizeof(s390_fp_regs));
477bb00d0b6SUlrich Weigand   return PeekUserArea(offsetof(user_regs_struct, fp_regs), buf, buf_size);
478bb00d0b6SUlrich Weigand }
479bb00d0b6SUlrich Weigand 
480b9c1b51eSKate Stone Error NativeRegisterContextLinux_s390x::DoWriteFPR(void *buf, size_t buf_size) {
481bb00d0b6SUlrich Weigand   assert(buf_size == sizeof(s390_fp_regs));
482bb00d0b6SUlrich Weigand   return PokeUserArea(offsetof(user_regs_struct, fp_regs), buf, buf_size);
483bb00d0b6SUlrich Weigand }
484bb00d0b6SUlrich Weigand 
485b9c1b51eSKate Stone Error NativeRegisterContextLinux_s390x::DoReadRegisterSet(uint32_t regset,
486b9c1b51eSKate Stone                                                           void *buf,
487b9c1b51eSKate Stone                                                           size_t buf_size) {
488bb00d0b6SUlrich Weigand   struct iovec iov;
489bb00d0b6SUlrich Weigand   iov.iov_base = buf;
490bb00d0b6SUlrich Weigand   iov.iov_len = buf_size;
491bb00d0b6SUlrich Weigand 
492bb00d0b6SUlrich Weigand   return ReadRegisterSet(&iov, buf_size, regset);
493bb00d0b6SUlrich Weigand }
494bb00d0b6SUlrich Weigand 
495b9c1b51eSKate Stone Error NativeRegisterContextLinux_s390x::DoWriteRegisterSet(uint32_t regset,
496b9c1b51eSKate Stone                                                            const void *buf,
497b9c1b51eSKate Stone                                                            size_t buf_size) {
498bb00d0b6SUlrich Weigand   struct iovec iov;
499bb00d0b6SUlrich Weigand   iov.iov_base = const_cast<void *>(buf);
500bb00d0b6SUlrich Weigand   iov.iov_len = buf_size;
501bb00d0b6SUlrich Weigand 
502bb00d0b6SUlrich Weigand   return WriteRegisterSet(&iov, buf_size, regset);
503bb00d0b6SUlrich Weigand }
504bb00d0b6SUlrich Weigand 
505b9c1b51eSKate Stone Error NativeRegisterContextLinux_s390x::IsWatchpointHit(uint32_t wp_index,
506b9c1b51eSKate Stone                                                         bool &is_hit) {
507bb00d0b6SUlrich Weigand   per_lowcore_bits per_lowcore;
508bb00d0b6SUlrich Weigand 
509bb00d0b6SUlrich Weigand   if (wp_index >= NumSupportedHardwareWatchpoints())
510bb00d0b6SUlrich Weigand     return Error("Watchpoint index out of range");
511bb00d0b6SUlrich Weigand 
512b9c1b51eSKate Stone   if (m_watchpoint_addr == LLDB_INVALID_ADDRESS) {
513bb00d0b6SUlrich Weigand     is_hit = false;
514665be50eSMehdi Amini     return Error();
515bb00d0b6SUlrich Weigand   }
516bb00d0b6SUlrich Weigand 
517b9c1b51eSKate Stone   Error error = PeekUserArea(offsetof(user_regs_struct, per_info.lowcore),
518b9c1b51eSKate Stone                              &per_lowcore, sizeof(per_lowcore));
519b9c1b51eSKate Stone   if (error.Fail()) {
520bb00d0b6SUlrich Weigand     is_hit = false;
521bb00d0b6SUlrich Weigand     return error;
522bb00d0b6SUlrich Weigand   }
523bb00d0b6SUlrich Weigand 
524b9c1b51eSKate Stone   is_hit = (per_lowcore.perc_storage_alteration == 1 &&
525b9c1b51eSKate Stone             per_lowcore.perc_store_real_address == 0);
526bb00d0b6SUlrich Weigand 
527b9c1b51eSKate Stone   if (is_hit) {
528bb00d0b6SUlrich Weigand     // Do not report this watchpoint again.
529bb00d0b6SUlrich Weigand     memset(&per_lowcore, 0, sizeof(per_lowcore));
530b9c1b51eSKate Stone     PokeUserArea(offsetof(user_regs_struct, per_info.lowcore), &per_lowcore,
531b9c1b51eSKate Stone                  sizeof(per_lowcore));
532bb00d0b6SUlrich Weigand   }
533bb00d0b6SUlrich Weigand 
534665be50eSMehdi Amini   return Error();
535bb00d0b6SUlrich Weigand }
536bb00d0b6SUlrich Weigand 
537b9c1b51eSKate Stone Error NativeRegisterContextLinux_s390x::GetWatchpointHitIndex(
538b9c1b51eSKate Stone     uint32_t &wp_index, lldb::addr_t trap_addr) {
539bb00d0b6SUlrich Weigand   uint32_t num_hw_wps = NumSupportedHardwareWatchpoints();
540b9c1b51eSKate Stone   for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) {
541bb00d0b6SUlrich Weigand     bool is_hit;
542bb00d0b6SUlrich Weigand     Error error = IsWatchpointHit(wp_index, is_hit);
543b9c1b51eSKate Stone     if (error.Fail()) {
544bb00d0b6SUlrich Weigand       wp_index = LLDB_INVALID_INDEX32;
545bb00d0b6SUlrich Weigand       return error;
546b9c1b51eSKate Stone     } else if (is_hit) {
547bb00d0b6SUlrich Weigand       return error;
548bb00d0b6SUlrich Weigand     }
549bb00d0b6SUlrich Weigand   }
550bb00d0b6SUlrich Weigand   wp_index = LLDB_INVALID_INDEX32;
551665be50eSMehdi Amini   return Error();
552bb00d0b6SUlrich Weigand }
553bb00d0b6SUlrich Weigand 
554b9c1b51eSKate Stone Error NativeRegisterContextLinux_s390x::IsWatchpointVacant(uint32_t wp_index,
555b9c1b51eSKate Stone                                                            bool &is_vacant) {
556bb00d0b6SUlrich Weigand   if (wp_index >= NumSupportedHardwareWatchpoints())
557bb00d0b6SUlrich Weigand     return Error("Watchpoint index out of range");
558bb00d0b6SUlrich Weigand 
559bb00d0b6SUlrich Weigand   is_vacant = m_watchpoint_addr == LLDB_INVALID_ADDRESS;
560bb00d0b6SUlrich Weigand 
561665be50eSMehdi Amini   return Error();
562bb00d0b6SUlrich Weigand }
563bb00d0b6SUlrich Weigand 
564b9c1b51eSKate Stone bool NativeRegisterContextLinux_s390x::ClearHardwareWatchpoint(
565b9c1b51eSKate Stone     uint32_t wp_index) {
566bb00d0b6SUlrich Weigand   per_struct per_info;
567bb00d0b6SUlrich Weigand 
568bb00d0b6SUlrich Weigand   if (wp_index >= NumSupportedHardwareWatchpoints())
569bb00d0b6SUlrich Weigand     return false;
570bb00d0b6SUlrich Weigand 
571b9c1b51eSKate Stone   Error error = PeekUserArea(offsetof(user_regs_struct, per_info), &per_info,
572b9c1b51eSKate Stone                              sizeof(per_info));
573bb00d0b6SUlrich Weigand   if (error.Fail())
574bb00d0b6SUlrich Weigand     return false;
575bb00d0b6SUlrich Weigand 
576bb00d0b6SUlrich Weigand   per_info.control_regs.bits.em_storage_alteration = 0;
577bb00d0b6SUlrich Weigand   per_info.control_regs.bits.storage_alt_space_ctl = 0;
578bb00d0b6SUlrich Weigand   per_info.starting_addr = 0;
579bb00d0b6SUlrich Weigand   per_info.ending_addr = 0;
580bb00d0b6SUlrich Weigand 
581b9c1b51eSKate Stone   error = PokeUserArea(offsetof(user_regs_struct, per_info), &per_info,
582b9c1b51eSKate Stone                        sizeof(per_info));
583bb00d0b6SUlrich Weigand   if (error.Fail())
584bb00d0b6SUlrich Weigand     return false;
585bb00d0b6SUlrich Weigand 
586bb00d0b6SUlrich Weigand   m_watchpoint_addr = LLDB_INVALID_ADDRESS;
587bb00d0b6SUlrich Weigand   return true;
588bb00d0b6SUlrich Weigand }
589bb00d0b6SUlrich Weigand 
590b9c1b51eSKate Stone Error NativeRegisterContextLinux_s390x::ClearAllHardwareWatchpoints() {
591bb00d0b6SUlrich Weigand   if (ClearHardwareWatchpoint(0))
592665be50eSMehdi Amini     return Error();
593bb00d0b6SUlrich Weigand   return Error("Clearing all hardware watchpoints failed.");
594bb00d0b6SUlrich Weigand }
595bb00d0b6SUlrich Weigand 
596b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_s390x::SetHardwareWatchpoint(
597b9c1b51eSKate Stone     lldb::addr_t addr, size_t size, uint32_t watch_flags) {
598bb00d0b6SUlrich Weigand   per_struct per_info;
599bb00d0b6SUlrich Weigand 
600bb00d0b6SUlrich Weigand   if (watch_flags != 0x1)
601bb00d0b6SUlrich Weigand     return LLDB_INVALID_INDEX32;
602bb00d0b6SUlrich Weigand 
603bb00d0b6SUlrich Weigand   if (m_watchpoint_addr != LLDB_INVALID_ADDRESS)
604bb00d0b6SUlrich Weigand     return LLDB_INVALID_INDEX32;
605bb00d0b6SUlrich Weigand 
606b9c1b51eSKate Stone   Error error = PeekUserArea(offsetof(user_regs_struct, per_info), &per_info,
607b9c1b51eSKate Stone                              sizeof(per_info));
608bb00d0b6SUlrich Weigand   if (error.Fail())
609bb00d0b6SUlrich Weigand     return LLDB_INVALID_INDEX32;
610bb00d0b6SUlrich Weigand 
611bb00d0b6SUlrich Weigand   per_info.control_regs.bits.em_storage_alteration = 1;
612bb00d0b6SUlrich Weigand   per_info.control_regs.bits.storage_alt_space_ctl = 1;
613bb00d0b6SUlrich Weigand   per_info.starting_addr = addr;
614bb00d0b6SUlrich Weigand   per_info.ending_addr = addr + size - 1;
615bb00d0b6SUlrich Weigand 
616b9c1b51eSKate Stone   error = PokeUserArea(offsetof(user_regs_struct, per_info), &per_info,
617b9c1b51eSKate Stone                        sizeof(per_info));
618bb00d0b6SUlrich Weigand   if (error.Fail())
619bb00d0b6SUlrich Weigand     return LLDB_INVALID_INDEX32;
620bb00d0b6SUlrich Weigand 
621bb00d0b6SUlrich Weigand   m_watchpoint_addr = addr;
622bb00d0b6SUlrich Weigand   return 0;
623bb00d0b6SUlrich Weigand }
624bb00d0b6SUlrich Weigand 
625bb00d0b6SUlrich Weigand lldb::addr_t
626b9c1b51eSKate Stone NativeRegisterContextLinux_s390x::GetWatchpointAddress(uint32_t wp_index) {
627bb00d0b6SUlrich Weigand   if (wp_index >= NumSupportedHardwareWatchpoints())
628bb00d0b6SUlrich Weigand     return LLDB_INVALID_ADDRESS;
629bb00d0b6SUlrich Weigand   return m_watchpoint_addr;
630bb00d0b6SUlrich Weigand }
631bb00d0b6SUlrich Weigand 
632b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_s390x::NumSupportedHardwareWatchpoints() {
633bb00d0b6SUlrich Weigand   return 1;
634bb00d0b6SUlrich Weigand }
635bb00d0b6SUlrich Weigand 
636bb00d0b6SUlrich Weigand #endif // defined(__s390x__) && defined(__linux__)
637