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