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