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