diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp @@ -499,6 +499,30 @@ return Status("Failed to write register value"); } +enum SavedRegistersKind : uint32_t { + GPR, + SVE, // Used for SVE and SSVE. + FPR, // When there is no SVE, or SVE in FPSIMD mode. + MTE, + TLS, +}; + +static uint8_t *AddSavedRegistersKind(uint8_t *dst, SavedRegistersKind kind) { + *(reinterpret_cast(dst)) = kind; + return dst + sizeof(uint32_t); +} + +static uint8_t *AddSavedRegistersData(uint8_t *dst, void *src, size_t size) { + ::memcpy(dst, src, size); + return dst + size; +} + +static uint8_t *AddSavedRegisters(uint8_t *dst, enum SavedRegistersKind kind, + void *src, size_t size) { + dst = AddSavedRegistersKind(dst, kind); + return AddSavedRegistersData(dst, src, size); +} + Status NativeRegisterContextLinux_arm64::ReadAllRegisterValues( lldb::WritableDataBufferSP &data_sp) { // AArch64 register data must contain GPRs and either FPR or SVE registers. @@ -512,33 +536,33 @@ // corresponds to register sets enabled by current register context. Status error; - uint32_t reg_data_byte_size = GetGPRBufferSize(); + uint32_t reg_data_byte_size = sizeof(SavedRegistersKind) + GetGPRBufferSize(); error = ReadGPR(); if (error.Fail()) return error; // If SVE is enabled we need not copy FPR separately. if (GetRegisterInfo().IsSVEEnabled() || GetRegisterInfo().IsSSVEEnabled()) { - reg_data_byte_size += GetSVEBufferSize(); - // Also store the current SVE mode. - reg_data_byte_size += sizeof(uint32_t); + // Store mode and register data. + reg_data_byte_size += + sizeof(SavedRegistersKind) + sizeof(uint32_t) + GetSVEBufferSize(); error = ReadAllSVE(); } else { - reg_data_byte_size += GetFPRSize(); + reg_data_byte_size += sizeof(SavedRegistersKind) + GetFPRSize(); error = ReadFPR(); } if (error.Fail()) return error; if (GetRegisterInfo().IsMTEEnabled()) { - reg_data_byte_size += GetMTEControlSize(); + reg_data_byte_size += sizeof(SavedRegistersKind) + GetMTEControlSize(); error = ReadMTEControl(); if (error.Fail()) return error; } // tpidr is always present but tpidr2 depends on SME. - reg_data_byte_size += GetTLSBufferSize(); + reg_data_byte_size += sizeof(SavedRegistersKind) + GetTLSBufferSize(); error = ReadTLS(); if (error.Fail()) return error; @@ -546,23 +570,26 @@ data_sp.reset(new DataBufferHeap(reg_data_byte_size, 0)); uint8_t *dst = data_sp->GetBytes(); - ::memcpy(dst, GetGPRBuffer(), GetGPRBufferSize()); - dst += GetGPRBufferSize(); + dst = AddSavedRegisters(dst, SavedRegistersKind::GPR, GetGPRBuffer(), + GetGPRBufferSize()); if (GetRegisterInfo().IsSVEEnabled() || GetRegisterInfo().IsSSVEEnabled()) { - *dst = static_cast(m_sve_state); - dst += sizeof(m_sve_state); - ::memcpy(dst, GetSVEBuffer(), GetSVEBufferSize()); - dst += GetSVEBufferSize(); + dst = AddSavedRegistersKind(dst, SavedRegistersKind::SVE); + *(reinterpret_cast(dst)) = static_cast(m_sve_state); + dst += sizeof(uint32_t); + dst = AddSavedRegistersData(dst, GetSVEBuffer(), GetSVEBufferSize()); } else { - ::memcpy(dst, GetFPRBuffer(), GetFPRSize()); - dst += GetFPRSize(); + dst = AddSavedRegisters(dst, SavedRegistersKind::FPR, GetFPRBuffer(), + GetFPRSize()); } - if (GetRegisterInfo().IsMTEEnabled()) - ::memcpy(dst, GetMTEControl(), GetMTEControlSize()); + if (GetRegisterInfo().IsMTEEnabled()) { + dst = AddSavedRegisters(dst, SavedRegistersKind::MTE, GetMTEControl(), + GetMTEControlSize()); + } - ::memcpy(dst, GetTLSBuffer(), GetTLSBufferSize()); + dst = AddSavedRegisters(dst, SavedRegistersKind::TLS, GetTLSBuffer(), + GetTLSBufferSize()); return error; } @@ -597,7 +624,8 @@ return error; } - uint64_t reg_data_min_size = GetGPRBufferSize() + GetFPRSize(); + uint64_t reg_data_min_size = + GetGPRBufferSize() + GetFPRSize() + 2 * (sizeof(SavedRegistersKind)); if (data_sp->GetByteSize() < reg_data_min_size) { error.SetErrorStringWithFormat( "NativeRegisterContextLinux_arm64::%s data_sp contained insufficient " @@ -606,71 +634,76 @@ return error; } - // Register data starts with GPRs - ::memcpy(GetGPRBuffer(), src, GetGPRBufferSize()); - m_gpr_is_valid = true; - - error = WriteGPR(); - if (error.Fail()) - return error; - - src += GetGPRBufferSize(); + const uint8_t *end = src + data_sp->GetByteSize(); + while (src < end) { + const SavedRegistersKind kind = + *reinterpret_cast(src); + src += sizeof(SavedRegistersKind); - // Verify if register data may contain SVE register values. - bool contains_sve_reg_data = - (data_sp->GetByteSize() > (reg_data_min_size + GetSVEHeaderSize())); + switch (kind) { + case SavedRegistersKind::GPR: + ::memcpy(GetGPRBuffer(), src, GetGPRBufferSize()); + m_gpr_is_valid = true; - if (contains_sve_reg_data) { - // Restore to the correct mode, streaming or not. - m_sve_state = static_cast(*src); - src += sizeof(m_sve_state); + error = WriteGPR(); + if (error.Fail()) + return error; - // We have SVE register data first write SVE header. - ::memcpy(GetSVEHeader(), src, GetSVEHeaderSize()); - if (!sve::vl_valid(m_sve_header.vl)) { - m_sve_header_is_valid = false; - error.SetErrorStringWithFormat("NativeRegisterContextLinux_arm64::%s " - "Invalid SVE header in data_sp", - __FUNCTION__); - return error; - } - m_sve_header_is_valid = true; - error = WriteSVEHeader(); - if (error.Fail()) - return error; + src += GetGPRBufferSize(); + + break; + case SavedRegistersKind::SVE: + // Restore to the correct mode, streaming or not. + m_sve_state = static_cast(*src); + src += sizeof(m_sve_state); + + // First write SVE header. + ::memcpy(GetSVEHeader(), src, GetSVEHeaderSize()); + if (!sve::vl_valid(m_sve_header.vl)) { + m_sve_header_is_valid = false; + error.SetErrorStringWithFormat("NativeRegisterContextLinux_arm64::%s " + "Invalid SVE header in data_sp", + __FUNCTION__); + return error; + } + m_sve_header_is_valid = true; + error = WriteSVEHeader(); + if (error.Fail()) + return error; - // SVE header has been written configure SVE vector length if needed. - ConfigureRegisterContext(); + // SVE header has been written configure SVE vector length if needed. + ConfigureRegisterContext(); - // Make sure data_sp contains sufficient data to write all SVE registers. - reg_data_min_size = GetGPRBufferSize() + GetSVEBufferSize(); - if (data_sp->GetByteSize() < reg_data_min_size) { - error.SetErrorStringWithFormat( - "NativeRegisterContextLinux_arm64::%s data_sp contained insufficient " - "register data bytes, expected %" PRIu64 ", actual %" PRIu64, - __FUNCTION__, reg_data_min_size, data_sp->GetByteSize()); - return error; - } + ::memcpy(GetSVEBuffer(), src, GetSVEBufferSize()); + m_sve_buffer_is_valid = true; + error = WriteAllSVE(); + if (error.Fail()) + return error; + src += GetSVEBufferSize(); - ::memcpy(GetSVEBuffer(), src, GetSVEBufferSize()); - m_sve_buffer_is_valid = true; - error = WriteAllSVE(); - src += GetSVEBufferSize(); - } else { - ::memcpy(GetFPRBuffer(), src, GetFPRSize()); - m_fpu_is_valid = true; - error = WriteFPR(); - src += GetFPRSize(); - } + break; + case SavedRegistersKind::FPR: + m_fpu_is_valid = true; + error = WriteFPR(); + if (error.Fail()) + return error; + src += GetFPRSize(); - if (error.Fail()) - return error; + break; + case SavedRegistersKind::MTE: + ::memcpy(GetMTEControl(), src, GetMTEControlSize()); + m_mte_ctrl_is_valid = true; + error = WriteMTEControl(); + if (error.Fail()) + return error; + src += GetMTEControlSize(); - if (GetRegisterInfo().IsMTEEnabled() && - data_sp->GetByteSize() > reg_data_min_size) { - ::memcpy(GetMTEControl(), src, GetMTEControlSize()); - m_mte_ctrl_is_valid = true; - error = WriteMTEControl(); + break; + case SavedRegistersKind::TLS: + // FIXME: Will be fixed by a follow up patch. + src += GetTLSBufferSize(); + break; + } } return error;