@@ -499,76 +499,119 @@ Status NativeRegisterContextLinux_arm64::WriteRegister(
499499 return Status (" Failed to write register value" );
500500}
501501
502- Status NativeRegisterContextLinux_arm64::ReadAllRegisterValues (
503- lldb::WritableDataBufferSP &data_sp) {
504- // AArch64 register data must contain GPRs and either FPR or SVE registers.
505- // SVE registers can be non-streaming (aka SVE) or streaming (aka SSVE).
506- // Finally an optional MTE register. Pointer Authentication (PAC) registers
507- // are read-only and will be skipped.
502+ enum RegisterSetType : uint32_t {
503+ GPR,
504+ SVE, // Used for SVE and SSVE.
505+ FPR, // When there is no SVE, or SVE in FPSIMD mode.
506+ MTE,
507+ TLS,
508+ };
509+
510+ static uint8_t *AddRegisterSetType (uint8_t *dst,
511+ RegisterSetType register_set_type) {
512+ *(reinterpret_cast <uint32_t *>(dst)) = register_set_type;
513+ return dst + sizeof (uint32_t );
514+ }
508515
509- // In order to create register data checkpoint we first read all register
510- // values if not done already and calculate total size of register set data.
511- // We store all register values in data_sp by copying full PTrace data that
512- // corresponds to register sets enabled by current register context.
516+ static uint8_t * AddSavedRegistersData ( uint8_t *dst, void *src, size_t size) {
517+ ::memcpy (dst, src, size);
518+ return dst + size;
519+ }
513520
521+ static uint8_t *AddSavedRegisters (uint8_t *dst,
522+ enum RegisterSetType register_set_type,
523+ void *src, size_t size) {
524+ dst = AddRegisterSetType (dst, register_set_type);
525+ return AddSavedRegistersData (dst, src, size);
526+ }
527+
528+ Status
529+ NativeRegisterContextLinux_arm64::CacheAllRegisters (uint32_t &cached_size) {
514530 Status error;
515- uint32_t reg_data_byte_size = GetGPRBufferSize ();
531+ cached_size = sizeof (RegisterSetType) + GetGPRBufferSize ();
516532 error = ReadGPR ();
517533 if (error.Fail ())
518534 return error;
519535
520536 // If SVE is enabled we need not copy FPR separately.
521537 if (GetRegisterInfo ().IsSVEEnabled () || GetRegisterInfo ().IsSSVEEnabled ()) {
522- reg_data_byte_size += GetSVEBufferSize ();
523- // Also store the current SVE mode.
524- reg_data_byte_size += sizeof (uint32_t );
538+ // Store mode and register data.
539+ cached_size +=
540+ sizeof (RegisterSetType) + sizeof (m_sve_state) + GetSVEBufferSize ( );
525541 error = ReadAllSVE ();
526542 } else {
527- reg_data_byte_size += GetFPRSize ();
543+ cached_size += sizeof (RegisterSetType) + GetFPRSize ();
528544 error = ReadFPR ();
529545 }
530546 if (error.Fail ())
531547 return error;
532548
533549 if (GetRegisterInfo ().IsMTEEnabled ()) {
534- reg_data_byte_size += GetMTEControlSize ();
550+ cached_size += sizeof (RegisterSetType) + GetMTEControlSize ();
535551 error = ReadMTEControl ();
536552 if (error.Fail ())
537553 return error;
538554 }
539555
540556 // tpidr is always present but tpidr2 depends on SME.
541- reg_data_byte_size += GetTLSBufferSize ();
557+ cached_size += sizeof (RegisterSetType) + GetTLSBufferSize ();
542558 error = ReadTLS ();
559+
560+ return error;
561+ }
562+
563+ Status NativeRegisterContextLinux_arm64::ReadAllRegisterValues (
564+ lldb::WritableDataBufferSP &data_sp) {
565+ // AArch64 register data must contain GPRs and either FPR or SVE registers.
566+ // SVE registers can be non-streaming (aka SVE) or streaming (aka SSVE).
567+ // Finally an optional MTE register. Pointer Authentication (PAC) registers
568+ // are read-only and will be skipped.
569+
570+ // In order to create register data checkpoint we first read all register
571+ // values if not done already and calculate total size of register set data.
572+ // We store all register values in data_sp by copying full PTrace data that
573+ // corresponds to register sets enabled by current register context.
574+
575+ uint32_t reg_data_byte_size = 0 ;
576+ Status error = CacheAllRegisters (reg_data_byte_size);
543577 if (error.Fail ())
544578 return error;
545579
546580 data_sp.reset (new DataBufferHeap (reg_data_byte_size, 0 ));
547581 uint8_t *dst = data_sp->GetBytes ();
548582
549- ::memcpy (dst, GetGPRBuffer(), GetGPRBufferSize());
550- dst += GetGPRBufferSize ();
583+ dst = AddSavedRegisters (dst, RegisterSetType::GPR, GetGPRBuffer (),
584+ GetGPRBufferSize () );
551585
552586 if (GetRegisterInfo ().IsSVEEnabled () || GetRegisterInfo ().IsSSVEEnabled ()) {
553- *dst = static_cast <uint8_t >(m_sve_state);
587+ dst = AddRegisterSetType (dst, RegisterSetType::SVE);
588+ *(reinterpret_cast <SVEState *>(dst)) = m_sve_state;
554589 dst += sizeof (m_sve_state);
555- ::memcpy (dst, GetSVEBuffer(), GetSVEBufferSize());
556- dst += GetSVEBufferSize ();
590+ dst = AddSavedRegistersData (dst, GetSVEBuffer (), GetSVEBufferSize ());
557591 } else {
558- ::memcpy (dst, GetFPRBuffer(), GetFPRSize());
559- dst += GetFPRSize ();
592+ dst = AddSavedRegisters (dst, RegisterSetType::FPR, GetFPRBuffer (),
593+ GetFPRSize () );
560594 }
561595
562596 if (GetRegisterInfo ().IsMTEEnabled ()) {
563- ::memcpy (dst, GetMTEControl(), GetMTEControlSize());
564- dst += GetMTEControlSize ();
597+ dst = AddSavedRegisters (dst, RegisterSetType::MTE, GetMTEControl (),
598+ GetMTEControlSize () );
565599 }
566600
567- ::memcpy (dst, GetTLSBuffer(), GetTLSBufferSize());
601+ dst = AddSavedRegisters (dst, RegisterSetType::TLS, GetTLSBuffer (),
602+ GetTLSBufferSize ());
568603
569604 return error;
570605}
571606
607+ static Status RestoreRegisters (void *buffer, const uint8_t **src, size_t len,
608+ bool &is_valid, std::function<Status()> writer) {
609+ ::memcpy (buffer, *src, len);
610+ is_valid = true ;
611+ *src += len;
612+ return writer ();
613+ }
614+
572615Status NativeRegisterContextLinux_arm64::WriteAllRegisterValues (
573616 const lldb::DataBufferSP &data_sp) {
574617 // AArch64 register data must contain GPRs, either FPR or SVE registers
@@ -599,7 +642,8 @@ Status NativeRegisterContextLinux_arm64::WriteAllRegisterValues(
599642 return error;
600643 }
601644
602- uint64_t reg_data_min_size = GetGPRBufferSize () + GetFPRSize ();
645+ uint64_t reg_data_min_size =
646+ GetGPRBufferSize () + GetFPRSize () + 2 * (sizeof (RegisterSetType));
603647 if (data_sp->GetByteSize () < reg_data_min_size) {
604648 error.SetErrorStringWithFormat (
605649 " NativeRegisterContextLinux_arm64::%s data_sp contained insufficient "
@@ -608,82 +652,67 @@ Status NativeRegisterContextLinux_arm64::WriteAllRegisterValues(
608652 return error;
609653 }
610654
611- // Register data starts with GPRs
612- ::memcpy (GetGPRBuffer(), src, GetGPRBufferSize());
613- m_gpr_is_valid = true ;
614-
615- error = WriteGPR ();
616- if (error.Fail ())
617- return error;
618-
619- src += GetGPRBufferSize ();
620-
621- // Verify if register data may contain SVE register values.
622- bool contains_sve_reg_data =
623- (data_sp->GetByteSize () > (reg_data_min_size + GetSVEHeaderSize ()));
624-
625- if (contains_sve_reg_data) {
626- // Restore to the correct mode, streaming or not.
627- m_sve_state = static_cast <SVEState>(*src);
628- src += sizeof (m_sve_state);
629-
630- // We have SVE register data first write SVE header.
631- ::memcpy (GetSVEHeader(), src, GetSVEHeaderSize());
632- if (!sve::vl_valid (m_sve_header.vl )) {
633- m_sve_header_is_valid = false ;
634- error.SetErrorStringWithFormat (" NativeRegisterContextLinux_arm64::%s "
635- " Invalid SVE header in data_sp" ,
636- __FUNCTION__);
637- return error;
638- }
639- m_sve_header_is_valid = true ;
640- error = WriteSVEHeader ();
641- if (error.Fail ())
642- return error;
643-
644- // SVE header has been written configure SVE vector length if needed.
645- ConfigureRegisterContext ();
655+ const uint8_t *end = src + data_sp->GetByteSize ();
656+ while (src < end) {
657+ const RegisterSetType kind =
658+ *reinterpret_cast <const RegisterSetType *>(src);
659+ src += sizeof (RegisterSetType);
660+
661+ switch (kind) {
662+ case RegisterSetType::GPR:
663+ error = RestoreRegisters (
664+ GetGPRBuffer (), &src, GetGPRBufferSize (), m_gpr_is_valid,
665+ std::bind (&NativeRegisterContextLinux_arm64::WriteGPR, this ));
666+ break ;
667+ case RegisterSetType::SVE:
668+ // Restore to the correct mode, streaming or not.
669+ m_sve_state = static_cast <SVEState>(*src);
670+ src += sizeof (m_sve_state);
671+
672+ // First write SVE header. We do not use RestoreRegisters because we do
673+ // not want src to be modified yet.
674+ ::memcpy (GetSVEHeader(), src, GetSVEHeaderSize());
675+ if (!sve::vl_valid (m_sve_header.vl )) {
676+ m_sve_header_is_valid = false ;
677+ error.SetErrorStringWithFormat (" NativeRegisterContextLinux_arm64::%s "
678+ " Invalid SVE header in data_sp" ,
679+ __FUNCTION__);
680+ return error;
681+ }
682+ m_sve_header_is_valid = true ;
683+ error = WriteSVEHeader ();
684+ if (error.Fail ())
685+ return error;
646686
647- // Make sure data_sp contains sufficient data to write all SVE registers.
648- reg_data_min_size = GetGPRBufferSize () + GetSVEBufferSize ();
649- if (data_sp->GetByteSize () < reg_data_min_size) {
650- error.SetErrorStringWithFormat (
651- " NativeRegisterContextLinux_arm64::%s data_sp contained insufficient "
652- " register data bytes, expected %" PRIu64 " , actual %" PRIu64,
653- __FUNCTION__, reg_data_min_size, data_sp->GetByteSize ());
654- return error;
687+ // SVE header has been written configure SVE vector length if needed.
688+ ConfigureRegisterContext ();
689+
690+ // Write header and register data, incrementing src this time.
691+ error = RestoreRegisters (
692+ GetSVEBuffer (), &src, GetSVEBufferSize (), m_sve_buffer_is_valid,
693+ std::bind (&NativeRegisterContextLinux_arm64::WriteAllSVE, this ));
694+ break ;
695+ case RegisterSetType::FPR:
696+ error = RestoreRegisters (
697+ GetFPRBuffer (), &src, GetFPRSize (), m_fpu_is_valid,
698+ std::bind (&NativeRegisterContextLinux_arm64::WriteFPR, this ));
699+ break ;
700+ case RegisterSetType::MTE:
701+ error = RestoreRegisters (
702+ GetMTEControl (), &src, GetMTEControlSize (), m_mte_ctrl_is_valid,
703+ std::bind (&NativeRegisterContextLinux_arm64::WriteMTEControl, this ));
704+ break ;
705+ case RegisterSetType::TLS:
706+ error = RestoreRegisters (
707+ GetTLSBuffer (), &src, GetTLSBufferSize (), m_tls_is_valid,
708+ std::bind (&NativeRegisterContextLinux_arm64::WriteTLS, this ));
709+ break ;
655710 }
656711
657- ::memcpy (GetSVEBuffer(), src, GetSVEBufferSize());
658- m_sve_buffer_is_valid = true ;
659- error = WriteAllSVE ();
660- src += GetSVEBufferSize ();
661- } else {
662- ::memcpy (GetFPRBuffer(), src, GetFPRSize());
663- m_fpu_is_valid = true ;
664- error = WriteFPR ();
665- src += GetFPRSize ();
666- }
667-
668- if (error.Fail ())
669- return error;
670-
671- if (GetRegisterInfo ().IsMTEEnabled () &&
672- data_sp->GetByteSize () > reg_data_min_size) {
673- ::memcpy (GetMTEControl(), src, GetMTEControlSize());
674- m_mte_ctrl_is_valid = true ;
675- error = WriteMTEControl ();
676712 if (error.Fail ())
677713 return error;
678- src += GetMTEControlSize ();
679714 }
680715
681- // There is always a TLS set. It changes size based on system properties, it's
682- // not something an expression can change.
683- ::memcpy (GetTLSBuffer(), src, GetTLSBufferSize());
684- m_tls_is_valid = true ;
685- error = WriteTLS ();
686-
687716 return error;
688717}
689718
0 commit comments