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 14 #include "lldb/Core/DataBufferHeap.h" 15 #include "lldb/Core/Error.h" 16 #include "lldb/Core/Log.h" 17 #include "lldb/Core/RegisterValue.h" 18 #include "lldb/Host/HostInfo.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 NativeRegisterContextLinux * 101 NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( 102 const ArchSpec &target_arch, NativeThreadProtocol &native_thread, 103 uint32_t concrete_frame_idx) { 104 return new NativeRegisterContextLinux_s390x(target_arch, native_thread, 105 concrete_frame_idx); 106 } 107 108 // ---------------------------------------------------------------------------- 109 // NativeRegisterContextLinux_s390x members. 110 // ---------------------------------------------------------------------------- 111 112 static RegisterInfoInterface * 113 CreateRegisterInfoInterface(const ArchSpec &target_arch) { 114 assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && 115 "Register setting path assumes this is a 64-bit host"); 116 return new RegisterContextLinux_s390x(target_arch); 117 } 118 119 NativeRegisterContextLinux_s390x::NativeRegisterContextLinux_s390x( 120 const ArchSpec &target_arch, NativeThreadProtocol &native_thread, 121 uint32_t concrete_frame_idx) 122 : NativeRegisterContextLinux(native_thread, concrete_frame_idx, 123 CreateRegisterInfoInterface(target_arch)) { 124 // Set up data about ranges of valid registers. 125 switch (target_arch.GetMachine()) { 126 case llvm::Triple::systemz: 127 m_reg_info.num_registers = k_num_registers_s390x; 128 m_reg_info.num_gpr_registers = k_num_gpr_registers_s390x; 129 m_reg_info.num_fpr_registers = k_num_fpr_registers_s390x; 130 m_reg_info.last_gpr = k_last_gpr_s390x; 131 m_reg_info.first_fpr = k_first_fpr_s390x; 132 m_reg_info.last_fpr = k_last_fpr_s390x; 133 break; 134 default: 135 assert(false && "Unhandled target architecture."); 136 break; 137 } 138 139 // Clear out the watchpoint state. 140 m_watchpoint_addr = LLDB_INVALID_ADDRESS; 141 } 142 143 uint32_t NativeRegisterContextLinux_s390x::GetRegisterSetCount() const { 144 uint32_t sets = 0; 145 for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) { 146 if (IsRegisterSetAvailable(set_index)) 147 ++sets; 148 } 149 150 return sets; 151 } 152 153 uint32_t NativeRegisterContextLinux_s390x::GetUserRegisterCount() const { 154 uint32_t count = 0; 155 for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) { 156 const RegisterSet *set = GetRegisterSet(set_index); 157 if (set) 158 count += set->num_registers; 159 } 160 return count; 161 } 162 163 const RegisterSet * 164 NativeRegisterContextLinux_s390x::GetRegisterSet(uint32_t set_index) const { 165 if (!IsRegisterSetAvailable(set_index)) 166 return nullptr; 167 168 switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { 169 case llvm::Triple::systemz: 170 return &g_reg_sets_s390x[set_index]; 171 default: 172 assert(false && "Unhandled target architecture."); 173 return nullptr; 174 } 175 176 return nullptr; 177 } 178 179 bool NativeRegisterContextLinux_s390x::IsRegisterSetAvailable( 180 uint32_t set_index) const { 181 return set_index < k_num_register_sets; 182 } 183 184 bool NativeRegisterContextLinux_s390x::IsGPR(uint32_t reg_index) const { 185 // GPRs come first. "orig_r2" counts as GPR since it is part of the GPR 186 // register area. 187 return reg_index <= m_reg_info.last_gpr || reg_index == lldb_orig_r2_s390x; 188 } 189 190 bool NativeRegisterContextLinux_s390x::IsFPR(uint32_t reg_index) const { 191 return (m_reg_info.first_fpr <= reg_index && 192 reg_index <= m_reg_info.last_fpr); 193 } 194 195 Error NativeRegisterContextLinux_s390x::ReadRegister( 196 const RegisterInfo *reg_info, RegisterValue ®_value) { 197 if (!reg_info) 198 return Error("reg_info NULL"); 199 200 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 201 if (reg == LLDB_INVALID_REGNUM) 202 return Error("register \"%s\" is an internal-only lldb register, cannot " 203 "read directly", 204 reg_info->name); 205 206 if (IsGPR(reg)) { 207 s390_regs regs; 208 Error error = DoReadGPR(®s, sizeof(regs)); 209 if (error.Fail()) 210 return error; 211 212 uint8_t *src = (uint8_t *)®s + reg_info->byte_offset; 213 assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(regs)); 214 switch (reg_info->byte_size) { 215 case 4: 216 reg_value.SetUInt32(*(uint32_t *)src); 217 break; 218 case 8: 219 reg_value.SetUInt64(*(uint64_t *)src); 220 break; 221 default: 222 assert(false && "Unhandled data size."); 223 return Error("unhandled byte size: %" PRIu32, reg_info->byte_size); 224 } 225 return Error(); 226 } 227 228 if (IsFPR(reg)) { 229 s390_fp_regs fp_regs; 230 Error error = DoReadFPR(&fp_regs, sizeof(fp_regs)); 231 if (error.Fail()) 232 return error; 233 234 // byte_offset is just the offset within FPR, not the whole user area. 235 uint8_t *src = (uint8_t *)&fp_regs + reg_info->byte_offset; 236 assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(fp_regs)); 237 switch (reg_info->byte_size) { 238 case 4: 239 reg_value.SetUInt32(*(uint32_t *)src); 240 break; 241 case 8: 242 reg_value.SetUInt64(*(uint64_t *)src); 243 break; 244 default: 245 assert(false && "Unhandled data size."); 246 return Error("unhandled byte size: %" PRIu32, reg_info->byte_size); 247 } 248 return Error(); 249 } 250 251 if (reg == lldb_last_break_s390x) { 252 uint64_t last_break; 253 Error error = DoReadRegisterSet(NT_S390_LAST_BREAK, &last_break, 8); 254 if (error.Fail()) 255 return error; 256 257 reg_value.SetUInt64(last_break); 258 return Error(); 259 } 260 261 if (reg == lldb_system_call_s390x) { 262 uint32_t system_call; 263 Error error = DoReadRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4); 264 if (error.Fail()) 265 return error; 266 267 reg_value.SetUInt32(system_call); 268 return Error(); 269 } 270 271 return Error("failed - register wasn't recognized"); 272 } 273 274 Error NativeRegisterContextLinux_s390x::WriteRegister( 275 const RegisterInfo *reg_info, const RegisterValue ®_value) { 276 if (!reg_info) 277 return Error("reg_info NULL"); 278 279 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 280 if (reg == LLDB_INVALID_REGNUM) 281 return Error("register \"%s\" is an internal-only lldb register, cannot " 282 "write directly", 283 reg_info->name); 284 285 if (IsGPR(reg)) { 286 s390_regs regs; 287 Error error = DoReadGPR(®s, sizeof(regs)); 288 if (error.Fail()) 289 return error; 290 291 uint8_t *dst = (uint8_t *)®s + reg_info->byte_offset; 292 assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(regs)); 293 switch (reg_info->byte_size) { 294 case 4: 295 *(uint32_t *)dst = reg_value.GetAsUInt32(); 296 break; 297 case 8: 298 *(uint64_t *)dst = reg_value.GetAsUInt64(); 299 break; 300 default: 301 assert(false && "Unhandled data size."); 302 return Error("unhandled byte size: %" PRIu32, reg_info->byte_size); 303 } 304 return DoWriteGPR(®s, sizeof(regs)); 305 } 306 307 if (IsFPR(reg)) { 308 s390_fp_regs fp_regs; 309 Error error = DoReadFPR(&fp_regs, sizeof(fp_regs)); 310 if (error.Fail()) 311 return error; 312 313 // byte_offset is just the offset within fp_regs, not the whole user area. 314 uint8_t *dst = (uint8_t *)&fp_regs + reg_info->byte_offset; 315 assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(fp_regs)); 316 switch (reg_info->byte_size) { 317 case 4: 318 *(uint32_t *)dst = reg_value.GetAsUInt32(); 319 break; 320 case 8: 321 *(uint64_t *)dst = reg_value.GetAsUInt64(); 322 break; 323 default: 324 assert(false && "Unhandled data size."); 325 return Error("unhandled byte size: %" PRIu32, reg_info->byte_size); 326 } 327 return DoWriteFPR(&fp_regs, sizeof(fp_regs)); 328 } 329 330 if (reg == lldb_last_break_s390x) { 331 return Error("The last break address is read-only"); 332 } 333 334 if (reg == lldb_system_call_s390x) { 335 uint32_t system_call = reg_value.GetAsUInt32(); 336 return DoWriteRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4); 337 } 338 339 return Error("failed - register wasn't recognized"); 340 } 341 342 Error NativeRegisterContextLinux_s390x::ReadAllRegisterValues( 343 lldb::DataBufferSP &data_sp) { 344 Error error; 345 346 data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); 347 if (!data_sp) { 348 error.SetErrorStringWithFormat( 349 "failed to allocate DataBufferHeap instance of size %" PRIu64, 350 REG_CONTEXT_SIZE); 351 return error; 352 } 353 354 uint8_t *dst = data_sp->GetBytes(); 355 if (dst == nullptr) { 356 error.SetErrorStringWithFormat("DataBufferHeap instance of size %" PRIu64 357 " returned a null pointer", 358 REG_CONTEXT_SIZE); 359 return error; 360 } 361 362 error = DoReadGPR(dst, sizeof(s390_regs)); 363 dst += sizeof(s390_regs); 364 if (error.Fail()) 365 return error; 366 367 error = DoReadFPR(dst, sizeof(s390_fp_regs)); 368 dst += sizeof(s390_fp_regs); 369 if (error.Fail()) 370 return error; 371 372 // Ignore errors if the regset is unsupported (happens on older kernels). 373 DoReadRegisterSet(NT_S390_SYSTEM_CALL, dst, 4); 374 dst += 4; 375 376 // To enable inferior function calls while the process is stopped in 377 // an interrupted system call, we need to clear the system call flag. 378 // It will be restored to its original value by WriteAllRegisterValues. 379 // Again we ignore error if the regset is unsupported. 380 uint32_t system_call = 0; 381 DoWriteRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4); 382 383 return error; 384 } 385 386 Error NativeRegisterContextLinux_s390x::WriteAllRegisterValues( 387 const lldb::DataBufferSP &data_sp) { 388 Error error; 389 390 if (!data_sp) { 391 error.SetErrorStringWithFormat( 392 "NativeRegisterContextLinux_s390x::%s invalid data_sp provided", 393 __FUNCTION__); 394 return error; 395 } 396 397 if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { 398 error.SetErrorStringWithFormat( 399 "NativeRegisterContextLinux_s390x::%s data_sp contained mismatched " 400 "data size, expected %" PRIu64 ", actual %" PRIu64, 401 __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); 402 return error; 403 } 404 405 uint8_t *src = data_sp->GetBytes(); 406 if (src == nullptr) { 407 error.SetErrorStringWithFormat("NativeRegisterContextLinux_s390x::%s " 408 "DataBuffer::GetBytes() returned a null " 409 "pointer", 410 __FUNCTION__); 411 return error; 412 } 413 414 error = DoWriteGPR(src, sizeof(s390_regs)); 415 src += sizeof(s390_regs); 416 if (error.Fail()) 417 return error; 418 419 error = DoWriteFPR(src, sizeof(s390_fp_regs)); 420 src += sizeof(s390_fp_regs); 421 if (error.Fail()) 422 return error; 423 424 // Ignore errors if the regset is unsupported (happens on older kernels). 425 DoWriteRegisterSet(NT_S390_SYSTEM_CALL, src, 4); 426 src += 4; 427 428 return error; 429 } 430 431 Error NativeRegisterContextLinux_s390x::DoReadRegisterValue( 432 uint32_t offset, const char *reg_name, uint32_t size, 433 RegisterValue &value) { 434 return Error("DoReadRegisterValue unsupported"); 435 } 436 437 Error NativeRegisterContextLinux_s390x::DoWriteRegisterValue( 438 uint32_t offset, const char *reg_name, const RegisterValue &value) { 439 return Error("DoWriteRegisterValue unsupported"); 440 } 441 442 Error NativeRegisterContextLinux_s390x::PeekUserArea(uint32_t offset, 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 Error 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 Error 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 Error NativeRegisterContextLinux_s390x::DoWriteGPR(void *buf, 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 Error 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 Error NativeRegisterContextLinux_s390x::DoWriteFPR(void *buf, size_t buf_size) { 481 assert(buf_size == sizeof(s390_fp_regs)); 482 return PokeUserArea(offsetof(user_regs_struct, fp_regs), buf, buf_size); 483 } 484 485 Error NativeRegisterContextLinux_s390x::DoReadRegisterSet(uint32_t regset, 486 void *buf, 487 size_t buf_size) { 488 struct iovec iov; 489 iov.iov_base = buf; 490 iov.iov_len = buf_size; 491 492 return ReadRegisterSet(&iov, buf_size, regset); 493 } 494 495 Error NativeRegisterContextLinux_s390x::DoWriteRegisterSet(uint32_t regset, 496 const void *buf, 497 size_t buf_size) { 498 struct iovec iov; 499 iov.iov_base = const_cast<void *>(buf); 500 iov.iov_len = buf_size; 501 502 return WriteRegisterSet(&iov, buf_size, regset); 503 } 504 505 Error NativeRegisterContextLinux_s390x::IsWatchpointHit(uint32_t wp_index, 506 bool &is_hit) { 507 per_lowcore_bits per_lowcore; 508 509 if (wp_index >= NumSupportedHardwareWatchpoints()) 510 return Error("Watchpoint index out of range"); 511 512 if (m_watchpoint_addr == LLDB_INVALID_ADDRESS) { 513 is_hit = false; 514 return Error(); 515 } 516 517 Error error = PeekUserArea(offsetof(user_regs_struct, per_info.lowcore), 518 &per_lowcore, sizeof(per_lowcore)); 519 if (error.Fail()) { 520 is_hit = false; 521 return error; 522 } 523 524 is_hit = (per_lowcore.perc_storage_alteration == 1 && 525 per_lowcore.perc_store_real_address == 0); 526 527 if (is_hit) { 528 // Do not report this watchpoint again. 529 memset(&per_lowcore, 0, sizeof(per_lowcore)); 530 PokeUserArea(offsetof(user_regs_struct, per_info.lowcore), &per_lowcore, 531 sizeof(per_lowcore)); 532 } 533 534 return Error(); 535 } 536 537 Error NativeRegisterContextLinux_s390x::GetWatchpointHitIndex( 538 uint32_t &wp_index, lldb::addr_t trap_addr) { 539 uint32_t num_hw_wps = NumSupportedHardwareWatchpoints(); 540 for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) { 541 bool is_hit; 542 Error error = IsWatchpointHit(wp_index, is_hit); 543 if (error.Fail()) { 544 wp_index = LLDB_INVALID_INDEX32; 545 return error; 546 } else if (is_hit) { 547 return error; 548 } 549 } 550 wp_index = LLDB_INVALID_INDEX32; 551 return Error(); 552 } 553 554 Error NativeRegisterContextLinux_s390x::IsWatchpointVacant(uint32_t wp_index, 555 bool &is_vacant) { 556 if (wp_index >= NumSupportedHardwareWatchpoints()) 557 return Error("Watchpoint index out of range"); 558 559 is_vacant = m_watchpoint_addr == LLDB_INVALID_ADDRESS; 560 561 return Error(); 562 } 563 564 bool NativeRegisterContextLinux_s390x::ClearHardwareWatchpoint( 565 uint32_t wp_index) { 566 per_struct per_info; 567 568 if (wp_index >= NumSupportedHardwareWatchpoints()) 569 return false; 570 571 Error error = PeekUserArea(offsetof(user_regs_struct, per_info), &per_info, 572 sizeof(per_info)); 573 if (error.Fail()) 574 return false; 575 576 per_info.control_regs.bits.em_storage_alteration = 0; 577 per_info.control_regs.bits.storage_alt_space_ctl = 0; 578 per_info.starting_addr = 0; 579 per_info.ending_addr = 0; 580 581 error = PokeUserArea(offsetof(user_regs_struct, per_info), &per_info, 582 sizeof(per_info)); 583 if (error.Fail()) 584 return false; 585 586 m_watchpoint_addr = LLDB_INVALID_ADDRESS; 587 return true; 588 } 589 590 Error NativeRegisterContextLinux_s390x::ClearAllHardwareWatchpoints() { 591 if (ClearHardwareWatchpoint(0)) 592 return Error(); 593 return Error("Clearing all hardware watchpoints failed."); 594 } 595 596 uint32_t NativeRegisterContextLinux_s390x::SetHardwareWatchpoint( 597 lldb::addr_t addr, size_t size, uint32_t watch_flags) { 598 per_struct per_info; 599 600 if (watch_flags != 0x1) 601 return LLDB_INVALID_INDEX32; 602 603 if (m_watchpoint_addr != LLDB_INVALID_ADDRESS) 604 return LLDB_INVALID_INDEX32; 605 606 Error error = PeekUserArea(offsetof(user_regs_struct, per_info), &per_info, 607 sizeof(per_info)); 608 if (error.Fail()) 609 return LLDB_INVALID_INDEX32; 610 611 per_info.control_regs.bits.em_storage_alteration = 1; 612 per_info.control_regs.bits.storage_alt_space_ctl = 1; 613 per_info.starting_addr = addr; 614 per_info.ending_addr = addr + size - 1; 615 616 error = PokeUserArea(offsetof(user_regs_struct, per_info), &per_info, 617 sizeof(per_info)); 618 if (error.Fail()) 619 return LLDB_INVALID_INDEX32; 620 621 m_watchpoint_addr = addr; 622 return 0; 623 } 624 625 lldb::addr_t 626 NativeRegisterContextLinux_s390x::GetWatchpointAddress(uint32_t wp_index) { 627 if (wp_index >= NumSupportedHardwareWatchpoints()) 628 return LLDB_INVALID_ADDRESS; 629 return m_watchpoint_addr; 630 } 631 632 uint32_t NativeRegisterContextLinux_s390x::NumSupportedHardwareWatchpoints() { 633 return 1; 634 } 635 636 #endif // defined(__s390x__) && defined(__linux__) 637