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