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