1 //===-- NativeRegisterContextLinux_arm64.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(__arm64__) || defined(__aarch64__)
10 
11 #include "NativeRegisterContextLinux_arm.h"
12 #include "NativeRegisterContextLinux_arm64.h"
13 
14 
15 #include "lldb/Host/common/NativeProcessProtocol.h"
16 #include "lldb/Utility/DataBufferHeap.h"
17 #include "lldb/Utility/Log.h"
18 #include "lldb/Utility/RegisterValue.h"
19 #include "lldb/Utility/Status.h"
20 
21 #include "Plugins/Process/Linux/NativeProcessLinux.h"
22 #include "Plugins/Process/Linux/Procfs.h"
23 #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
24 #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
25 
26 // System includes - They have to be included after framework includes because
27 // they define some macros which collide with variable names in other modules
28 #include <sys/socket.h>
29 // NT_PRSTATUS and NT_FPREGSET definition
30 #include <elf.h>
31 
32 #ifndef NT_ARM_SVE
33 #define NT_ARM_SVE 0x405 /* ARM Scalable Vector Extension */
34 #endif
35 
36 #define REG_CONTEXT_SIZE (GetGPRSize() + GetFPRSize())
37 
38 using namespace lldb;
39 using namespace lldb_private;
40 using namespace lldb_private::process_linux;
41 
42 std::unique_ptr<NativeRegisterContextLinux>
43 NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(
44     const ArchSpec &target_arch, NativeThreadLinux &native_thread) {
45   switch (target_arch.GetMachine()) {
46   case llvm::Triple::arm:
47     return std::make_unique<NativeRegisterContextLinux_arm>(target_arch,
48                                                              native_thread);
49   case llvm::Triple::aarch64: {
50     // Configure register sets supported by this AArch64 target.
51     // Read SVE header to check for SVE support.
52     struct user_sve_header sve_header;
53     struct iovec ioVec;
54     ioVec.iov_base = &sve_header;
55     ioVec.iov_len = sizeof(sve_header);
56     unsigned int regset = NT_ARM_SVE;
57 
58     Flags opt_regsets;
59     if (NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET,
60                                           native_thread.GetID(), &regset,
61                                           &ioVec, sizeof(sve_header))
62             .Success())
63       opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskSVE);
64 
65     auto register_info_up =
66         std::make_unique<RegisterInfoPOSIX_arm64>(target_arch, opt_regsets);
67     return std::make_unique<NativeRegisterContextLinux_arm64>(
68         target_arch, native_thread, std::move(register_info_up));
69   }
70   default:
71     llvm_unreachable("have no register context for architecture");
72   }
73 }
74 
75 NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64(
76     const ArchSpec &target_arch, NativeThreadProtocol &native_thread,
77     std::unique_ptr<RegisterInfoPOSIX_arm64> register_info_up)
78     : NativeRegisterContextRegisterInfo(native_thread,
79                                         register_info_up.release()),
80       NativeRegisterContextLinux(native_thread) {
81   ::memset(&m_fpr, 0, sizeof(m_fpr));
82   ::memset(&m_gpr_arm64, 0, sizeof(m_gpr_arm64));
83   ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs));
84   ::memset(&m_hbp_regs, 0, sizeof(m_hbp_regs));
85   ::memset(&m_sve_header, 0, sizeof(m_sve_header));
86 
87   // 16 is just a maximum value, query hardware for actual watchpoint count
88   m_max_hwp_supported = 16;
89   m_max_hbp_supported = 16;
90 
91   m_refresh_hwdebug_info = true;
92 
93   m_gpr_is_valid = false;
94   m_fpu_is_valid = false;
95   m_sve_buffer_is_valid = false;
96   m_sve_header_is_valid = false;
97 
98   if (GetRegisterInfo().IsSVEEnabled())
99     m_sve_state = SVEState::Unknown;
100   else
101     m_sve_state = SVEState::Disabled;
102 }
103 
104 RegisterInfoPOSIX_arm64 &
105 NativeRegisterContextLinux_arm64::GetRegisterInfo() const {
106   return static_cast<RegisterInfoPOSIX_arm64 &>(*m_register_info_interface_up);
107 }
108 
109 uint32_t NativeRegisterContextLinux_arm64::GetRegisterSetCount() const {
110   return GetRegisterInfo().GetRegisterSetCount();
111 }
112 
113 const RegisterSet *
114 NativeRegisterContextLinux_arm64::GetRegisterSet(uint32_t set_index) const {
115   return GetRegisterInfo().GetRegisterSet(set_index);
116 }
117 
118 uint32_t NativeRegisterContextLinux_arm64::GetUserRegisterCount() const {
119   uint32_t count = 0;
120   for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index)
121     count += GetRegisterSet(set_index)->num_registers;
122   return count;
123 }
124 
125 Status
126 NativeRegisterContextLinux_arm64::ReadRegister(const RegisterInfo *reg_info,
127                                                RegisterValue &reg_value) {
128   Status error;
129 
130   if (!reg_info) {
131     error.SetErrorString("reg_info NULL");
132     return error;
133   }
134 
135   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
136 
137   if (reg == LLDB_INVALID_REGNUM)
138     return Status("no lldb regnum for %s", reg_info && reg_info->name
139                                                ? reg_info->name
140                                                : "<unknown register>");
141 
142   uint8_t *src;
143   uint32_t offset = LLDB_INVALID_INDEX32;
144   uint64_t sve_vg;
145   std::vector<uint8_t> sve_reg_non_live;
146 
147   if (IsGPR(reg)) {
148     error = ReadGPR();
149     if (error.Fail())
150       return error;
151 
152     offset = reg_info->byte_offset;
153     assert(offset < GetGPRSize());
154     src = (uint8_t *)GetGPRBuffer() + offset;
155 
156   } else if (IsFPR(reg)) {
157     if (m_sve_state == SVEState::Disabled) {
158       // SVE is disabled take legacy route for FPU register access
159       error = ReadFPR();
160       if (error.Fail())
161         return error;
162 
163       offset = CalculateFprOffset(reg_info);
164       assert(offset < GetFPRSize());
165       src = (uint8_t *)GetFPRBuffer() + offset;
166     } else {
167       // SVE enabled, we will read and cache SVE ptrace data
168       error = ReadAllSVE();
169       if (error.Fail())
170         return error;
171 
172       // FPSR and FPCR will be located right after Z registers in
173       // SVEState::FPSIMD while in SVEState::Full they will be located at the
174       // end of register data after an alignment correction based on currently
175       // selected vector length.
176       uint32_t sve_reg_num = LLDB_INVALID_REGNUM;
177       if (reg == GetRegisterInfo().GetRegNumFPSR()) {
178         sve_reg_num = reg;
179         if (m_sve_state == SVEState::Full)
180           offset = SVE_PT_SVE_FPSR_OFFSET(sve_vq_from_vl(m_sve_header.vl));
181         else if (m_sve_state == SVEState::FPSIMD)
182           offset = SVE_PT_FPSIMD_OFFSET + (32 * 16);
183       } else if (reg == GetRegisterInfo().GetRegNumFPCR()) {
184         sve_reg_num = reg;
185         if (m_sve_state == SVEState::Full)
186           offset = SVE_PT_SVE_FPCR_OFFSET(sve_vq_from_vl(m_sve_header.vl));
187         else if (m_sve_state == SVEState::FPSIMD)
188           offset = SVE_PT_FPSIMD_OFFSET + (32 * 16) + 4;
189       } else {
190         // Extract SVE Z register value register number for this reg_info
191         if (reg_info->value_regs &&
192             reg_info->value_regs[0] != LLDB_INVALID_REGNUM)
193           sve_reg_num = reg_info->value_regs[0];
194         offset = CalculateSVEOffset(GetRegisterInfoAtIndex(sve_reg_num));
195       }
196 
197       assert(offset < GetSVEBufferSize());
198       src = (uint8_t *)GetSVEBuffer() + offset;
199     }
200   } else if (IsSVE(reg)) {
201 
202     if (m_sve_state == SVEState::Disabled || m_sve_state == SVEState::Unknown)
203       return Status("SVE disabled or not supported");
204 
205     if (GetRegisterInfo().IsSVERegVG(reg)) {
206       sve_vg = GetSVERegVG();
207       src = (uint8_t *)&sve_vg;
208     } else {
209       // SVE enabled, we will read and cache SVE ptrace data
210       error = ReadAllSVE();
211       if (error.Fail())
212         return error;
213 
214       if (m_sve_state == SVEState::FPSIMD) {
215         // In FPSIMD state SVE payload mirrors legacy fpsimd struct and so
216         // just copy 16 bytes of v register to the start of z register. All
217         // other SVE register will be set to zero.
218         sve_reg_non_live.resize(reg_info->byte_size, 0);
219         src = sve_reg_non_live.data();
220 
221         if (GetRegisterInfo().IsSVEZReg(reg)) {
222           offset = CalculateSVEOffset(reg_info);
223           assert(offset < GetSVEBufferSize());
224           ::memcpy(sve_reg_non_live.data(), (uint8_t *)GetSVEBuffer() + offset,
225                    16);
226         }
227       } else {
228         offset = CalculateSVEOffset(reg_info);
229         assert(offset < GetSVEBufferSize());
230         src = (uint8_t *)GetSVEBuffer() + offset;
231       }
232     }
233   } else
234     return Status("failed - register wasn't recognized to be a GPR or an FPR, "
235                   "write strategy unknown");
236 
237   reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size,
238                               eByteOrderLittle, error);
239 
240   return error;
241 }
242 
243 Status NativeRegisterContextLinux_arm64::WriteRegister(
244     const RegisterInfo *reg_info, const RegisterValue &reg_value) {
245   Status error;
246 
247   if (!reg_info)
248     return Status("reg_info NULL");
249 
250   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
251 
252   if (reg == LLDB_INVALID_REGNUM)
253     return Status("no lldb regnum for %s", reg_info && reg_info->name
254                                                ? reg_info->name
255                                                : "<unknown register>");
256 
257   uint8_t *dst;
258   uint32_t offset = LLDB_INVALID_INDEX32;
259   std::vector<uint8_t> sve_reg_non_live;
260 
261   if (IsGPR(reg)) {
262     error = ReadGPR();
263     if (error.Fail())
264       return error;
265 
266     assert(reg_info->byte_offset < GetGPRSize());
267     dst = (uint8_t *)GetGPRBuffer() + reg_info->byte_offset;
268     ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size);
269 
270     return WriteGPR();
271   } else if (IsFPR(reg)) {
272     if (m_sve_state == SVEState::Disabled) {
273       // SVE is disabled take legacy route for FPU register access
274       error = ReadFPR();
275       if (error.Fail())
276         return error;
277 
278       offset = CalculateFprOffset(reg_info);
279       assert(offset < GetFPRSize());
280       dst = (uint8_t *)GetFPRBuffer() + offset;
281       ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size);
282 
283       return WriteFPR();
284     } else {
285       // SVE enabled, we will read and cache SVE ptrace data
286       error = ReadAllSVE();
287       if (error.Fail())
288         return error;
289 
290       // FPSR and FPCR will be located right after Z registers in
291       // SVEState::FPSIMD while in SVEState::Full they will be located at the
292       // end of register data after an alignment correction based on currently
293       // selected vector length.
294       uint32_t sve_reg_num = LLDB_INVALID_REGNUM;
295       if (reg == GetRegisterInfo().GetRegNumFPSR()) {
296         sve_reg_num = reg;
297         if (m_sve_state == SVEState::Full)
298           offset = SVE_PT_SVE_FPSR_OFFSET(sve_vq_from_vl(m_sve_header.vl));
299         else if (m_sve_state == SVEState::FPSIMD)
300           offset = SVE_PT_FPSIMD_OFFSET + (32 * 16);
301       } else if (reg == GetRegisterInfo().GetRegNumFPCR()) {
302         sve_reg_num = reg;
303         if (m_sve_state == SVEState::Full)
304           offset = SVE_PT_SVE_FPCR_OFFSET(sve_vq_from_vl(m_sve_header.vl));
305         else if (m_sve_state == SVEState::FPSIMD)
306           offset = SVE_PT_FPSIMD_OFFSET + (32 * 16) + 4;
307       } else {
308         // Extract SVE Z register value register number for this reg_info
309         if (reg_info->value_regs &&
310             reg_info->value_regs[0] != LLDB_INVALID_REGNUM)
311           sve_reg_num = reg_info->value_regs[0];
312         offset = CalculateSVEOffset(GetRegisterInfoAtIndex(sve_reg_num));
313       }
314 
315       assert(offset < GetSVEBufferSize());
316       dst = (uint8_t *)GetSVEBuffer() + offset;
317       ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size);
318       return WriteAllSVE();
319     }
320   } else if (IsSVE(reg)) {
321     if (m_sve_state == SVEState::Disabled || m_sve_state == SVEState::Unknown)
322       return Status("SVE disabled or not supported");
323     else {
324       // Target has SVE enabled, we will read and cache SVE ptrace data
325       error = ReadAllSVE();
326       if (error.Fail())
327         return error;
328 
329       if (GetRegisterInfo().IsSVERegVG(reg)) {
330         uint64_t vg_value = reg_value.GetAsUInt64();
331 
332         if (sve_vl_valid(vg_value * 8)) {
333           if (m_sve_header_is_valid && vg_value == GetSVERegVG())
334             return error;
335 
336           SetSVERegVG(vg_value);
337 
338           error = WriteSVEHeader();
339           if (error.Success())
340             ConfigureRegisterContext();
341 
342           if (m_sve_header_is_valid && vg_value == GetSVERegVG())
343             return error;
344         }
345 
346         return Status("SVE vector length update failed.");
347       }
348 
349       // If target supports SVE but currently in FPSIMD mode.
350       if (m_sve_state == SVEState::FPSIMD) {
351         // Here we will check if writing this SVE register enables
352         // SVEState::Full
353         bool set_sve_state_full = false;
354         const uint8_t *reg_bytes = (const uint8_t *)reg_value.GetBytes();
355         if (GetRegisterInfo().IsSVEZReg(reg)) {
356           for (uint32_t i = 16; i < reg_info->byte_size; i++) {
357             if (reg_bytes[i]) {
358               set_sve_state_full = true;
359               break;
360             }
361           }
362         } else if (GetRegisterInfo().IsSVEPReg(reg) ||
363                    reg == GetRegisterInfo().GetRegNumSVEFFR()) {
364           for (uint32_t i = 0; i < reg_info->byte_size; i++) {
365             if (reg_bytes[i]) {
366               set_sve_state_full = true;
367               break;
368             }
369           }
370         }
371 
372         if (!set_sve_state_full && GetRegisterInfo().IsSVEZReg(reg)) {
373           // We are writing a Z register which is zero beyond 16 bytes so copy
374           // first 16 bytes only as SVE payload mirrors legacy fpsimd structure
375           offset = CalculateSVEOffset(reg_info);
376           assert(offset < GetSVEBufferSize());
377           dst = (uint8_t *)GetSVEBuffer() + offset;
378           ::memcpy(dst, reg_value.GetBytes(), 16);
379 
380           return WriteAllSVE();
381         } else
382           return Status("SVE state change operation not supported");
383       } else {
384         offset = CalculateSVEOffset(reg_info);
385         assert(offset < GetSVEBufferSize());
386         dst = (uint8_t *)GetSVEBuffer() + offset;
387         ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size);
388         return WriteAllSVE();
389       }
390     }
391   }
392 
393   return Status("Failed to write register value");
394 }
395 
396 Status NativeRegisterContextLinux_arm64::ReadAllRegisterValues(
397     lldb::DataBufferSP &data_sp) {
398   Status error;
399 
400   data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
401 
402   error = ReadGPR();
403   if (error.Fail())
404     return error;
405 
406   error = ReadFPR();
407   if (error.Fail())
408     return error;
409 
410   uint8_t *dst = data_sp->GetBytes();
411   ::memcpy(dst, GetGPRBuffer(), GetGPRSize());
412   dst += GetGPRSize();
413   ::memcpy(dst, GetFPRBuffer(), GetFPRSize());
414 
415   return error;
416 }
417 
418 Status NativeRegisterContextLinux_arm64::WriteAllRegisterValues(
419     const lldb::DataBufferSP &data_sp) {
420   Status error;
421 
422   if (!data_sp) {
423     error.SetErrorStringWithFormat(
424         "NativeRegisterContextLinux_x86_64::%s invalid data_sp provided",
425         __FUNCTION__);
426     return error;
427   }
428 
429   if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
430     error.SetErrorStringWithFormat(
431         "NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched "
432         "data size, expected %" PRIu64 ", actual %" PRIu64,
433         __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
434     return error;
435   }
436 
437   uint8_t *src = data_sp->GetBytes();
438   if (src == nullptr) {
439     error.SetErrorStringWithFormat("NativeRegisterContextLinux_x86_64::%s "
440                                    "DataBuffer::GetBytes() returned a null "
441                                    "pointer",
442                                    __FUNCTION__);
443     return error;
444   }
445   ::memcpy(GetGPRBuffer(), src, GetRegisterInfoInterface().GetGPRSize());
446 
447   error = WriteGPR();
448   if (error.Fail())
449     return error;
450 
451   src += GetRegisterInfoInterface().GetGPRSize();
452   ::memcpy(GetFPRBuffer(), src, GetFPRSize());
453 
454   error = WriteFPR();
455   if (error.Fail())
456     return error;
457 
458   return error;
459 }
460 
461 bool NativeRegisterContextLinux_arm64::IsGPR(unsigned reg) const {
462   if (GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
463       RegisterInfoPOSIX_arm64::GPRegSet)
464     return true;
465   return false;
466 }
467 
468 bool NativeRegisterContextLinux_arm64::IsFPR(unsigned reg) const {
469   if (GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
470       RegisterInfoPOSIX_arm64::FPRegSet)
471     return true;
472   return false;
473 }
474 
475 bool NativeRegisterContextLinux_arm64::IsSVE(unsigned reg) const {
476   return GetRegisterInfo().IsSVEReg(reg);
477 }
478 
479 llvm::Error NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo() {
480   if (!m_refresh_hwdebug_info) {
481     return llvm::Error::success();
482   }
483 
484   ::pid_t tid = m_thread.GetID();
485 
486   int regset = NT_ARM_HW_WATCH;
487   struct iovec ioVec;
488   struct user_hwdebug_state dreg_state;
489   Status error;
490 
491   ioVec.iov_base = &dreg_state;
492   ioVec.iov_len = sizeof(dreg_state);
493   error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset,
494                                             &ioVec, ioVec.iov_len);
495 
496   if (error.Fail())
497     return error.ToError();
498 
499   m_max_hwp_supported = dreg_state.dbg_info & 0xff;
500 
501   regset = NT_ARM_HW_BREAK;
502   error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset,
503                                             &ioVec, ioVec.iov_len);
504 
505   if (error.Fail())
506     return error.ToError();
507 
508   m_max_hbp_supported = dreg_state.dbg_info & 0xff;
509   m_refresh_hwdebug_info = false;
510 
511   return llvm::Error::success();
512 }
513 
514 llvm::Error
515 NativeRegisterContextLinux_arm64::WriteHardwareDebugRegs(DREGType hwbType) {
516   struct iovec ioVec;
517   struct user_hwdebug_state dreg_state;
518   int regset;
519 
520   memset(&dreg_state, 0, sizeof(dreg_state));
521   ioVec.iov_base = &dreg_state;
522 
523   switch (hwbType) {
524   case eDREGTypeWATCH:
525     regset = NT_ARM_HW_WATCH;
526     ioVec.iov_len = sizeof(dreg_state.dbg_info) + sizeof(dreg_state.pad) +
527                     (sizeof(dreg_state.dbg_regs[0]) * m_max_hwp_supported);
528 
529     for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
530       dreg_state.dbg_regs[i].addr = m_hwp_regs[i].address;
531       dreg_state.dbg_regs[i].ctrl = m_hwp_regs[i].control;
532     }
533     break;
534   case eDREGTypeBREAK:
535     regset = NT_ARM_HW_BREAK;
536     ioVec.iov_len = sizeof(dreg_state.dbg_info) + sizeof(dreg_state.pad) +
537                     (sizeof(dreg_state.dbg_regs[0]) * m_max_hbp_supported);
538 
539     for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
540       dreg_state.dbg_regs[i].addr = m_hbp_regs[i].address;
541       dreg_state.dbg_regs[i].ctrl = m_hbp_regs[i].control;
542     }
543     break;
544   }
545 
546   return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(),
547                                            &regset, &ioVec, ioVec.iov_len)
548       .ToError();
549 }
550 
551 Status NativeRegisterContextLinux_arm64::ReadGPR() {
552   Status error;
553 
554   if (m_gpr_is_valid)
555     return error;
556 
557   struct iovec ioVec;
558   ioVec.iov_base = GetGPRBuffer();
559   ioVec.iov_len = GetGPRBufferSize();
560 
561   error = ReadRegisterSet(&ioVec, GetGPRBufferSize(), NT_PRSTATUS);
562 
563   if (error.Success())
564     m_gpr_is_valid = true;
565 
566   return error;
567 }
568 
569 Status NativeRegisterContextLinux_arm64::WriteGPR() {
570   Status error = ReadGPR();
571   if (error.Fail())
572     return error;
573 
574   struct iovec ioVec;
575   ioVec.iov_base = GetGPRBuffer();
576   ioVec.iov_len = GetGPRBufferSize();
577 
578   m_gpr_is_valid = false;
579 
580   return WriteRegisterSet(&ioVec, GetGPRBufferSize(), NT_PRSTATUS);
581 }
582 
583 Status NativeRegisterContextLinux_arm64::ReadFPR() {
584   Status error;
585 
586   if (m_fpu_is_valid)
587     return error;
588 
589   struct iovec ioVec;
590   ioVec.iov_base = GetFPRBuffer();
591   ioVec.iov_len = GetFPRSize();
592 
593   error = ReadRegisterSet(&ioVec, GetFPRSize(), NT_FPREGSET);
594 
595   if (error.Success())
596     m_fpu_is_valid = true;
597 
598   return error;
599 }
600 
601 Status NativeRegisterContextLinux_arm64::WriteFPR() {
602   Status error = ReadFPR();
603   if (error.Fail())
604     return error;
605 
606   struct iovec ioVec;
607   ioVec.iov_base = GetFPRBuffer();
608   ioVec.iov_len = GetFPRSize();
609 
610   m_fpu_is_valid = false;
611 
612   return WriteRegisterSet(&ioVec, GetFPRSize(), NT_FPREGSET);
613 }
614 
615 void NativeRegisterContextLinux_arm64::InvalidateAllRegisters() {
616   m_gpr_is_valid = false;
617   m_fpu_is_valid = false;
618   m_sve_buffer_is_valid = false;
619   m_sve_header_is_valid = false;
620 
621   // Update SVE registers in case there is change in configuration.
622   ConfigureRegisterContext();
623 }
624 
625 Status NativeRegisterContextLinux_arm64::ReadSVEHeader() {
626   Status error;
627 
628   if (m_sve_header_is_valid)
629     return error;
630 
631   struct iovec ioVec;
632   ioVec.iov_base = GetSVEHeader();
633   ioVec.iov_len = GetSVEHeaderSize();
634 
635   error = ReadRegisterSet(&ioVec, GetSVEHeaderSize(), NT_ARM_SVE);
636 
637   m_sve_header_is_valid = true;
638 
639   return error;
640 }
641 
642 Status NativeRegisterContextLinux_arm64::WriteSVEHeader() {
643   Status error;
644 
645   error = ReadSVEHeader();
646   if (error.Fail())
647     return error;
648 
649   struct iovec ioVec;
650   ioVec.iov_base = GetSVEHeader();
651   ioVec.iov_len = GetSVEHeaderSize();
652 
653   m_sve_buffer_is_valid = false;
654   m_sve_header_is_valid = false;
655   m_fpu_is_valid = false;
656 
657   return WriteRegisterSet(&ioVec, GetSVEHeaderSize(), NT_ARM_SVE);
658 }
659 
660 Status NativeRegisterContextLinux_arm64::ReadAllSVE() {
661   Status error;
662 
663   if (m_sve_buffer_is_valid)
664     return error;
665 
666   struct iovec ioVec;
667   ioVec.iov_base = GetSVEBuffer();
668   ioVec.iov_len = GetSVEBufferSize();
669 
670   error = ReadRegisterSet(&ioVec, GetSVEBufferSize(), NT_ARM_SVE);
671 
672   if (error.Success())
673     m_sve_buffer_is_valid = true;
674 
675   return error;
676 }
677 
678 Status NativeRegisterContextLinux_arm64::WriteAllSVE() {
679   Status error;
680 
681   error = ReadAllSVE();
682   if (error.Fail())
683     return error;
684 
685   struct iovec ioVec;
686 
687   ioVec.iov_base = GetSVEBuffer();
688   ioVec.iov_len = GetSVEBufferSize();
689 
690   m_sve_buffer_is_valid = false;
691   m_sve_header_is_valid = false;
692   m_fpu_is_valid = false;
693 
694   return WriteRegisterSet(&ioVec, GetSVEBufferSize(), NT_ARM_SVE);
695 }
696 
697 void NativeRegisterContextLinux_arm64::ConfigureRegisterContext() {
698   // ConfigureRegisterContext gets called from InvalidateAllRegisters
699   // on every stop and configures SVE vector length.
700   // If m_sve_state is set to SVEState::Disabled on first stop, code below will
701   // be deemed non operational for the lifetime of current process.
702   if (!m_sve_header_is_valid && m_sve_state != SVEState::Disabled) {
703     Status error = ReadSVEHeader();
704     if (error.Success()) {
705       // If SVE is enabled thread can switch between SVEState::FPSIMD and
706       // SVEState::Full on every stop.
707       if ((m_sve_header.flags & SVE_PT_REGS_MASK) == SVE_PT_REGS_FPSIMD)
708         m_sve_state = SVEState::FPSIMD;
709       else if ((m_sve_header.flags & SVE_PT_REGS_MASK) == SVE_PT_REGS_SVE)
710         m_sve_state = SVEState::Full;
711 
712       // On every stop we configure SVE vector length by calling
713       // ConfigureVectorLength regardless of current SVEState of this thread.
714       uint32_t vq = RegisterInfoPOSIX_arm64::eVectorQuadwordAArch64SVE;
715       if (sve_vl_valid(m_sve_header.vl))
716         vq = sve_vq_from_vl(m_sve_header.vl);
717 
718       GetRegisterInfo().ConfigureVectorLength(vq);
719       m_sve_ptrace_payload.resize(SVE_PT_SIZE(vq, SVE_PT_REGS_SVE));
720     }
721   }
722 }
723 
724 uint32_t NativeRegisterContextLinux_arm64::CalculateFprOffset(
725     const RegisterInfo *reg_info) const {
726   return reg_info->byte_offset - GetGPRSize();
727 }
728 
729 uint32_t NativeRegisterContextLinux_arm64::CalculateSVEOffset(
730     const RegisterInfo *reg_info) const {
731   // Start of Z0 data is after GPRs plus 8 bytes of vg register
732   uint32_t sve_reg_offset = LLDB_INVALID_INDEX32;
733   if (m_sve_state == SVEState::FPSIMD) {
734     const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
735     sve_reg_offset =
736         SVE_PT_FPSIMD_OFFSET + (reg - GetRegisterInfo().GetRegNumSVEZ0()) * 16;
737   } else if (m_sve_state == SVEState::Full) {
738     uint32_t sve_z0_offset = GetGPRSize() + 16;
739     sve_reg_offset =
740         SVE_SIG_REGS_OFFSET + reg_info->byte_offset - sve_z0_offset;
741   }
742   return sve_reg_offset;
743 }
744 
745 void *NativeRegisterContextLinux_arm64::GetSVEBuffer() {
746   if (m_sve_state == SVEState::FPSIMD)
747     return m_sve_ptrace_payload.data() + SVE_PT_FPSIMD_OFFSET;
748 
749   return m_sve_ptrace_payload.data();
750 }
751 
752 std::vector<uint32_t> NativeRegisterContextLinux_arm64::GetExpeditedRegisters(
753     ExpeditedRegs expType) const {
754   std::vector<uint32_t> expedited_reg_nums =
755       NativeRegisterContext::GetExpeditedRegisters(expType);
756   if (m_sve_state == SVEState::FPSIMD || m_sve_state == SVEState::Full)
757     expedited_reg_nums.push_back(GetRegisterInfo().GetRegNumSVEVG());
758 
759   return expedited_reg_nums;
760 }
761 
762 #endif // defined (__arm64__) || defined (__aarch64__)
763