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