46
46
#define HWCAP_PACA (1 << 30 )
47
47
#define HWCAP2_MTE (1 << 18 )
48
48
49
- #define REG_CONTEXT_SIZE (GetGPRSize() + GetFPRSize())
50
-
51
49
using namespace lldb ;
52
50
using namespace lldb_private ;
53
51
using namespace lldb_private ::process_linux;
@@ -452,45 +450,80 @@ Status NativeRegisterContextLinux_arm64::WriteRegister(
452
450
453
451
Status NativeRegisterContextLinux_arm64::ReadAllRegisterValues (
454
452
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.
456
456
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.
458
461
462
+ Status error;
463
+ uint32_t reg_data_byte_size = GetGPRBufferSize ();
459
464
error = ReadGPR ();
460
465
if (error.Fail ())
461
466
return error;
462
467
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
+ }
464
476
if (error.Fail ())
465
477
return error;
466
478
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 ));
467
487
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());
471
502
472
503
return error;
473
504
}
474
505
475
506
Status NativeRegisterContextLinux_arm64::WriteAllRegisterValues (
476
507
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.
478
518
519
+ Status error;
479
520
if (!data_sp) {
480
521
error.SetErrorStringWithFormat (
481
- " NativeRegisterContextLinux_x86_64 ::%s invalid data_sp provided" ,
522
+ " NativeRegisterContextLinux_arm64 ::%s invalid data_sp provided" ,
482
523
__FUNCTION__);
483
524
return error;
484
525
}
485
526
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
-
494
527
uint8_t *src = data_sp->GetBytes ();
495
528
if (src == nullptr ) {
496
529
error.SetErrorStringWithFormat (" NativeRegisterContextLinux_x86_64::%s "
@@ -499,19 +532,79 @@ Status NativeRegisterContextLinux_arm64::WriteAllRegisterValues(
499
532
__FUNCTION__);
500
533
return error;
501
534
}
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 ;
503
548
504
549
error = WriteGPR ();
505
550
if (error.Fail ())
506
551
return error;
507
552
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
+ }
510
597
511
- error = WriteFPR ();
512
598
if (error.Fail ())
513
599
return error;
514
600
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
+
515
608
return error;
516
609
}
517
610
@@ -864,13 +957,6 @@ uint32_t NativeRegisterContextLinux_arm64::CalculateSVEOffset(
864
957
return sve_reg_offset;
865
958
}
866
959
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
-
874
960
std::vector<uint32_t > NativeRegisterContextLinux_arm64::GetExpeditedRegisters (
875
961
ExpeditedRegs expType) const {
876
962
std::vector<uint32_t > expedited_reg_nums =
0 commit comments