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 ®_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 ®_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