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 if (dst == nullptr) { 341 error.SetErrorStringWithFormat("DataBufferHeap instance of size %" PRIu64 342 " returned a null pointer", 343 REG_CONTEXT_SIZE); 344 return error; 345 } 346 347 error = DoReadGPR(dst, sizeof(s390_regs)); 348 dst += sizeof(s390_regs); 349 if (error.Fail()) 350 return error; 351 352 error = DoReadFPR(dst, sizeof(s390_fp_regs)); 353 dst += sizeof(s390_fp_regs); 354 if (error.Fail()) 355 return error; 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.SetErrorStringWithFormat( 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.SetErrorStringWithFormat( 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 uint8_t *src = data_sp->GetBytes(); 391 if (src == nullptr) { 392 error.SetErrorStringWithFormat("NativeRegisterContextLinux_s390x::%s " 393 "DataBuffer::GetBytes() returned a null " 394 "pointer", 395 __FUNCTION__); 396 return error; 397 } 398 399 error = DoWriteGPR(src, sizeof(s390_regs)); 400 src += sizeof(s390_regs); 401 if (error.Fail()) 402 return error; 403 404 error = DoWriteFPR(src, sizeof(s390_fp_regs)); 405 src += sizeof(s390_fp_regs); 406 if (error.Fail()) 407 return error; 408 409 // Ignore errors if the regset is unsupported (happens on older kernels). 410 DoWriteRegisterSet(NT_S390_SYSTEM_CALL, src, 4); 411 src += 4; 412 413 return error; 414 } 415 416 Status NativeRegisterContextLinux_s390x::DoReadRegisterValue( 417 uint32_t offset, const char *reg_name, uint32_t size, 418 RegisterValue &value) { 419 return Status("DoReadRegisterValue unsupported"); 420 } 421 422 Status NativeRegisterContextLinux_s390x::DoWriteRegisterValue( 423 uint32_t offset, const char *reg_name, const RegisterValue &value) { 424 return Status("DoWriteRegisterValue unsupported"); 425 } 426 427 Status NativeRegisterContextLinux_s390x::PeekUserArea(uint32_t offset, 428 void *buf, 429 size_t buf_size) { 430 ptrace_area parea; 431 parea.len = buf_size; 432 parea.process_addr = (addr_t)buf; 433 parea.kernel_addr = offset; 434 435 return NativeProcessLinux::PtraceWrapper(PTRACE_PEEKUSR_AREA, 436 m_thread.GetID(), &parea); 437 } 438 439 Status NativeRegisterContextLinux_s390x::PokeUserArea(uint32_t offset, 440 const void *buf, 441 size_t buf_size) { 442 ptrace_area parea; 443 parea.len = buf_size; 444 parea.process_addr = (addr_t)buf; 445 parea.kernel_addr = offset; 446 447 return NativeProcessLinux::PtraceWrapper(PTRACE_POKEUSR_AREA, 448 m_thread.GetID(), &parea); 449 } 450 451 Status NativeRegisterContextLinux_s390x::DoReadGPR(void *buf, size_t buf_size) { 452 assert(buf_size == sizeof(s390_regs)); 453 return PeekUserArea(offsetof(user_regs_struct, psw), buf, buf_size); 454 } 455 456 Status NativeRegisterContextLinux_s390x::DoWriteGPR(void *buf, 457 size_t buf_size) { 458 assert(buf_size == sizeof(s390_regs)); 459 return PokeUserArea(offsetof(user_regs_struct, psw), buf, buf_size); 460 } 461 462 Status NativeRegisterContextLinux_s390x::DoReadFPR(void *buf, size_t buf_size) { 463 assert(buf_size == sizeof(s390_fp_regs)); 464 return PeekUserArea(offsetof(user_regs_struct, fp_regs), buf, buf_size); 465 } 466 467 Status NativeRegisterContextLinux_s390x::DoWriteFPR(void *buf, 468 size_t buf_size) { 469 assert(buf_size == sizeof(s390_fp_regs)); 470 return PokeUserArea(offsetof(user_regs_struct, fp_regs), buf, buf_size); 471 } 472 473 Status NativeRegisterContextLinux_s390x::DoReadRegisterSet(uint32_t regset, 474 void *buf, 475 size_t buf_size) { 476 struct iovec iov; 477 iov.iov_base = buf; 478 iov.iov_len = buf_size; 479 480 return ReadRegisterSet(&iov, buf_size, regset); 481 } 482 483 Status NativeRegisterContextLinux_s390x::DoWriteRegisterSet(uint32_t regset, 484 const void *buf, 485 size_t buf_size) { 486 struct iovec iov; 487 iov.iov_base = const_cast<void *>(buf); 488 iov.iov_len = buf_size; 489 490 return WriteRegisterSet(&iov, buf_size, regset); 491 } 492 493 Status NativeRegisterContextLinux_s390x::IsWatchpointHit(uint32_t wp_index, 494 bool &is_hit) { 495 per_lowcore_bits per_lowcore; 496 497 if (wp_index >= NumSupportedHardwareWatchpoints()) 498 return Status("Watchpoint index out of range"); 499 500 if (m_watchpoint_addr == LLDB_INVALID_ADDRESS) { 501 is_hit = false; 502 return Status(); 503 } 504 505 Status error = PeekUserArea(offsetof(user_regs_struct, per_info.lowcore), 506 &per_lowcore, sizeof(per_lowcore)); 507 if (error.Fail()) { 508 is_hit = false; 509 return error; 510 } 511 512 is_hit = (per_lowcore.perc_storage_alteration == 1 && 513 per_lowcore.perc_store_real_address == 0); 514 515 if (is_hit) { 516 // Do not report this watchpoint again. 517 memset(&per_lowcore, 0, sizeof(per_lowcore)); 518 PokeUserArea(offsetof(user_regs_struct, per_info.lowcore), &per_lowcore, 519 sizeof(per_lowcore)); 520 } 521 522 return Status(); 523 } 524 525 Status NativeRegisterContextLinux_s390x::GetWatchpointHitIndex( 526 uint32_t &wp_index, lldb::addr_t trap_addr) { 527 uint32_t num_hw_wps = NumSupportedHardwareWatchpoints(); 528 for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) { 529 bool is_hit; 530 Status error = IsWatchpointHit(wp_index, is_hit); 531 if (error.Fail()) { 532 wp_index = LLDB_INVALID_INDEX32; 533 return error; 534 } else if (is_hit) { 535 return error; 536 } 537 } 538 wp_index = LLDB_INVALID_INDEX32; 539 return Status(); 540 } 541 542 Status NativeRegisterContextLinux_s390x::IsWatchpointVacant(uint32_t wp_index, 543 bool &is_vacant) { 544 if (wp_index >= NumSupportedHardwareWatchpoints()) 545 return Status("Watchpoint index out of range"); 546 547 is_vacant = m_watchpoint_addr == LLDB_INVALID_ADDRESS; 548 549 return Status(); 550 } 551 552 bool NativeRegisterContextLinux_s390x::ClearHardwareWatchpoint( 553 uint32_t wp_index) { 554 per_struct per_info; 555 556 if (wp_index >= NumSupportedHardwareWatchpoints()) 557 return false; 558 559 Status error = PeekUserArea(offsetof(user_regs_struct, per_info), &per_info, 560 sizeof(per_info)); 561 if (error.Fail()) 562 return false; 563 564 per_info.control_regs.bits.em_storage_alteration = 0; 565 per_info.control_regs.bits.storage_alt_space_ctl = 0; 566 per_info.starting_addr = 0; 567 per_info.ending_addr = 0; 568 569 error = PokeUserArea(offsetof(user_regs_struct, per_info), &per_info, 570 sizeof(per_info)); 571 if (error.Fail()) 572 return false; 573 574 m_watchpoint_addr = LLDB_INVALID_ADDRESS; 575 return true; 576 } 577 578 Status NativeRegisterContextLinux_s390x::ClearAllHardwareWatchpoints() { 579 if (ClearHardwareWatchpoint(0)) 580 return Status(); 581 return Status("Clearing all hardware watchpoints failed."); 582 } 583 584 uint32_t NativeRegisterContextLinux_s390x::SetHardwareWatchpoint( 585 lldb::addr_t addr, size_t size, uint32_t watch_flags) { 586 per_struct per_info; 587 588 if (watch_flags != 0x1) 589 return LLDB_INVALID_INDEX32; 590 591 if (m_watchpoint_addr != LLDB_INVALID_ADDRESS) 592 return LLDB_INVALID_INDEX32; 593 594 Status error = PeekUserArea(offsetof(user_regs_struct, per_info), &per_info, 595 sizeof(per_info)); 596 if (error.Fail()) 597 return LLDB_INVALID_INDEX32; 598 599 per_info.control_regs.bits.em_storage_alteration = 1; 600 per_info.control_regs.bits.storage_alt_space_ctl = 1; 601 per_info.starting_addr = addr; 602 per_info.ending_addr = addr + size - 1; 603 604 error = PokeUserArea(offsetof(user_regs_struct, per_info), &per_info, 605 sizeof(per_info)); 606 if (error.Fail()) 607 return LLDB_INVALID_INDEX32; 608 609 m_watchpoint_addr = addr; 610 return 0; 611 } 612 613 lldb::addr_t 614 NativeRegisterContextLinux_s390x::GetWatchpointAddress(uint32_t wp_index) { 615 if (wp_index >= NumSupportedHardwareWatchpoints()) 616 return LLDB_INVALID_ADDRESS; 617 return m_watchpoint_addr; 618 } 619 620 uint32_t NativeRegisterContextLinux_s390x::NumSupportedHardwareWatchpoints() { 621 return 1; 622 } 623 624 #endif // defined(__s390x__) && defined(__linux__) 625