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/RegisterValue.h" 15 #include "lldb/Host/HostInfo.h" 16 #include "lldb/Utility/DataBufferHeap.h" 17 #include "lldb/Utility/Log.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 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 Status 196 NativeRegisterContextLinux_s390x::ReadRegister(const RegisterInfo *reg_info, 197 RegisterValue ®_value) { 198 if (!reg_info) 199 return Status("reg_info NULL"); 200 201 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 202 if (reg == LLDB_INVALID_REGNUM) 203 return Status("register \"%s\" is an internal-only lldb register, cannot " 204 "read directly", 205 reg_info->name); 206 207 if (IsGPR(reg)) { 208 s390_regs regs; 209 Status error = DoReadGPR(®s, sizeof(regs)); 210 if (error.Fail()) 211 return error; 212 213 uint8_t *src = (uint8_t *)®s + reg_info->byte_offset; 214 assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(regs)); 215 switch (reg_info->byte_size) { 216 case 4: 217 reg_value.SetUInt32(*(uint32_t *)src); 218 break; 219 case 8: 220 reg_value.SetUInt64(*(uint64_t *)src); 221 break; 222 default: 223 assert(false && "Unhandled data size."); 224 return Status("unhandled byte size: %" PRIu32, reg_info->byte_size); 225 } 226 return Status(); 227 } 228 229 if (IsFPR(reg)) { 230 s390_fp_regs fp_regs; 231 Status error = DoReadFPR(&fp_regs, sizeof(fp_regs)); 232 if (error.Fail()) 233 return error; 234 235 // byte_offset is just the offset within FPR, not the whole user area. 236 uint8_t *src = (uint8_t *)&fp_regs + reg_info->byte_offset; 237 assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(fp_regs)); 238 switch (reg_info->byte_size) { 239 case 4: 240 reg_value.SetUInt32(*(uint32_t *)src); 241 break; 242 case 8: 243 reg_value.SetUInt64(*(uint64_t *)src); 244 break; 245 default: 246 assert(false && "Unhandled data size."); 247 return Status("unhandled byte size: %" PRIu32, reg_info->byte_size); 248 } 249 return Status(); 250 } 251 252 if (reg == lldb_last_break_s390x) { 253 uint64_t last_break; 254 Status error = DoReadRegisterSet(NT_S390_LAST_BREAK, &last_break, 8); 255 if (error.Fail()) 256 return error; 257 258 reg_value.SetUInt64(last_break); 259 return Status(); 260 } 261 262 if (reg == lldb_system_call_s390x) { 263 uint32_t system_call; 264 Status error = DoReadRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4); 265 if (error.Fail()) 266 return error; 267 268 reg_value.SetUInt32(system_call); 269 return Status(); 270 } 271 272 return Status("failed - register wasn't recognized"); 273 } 274 275 Status NativeRegisterContextLinux_s390x::WriteRegister( 276 const RegisterInfo *reg_info, const RegisterValue ®_value) { 277 if (!reg_info) 278 return Status("reg_info NULL"); 279 280 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 281 if (reg == LLDB_INVALID_REGNUM) 282 return Status("register \"%s\" is an internal-only lldb register, cannot " 283 "write directly", 284 reg_info->name); 285 286 if (IsGPR(reg)) { 287 s390_regs regs; 288 Status error = DoReadGPR(®s, sizeof(regs)); 289 if (error.Fail()) 290 return error; 291 292 uint8_t *dst = (uint8_t *)®s + reg_info->byte_offset; 293 assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(regs)); 294 switch (reg_info->byte_size) { 295 case 4: 296 *(uint32_t *)dst = reg_value.GetAsUInt32(); 297 break; 298 case 8: 299 *(uint64_t *)dst = reg_value.GetAsUInt64(); 300 break; 301 default: 302 assert(false && "Unhandled data size."); 303 return Status("unhandled byte size: %" PRIu32, reg_info->byte_size); 304 } 305 return DoWriteGPR(®s, sizeof(regs)); 306 } 307 308 if (IsFPR(reg)) { 309 s390_fp_regs fp_regs; 310 Status error = DoReadFPR(&fp_regs, sizeof(fp_regs)); 311 if (error.Fail()) 312 return error; 313 314 // byte_offset is just the offset within fp_regs, not the whole user area. 315 uint8_t *dst = (uint8_t *)&fp_regs + reg_info->byte_offset; 316 assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(fp_regs)); 317 switch (reg_info->byte_size) { 318 case 4: 319 *(uint32_t *)dst = reg_value.GetAsUInt32(); 320 break; 321 case 8: 322 *(uint64_t *)dst = reg_value.GetAsUInt64(); 323 break; 324 default: 325 assert(false && "Unhandled data size."); 326 return Status("unhandled byte size: %" PRIu32, reg_info->byte_size); 327 } 328 return DoWriteFPR(&fp_regs, sizeof(fp_regs)); 329 } 330 331 if (reg == lldb_last_break_s390x) { 332 return Status("The last break address is read-only"); 333 } 334 335 if (reg == lldb_system_call_s390x) { 336 uint32_t system_call = reg_value.GetAsUInt32(); 337 return DoWriteRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4); 338 } 339 340 return Status("failed - register wasn't recognized"); 341 } 342 343 Status NativeRegisterContextLinux_s390x::ReadAllRegisterValues( 344 lldb::DataBufferSP &data_sp) { 345 Status error; 346 347 data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); 348 if (!data_sp) { 349 error.SetErrorStringWithFormat( 350 "failed to allocate DataBufferHeap instance of size %" PRIu64, 351 REG_CONTEXT_SIZE); 352 return error; 353 } 354 355 uint8_t *dst = data_sp->GetBytes(); 356 if (dst == nullptr) { 357 error.SetErrorStringWithFormat("DataBufferHeap instance of size %" PRIu64 358 " returned a null pointer", 359 REG_CONTEXT_SIZE); 360 return error; 361 } 362 363 error = DoReadGPR(dst, sizeof(s390_regs)); 364 dst += sizeof(s390_regs); 365 if (error.Fail()) 366 return error; 367 368 error = DoReadFPR(dst, sizeof(s390_fp_regs)); 369 dst += sizeof(s390_fp_regs); 370 if (error.Fail()) 371 return error; 372 373 // Ignore errors if the regset is unsupported (happens on older kernels). 374 DoReadRegisterSet(NT_S390_SYSTEM_CALL, dst, 4); 375 dst += 4; 376 377 // To enable inferior function calls while the process is stopped in 378 // an interrupted system call, we need to clear the system call flag. 379 // It will be restored to its original value by WriteAllRegisterValues. 380 // Again we ignore error if the regset is unsupported. 381 uint32_t system_call = 0; 382 DoWriteRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4); 383 384 return error; 385 } 386 387 Status NativeRegisterContextLinux_s390x::WriteAllRegisterValues( 388 const lldb::DataBufferSP &data_sp) { 389 Status error; 390 391 if (!data_sp) { 392 error.SetErrorStringWithFormat( 393 "NativeRegisterContextLinux_s390x::%s invalid data_sp provided", 394 __FUNCTION__); 395 return error; 396 } 397 398 if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { 399 error.SetErrorStringWithFormat( 400 "NativeRegisterContextLinux_s390x::%s data_sp contained mismatched " 401 "data size, expected %" PRIu64 ", actual %" PRIu64, 402 __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); 403 return error; 404 } 405 406 uint8_t *src = data_sp->GetBytes(); 407 if (src == nullptr) { 408 error.SetErrorStringWithFormat("NativeRegisterContextLinux_s390x::%s " 409 "DataBuffer::GetBytes() returned a null " 410 "pointer", 411 __FUNCTION__); 412 return error; 413 } 414 415 error = DoWriteGPR(src, sizeof(s390_regs)); 416 src += sizeof(s390_regs); 417 if (error.Fail()) 418 return error; 419 420 error = DoWriteFPR(src, sizeof(s390_fp_regs)); 421 src += sizeof(s390_fp_regs); 422 if (error.Fail()) 423 return error; 424 425 // Ignore errors if the regset is unsupported (happens on older kernels). 426 DoWriteRegisterSet(NT_S390_SYSTEM_CALL, src, 4); 427 src += 4; 428 429 return error; 430 } 431 432 Status NativeRegisterContextLinux_s390x::DoReadRegisterValue( 433 uint32_t offset, const char *reg_name, uint32_t size, 434 RegisterValue &value) { 435 return Status("DoReadRegisterValue unsupported"); 436 } 437 438 Status NativeRegisterContextLinux_s390x::DoWriteRegisterValue( 439 uint32_t offset, const char *reg_name, const RegisterValue &value) { 440 return Status("DoWriteRegisterValue unsupported"); 441 } 442 443 Status NativeRegisterContextLinux_s390x::PeekUserArea(uint32_t offset, 444 void *buf, 445 size_t buf_size) { 446 ptrace_area parea; 447 parea.len = buf_size; 448 parea.process_addr = (addr_t)buf; 449 parea.kernel_addr = offset; 450 451 return NativeProcessLinux::PtraceWrapper(PTRACE_PEEKUSR_AREA, 452 m_thread.GetID(), &parea); 453 } 454 455 Status NativeRegisterContextLinux_s390x::PokeUserArea(uint32_t offset, 456 const void *buf, 457 size_t buf_size) { 458 ptrace_area parea; 459 parea.len = buf_size; 460 parea.process_addr = (addr_t)buf; 461 parea.kernel_addr = offset; 462 463 return NativeProcessLinux::PtraceWrapper(PTRACE_POKEUSR_AREA, 464 m_thread.GetID(), &parea); 465 } 466 467 Status NativeRegisterContextLinux_s390x::DoReadGPR(void *buf, size_t buf_size) { 468 assert(buf_size == sizeof(s390_regs)); 469 return PeekUserArea(offsetof(user_regs_struct, psw), buf, buf_size); 470 } 471 472 Status NativeRegisterContextLinux_s390x::DoWriteGPR(void *buf, 473 size_t buf_size) { 474 assert(buf_size == sizeof(s390_regs)); 475 return PokeUserArea(offsetof(user_regs_struct, psw), buf, buf_size); 476 } 477 478 Status NativeRegisterContextLinux_s390x::DoReadFPR(void *buf, size_t buf_size) { 479 assert(buf_size == sizeof(s390_fp_regs)); 480 return PeekUserArea(offsetof(user_regs_struct, fp_regs), buf, buf_size); 481 } 482 483 Status NativeRegisterContextLinux_s390x::DoWriteFPR(void *buf, 484 size_t buf_size) { 485 assert(buf_size == sizeof(s390_fp_regs)); 486 return PokeUserArea(offsetof(user_regs_struct, fp_regs), buf, buf_size); 487 } 488 489 Status NativeRegisterContextLinux_s390x::DoReadRegisterSet(uint32_t regset, 490 void *buf, 491 size_t buf_size) { 492 struct iovec iov; 493 iov.iov_base = buf; 494 iov.iov_len = buf_size; 495 496 return ReadRegisterSet(&iov, buf_size, regset); 497 } 498 499 Status NativeRegisterContextLinux_s390x::DoWriteRegisterSet(uint32_t regset, 500 const void *buf, 501 size_t buf_size) { 502 struct iovec iov; 503 iov.iov_base = const_cast<void *>(buf); 504 iov.iov_len = buf_size; 505 506 return WriteRegisterSet(&iov, buf_size, regset); 507 } 508 509 Status NativeRegisterContextLinux_s390x::IsWatchpointHit(uint32_t wp_index, 510 bool &is_hit) { 511 per_lowcore_bits per_lowcore; 512 513 if (wp_index >= NumSupportedHardwareWatchpoints()) 514 return Status("Watchpoint index out of range"); 515 516 if (m_watchpoint_addr == LLDB_INVALID_ADDRESS) { 517 is_hit = false; 518 return Status(); 519 } 520 521 Status error = PeekUserArea(offsetof(user_regs_struct, per_info.lowcore), 522 &per_lowcore, sizeof(per_lowcore)); 523 if (error.Fail()) { 524 is_hit = false; 525 return error; 526 } 527 528 is_hit = (per_lowcore.perc_storage_alteration == 1 && 529 per_lowcore.perc_store_real_address == 0); 530 531 if (is_hit) { 532 // Do not report this watchpoint again. 533 memset(&per_lowcore, 0, sizeof(per_lowcore)); 534 PokeUserArea(offsetof(user_regs_struct, per_info.lowcore), &per_lowcore, 535 sizeof(per_lowcore)); 536 } 537 538 return Status(); 539 } 540 541 Status NativeRegisterContextLinux_s390x::GetWatchpointHitIndex( 542 uint32_t &wp_index, lldb::addr_t trap_addr) { 543 uint32_t num_hw_wps = NumSupportedHardwareWatchpoints(); 544 for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) { 545 bool is_hit; 546 Status error = IsWatchpointHit(wp_index, is_hit); 547 if (error.Fail()) { 548 wp_index = LLDB_INVALID_INDEX32; 549 return error; 550 } else if (is_hit) { 551 return error; 552 } 553 } 554 wp_index = LLDB_INVALID_INDEX32; 555 return Status(); 556 } 557 558 Status NativeRegisterContextLinux_s390x::IsWatchpointVacant(uint32_t wp_index, 559 bool &is_vacant) { 560 if (wp_index >= NumSupportedHardwareWatchpoints()) 561 return Status("Watchpoint index out of range"); 562 563 is_vacant = m_watchpoint_addr == LLDB_INVALID_ADDRESS; 564 565 return Status(); 566 } 567 568 bool NativeRegisterContextLinux_s390x::ClearHardwareWatchpoint( 569 uint32_t wp_index) { 570 per_struct per_info; 571 572 if (wp_index >= NumSupportedHardwareWatchpoints()) 573 return false; 574 575 Status error = PeekUserArea(offsetof(user_regs_struct, per_info), &per_info, 576 sizeof(per_info)); 577 if (error.Fail()) 578 return false; 579 580 per_info.control_regs.bits.em_storage_alteration = 0; 581 per_info.control_regs.bits.storage_alt_space_ctl = 0; 582 per_info.starting_addr = 0; 583 per_info.ending_addr = 0; 584 585 error = PokeUserArea(offsetof(user_regs_struct, per_info), &per_info, 586 sizeof(per_info)); 587 if (error.Fail()) 588 return false; 589 590 m_watchpoint_addr = LLDB_INVALID_ADDRESS; 591 return true; 592 } 593 594 Status NativeRegisterContextLinux_s390x::ClearAllHardwareWatchpoints() { 595 if (ClearHardwareWatchpoint(0)) 596 return Status(); 597 return Status("Clearing all hardware watchpoints failed."); 598 } 599 600 uint32_t NativeRegisterContextLinux_s390x::SetHardwareWatchpoint( 601 lldb::addr_t addr, size_t size, uint32_t watch_flags) { 602 per_struct per_info; 603 604 if (watch_flags != 0x1) 605 return LLDB_INVALID_INDEX32; 606 607 if (m_watchpoint_addr != LLDB_INVALID_ADDRESS) 608 return LLDB_INVALID_INDEX32; 609 610 Status error = PeekUserArea(offsetof(user_regs_struct, per_info), &per_info, 611 sizeof(per_info)); 612 if (error.Fail()) 613 return LLDB_INVALID_INDEX32; 614 615 per_info.control_regs.bits.em_storage_alteration = 1; 616 per_info.control_regs.bits.storage_alt_space_ctl = 1; 617 per_info.starting_addr = addr; 618 per_info.ending_addr = addr + size - 1; 619 620 error = PokeUserArea(offsetof(user_regs_struct, per_info), &per_info, 621 sizeof(per_info)); 622 if (error.Fail()) 623 return LLDB_INVALID_INDEX32; 624 625 m_watchpoint_addr = addr; 626 return 0; 627 } 628 629 lldb::addr_t 630 NativeRegisterContextLinux_s390x::GetWatchpointAddress(uint32_t wp_index) { 631 if (wp_index >= NumSupportedHardwareWatchpoints()) 632 return LLDB_INVALID_ADDRESS; 633 return m_watchpoint_addr; 634 } 635 636 uint32_t NativeRegisterContextLinux_s390x::NumSupportedHardwareWatchpoints() { 637 return 1; 638 } 639 640 #endif // defined(__s390x__) && defined(__linux__) 641