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