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