@@ -23,8 +23,13 @@ RegisterContextCorePOSIX_arm64::Create(Thread &thread, const ArchSpec &arch,
23
23
llvm::ArrayRef<CoreNote> notes) {
24
24
Flags opt_regsets = RegisterInfoPOSIX_arm64::eRegsetMaskDefault;
25
25
26
+ DataExtractor ssve_data =
27
+ getRegset (notes, arch.GetTriple (), AARCH64_SSVE_Desc);
28
+ if (ssve_data.GetByteSize () >= sizeof (sve::user_sve_header))
29
+ opt_regsets.Set (RegisterInfoPOSIX_arm64::eRegsetMaskSSVE);
30
+
26
31
DataExtractor sve_data = getRegset (notes, arch.GetTriple (), AARCH64_SVE_Desc);
27
- if (sve_data.GetByteSize () > sizeof (sve::user_sve_header))
32
+ if (sve_data.GetByteSize () >= sizeof (sve::user_sve_header))
28
33
opt_regsets.Set (RegisterInfoPOSIX_arm64::eRegsetMaskSVE);
29
34
30
35
// Pointer Authentication register set data is based on struct
@@ -40,6 +45,11 @@ RegisterContextCorePOSIX_arm64::Create(Thread &thread, const ArchSpec &arch,
40
45
if (tls_data.GetByteSize () >= sizeof (uint64_t ))
41
46
opt_regsets.Set (RegisterInfoPOSIX_arm64::eRegsetMaskTLS);
42
47
48
+ DataExtractor za_data = getRegset (notes, arch.GetTriple (), AARCH64_ZA_Desc);
49
+ // Nothing if ZA is not present, just the header if it is disabled.
50
+ if (za_data.GetByteSize () >= sizeof (sve::user_za_header))
51
+ opt_regsets.Set (RegisterInfoPOSIX_arm64::eRegsetMaskZA);
52
+
43
53
auto register_info_up =
44
54
std::make_unique<RegisterInfoPOSIX_arm64>(arch, opt_regsets);
45
55
return std::unique_ptr<RegisterContextCorePOSIX_arm64>(
@@ -51,6 +61,8 @@ RegisterContextCorePOSIX_arm64::RegisterContextCorePOSIX_arm64(
51
61
Thread &thread, std::unique_ptr<RegisterInfoPOSIX_arm64> register_info,
52
62
const DataExtractor &gpregset, llvm::ArrayRef<CoreNote> notes)
53
63
: RegisterContextPOSIX_arm64(thread, std::move(register_info)) {
64
+ ::memset (&m_sme_pseudo_regs, 0 , sizeof (m_sme_pseudo_regs));
65
+
54
66
m_gpr_data.SetData (std::make_shared<DataBufferHeap>(gpregset.GetDataStart (),
55
67
gpregset.GetByteSize ()));
56
68
m_gpr_data.SetByteOrder (gpregset.GetByteOrder ());
@@ -59,7 +71,15 @@ RegisterContextCorePOSIX_arm64::RegisterContextCorePOSIX_arm64(
59
71
m_register_info_up->GetTargetArchitecture ().GetTriple ();
60
72
m_fpr_data = getRegset (notes, target_triple, FPR_Desc);
61
73
62
- if (m_register_info_up->IsSVEEnabled ())
74
+ if (m_register_info_up->IsSSVEEnabled ()) {
75
+ m_sve_data = getRegset (notes, target_triple, AARCH64_SSVE_Desc);
76
+ lldb::offset_t flags_offset = 12 ;
77
+ uint16_t flags = m_sve_data.GetU32 (&flags_offset);
78
+ if ((flags & sve::ptrace_regs_mask) == sve::ptrace_regs_sve)
79
+ m_sve_state = SVEState::Streaming;
80
+ }
81
+
82
+ if (m_sve_state != SVEState::Streaming && m_register_info_up->IsSVEEnabled ())
63
83
m_sve_data = getRegset (notes, target_triple, AARCH64_SVE_Desc);
64
84
65
85
if (m_register_info_up->IsPAuthEnabled ())
@@ -68,6 +88,9 @@ RegisterContextCorePOSIX_arm64::RegisterContextCorePOSIX_arm64(
68
88
if (m_register_info_up->IsTLSEnabled ())
69
89
m_tls_data = getRegset (notes, target_triple, AARCH64_TLS_Desc);
70
90
91
+ if (m_register_info_up->IsZAEnabled ())
92
+ m_za_data = getRegset (notes, target_triple, AARCH64_ZA_Desc);
93
+
71
94
ConfigureRegisterContext ();
72
95
}
73
96
@@ -95,15 +118,18 @@ void RegisterContextCorePOSIX_arm64::ConfigureRegisterContext() {
95
118
if (m_sve_data.GetByteSize () > sizeof (sve::user_sve_header)) {
96
119
uint64_t sve_header_field_offset = 8 ;
97
120
m_sve_vector_length = m_sve_data.GetU16 (&sve_header_field_offset);
98
- sve_header_field_offset = 12 ;
99
- uint16_t sve_header_flags_field =
100
- m_sve_data.GetU16 (&sve_header_field_offset);
101
- if ((sve_header_flags_field & sve::ptrace_regs_mask) ==
102
- sve::ptrace_regs_fpsimd)
103
- m_sve_state = SVEState::FPSIMD;
104
- else if ((sve_header_flags_field & sve::ptrace_regs_mask) ==
105
- sve::ptrace_regs_sve)
106
- m_sve_state = SVEState::Full;
121
+
122
+ if (m_sve_state != SVEState::Streaming) {
123
+ sve_header_field_offset = 12 ;
124
+ uint16_t sve_header_flags_field =
125
+ m_sve_data.GetU16 (&sve_header_field_offset);
126
+ if ((sve_header_flags_field & sve::ptrace_regs_mask) ==
127
+ sve::ptrace_regs_fpsimd)
128
+ m_sve_state = SVEState::FPSIMD;
129
+ else if ((sve_header_flags_field & sve::ptrace_regs_mask) ==
130
+ sve::ptrace_regs_sve)
131
+ m_sve_state = SVEState::Full;
132
+ }
107
133
108
134
if (!sve::vl_valid (m_sve_vector_length)) {
109
135
m_sve_state = SVEState::Disabled;
@@ -115,6 +141,23 @@ void RegisterContextCorePOSIX_arm64::ConfigureRegisterContext() {
115
141
if (m_sve_state != SVEState::Disabled)
116
142
m_register_info_up->ConfigureVectorLengthSVE (
117
143
sve::vq_from_vl (m_sve_vector_length));
144
+
145
+ if (m_sve_state == SVEState::Streaming)
146
+ m_sme_pseudo_regs.ctrl_reg |= 1 ;
147
+
148
+ if (m_za_data.GetByteSize () >= sizeof (sve::user_za_header)) {
149
+ lldb::offset_t vlen_offset = 8 ;
150
+ uint16_t svl = m_za_data.GetU16 (&vlen_offset);
151
+ m_sme_pseudo_regs.svg_reg = svl / 8 ;
152
+ m_register_info_up->ConfigureVectorLengthZA (svl / 16 );
153
+
154
+ // If there is register data then ZA is active. The size of the note may be
155
+ // misleading here so we use the size field of the embedded header.
156
+ lldb::offset_t size_offset = 0 ;
157
+ uint32_t size = m_za_data.GetU32 (&size_offset);
158
+ if (size > sizeof (sve::user_za_header))
159
+ m_sme_pseudo_regs.ctrl_reg |= 1 << 1 ;
160
+ }
118
161
}
119
162
120
163
uint32_t RegisterContextCorePOSIX_arm64::CalculateSVEOffset (
@@ -124,7 +167,8 @@ uint32_t RegisterContextCorePOSIX_arm64::CalculateSVEOffset(
124
167
if (m_sve_state == SVEState::FPSIMD) {
125
168
const uint32_t reg = reg_info->kinds [lldb::eRegisterKindLLDB];
126
169
sve_reg_offset = sve::ptrace_fpsimd_offset + (reg - GetRegNumSVEZ0 ()) * 16 ;
127
- } else if (m_sve_state == SVEState::Full) {
170
+ } else if (m_sve_state == SVEState::Full ||
171
+ m_sve_state == SVEState::Streaming) {
128
172
uint32_t sve_z0_offset = GetGPRSize () + 16 ;
129
173
sve_reg_offset =
130
174
sve::SigRegsOffset () + reg_info->byte_offset - sve_z0_offset;
@@ -163,19 +207,19 @@ bool RegisterContextCorePOSIX_arm64::ReadRegister(const RegisterInfo *reg_info,
163
207
}
164
208
} else {
165
209
// FPSR and FPCR will be located right after Z registers in
166
- // SVEState::FPSIMD while in SVEState::Full they will be located at the
167
- // end of register data after an alignment correction based on currently
168
- // selected vector length.
210
+ // SVEState::FPSIMD while in SVEState::Full/SVEState::Streaming they will
211
+ // be located at the end of register data after an alignment correction
212
+ // based on currently selected vector length.
169
213
uint32_t sve_reg_num = LLDB_INVALID_REGNUM;
170
214
if (reg == GetRegNumFPSR ()) {
171
215
sve_reg_num = reg;
172
- if (m_sve_state == SVEState::Full)
216
+ if (m_sve_state == SVEState::Full || m_sve_state == SVEState::Streaming )
173
217
offset = sve::PTraceFPSROffset (sve::vq_from_vl (m_sve_vector_length));
174
218
else if (m_sve_state == SVEState::FPSIMD)
175
219
offset = sve::ptrace_fpsimd_offset + (32 * 16 );
176
220
} else if (reg == GetRegNumFPCR ()) {
177
221
sve_reg_num = reg;
178
- if (m_sve_state == SVEState::Full)
222
+ if (m_sve_state == SVEState::Full || m_sve_state == SVEState::Streaming )
179
223
offset = sve::PTraceFPCROffset (sve::vq_from_vl (m_sve_vector_length));
180
224
else if (m_sve_state == SVEState::FPSIMD)
181
225
offset = sve::ptrace_fpsimd_offset + (32 * 16 ) + 4 ;
@@ -217,6 +261,7 @@ bool RegisterContextCorePOSIX_arm64::ReadRegister(const RegisterInfo *reg_info,
217
261
error);
218
262
} break ;
219
263
case SVEState::Full:
264
+ case SVEState::Streaming:
220
265
offset = CalculateSVEOffset (reg_info);
221
266
assert (offset < m_sve_data.GetByteSize ());
222
267
value.SetFromMemoryData (*reg_info, GetSVEBuffer (offset),
@@ -237,6 +282,54 @@ bool RegisterContextCorePOSIX_arm64::ReadRegister(const RegisterInfo *reg_info,
237
282
assert (offset < m_tls_data.GetByteSize ());
238
283
value.SetFromMemoryData (*reg_info, m_tls_data.GetDataStart () + offset,
239
284
reg_info->byte_size , lldb::eByteOrderLittle, error);
285
+ } else if (IsSME (reg)) {
286
+ // If you had SME in the process, active or otherwise, there will at least
287
+ // be a ZA header. No header, no SME at all.
288
+ if (m_za_data.GetByteSize () < sizeof (sve::user_za_header))
289
+ return false ;
290
+
291
+ if (!IsSMEZA (reg)) {
292
+ offset = reg_info->byte_offset - m_register_info_up->GetSMEOffset ();
293
+ assert (offset < sizeof (m_sme_pseudo_regs));
294
+ // Host endian since these values are derived instead of being read from a
295
+ // core file note.
296
+ value.SetFromMemoryData (
297
+ *reg_info, reinterpret_cast <uint8_t *>(&m_sme_pseudo_regs) + offset,
298
+ reg_info->byte_size , lldb_private::endian::InlHostByteOrder (), error);
299
+ } else {
300
+ // If the process did not have the SME extension.
301
+ if (m_za_data.GetByteSize () < sizeof (sve::user_za_header))
302
+ return false ;
303
+
304
+ // Don't use the size of the note to tell whether ZA is enabled. There may
305
+ // be non-register padding data after the header. Use the embedded
306
+ // header's size field instead.
307
+ lldb::offset_t size_offset = 0 ;
308
+ uint32_t size = m_za_data.GetU32 (&size_offset);
309
+ bool za_enabled = size > sizeof (sve::user_za_header);
310
+
311
+ size_t za_note_size = m_za_data.GetByteSize ();
312
+ // For a disabled ZA we fake a value of all 0s.
313
+ if (!za_enabled) {
314
+ uint64_t svl = m_sme_pseudo_regs.svg_reg * 8 ;
315
+ za_note_size = sizeof (sve::user_za_header) + (svl * svl);
316
+ }
317
+
318
+ const uint8_t *src = nullptr ;
319
+ std::vector<uint8_t > disabled_za_data;
320
+
321
+ if (za_enabled)
322
+ src = m_za_data.GetDataStart ();
323
+ else {
324
+ disabled_za_data.resize (za_note_size);
325
+ std::fill (disabled_za_data.begin (), disabled_za_data.end (), 0 );
326
+ src = disabled_za_data.data ();
327
+ }
328
+
329
+ value.SetFromMemoryData (*reg_info, src + sizeof (sve::user_za_header),
330
+ reg_info->byte_size , lldb::eByteOrderLittle,
331
+ error);
332
+ }
240
333
} else
241
334
return false ;
242
335
0 commit comments