4646#define HWCAP_PACA (1 << 30 )
4747#define HWCAP2_MTE (1 << 18 )
4848
49- #define REG_CONTEXT_SIZE (GetGPRSize() + GetFPRSize())
50-
5149using namespace lldb ;
5250using namespace lldb_private ;
5351using namespace lldb_private ::process_linux;
@@ -452,45 +450,80 @@ Status NativeRegisterContextLinux_arm64::WriteRegister(
452450
453451Status NativeRegisterContextLinux_arm64::ReadAllRegisterValues (
454452 lldb::DataBufferSP &data_sp) {
455- Status error;
453+ // AArch64 register data must contain GPRs, either FPR or SVE registers
454+ // and optional MTE register. Pointer Authentication (PAC) registers are
455+ // read-only and will be skiped.
456456
457- data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0 ));
457+ // In order to create register data checkpoint we first read all register
458+ // values if not done already and calculate total size of register set data.
459+ // We store all register values in data_sp by copying full PTrace data that
460+ // corresponds to register sets enabled by current register context.
458461
462+ Status error;
463+ uint32_t reg_data_byte_size = GetGPRBufferSize ();
459464 error = ReadGPR ();
460465 if (error.Fail ())
461466 return error;
462467
463- error = ReadFPR ();
468+ // If SVE is enabled we need not copy FPR separately.
469+ if (GetRegisterInfo ().IsSVEEnabled ()) {
470+ reg_data_byte_size += GetSVEBufferSize ();
471+ error = ReadAllSVE ();
472+ } else {
473+ reg_data_byte_size += GetFPRSize ();
474+ error = ReadFPR ();
475+ }
464476 if (error.Fail ())
465477 return error;
466478
479+ if (GetRegisterInfo ().IsMTEEnabled ()) {
480+ reg_data_byte_size += GetMTEControlSize ();
481+ error = ReadMTEControl ();
482+ if (error.Fail ())
483+ return error;
484+ }
485+
486+ data_sp.reset (new DataBufferHeap (reg_data_byte_size, 0 ));
467487 uint8_t *dst = data_sp->GetBytes ();
468- ::memcpy (dst, GetGPRBuffer(), GetGPRSize());
469- dst += GetGPRSize ();
470- ::memcpy (dst, GetFPRBuffer(), GetFPRSize());
488+
489+ ::memcpy (dst, GetGPRBuffer(), GetGPRBufferSize());
490+ dst += GetGPRBufferSize ();
491+
492+ if (GetRegisterInfo ().IsSVEEnabled ()) {
493+ ::memcpy (dst, GetSVEBuffer(), GetSVEBufferSize());
494+ dst += GetSVEBufferSize ();
495+ } else {
496+ ::memcpy (dst, GetFPRBuffer(), GetFPRSize());
497+ dst += GetFPRSize ();
498+ }
499+
500+ if (GetRegisterInfo ().IsMTEEnabled ())
501+ ::memcpy (dst, GetMTEControl(), GetMTEControlSize());
471502
472503 return error;
473504}
474505
475506Status NativeRegisterContextLinux_arm64::WriteAllRegisterValues (
476507 const lldb::DataBufferSP &data_sp) {
477- Status error;
508+ // AArch64 register data must contain GPRs, either FPR or SVE registers
509+ // and optional MTE register. Pointer Authentication (PAC) registers are
510+ // read-only and will be skiped.
511+
512+ // We store all register values in data_sp by copying full PTrace data that
513+ // corresponds to register sets enabled by current register context. In order
514+ // to restore from register data checkpoint we will first restore GPRs, based
515+ // on size of remaining register data either SVE or FPRs should be restored
516+ // next. SVE is not enabled if we have register data size less than or equal
517+ // to size of GPR + FPR + MTE.
478518
519+ Status error;
479520 if (!data_sp) {
480521 error.SetErrorStringWithFormat (
481- " NativeRegisterContextLinux_x86_64 ::%s invalid data_sp provided" ,
522+ " NativeRegisterContextLinux_arm64 ::%s invalid data_sp provided" ,
482523 __FUNCTION__);
483524 return error;
484525 }
485526
486- if (data_sp->GetByteSize () != REG_CONTEXT_SIZE) {
487- error.SetErrorStringWithFormat (
488- " NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched "
489- " data size, expected %" PRIu64 " , actual %" PRIu64,
490- __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize ());
491- return error;
492- }
493-
494527 uint8_t *src = data_sp->GetBytes ();
495528 if (src == nullptr ) {
496529 error.SetErrorStringWithFormat (" NativeRegisterContextLinux_x86_64::%s "
@@ -499,19 +532,79 @@ Status NativeRegisterContextLinux_arm64::WriteAllRegisterValues(
499532 __FUNCTION__);
500533 return error;
501534 }
502- ::memcpy (GetGPRBuffer(), src, GetRegisterInfoInterface().GetGPRSize());
535+
536+ uint64_t reg_data_min_size = GetGPRBufferSize () + GetFPRSize ();
537+ if (data_sp->GetByteSize () < reg_data_min_size) {
538+ error.SetErrorStringWithFormat (
539+ " NativeRegisterContextLinux_arm64::%s data_sp contained insufficient "
540+ " register data bytes, expected at least %" PRIu64 " , actual %" PRIu64,
541+ __FUNCTION__, reg_data_min_size, data_sp->GetByteSize ());
542+ return error;
543+ }
544+
545+ // Register data starts with GPRs
546+ ::memcpy (GetGPRBuffer(), src, GetGPRBufferSize());
547+ m_gpr_is_valid = true ;
503548
504549 error = WriteGPR ();
505550 if (error.Fail ())
506551 return error;
507552
508- src += GetRegisterInfoInterface ().GetGPRSize ();
509- ::memcpy (GetFPRBuffer(), src, GetFPRSize());
553+ src += GetGPRBufferSize ();
554+
555+ // Verify if register data may contain SVE register values.
556+ bool contains_sve_reg_data =
557+ (data_sp->GetByteSize () > (reg_data_min_size + GetSVEHeaderSize ()));
558+
559+ if (contains_sve_reg_data) {
560+ // We have SVE register data first write SVE header.
561+ ::memcpy (GetSVEHeader(), src, GetSVEHeaderSize());
562+ if (!sve_vl_valid (m_sve_header.vl )) {
563+ m_sve_header_is_valid = false ;
564+ error.SetErrorStringWithFormat (" NativeRegisterContextLinux_arm64::%s "
565+ " Invalid SVE header in data_sp" ,
566+ __FUNCTION__);
567+ return error;
568+ }
569+ m_sve_header_is_valid = true ;
570+ error = WriteSVEHeader ();
571+ if (error.Fail ())
572+ return error;
573+
574+ // SVE header has been written configure SVE vector length if needed.
575+ ConfigureRegisterContext ();
576+
577+ // Make sure data_sp contains sufficient data to write all SVE registers.
578+ reg_data_min_size = GetGPRBufferSize () + GetSVEBufferSize ();
579+ if (data_sp->GetByteSize () < reg_data_min_size) {
580+ error.SetErrorStringWithFormat (
581+ " NativeRegisterContextLinux_arm64::%s data_sp contained insufficient "
582+ " register data bytes, expected %" PRIu64 " , actual %" PRIu64,
583+ __FUNCTION__, reg_data_min_size, data_sp->GetByteSize ());
584+ return error;
585+ }
586+
587+ ::memcpy (GetSVEBuffer(), src, GetSVEBufferSize());
588+ m_sve_buffer_is_valid = true ;
589+ error = WriteAllSVE ();
590+ src += GetSVEBufferSize ();
591+ } else {
592+ ::memcpy (GetFPRBuffer(), src, GetFPRSize());
593+ m_fpu_is_valid = true ;
594+ error = WriteFPR ();
595+ src += GetFPRSize ();
596+ }
510597
511- error = WriteFPR ();
512598 if (error.Fail ())
513599 return error;
514600
601+ if (GetRegisterInfo ().IsMTEEnabled () &&
602+ data_sp->GetByteSize () > reg_data_min_size) {
603+ ::memcpy (GetMTEControl(), src, GetMTEControlSize());
604+ m_mte_ctrl_is_valid = true ;
605+ error = WriteMTEControl ();
606+ }
607+
515608 return error;
516609}
517610
@@ -864,13 +957,6 @@ uint32_t NativeRegisterContextLinux_arm64::CalculateSVEOffset(
864957 return sve_reg_offset;
865958}
866959
867- void *NativeRegisterContextLinux_arm64::GetSVEBuffer () {
868- if (m_sve_state == SVEState::FPSIMD)
869- return m_sve_ptrace_payload.data () + sve::ptrace_fpsimd_offset;
870-
871- return m_sve_ptrace_payload.data ();
872- }
873-
874960std::vector<uint32_t > NativeRegisterContextLinux_arm64::GetExpeditedRegisters (
875961 ExpeditedRegs expType) const {
876962 std::vector<uint32_t > expedited_reg_nums =
0 commit comments