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,
GetGPRBuffer()83      g_linux_regnums_s390x},
84 };
GetFPRBuffer()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, NativeThreadLinux &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     : NativeRegisterContextRegisterInfo(
113           native_thread, CreateRegisterInfoInterface(target_arch)),
114       NativeRegisterContextLinux(native_thread) {
115   // Set up data about ranges of valid registers.
116   switch (target_arch.GetMachine()) {
117   case llvm::Triple::systemz:
118     m_reg_info.num_registers = k_num_registers_s390x;
119     m_reg_info.num_gpr_registers = k_num_gpr_registers_s390x;
120     m_reg_info.num_fpr_registers = k_num_fpr_registers_s390x;
121     m_reg_info.last_gpr = k_last_gpr_s390x;
122     m_reg_info.first_fpr = k_first_fpr_s390x;
123     m_reg_info.last_fpr = k_last_fpr_s390x;
124     break;
125   default:
126     assert(false && "Unhandled target architecture.");
127     break;
128   }
129 
130   // Clear out the watchpoint state.
131   m_watchpoint_addr = LLDB_INVALID_ADDRESS;
132 }
133 
134 uint32_t NativeRegisterContextLinux_s390x::GetRegisterSetCount() const {
135   uint32_t sets = 0;
136   for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) {
137     if (IsRegisterSetAvailable(set_index))
138       ++sets;
139   }
140 
141   return sets;
142 }
143 
144 uint32_t NativeRegisterContextLinux_s390x::GetUserRegisterCount() const {
145   uint32_t count = 0;
146   for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) {
147     const RegisterSet *set = GetRegisterSet(set_index);
148     if (set)
149       count += set->num_registers;
150   }
151   return count;
152 }
153 
154 const RegisterSet *
155 NativeRegisterContextLinux_s390x::GetRegisterSet(uint32_t set_index) const {
156   if (!IsRegisterSetAvailable(set_index))
157     return nullptr;
158 
159   switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
160   case llvm::Triple::systemz:
161     return &g_reg_sets_s390x[set_index];
162   default:
163     assert(false && "Unhandled target architecture.");
164     return nullptr;
165   }
166 
167   return nullptr;
168 }
169 
170 bool NativeRegisterContextLinux_s390x::IsRegisterSetAvailable(
171     uint32_t set_index) const {
172   return set_index < k_num_register_sets;
173 }
174 
175 bool NativeRegisterContextLinux_s390x::IsGPR(uint32_t reg_index) const {
176   // GPRs come first.  "orig_r2" counts as GPR since it is part of the GPR
177   // register area.
178   return reg_index <= m_reg_info.last_gpr || reg_index == lldb_orig_r2_s390x;
179 }
180 
181 bool NativeRegisterContextLinux_s390x::IsFPR(uint32_t reg_index) const {
182   return (m_reg_info.first_fpr <= reg_index &&
183           reg_index <= m_reg_info.last_fpr);
184 }
185 
186 Status
187 NativeRegisterContextLinux_s390x::ReadRegister(const RegisterInfo *reg_info,
188                                                RegisterValue &reg_value) {
189   if (!reg_info)
190     return Status("reg_info NULL");
191 
192   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
193   if (reg == LLDB_INVALID_REGNUM)
194     return Status("register \"%s\" is an internal-only lldb register, cannot "
195                   "read directly",
196                   reg_info->name);
197 
198   if (IsGPR(reg)) {
199     Status error = ReadGPR();
200     if (error.Fail())
201       return error;
202 
203     uint8_t *src = (uint8_t *)&m_regs + reg_info->byte_offset;
204     assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(m_regs));
205     switch (reg_info->byte_size) {
206     case 4:
207       reg_value.SetUInt32(*(uint32_t *)src);
208       break;
209     case 8:
210       reg_value.SetUInt64(*(uint64_t *)src);
211       break;
212     default:
213       assert(false && "Unhandled data size.");
214       return Status("unhandled byte size: %" PRIu32, reg_info->byte_size);
215     }
216     return Status();
217   }
218 
219   if (IsFPR(reg)) {
220     Status error = ReadFPR();
221     if (error.Fail())
222       return error;
223 
224     // byte_offset is just the offset within FPR, not the whole user area.
225     uint8_t *src = (uint8_t *)&m_fp_regs + reg_info->byte_offset;
226     assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(m_fp_regs));
227     switch (reg_info->byte_size) {
228     case 4:
229       reg_value.SetUInt32(*(uint32_t *)src);
230       break;
231     case 8:
232       reg_value.SetUInt64(*(uint64_t *)src);
233       break;
234     default:
235       assert(false && "Unhandled data size.");
236       return Status("unhandled byte size: %" PRIu32, reg_info->byte_size);
237     }
238     return Status();
239   }
240 
241   if (reg == lldb_last_break_s390x) {
242     uint64_t last_break;
243     Status error = DoReadRegisterSet(NT_S390_LAST_BREAK, &last_break, 8);
244     if (error.Fail())
245       return error;
246 
247     reg_value.SetUInt64(last_break);
248     return Status();
249   }
250 
251   if (reg == lldb_system_call_s390x) {
252     uint32_t system_call;
253     Status error = DoReadRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4);
254     if (error.Fail())
255       return error;
256 
257     reg_value.SetUInt32(system_call);
258     return Status();
259   }
260 
261   return Status("failed - register wasn't recognized");
262 }
263 
264 Status NativeRegisterContextLinux_s390x::WriteRegister(
265     const RegisterInfo *reg_info, const RegisterValue &reg_value) {
266   if (!reg_info)
267     return Status("reg_info NULL");
268 
269   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
270   if (reg == LLDB_INVALID_REGNUM)
271     return Status("register \"%s\" is an internal-only lldb register, cannot "
272                   "write directly",
273                   reg_info->name);
274 
275   if (IsGPR(reg)) {
276     Status error = ReadGPR();
277     if (error.Fail())
278       return error;
279 
280     uint8_t *dst = (uint8_t *)&m_regs + reg_info->byte_offset;
281     assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(m_regs));
282     switch (reg_info->byte_size) {
283     case 4:
284       *(uint32_t *)dst = reg_value.GetAsUInt32();
285       break;
286     case 8:
287       *(uint64_t *)dst = reg_value.GetAsUInt64();
288       break;
289     default:
290       assert(false && "Unhandled data size.");
291       return Status("unhandled byte size: %" PRIu32, reg_info->byte_size);
292     }
293     return WriteGPR();
294   }
295 
296   if (IsFPR(reg)) {
297     Status error = ReadFPR();
298     if (error.Fail())
299       return error;
300 
301     // byte_offset is just the offset within fp_regs, not the whole user area.
302     uint8_t *dst = (uint8_t *)&m_fp_regs + reg_info->byte_offset;
303     assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(m_fp_regs));
304     switch (reg_info->byte_size) {
305     case 4:
306       *(uint32_t *)dst = reg_value.GetAsUInt32();
307       break;
308     case 8:
309       *(uint64_t *)dst = reg_value.GetAsUInt64();
310       break;
311     default:
312       assert(false && "Unhandled data size.");
313       return Status("unhandled byte size: %" PRIu32, reg_info->byte_size);
314     }
315     return WriteFPR();
316   }
317 
318   if (reg == lldb_last_break_s390x) {
319     return Status("The last break address is read-only");
320   }
321 
322   if (reg == lldb_system_call_s390x) {
323     uint32_t system_call = reg_value.GetAsUInt32();
324     return DoWriteRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4);
325   }
326 
327   return Status("failed - register wasn't recognized");
328 }
329 
330 Status NativeRegisterContextLinux_s390x::ReadAllRegisterValues(
331     lldb::DataBufferSP &data_sp) {
332   Status error;
333 
334   data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
335   uint8_t *dst = data_sp->GetBytes();
336   error = ReadGPR();
337   if (error.Fail())
338     return error;
339   memcpy(dst, GetGPRBuffer(), GetGPRSize());
340   dst += GetGPRSize();
341 
342   error = ReadFPR();
343   if (error.Fail())
344     return error;
345   memcpy(dst, GetFPRBuffer(), GetFPRSize());
346   dst += GetFPRSize();
347 
348   // Ignore errors if the regset is unsupported (happens on older kernels).
349   DoReadRegisterSet(NT_S390_SYSTEM_CALL, dst, 4);
350   dst += 4;
351 
352   // To enable inferior function calls while the process is stopped in an
353   // interrupted system call, we need to clear the system call flag. It will be
354   // restored to its original value by WriteAllRegisterValues. Again we ignore
355   // error if the regset is unsupported.
356   uint32_t system_call = 0;
357   DoWriteRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4);
358 
359   return error;
360 }
361 
362 Status NativeRegisterContextLinux_s390x::WriteAllRegisterValues(
363     const lldb::DataBufferSP &data_sp) {
364   Status error;
365 
366   if (!data_sp) {
367     error.SetErrorStringWithFormat(
368         "NativeRegisterContextLinux_s390x::%s invalid data_sp provided",
369         __FUNCTION__);
370     return error;
371   }
372 
373   if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
374     error.SetErrorStringWithFormat(
375         "NativeRegisterContextLinux_s390x::%s data_sp contained mismatched "
376         "data size, expected %" PRIu64 ", actual %" PRIu64,
377         __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
378     return error;
379   }
380 
381   const uint8_t *src = data_sp->GetBytes();
382   if (src == nullptr) {
383     error.SetErrorStringWithFormat("NativeRegisterContextLinux_s390x::%s "
384                                    "DataBuffer::GetBytes() returned a null "
385                                    "pointer",
386                                    __FUNCTION__);
387     return error;
388   }
389 
390   memcpy(GetGPRBuffer(), src, GetGPRSize());
391   src += GetGPRSize();
392   error = WriteGPR();
393   if (error.Fail())
394     return error;
395 
396   memcpy(GetFPRBuffer(), src, GetFPRSize());
397   src += GetFPRSize();
398   error = WriteFPR();
399   if (error.Fail())
400     return error;
401 
402   // Ignore errors if the regset is unsupported (happens on older kernels).
403   DoWriteRegisterSet(NT_S390_SYSTEM_CALL, src, 4);
404   src += 4;
405 
406   return error;
407 }
408 
409 Status NativeRegisterContextLinux_s390x::DoReadRegisterValue(
410     uint32_t offset, const char *reg_name, uint32_t size,
411     RegisterValue &value) {
412   return Status("DoReadRegisterValue unsupported");
413 }
414 
415 Status NativeRegisterContextLinux_s390x::DoWriteRegisterValue(
416     uint32_t offset, const char *reg_name, const RegisterValue &value) {
417   return Status("DoWriteRegisterValue unsupported");
418 }
419 
420 Status NativeRegisterContextLinux_s390x::PeekUserArea(uint32_t offset,
421                                                       void *buf,
422                                                       size_t buf_size) {
423   ptrace_area parea;
424   parea.len = buf_size;
425   parea.process_addr = (addr_t)buf;
426   parea.kernel_addr = offset;
427 
428   return NativeProcessLinux::PtraceWrapper(PTRACE_PEEKUSR_AREA,
429                                            m_thread.GetID(), &parea);
430 }
431 
432 Status NativeRegisterContextLinux_s390x::PokeUserArea(uint32_t offset,
433                                                       const void *buf,
434                                                       size_t buf_size) {
435   ptrace_area parea;
436   parea.len = buf_size;
437   parea.process_addr = (addr_t)buf;
438   parea.kernel_addr = offset;
439 
440   return NativeProcessLinux::PtraceWrapper(PTRACE_POKEUSR_AREA,
441                                            m_thread.GetID(), &parea);
442 }
443 
444 Status NativeRegisterContextLinux_s390x::ReadGPR() {
445   return PeekUserArea(offsetof(user_regs_struct, psw), GetGPRBuffer(),
446                       GetGPRSize());
447 }
448 
449 Status NativeRegisterContextLinux_s390x::WriteGPR() {
450   return PokeUserArea(offsetof(user_regs_struct, psw), GetGPRBuffer(),
451                       GetGPRSize());
452 }
453 
454 Status NativeRegisterContextLinux_s390x::ReadFPR() {
455   return PeekUserArea(offsetof(user_regs_struct, fp_regs), GetGPRBuffer(),
456                       GetGPRSize());
457 }
458 
459 Status NativeRegisterContextLinux_s390x::WriteFPR() {
460   return PokeUserArea(offsetof(user_regs_struct, fp_regs), GetGPRBuffer(),
461                       GetGPRSize());
462 }
463 
464 Status NativeRegisterContextLinux_s390x::DoReadRegisterSet(uint32_t regset,
465                                                            void *buf,
466                                                            size_t buf_size) {
467   struct iovec iov;
468   iov.iov_base = buf;
469   iov.iov_len = buf_size;
470 
471   return ReadRegisterSet(&iov, buf_size, regset);
472 }
473 
474 Status NativeRegisterContextLinux_s390x::DoWriteRegisterSet(uint32_t regset,
475                                                             const void *buf,
476                                                             size_t buf_size) {
477   struct iovec iov;
478   iov.iov_base = const_cast<void *>(buf);
479   iov.iov_len = buf_size;
480 
481   return WriteRegisterSet(&iov, buf_size, regset);
482 }
483 
484 Status NativeRegisterContextLinux_s390x::IsWatchpointHit(uint32_t wp_index,
485                                                          bool &is_hit) {
486   per_lowcore_bits per_lowcore;
487 
488   if (wp_index >= NumSupportedHardwareWatchpoints())
489     return Status("Watchpoint index out of range");
490 
491   if (m_watchpoint_addr == LLDB_INVALID_ADDRESS) {
492     is_hit = false;
493     return Status();
494   }
495 
496   Status error = PeekUserArea(offsetof(user_regs_struct, per_info.lowcore),
497                               &per_lowcore, sizeof(per_lowcore));
498   if (error.Fail()) {
499     is_hit = false;
500     return error;
501   }
502 
503   is_hit = (per_lowcore.perc_storage_alteration == 1 &&
504             per_lowcore.perc_store_real_address == 0);
505 
506   if (is_hit) {
507     // Do not report this watchpoint again.
508     memset(&per_lowcore, 0, sizeof(per_lowcore));
509     PokeUserArea(offsetof(user_regs_struct, per_info.lowcore), &per_lowcore,
510                  sizeof(per_lowcore));
511   }
512 
513   return Status();
514 }
515 
516 Status NativeRegisterContextLinux_s390x::GetWatchpointHitIndex(
517     uint32_t &wp_index, lldb::addr_t trap_addr) {
518   uint32_t num_hw_wps = NumSupportedHardwareWatchpoints();
519   for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) {
520     bool is_hit;
521     Status error = IsWatchpointHit(wp_index, is_hit);
522     if (error.Fail()) {
523       wp_index = LLDB_INVALID_INDEX32;
524       return error;
525     } else if (is_hit) {
526       return error;
527     }
528   }
529   wp_index = LLDB_INVALID_INDEX32;
530   return Status();
531 }
532 
533 Status NativeRegisterContextLinux_s390x::IsWatchpointVacant(uint32_t wp_index,
534                                                             bool &is_vacant) {
535   if (wp_index >= NumSupportedHardwareWatchpoints())
536     return Status("Watchpoint index out of range");
537 
538   is_vacant = m_watchpoint_addr == LLDB_INVALID_ADDRESS;
539 
540   return Status();
541 }
542 
543 bool NativeRegisterContextLinux_s390x::ClearHardwareWatchpoint(
544     uint32_t wp_index) {
545   per_struct per_info;
546 
547   if (wp_index >= NumSupportedHardwareWatchpoints())
548     return false;
549 
550   Status error = PeekUserArea(offsetof(user_regs_struct, per_info), &per_info,
551                               sizeof(per_info));
552   if (error.Fail())
553     return false;
554 
555   per_info.control_regs.bits.em_storage_alteration = 0;
556   per_info.control_regs.bits.storage_alt_space_ctl = 0;
557   per_info.starting_addr = 0;
558   per_info.ending_addr = 0;
559 
560   error = PokeUserArea(offsetof(user_regs_struct, per_info), &per_info,
561                        sizeof(per_info));
562   if (error.Fail())
563     return false;
564 
565   m_watchpoint_addr = LLDB_INVALID_ADDRESS;
566   return true;
567 }
568 
569 Status NativeRegisterContextLinux_s390x::ClearAllHardwareWatchpoints() {
570   if (ClearHardwareWatchpoint(0))
571     return Status();
572   return Status("Clearing all hardware watchpoints failed.");
573 }
574 
575 uint32_t NativeRegisterContextLinux_s390x::SetHardwareWatchpoint(
576     lldb::addr_t addr, size_t size, uint32_t watch_flags) {
577   per_struct per_info;
578 
579   if (watch_flags != 0x1)
580     return LLDB_INVALID_INDEX32;
581 
582   if (m_watchpoint_addr != LLDB_INVALID_ADDRESS)
583     return LLDB_INVALID_INDEX32;
584 
585   Status error = PeekUserArea(offsetof(user_regs_struct, per_info), &per_info,
586                               sizeof(per_info));
587   if (error.Fail())
588     return LLDB_INVALID_INDEX32;
589 
590   per_info.control_regs.bits.em_storage_alteration = 1;
591   per_info.control_regs.bits.storage_alt_space_ctl = 1;
592   per_info.starting_addr = addr;
593   per_info.ending_addr = addr + size - 1;
594 
595   error = PokeUserArea(offsetof(user_regs_struct, per_info), &per_info,
596                        sizeof(per_info));
597   if (error.Fail())
598     return LLDB_INVALID_INDEX32;
599 
600   m_watchpoint_addr = addr;
601   return 0;
602 }
603 
604 lldb::addr_t
605 NativeRegisterContextLinux_s390x::GetWatchpointAddress(uint32_t wp_index) {
606   if (wp_index >= NumSupportedHardwareWatchpoints())
607     return LLDB_INVALID_ADDRESS;
608   return m_watchpoint_addr;
609 }
610 
611 uint32_t NativeRegisterContextLinux_s390x::NumSupportedHardwareWatchpoints() {
612   return 1;
613 }
614 
615 #endif // defined(__s390x__) && defined(__linux__)
616