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