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