1 //===-- NativeRegisterContextLinux_s390x.cpp --------------------*- C++ -*-===// 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 <asm/ptrace.h> 22 #include <linux/uio.h> 23 #include <sys/ptrace.h> 24 25 using namespace lldb_private; 26 using namespace lldb_private::process_linux; 27 28 // Private namespace. 29 30 namespace { 31 // s390x 64-bit general purpose registers. 32 static const uint32_t g_gpr_regnums_s390x[] = { 33 lldb_r0_s390x, lldb_r1_s390x, lldb_r2_s390x, lldb_r3_s390x, 34 lldb_r4_s390x, lldb_r5_s390x, lldb_r6_s390x, lldb_r7_s390x, 35 lldb_r8_s390x, lldb_r9_s390x, lldb_r10_s390x, lldb_r11_s390x, 36 lldb_r12_s390x, lldb_r13_s390x, lldb_r14_s390x, lldb_r15_s390x, 37 lldb_acr0_s390x, lldb_acr1_s390x, lldb_acr2_s390x, lldb_acr3_s390x, 38 lldb_acr4_s390x, lldb_acr5_s390x, lldb_acr6_s390x, lldb_acr7_s390x, 39 lldb_acr8_s390x, lldb_acr9_s390x, lldb_acr10_s390x, lldb_acr11_s390x, 40 lldb_acr12_s390x, lldb_acr13_s390x, lldb_acr14_s390x, lldb_acr15_s390x, 41 lldb_pswm_s390x, lldb_pswa_s390x, 42 LLDB_INVALID_REGNUM // register sets need to end with this flag 43 }; 44 static_assert((sizeof(g_gpr_regnums_s390x) / sizeof(g_gpr_regnums_s390x[0])) - 45 1 == 46 k_num_gpr_registers_s390x, 47 "g_gpr_regnums_s390x has wrong number of register infos"); 48 49 // s390x 64-bit floating point registers. 50 static const uint32_t g_fpu_regnums_s390x[] = { 51 lldb_f0_s390x, lldb_f1_s390x, lldb_f2_s390x, lldb_f3_s390x, 52 lldb_f4_s390x, lldb_f5_s390x, lldb_f6_s390x, lldb_f7_s390x, 53 lldb_f8_s390x, lldb_f9_s390x, lldb_f10_s390x, lldb_f11_s390x, 54 lldb_f12_s390x, lldb_f13_s390x, lldb_f14_s390x, lldb_f15_s390x, 55 lldb_fpc_s390x, 56 LLDB_INVALID_REGNUM // register sets need to end with this flag 57 }; 58 static_assert((sizeof(g_fpu_regnums_s390x) / sizeof(g_fpu_regnums_s390x[0])) - 59 1 == 60 k_num_fpr_registers_s390x, 61 "g_fpu_regnums_s390x has wrong number of register infos"); 62 63 // s390x Linux operating-system information. 64 static const uint32_t g_linux_regnums_s390x[] = { 65 lldb_orig_r2_s390x, lldb_last_break_s390x, lldb_system_call_s390x, 66 LLDB_INVALID_REGNUM // register sets need to end with this flag 67 }; 68 static_assert((sizeof(g_linux_regnums_s390x) / 69 sizeof(g_linux_regnums_s390x[0])) - 70 1 == 71 k_num_linux_registers_s390x, 72 "g_linux_regnums_s390x has wrong number of register infos"); 73 74 // Number of register sets provided by this context. 75 enum { k_num_register_sets = 3 }; 76 77 // Register sets for s390x 64-bit. 78 static const RegisterSet g_reg_sets_s390x[k_num_register_sets] = { 79 {"General Purpose Registers", "gpr", k_num_gpr_registers_s390x, 80 g_gpr_regnums_s390x}, 81 {"Floating Point Registers", "fpr", k_num_fpr_registers_s390x, 82 g_fpu_regnums_s390x}, 83 {"Linux Operating System Data", "linux", k_num_linux_registers_s390x, 84 g_linux_regnums_s390x}, 85 }; 86 } 87 88 #define REG_CONTEXT_SIZE (sizeof(s390_regs) + sizeof(s390_fp_regs) + 4) 89 90 // Required ptrace defines. 91 92 #define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */ 93 #define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */ 94 95 std::unique_ptr<NativeRegisterContextLinux> 96 NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( 97 const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { 98 return llvm::make_unique<NativeRegisterContextLinux_s390x>(target_arch, 99 native_thread); 100 } 101 102 // NativeRegisterContextLinux_s390x members. 103 104 static RegisterInfoInterface * 105 CreateRegisterInfoInterface(const ArchSpec &target_arch) { 106 assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && 107 "Register setting path assumes this is a 64-bit host"); 108 return new RegisterContextLinux_s390x(target_arch); 109 } 110 111 NativeRegisterContextLinux_s390x::NativeRegisterContextLinux_s390x( 112 const ArchSpec &target_arch, NativeThreadProtocol &native_thread) 113 : NativeRegisterContextLinux(native_thread, 114 CreateRegisterInfoInterface(target_arch)) { 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 ®_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 s390_regs regs; 200 Status error = DoReadGPR(®s, sizeof(regs)); 201 if (error.Fail()) 202 return error; 203 204 uint8_t *src = (uint8_t *)®s + reg_info->byte_offset; 205 assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(regs)); 206 switch (reg_info->byte_size) { 207 case 4: 208 reg_value.SetUInt32(*(uint32_t *)src); 209 break; 210 case 8: 211 reg_value.SetUInt64(*(uint64_t *)src); 212 break; 213 default: 214 assert(false && "Unhandled data size."); 215 return Status("unhandled byte size: %" PRIu32, reg_info->byte_size); 216 } 217 return Status(); 218 } 219 220 if (IsFPR(reg)) { 221 s390_fp_regs fp_regs; 222 Status error = DoReadFPR(&fp_regs, sizeof(fp_regs)); 223 if (error.Fail()) 224 return error; 225 226 // byte_offset is just the offset within FPR, not the whole user area. 227 uint8_t *src = (uint8_t *)&fp_regs + reg_info->byte_offset; 228 assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(fp_regs)); 229 switch (reg_info->byte_size) { 230 case 4: 231 reg_value.SetUInt32(*(uint32_t *)src); 232 break; 233 case 8: 234 reg_value.SetUInt64(*(uint64_t *)src); 235 break; 236 default: 237 assert(false && "Unhandled data size."); 238 return Status("unhandled byte size: %" PRIu32, reg_info->byte_size); 239 } 240 return Status(); 241 } 242 243 if (reg == lldb_last_break_s390x) { 244 uint64_t last_break; 245 Status error = DoReadRegisterSet(NT_S390_LAST_BREAK, &last_break, 8); 246 if (error.Fail()) 247 return error; 248 249 reg_value.SetUInt64(last_break); 250 return Status(); 251 } 252 253 if (reg == lldb_system_call_s390x) { 254 uint32_t system_call; 255 Status error = DoReadRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4); 256 if (error.Fail()) 257 return error; 258 259 reg_value.SetUInt32(system_call); 260 return Status(); 261 } 262 263 return Status("failed - register wasn't recognized"); 264 } 265 266 Status NativeRegisterContextLinux_s390x::WriteRegister( 267 const RegisterInfo *reg_info, const RegisterValue ®_value) { 268 if (!reg_info) 269 return Status("reg_info NULL"); 270 271 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 272 if (reg == LLDB_INVALID_REGNUM) 273 return Status("register \"%s\" is an internal-only lldb register, cannot " 274 "write directly", 275 reg_info->name); 276 277 if (IsGPR(reg)) { 278 s390_regs regs; 279 Status error = DoReadGPR(®s, sizeof(regs)); 280 if (error.Fail()) 281 return error; 282 283 uint8_t *dst = (uint8_t *)®s + reg_info->byte_offset; 284 assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(regs)); 285 switch (reg_info->byte_size) { 286 case 4: 287 *(uint32_t *)dst = reg_value.GetAsUInt32(); 288 break; 289 case 8: 290 *(uint64_t *)dst = reg_value.GetAsUInt64(); 291 break; 292 default: 293 assert(false && "Unhandled data size."); 294 return Status("unhandled byte size: %" PRIu32, reg_info->byte_size); 295 } 296 return DoWriteGPR(®s, sizeof(regs)); 297 } 298 299 if (IsFPR(reg)) { 300 s390_fp_regs fp_regs; 301 Status error = DoReadFPR(&fp_regs, sizeof(fp_regs)); 302 if (error.Fail()) 303 return error; 304 305 // byte_offset is just the offset within fp_regs, not the whole user area. 306 uint8_t *dst = (uint8_t *)&fp_regs + reg_info->byte_offset; 307 assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(fp_regs)); 308 switch (reg_info->byte_size) { 309 case 4: 310 *(uint32_t *)dst = reg_value.GetAsUInt32(); 311 break; 312 case 8: 313 *(uint64_t *)dst = reg_value.GetAsUInt64(); 314 break; 315 default: 316 assert(false && "Unhandled data size."); 317 return Status("unhandled byte size: %" PRIu32, reg_info->byte_size); 318 } 319 return DoWriteFPR(&fp_regs, sizeof(fp_regs)); 320 } 321 322 if (reg == lldb_last_break_s390x) { 323 return Status("The last break address is read-only"); 324 } 325 326 if (reg == lldb_system_call_s390x) { 327 uint32_t system_call = reg_value.GetAsUInt32(); 328 return DoWriteRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4); 329 } 330 331 return Status("failed - register wasn't recognized"); 332 } 333 334 Status NativeRegisterContextLinux_s390x::ReadAllRegisterValues( 335 lldb::DataBufferSP &data_sp) { 336 Status error; 337 338 data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); 339 uint8_t *dst = data_sp->GetBytes(); 340 error = DoReadGPR(dst, sizeof(s390_regs)); 341 dst += sizeof(s390_regs); 342 if (error.Fail()) 343 return error; 344 345 error = DoReadFPR(dst, sizeof(s390_fp_regs)); 346 dst += sizeof(s390_fp_regs); 347 if (error.Fail()) 348 return error; 349 350 // Ignore errors if the regset is unsupported (happens on older kernels). 351 DoReadRegisterSet(NT_S390_SYSTEM_CALL, dst, 4); 352 dst += 4; 353 354 // To enable inferior function calls while the process is stopped in an 355 // interrupted system call, we need to clear the system call flag. It will be 356 // restored to its original value by WriteAllRegisterValues. Again we ignore 357 // error if the regset is unsupported. 358 uint32_t system_call = 0; 359 DoWriteRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4); 360 361 return error; 362 } 363 364 Status NativeRegisterContextLinux_s390x::WriteAllRegisterValues( 365 const lldb::DataBufferSP &data_sp) { 366 Status error; 367 368 if (!data_sp) { 369 error.SetErrorStringWithFormat( 370 "NativeRegisterContextLinux_s390x::%s invalid data_sp provided", 371 __FUNCTION__); 372 return error; 373 } 374 375 if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { 376 error.SetErrorStringWithFormat( 377 "NativeRegisterContextLinux_s390x::%s data_sp contained mismatched " 378 "data size, expected %" PRIu64 ", actual %" PRIu64, 379 __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); 380 return error; 381 } 382 383 uint8_t *src = data_sp->GetBytes(); 384 if (src == nullptr) { 385 error.SetErrorStringWithFormat("NativeRegisterContextLinux_s390x::%s " 386 "DataBuffer::GetBytes() returned a null " 387 "pointer", 388 __FUNCTION__); 389 return error; 390 } 391 392 error = DoWriteGPR(src, sizeof(s390_regs)); 393 src += sizeof(s390_regs); 394 if (error.Fail()) 395 return error; 396 397 error = DoWriteFPR(src, sizeof(s390_fp_regs)); 398 src += sizeof(s390_fp_regs); 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::DoReadGPR(void *buf, size_t buf_size) { 445 assert(buf_size == sizeof(s390_regs)); 446 return PeekUserArea(offsetof(user_regs_struct, psw), buf, buf_size); 447 } 448 449 Status NativeRegisterContextLinux_s390x::DoWriteGPR(void *buf, 450 size_t buf_size) { 451 assert(buf_size == sizeof(s390_regs)); 452 return PokeUserArea(offsetof(user_regs_struct, psw), buf, buf_size); 453 } 454 455 Status NativeRegisterContextLinux_s390x::DoReadFPR(void *buf, size_t buf_size) { 456 assert(buf_size == sizeof(s390_fp_regs)); 457 return PeekUserArea(offsetof(user_regs_struct, fp_regs), buf, buf_size); 458 } 459 460 Status NativeRegisterContextLinux_s390x::DoWriteFPR(void *buf, 461 size_t buf_size) { 462 assert(buf_size == sizeof(s390_fp_regs)); 463 return PokeUserArea(offsetof(user_regs_struct, fp_regs), buf, buf_size); 464 } 465 466 Status NativeRegisterContextLinux_s390x::DoReadRegisterSet(uint32_t regset, 467 void *buf, 468 size_t buf_size) { 469 struct iovec iov; 470 iov.iov_base = buf; 471 iov.iov_len = buf_size; 472 473 return ReadRegisterSet(&iov, buf_size, regset); 474 } 475 476 Status NativeRegisterContextLinux_s390x::DoWriteRegisterSet(uint32_t regset, 477 const void *buf, 478 size_t buf_size) { 479 struct iovec iov; 480 iov.iov_base = const_cast<void *>(buf); 481 iov.iov_len = buf_size; 482 483 return WriteRegisterSet(&iov, buf_size, regset); 484 } 485 486 Status NativeRegisterContextLinux_s390x::IsWatchpointHit(uint32_t wp_index, 487 bool &is_hit) { 488 per_lowcore_bits per_lowcore; 489 490 if (wp_index >= NumSupportedHardwareWatchpoints()) 491 return Status("Watchpoint index out of range"); 492 493 if (m_watchpoint_addr == LLDB_INVALID_ADDRESS) { 494 is_hit = false; 495 return Status(); 496 } 497 498 Status error = PeekUserArea(offsetof(user_regs_struct, per_info.lowcore), 499 &per_lowcore, sizeof(per_lowcore)); 500 if (error.Fail()) { 501 is_hit = false; 502 return error; 503 } 504 505 is_hit = (per_lowcore.perc_storage_alteration == 1 && 506 per_lowcore.perc_store_real_address == 0); 507 508 if (is_hit) { 509 // Do not report this watchpoint again. 510 memset(&per_lowcore, 0, sizeof(per_lowcore)); 511 PokeUserArea(offsetof(user_regs_struct, per_info.lowcore), &per_lowcore, 512 sizeof(per_lowcore)); 513 } 514 515 return Status(); 516 } 517 518 Status NativeRegisterContextLinux_s390x::GetWatchpointHitIndex( 519 uint32_t &wp_index, lldb::addr_t trap_addr) { 520 uint32_t num_hw_wps = NumSupportedHardwareWatchpoints(); 521 for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) { 522 bool is_hit; 523 Status error = IsWatchpointHit(wp_index, is_hit); 524 if (error.Fail()) { 525 wp_index = LLDB_INVALID_INDEX32; 526 return error; 527 } else if (is_hit) { 528 return error; 529 } 530 } 531 wp_index = LLDB_INVALID_INDEX32; 532 return Status(); 533 } 534 535 Status NativeRegisterContextLinux_s390x::IsWatchpointVacant(uint32_t wp_index, 536 bool &is_vacant) { 537 if (wp_index >= NumSupportedHardwareWatchpoints()) 538 return Status("Watchpoint index out of range"); 539 540 is_vacant = m_watchpoint_addr == LLDB_INVALID_ADDRESS; 541 542 return Status(); 543 } 544 545 bool NativeRegisterContextLinux_s390x::ClearHardwareWatchpoint( 546 uint32_t wp_index) { 547 per_struct per_info; 548 549 if (wp_index >= NumSupportedHardwareWatchpoints()) 550 return false; 551 552 Status error = PeekUserArea(offsetof(user_regs_struct, per_info), &per_info, 553 sizeof(per_info)); 554 if (error.Fail()) 555 return false; 556 557 per_info.control_regs.bits.em_storage_alteration = 0; 558 per_info.control_regs.bits.storage_alt_space_ctl = 0; 559 per_info.starting_addr = 0; 560 per_info.ending_addr = 0; 561 562 error = PokeUserArea(offsetof(user_regs_struct, per_info), &per_info, 563 sizeof(per_info)); 564 if (error.Fail()) 565 return false; 566 567 m_watchpoint_addr = LLDB_INVALID_ADDRESS; 568 return true; 569 } 570 571 Status NativeRegisterContextLinux_s390x::ClearAllHardwareWatchpoints() { 572 if (ClearHardwareWatchpoint(0)) 573 return Status(); 574 return Status("Clearing all hardware watchpoints failed."); 575 } 576 577 uint32_t NativeRegisterContextLinux_s390x::SetHardwareWatchpoint( 578 lldb::addr_t addr, size_t size, uint32_t watch_flags) { 579 per_struct per_info; 580 581 if (watch_flags != 0x1) 582 return LLDB_INVALID_INDEX32; 583 584 if (m_watchpoint_addr != LLDB_INVALID_ADDRESS) 585 return LLDB_INVALID_INDEX32; 586 587 Status error = PeekUserArea(offsetof(user_regs_struct, per_info), &per_info, 588 sizeof(per_info)); 589 if (error.Fail()) 590 return LLDB_INVALID_INDEX32; 591 592 per_info.control_regs.bits.em_storage_alteration = 1; 593 per_info.control_regs.bits.storage_alt_space_ctl = 1; 594 per_info.starting_addr = addr; 595 per_info.ending_addr = addr + size - 1; 596 597 error = PokeUserArea(offsetof(user_regs_struct, per_info), &per_info, 598 sizeof(per_info)); 599 if (error.Fail()) 600 return LLDB_INVALID_INDEX32; 601 602 m_watchpoint_addr = addr; 603 return 0; 604 } 605 606 lldb::addr_t 607 NativeRegisterContextLinux_s390x::GetWatchpointAddress(uint32_t wp_index) { 608 if (wp_index >= NumSupportedHardwareWatchpoints()) 609 return LLDB_INVALID_ADDRESS; 610 return m_watchpoint_addr; 611 } 612 613 uint32_t NativeRegisterContextLinux_s390x::NumSupportedHardwareWatchpoints() { 614 return 1; 615 } 616 617 #endif // defined(__s390x__) && defined(__linux__) 618