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