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 // ---------------------------------------------------------------------------- 29 // Private namespace. 30 // ---------------------------------------------------------------------------- 31 32 namespace { 33 // s390x 64-bit general purpose registers. 34 static const uint32_t g_gpr_regnums_s390x[] = { 35 lldb_r0_s390x, lldb_r1_s390x, lldb_r2_s390x, lldb_r3_s390x, 36 lldb_r4_s390x, lldb_r5_s390x, lldb_r6_s390x, lldb_r7_s390x, 37 lldb_r8_s390x, lldb_r9_s390x, lldb_r10_s390x, lldb_r11_s390x, 38 lldb_r12_s390x, lldb_r13_s390x, lldb_r14_s390x, lldb_r15_s390x, 39 lldb_acr0_s390x, lldb_acr1_s390x, lldb_acr2_s390x, lldb_acr3_s390x, 40 lldb_acr4_s390x, lldb_acr5_s390x, lldb_acr6_s390x, lldb_acr7_s390x, 41 lldb_acr8_s390x, lldb_acr9_s390x, lldb_acr10_s390x, lldb_acr11_s390x, 42 lldb_acr12_s390x, lldb_acr13_s390x, lldb_acr14_s390x, lldb_acr15_s390x, 43 lldb_pswm_s390x, lldb_pswa_s390x, 44 LLDB_INVALID_REGNUM // register sets need to end with this flag 45 }; 46 static_assert((sizeof(g_gpr_regnums_s390x) / sizeof(g_gpr_regnums_s390x[0])) - 47 1 == 48 k_num_gpr_registers_s390x, 49 "g_gpr_regnums_s390x has wrong number of register infos"); 50 51 // s390x 64-bit floating point registers. 52 static const uint32_t g_fpu_regnums_s390x[] = { 53 lldb_f0_s390x, lldb_f1_s390x, lldb_f2_s390x, lldb_f3_s390x, 54 lldb_f4_s390x, lldb_f5_s390x, lldb_f6_s390x, lldb_f7_s390x, 55 lldb_f8_s390x, lldb_f9_s390x, lldb_f10_s390x, lldb_f11_s390x, 56 lldb_f12_s390x, lldb_f13_s390x, lldb_f14_s390x, lldb_f15_s390x, 57 lldb_fpc_s390x, 58 LLDB_INVALID_REGNUM // register sets need to end with this flag 59 }; 60 static_assert((sizeof(g_fpu_regnums_s390x) / sizeof(g_fpu_regnums_s390x[0])) - 61 1 == 62 k_num_fpr_registers_s390x, 63 "g_fpu_regnums_s390x has wrong number of register infos"); 64 65 // s390x Linux operating-system information. 66 static const uint32_t g_linux_regnums_s390x[] = { 67 lldb_orig_r2_s390x, lldb_last_break_s390x, lldb_system_call_s390x, 68 LLDB_INVALID_REGNUM // register sets need to end with this flag 69 }; 70 static_assert((sizeof(g_linux_regnums_s390x) / 71 sizeof(g_linux_regnums_s390x[0])) - 72 1 == 73 k_num_linux_registers_s390x, 74 "g_linux_regnums_s390x has wrong number of register infos"); 75 76 // Number of register sets provided by this context. 77 enum { k_num_register_sets = 3 }; 78 79 // Register sets for s390x 64-bit. 80 static const RegisterSet g_reg_sets_s390x[k_num_register_sets] = { 81 {"General Purpose Registers", "gpr", k_num_gpr_registers_s390x, 82 g_gpr_regnums_s390x}, 83 {"Floating Point Registers", "fpr", k_num_fpr_registers_s390x, 84 g_fpu_regnums_s390x}, 85 {"Linux Operating System Data", "linux", k_num_linux_registers_s390x, 86 g_linux_regnums_s390x}, 87 }; 88 } 89 90 #define REG_CONTEXT_SIZE (sizeof(s390_regs) + sizeof(s390_fp_regs) + 4) 91 92 // ---------------------------------------------------------------------------- 93 // Required ptrace defines. 94 // ---------------------------------------------------------------------------- 95 96 #define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */ 97 #define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */ 98 99 std::unique_ptr<NativeRegisterContextLinux> 100 NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( 101 const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { 102 return llvm::make_unique<NativeRegisterContextLinux_s390x>(target_arch, 103 native_thread); 104 } 105 106 // ---------------------------------------------------------------------------- 107 // NativeRegisterContextLinux_s390x members. 108 // ---------------------------------------------------------------------------- 109 110 static RegisterInfoInterface * 111 CreateRegisterInfoInterface(const ArchSpec &target_arch) { 112 assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && 113 "Register setting path assumes this is a 64-bit host"); 114 return new RegisterContextLinux_s390x(target_arch); 115 } 116 117 NativeRegisterContextLinux_s390x::NativeRegisterContextLinux_s390x( 118 const ArchSpec &target_arch, NativeThreadProtocol &native_thread) 119 : NativeRegisterContextLinux(native_thread, 120 CreateRegisterInfoInterface(target_arch)) { 121 // Set up data about ranges of valid registers. 122 switch (target_arch.GetMachine()) { 123 case llvm::Triple::systemz: 124 m_reg_info.num_registers = k_num_registers_s390x; 125 m_reg_info.num_gpr_registers = k_num_gpr_registers_s390x; 126 m_reg_info.num_fpr_registers = k_num_fpr_registers_s390x; 127 m_reg_info.last_gpr = k_last_gpr_s390x; 128 m_reg_info.first_fpr = k_first_fpr_s390x; 129 m_reg_info.last_fpr = k_last_fpr_s390x; 130 break; 131 default: 132 assert(false && "Unhandled target architecture."); 133 break; 134 } 135 136 // Clear out the watchpoint state. 137 m_watchpoint_addr = LLDB_INVALID_ADDRESS; 138 } 139 140 uint32_t NativeRegisterContextLinux_s390x::GetRegisterSetCount() const { 141 uint32_t sets = 0; 142 for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) { 143 if (IsRegisterSetAvailable(set_index)) 144 ++sets; 145 } 146 147 return sets; 148 } 149 150 uint32_t NativeRegisterContextLinux_s390x::GetUserRegisterCount() const { 151 uint32_t count = 0; 152 for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) { 153 const RegisterSet *set = GetRegisterSet(set_index); 154 if (set) 155 count += set->num_registers; 156 } 157 return count; 158 } 159 160 const RegisterSet * 161 NativeRegisterContextLinux_s390x::GetRegisterSet(uint32_t set_index) const { 162 if (!IsRegisterSetAvailable(set_index)) 163 return nullptr; 164 165 switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { 166 case llvm::Triple::systemz: 167 return &g_reg_sets_s390x[set_index]; 168 default: 169 assert(false && "Unhandled target architecture."); 170 return nullptr; 171 } 172 173 return nullptr; 174 } 175 176 bool NativeRegisterContextLinux_s390x::IsRegisterSetAvailable( 177 uint32_t set_index) const { 178 return set_index < k_num_register_sets; 179 } 180 181 bool NativeRegisterContextLinux_s390x::IsGPR(uint32_t reg_index) const { 182 // GPRs come first. "orig_r2" counts as GPR since it is part of the GPR 183 // register area. 184 return reg_index <= m_reg_info.last_gpr || reg_index == lldb_orig_r2_s390x; 185 } 186 187 bool NativeRegisterContextLinux_s390x::IsFPR(uint32_t reg_index) const { 188 return (m_reg_info.first_fpr <= reg_index && 189 reg_index <= m_reg_info.last_fpr); 190 } 191 192 Status 193 NativeRegisterContextLinux_s390x::ReadRegister(const RegisterInfo *reg_info, 194 RegisterValue ®_value) { 195 if (!reg_info) 196 return Status("reg_info NULL"); 197 198 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 199 if (reg == LLDB_INVALID_REGNUM) 200 return Status("register \"%s\" is an internal-only lldb register, cannot " 201 "read directly", 202 reg_info->name); 203 204 if (IsGPR(reg)) { 205 s390_regs regs; 206 Status error = DoReadGPR(®s, sizeof(regs)); 207 if (error.Fail()) 208 return error; 209 210 uint8_t *src = (uint8_t *)®s + reg_info->byte_offset; 211 assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(regs)); 212 switch (reg_info->byte_size) { 213 case 4: 214 reg_value.SetUInt32(*(uint32_t *)src); 215 break; 216 case 8: 217 reg_value.SetUInt64(*(uint64_t *)src); 218 break; 219 default: 220 assert(false && "Unhandled data size."); 221 return Status("unhandled byte size: %" PRIu32, reg_info->byte_size); 222 } 223 return Status(); 224 } 225 226 if (IsFPR(reg)) { 227 s390_fp_regs fp_regs; 228 Status error = DoReadFPR(&fp_regs, sizeof(fp_regs)); 229 if (error.Fail()) 230 return error; 231 232 // byte_offset is just the offset within FPR, not the whole user area. 233 uint8_t *src = (uint8_t *)&fp_regs + reg_info->byte_offset; 234 assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(fp_regs)); 235 switch (reg_info->byte_size) { 236 case 4: 237 reg_value.SetUInt32(*(uint32_t *)src); 238 break; 239 case 8: 240 reg_value.SetUInt64(*(uint64_t *)src); 241 break; 242 default: 243 assert(false && "Unhandled data size."); 244 return Status("unhandled byte size: %" PRIu32, reg_info->byte_size); 245 } 246 return Status(); 247 } 248 249 if (reg == lldb_last_break_s390x) { 250 uint64_t last_break; 251 Status error = DoReadRegisterSet(NT_S390_LAST_BREAK, &last_break, 8); 252 if (error.Fail()) 253 return error; 254 255 reg_value.SetUInt64(last_break); 256 return Status(); 257 } 258 259 if (reg == lldb_system_call_s390x) { 260 uint32_t system_call; 261 Status error = DoReadRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4); 262 if (error.Fail()) 263 return error; 264 265 reg_value.SetUInt32(system_call); 266 return Status(); 267 } 268 269 return Status("failed - register wasn't recognized"); 270 } 271 272 Status NativeRegisterContextLinux_s390x::WriteRegister( 273 const RegisterInfo *reg_info, const RegisterValue ®_value) { 274 if (!reg_info) 275 return Status("reg_info NULL"); 276 277 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 278 if (reg == LLDB_INVALID_REGNUM) 279 return Status("register \"%s\" is an internal-only lldb register, cannot " 280 "write directly", 281 reg_info->name); 282 283 if (IsGPR(reg)) { 284 s390_regs regs; 285 Status error = DoReadGPR(®s, sizeof(regs)); 286 if (error.Fail()) 287 return error; 288 289 uint8_t *dst = (uint8_t *)®s + reg_info->byte_offset; 290 assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(regs)); 291 switch (reg_info->byte_size) { 292 case 4: 293 *(uint32_t *)dst = reg_value.GetAsUInt32(); 294 break; 295 case 8: 296 *(uint64_t *)dst = reg_value.GetAsUInt64(); 297 break; 298 default: 299 assert(false && "Unhandled data size."); 300 return Status("unhandled byte size: %" PRIu32, reg_info->byte_size); 301 } 302 return DoWriteGPR(®s, sizeof(regs)); 303 } 304 305 if (IsFPR(reg)) { 306 s390_fp_regs fp_regs; 307 Status error = DoReadFPR(&fp_regs, sizeof(fp_regs)); 308 if (error.Fail()) 309 return error; 310 311 // byte_offset is just the offset within fp_regs, not the whole user area. 312 uint8_t *dst = (uint8_t *)&fp_regs + reg_info->byte_offset; 313 assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(fp_regs)); 314 switch (reg_info->byte_size) { 315 case 4: 316 *(uint32_t *)dst = reg_value.GetAsUInt32(); 317 break; 318 case 8: 319 *(uint64_t *)dst = reg_value.GetAsUInt64(); 320 break; 321 default: 322 assert(false && "Unhandled data size."); 323 return Status("unhandled byte size: %" PRIu32, reg_info->byte_size); 324 } 325 return DoWriteFPR(&fp_regs, sizeof(fp_regs)); 326 } 327 328 if (reg == lldb_last_break_s390x) { 329 return Status("The last break address is read-only"); 330 } 331 332 if (reg == lldb_system_call_s390x) { 333 uint32_t system_call = reg_value.GetAsUInt32(); 334 return DoWriteRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4); 335 } 336 337 return Status("failed - register wasn't recognized"); 338 } 339 340 Status NativeRegisterContextLinux_s390x::ReadAllRegisterValues( 341 lldb::DataBufferSP &data_sp) { 342 Status error; 343 344 data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); 345 if (!data_sp) { 346 error.SetErrorStringWithFormat( 347 "failed to allocate DataBufferHeap instance of size %" PRIu64, 348 REG_CONTEXT_SIZE); 349 return error; 350 } 351 352 uint8_t *dst = data_sp->GetBytes(); 353 if (dst == nullptr) { 354 error.SetErrorStringWithFormat("DataBufferHeap instance of size %" PRIu64 355 " returned a null pointer", 356 REG_CONTEXT_SIZE); 357 return error; 358 } 359 360 error = DoReadGPR(dst, sizeof(s390_regs)); 361 dst += sizeof(s390_regs); 362 if (error.Fail()) 363 return error; 364 365 error = DoReadFPR(dst, sizeof(s390_fp_regs)); 366 dst += sizeof(s390_fp_regs); 367 if (error.Fail()) 368 return error; 369 370 // Ignore errors if the regset is unsupported (happens on older kernels). 371 DoReadRegisterSet(NT_S390_SYSTEM_CALL, dst, 4); 372 dst += 4; 373 374 // To enable inferior function calls while the process is stopped in an 375 // interrupted system call, we need to clear the system call flag. It will be 376 // restored to its original value by WriteAllRegisterValues. Again we ignore 377 // error if the regset is unsupported. 378 uint32_t system_call = 0; 379 DoWriteRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4); 380 381 return error; 382 } 383 384 Status NativeRegisterContextLinux_s390x::WriteAllRegisterValues( 385 const lldb::DataBufferSP &data_sp) { 386 Status error; 387 388 if (!data_sp) { 389 error.SetErrorStringWithFormat( 390 "NativeRegisterContextLinux_s390x::%s invalid data_sp provided", 391 __FUNCTION__); 392 return error; 393 } 394 395 if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { 396 error.SetErrorStringWithFormat( 397 "NativeRegisterContextLinux_s390x::%s data_sp contained mismatched " 398 "data size, expected %" PRIu64 ", actual %" PRIu64, 399 __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); 400 return error; 401 } 402 403 uint8_t *src = data_sp->GetBytes(); 404 if (src == nullptr) { 405 error.SetErrorStringWithFormat("NativeRegisterContextLinux_s390x::%s " 406 "DataBuffer::GetBytes() returned a null " 407 "pointer", 408 __FUNCTION__); 409 return error; 410 } 411 412 error = DoWriteGPR(src, sizeof(s390_regs)); 413 src += sizeof(s390_regs); 414 if (error.Fail()) 415 return error; 416 417 error = DoWriteFPR(src, sizeof(s390_fp_regs)); 418 src += sizeof(s390_fp_regs); 419 if (error.Fail()) 420 return error; 421 422 // Ignore errors if the regset is unsupported (happens on older kernels). 423 DoWriteRegisterSet(NT_S390_SYSTEM_CALL, src, 4); 424 src += 4; 425 426 return error; 427 } 428 429 Status NativeRegisterContextLinux_s390x::DoReadRegisterValue( 430 uint32_t offset, const char *reg_name, uint32_t size, 431 RegisterValue &value) { 432 return Status("DoReadRegisterValue unsupported"); 433 } 434 435 Status NativeRegisterContextLinux_s390x::DoWriteRegisterValue( 436 uint32_t offset, const char *reg_name, const RegisterValue &value) { 437 return Status("DoWriteRegisterValue unsupported"); 438 } 439 440 Status NativeRegisterContextLinux_s390x::PeekUserArea(uint32_t offset, 441 void *buf, 442 size_t buf_size) { 443 ptrace_area parea; 444 parea.len = buf_size; 445 parea.process_addr = (addr_t)buf; 446 parea.kernel_addr = offset; 447 448 return NativeProcessLinux::PtraceWrapper(PTRACE_PEEKUSR_AREA, 449 m_thread.GetID(), &parea); 450 } 451 452 Status NativeRegisterContextLinux_s390x::PokeUserArea(uint32_t offset, 453 const void *buf, 454 size_t buf_size) { 455 ptrace_area parea; 456 parea.len = buf_size; 457 parea.process_addr = (addr_t)buf; 458 parea.kernel_addr = offset; 459 460 return NativeProcessLinux::PtraceWrapper(PTRACE_POKEUSR_AREA, 461 m_thread.GetID(), &parea); 462 } 463 464 Status NativeRegisterContextLinux_s390x::DoReadGPR(void *buf, size_t buf_size) { 465 assert(buf_size == sizeof(s390_regs)); 466 return PeekUserArea(offsetof(user_regs_struct, psw), buf, buf_size); 467 } 468 469 Status NativeRegisterContextLinux_s390x::DoWriteGPR(void *buf, 470 size_t buf_size) { 471 assert(buf_size == sizeof(s390_regs)); 472 return PokeUserArea(offsetof(user_regs_struct, psw), buf, buf_size); 473 } 474 475 Status NativeRegisterContextLinux_s390x::DoReadFPR(void *buf, size_t buf_size) { 476 assert(buf_size == sizeof(s390_fp_regs)); 477 return PeekUserArea(offsetof(user_regs_struct, fp_regs), buf, buf_size); 478 } 479 480 Status NativeRegisterContextLinux_s390x::DoWriteFPR(void *buf, 481 size_t buf_size) { 482 assert(buf_size == sizeof(s390_fp_regs)); 483 return PokeUserArea(offsetof(user_regs_struct, fp_regs), buf, buf_size); 484 } 485 486 Status NativeRegisterContextLinux_s390x::DoReadRegisterSet(uint32_t regset, 487 void *buf, 488 size_t buf_size) { 489 struct iovec iov; 490 iov.iov_base = buf; 491 iov.iov_len = buf_size; 492 493 return ReadRegisterSet(&iov, buf_size, regset); 494 } 495 496 Status NativeRegisterContextLinux_s390x::DoWriteRegisterSet(uint32_t regset, 497 const void *buf, 498 size_t buf_size) { 499 struct iovec iov; 500 iov.iov_base = const_cast<void *>(buf); 501 iov.iov_len = buf_size; 502 503 return WriteRegisterSet(&iov, buf_size, regset); 504 } 505 506 Status NativeRegisterContextLinux_s390x::IsWatchpointHit(uint32_t wp_index, 507 bool &is_hit) { 508 per_lowcore_bits per_lowcore; 509 510 if (wp_index >= NumSupportedHardwareWatchpoints()) 511 return Status("Watchpoint index out of range"); 512 513 if (m_watchpoint_addr == LLDB_INVALID_ADDRESS) { 514 is_hit = false; 515 return Status(); 516 } 517 518 Status error = PeekUserArea(offsetof(user_regs_struct, per_info.lowcore), 519 &per_lowcore, sizeof(per_lowcore)); 520 if (error.Fail()) { 521 is_hit = false; 522 return error; 523 } 524 525 is_hit = (per_lowcore.perc_storage_alteration == 1 && 526 per_lowcore.perc_store_real_address == 0); 527 528 if (is_hit) { 529 // Do not report this watchpoint again. 530 memset(&per_lowcore, 0, sizeof(per_lowcore)); 531 PokeUserArea(offsetof(user_regs_struct, per_info.lowcore), &per_lowcore, 532 sizeof(per_lowcore)); 533 } 534 535 return Status(); 536 } 537 538 Status NativeRegisterContextLinux_s390x::GetWatchpointHitIndex( 539 uint32_t &wp_index, lldb::addr_t trap_addr) { 540 uint32_t num_hw_wps = NumSupportedHardwareWatchpoints(); 541 for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) { 542 bool is_hit; 543 Status error = IsWatchpointHit(wp_index, is_hit); 544 if (error.Fail()) { 545 wp_index = LLDB_INVALID_INDEX32; 546 return error; 547 } else if (is_hit) { 548 return error; 549 } 550 } 551 wp_index = LLDB_INVALID_INDEX32; 552 return Status(); 553 } 554 555 Status NativeRegisterContextLinux_s390x::IsWatchpointVacant(uint32_t wp_index, 556 bool &is_vacant) { 557 if (wp_index >= NumSupportedHardwareWatchpoints()) 558 return Status("Watchpoint index out of range"); 559 560 is_vacant = m_watchpoint_addr == LLDB_INVALID_ADDRESS; 561 562 return Status(); 563 } 564 565 bool NativeRegisterContextLinux_s390x::ClearHardwareWatchpoint( 566 uint32_t wp_index) { 567 per_struct per_info; 568 569 if (wp_index >= NumSupportedHardwareWatchpoints()) 570 return false; 571 572 Status error = PeekUserArea(offsetof(user_regs_struct, per_info), &per_info, 573 sizeof(per_info)); 574 if (error.Fail()) 575 return false; 576 577 per_info.control_regs.bits.em_storage_alteration = 0; 578 per_info.control_regs.bits.storage_alt_space_ctl = 0; 579 per_info.starting_addr = 0; 580 per_info.ending_addr = 0; 581 582 error = PokeUserArea(offsetof(user_regs_struct, per_info), &per_info, 583 sizeof(per_info)); 584 if (error.Fail()) 585 return false; 586 587 m_watchpoint_addr = LLDB_INVALID_ADDRESS; 588 return true; 589 } 590 591 Status NativeRegisterContextLinux_s390x::ClearAllHardwareWatchpoints() { 592 if (ClearHardwareWatchpoint(0)) 593 return Status(); 594 return Status("Clearing all hardware watchpoints failed."); 595 } 596 597 uint32_t NativeRegisterContextLinux_s390x::SetHardwareWatchpoint( 598 lldb::addr_t addr, size_t size, uint32_t watch_flags) { 599 per_struct per_info; 600 601 if (watch_flags != 0x1) 602 return LLDB_INVALID_INDEX32; 603 604 if (m_watchpoint_addr != LLDB_INVALID_ADDRESS) 605 return LLDB_INVALID_INDEX32; 606 607 Status error = PeekUserArea(offsetof(user_regs_struct, per_info), &per_info, 608 sizeof(per_info)); 609 if (error.Fail()) 610 return LLDB_INVALID_INDEX32; 611 612 per_info.control_regs.bits.em_storage_alteration = 1; 613 per_info.control_regs.bits.storage_alt_space_ctl = 1; 614 per_info.starting_addr = addr; 615 per_info.ending_addr = addr + size - 1; 616 617 error = PokeUserArea(offsetof(user_regs_struct, per_info), &per_info, 618 sizeof(per_info)); 619 if (error.Fail()) 620 return LLDB_INVALID_INDEX32; 621 622 m_watchpoint_addr = addr; 623 return 0; 624 } 625 626 lldb::addr_t 627 NativeRegisterContextLinux_s390x::GetWatchpointAddress(uint32_t wp_index) { 628 if (wp_index >= NumSupportedHardwareWatchpoints()) 629 return LLDB_INVALID_ADDRESS; 630 return m_watchpoint_addr; 631 } 632 633 uint32_t NativeRegisterContextLinux_s390x::NumSupportedHardwareWatchpoints() { 634 return 1; 635 } 636 637 #endif // defined(__s390x__) && defined(__linux__) 638