1//===- ARMAttributeParser.cpp - ARM Attribute Information Printer ---------===//
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#include "llvm/Support/ARMAttributeParser.h"
10#include "llvm/ADT/StringExtras.h"
11#include "llvm/Support/ARMBuildAttributes.h"
12#include "llvm/Support/Errc.h"
13#include "llvm/Support/ScopedPrinter.h"
14#include <optional>
15
16using namespace llvm;
17using namespace llvm::ARMBuildAttrs;
18
19#define ATTRIBUTE_HANDLER(attr) \
20 { ARMBuildAttrs::attr, &ARMAttributeParser::attr }
21
22const ARMAttributeParser::DisplayHandler ARMAttributeParser::displayRoutines[] =
23 {
24 {.attribute: ARMBuildAttrs::CPU_raw_name, .routine: &ARMAttributeParser::stringAttribute},
25 {.attribute: ARMBuildAttrs::CPU_name, .routine: &ARMAttributeParser::stringAttribute},
26 ATTRIBUTE_HANDLER(CPU_arch),
27 ATTRIBUTE_HANDLER(CPU_arch_profile),
28 ATTRIBUTE_HANDLER(ARM_ISA_use),
29 ATTRIBUTE_HANDLER(THUMB_ISA_use),
30 ATTRIBUTE_HANDLER(FP_arch),
31 ATTRIBUTE_HANDLER(WMMX_arch),
32 ATTRIBUTE_HANDLER(Advanced_SIMD_arch),
33 ATTRIBUTE_HANDLER(MVE_arch),
34 ATTRIBUTE_HANDLER(PCS_config),
35 ATTRIBUTE_HANDLER(ABI_PCS_R9_use),
36 ATTRIBUTE_HANDLER(ABI_PCS_RW_data),
37 ATTRIBUTE_HANDLER(ABI_PCS_RO_data),
38 ATTRIBUTE_HANDLER(ABI_PCS_GOT_use),
39 ATTRIBUTE_HANDLER(ABI_PCS_wchar_t),
40 ATTRIBUTE_HANDLER(ABI_FP_rounding),
41 ATTRIBUTE_HANDLER(ABI_FP_denormal),
42 ATTRIBUTE_HANDLER(ABI_FP_exceptions),
43 ATTRIBUTE_HANDLER(ABI_FP_user_exceptions),
44 ATTRIBUTE_HANDLER(ABI_FP_number_model),
45 ATTRIBUTE_HANDLER(ABI_align_needed),
46 ATTRIBUTE_HANDLER(ABI_align_preserved),
47 ATTRIBUTE_HANDLER(ABI_enum_size),
48 ATTRIBUTE_HANDLER(ABI_HardFP_use),
49 ATTRIBUTE_HANDLER(ABI_VFP_args),
50 ATTRIBUTE_HANDLER(ABI_WMMX_args),
51 ATTRIBUTE_HANDLER(ABI_optimization_goals),
52 ATTRIBUTE_HANDLER(ABI_FP_optimization_goals),
53 ATTRIBUTE_HANDLER(compatibility),
54 ATTRIBUTE_HANDLER(CPU_unaligned_access),
55 ATTRIBUTE_HANDLER(FP_HP_extension),
56 ATTRIBUTE_HANDLER(ABI_FP_16bit_format),
57 ATTRIBUTE_HANDLER(MPextension_use),
58 ATTRIBUTE_HANDLER(DIV_use),
59 ATTRIBUTE_HANDLER(DSP_extension),
60 ATTRIBUTE_HANDLER(T2EE_use),
61 ATTRIBUTE_HANDLER(Virtualization_use),
62 ATTRIBUTE_HANDLER(PAC_extension),
63 ATTRIBUTE_HANDLER(BTI_extension),
64 ATTRIBUTE_HANDLER(PACRET_use),
65 ATTRIBUTE_HANDLER(BTI_use),
66 ATTRIBUTE_HANDLER(nodefaults),
67 ATTRIBUTE_HANDLER(also_compatible_with),
68};
69
70#undef ATTRIBUTE_HANDLER
71
72Error ARMAttributeParser::stringAttribute(AttrType tag) {
73 StringRef tagName =
74 ELFAttrs::attrTypeAsString(attr: tag, tagNameMap: tagToStringMap, /*hasTagPrefix=*/false);
75 StringRef desc = de.getCStrRef(C&: cursor);
76
77 if (sw) {
78 DictScope scope(*sw, "Attribute");
79 sw->printNumber(Label: "Tag", Value: tag);
80 if (!tagName.empty())
81 sw->printString(Label: "TagName", Value: tagName);
82 sw->printString(Label: "Value", Value: desc);
83 }
84 return Error::success();
85}
86
87static const char *const CPU_arch_strings[] = {"Pre-v4",
88 "ARM v4",
89 "ARM v4T",
90 "ARM v5T",
91 "ARM v5TE",
92 "ARM v5TEJ",
93 "ARM v6",
94 "ARM v6KZ",
95 "ARM v6T2",
96 "ARM v6K",
97 "ARM v7",
98 "ARM v6-M",
99 "ARM v6S-M",
100 "ARM v7E-M",
101 "ARM v8-A",
102 "ARM v8-R",
103 "ARM v8-M Baseline",
104 "ARM v8-M Mainline",
105 nullptr,
106 nullptr,
107 nullptr,
108 "ARM v8.1-M Mainline",
109 "ARM v9-A"};
110
111Error ARMAttributeParser::CPU_arch(AttrType tag) {
112 return parseStringAttribute(name: "CPU_arch", tag, strings: ArrayRef(CPU_arch_strings));
113}
114
115Error ARMAttributeParser::CPU_arch_profile(AttrType tag) {
116 uint64_t value = de.getULEB128(C&: cursor);
117
118 StringRef profile;
119 switch (value) {
120 default: profile = "Unknown"; break;
121 case 'A': profile = "Application"; break;
122 case 'R': profile = "Real-time"; break;
123 case 'M': profile = "Microcontroller"; break;
124 case 'S': profile = "Classic"; break;
125 case 0: profile = "None"; break;
126 }
127
128 printAttribute(tag, value, valueDesc: profile);
129 return Error::success();
130}
131
132Error ARMAttributeParser::ARM_ISA_use(AttrType tag) {
133 static const char *const strings[] = {"Not Permitted", "Permitted"};
134 return parseStringAttribute(name: "ARM_ISA_use", tag, strings: ArrayRef(strings));
135}
136
137Error ARMAttributeParser::THUMB_ISA_use(AttrType tag) {
138 static const char *const strings[] = {"Not Permitted", "Thumb-1", "Thumb-2",
139 "Permitted"};
140 return parseStringAttribute(name: "THUMB_ISA_use", tag, strings: ArrayRef(strings));
141}
142
143Error ARMAttributeParser::FP_arch(AttrType tag) {
144 static const char *const strings[] = {
145 "Not Permitted", "VFPv1", "VFPv2", "VFPv3", "VFPv3-D16",
146 "VFPv4", "VFPv4-D16", "ARMv8-a FP", "ARMv8-a FP-D16"};
147 return parseStringAttribute(name: "FP_arch", tag, strings: ArrayRef(strings));
148}
149
150Error ARMAttributeParser::WMMX_arch(AttrType tag) {
151 static const char *const strings[] = {"Not Permitted", "WMMXv1", "WMMXv2"};
152 return parseStringAttribute(name: "WMMX_arch", tag, strings: ArrayRef(strings));
153}
154
155Error ARMAttributeParser::Advanced_SIMD_arch(AttrType tag) {
156 static const char *const strings[] = {"Not Permitted", "NEONv1", "NEONv2+FMA",
157 "ARMv8-a NEON", "ARMv8.1-a NEON"};
158 return parseStringAttribute(name: "Advanced_SIMD_arch", tag, strings: ArrayRef(strings));
159}
160
161Error ARMAttributeParser::MVE_arch(AttrType tag) {
162 static const char *const strings[] = {"Not Permitted", "MVE integer",
163 "MVE integer and float"};
164 return parseStringAttribute(name: "MVE_arch", tag, strings: ArrayRef(strings));
165}
166
167Error ARMAttributeParser::PCS_config(AttrType tag) {
168 static const char *const strings[] = {"None",
169 "Bare Platform",
170 "Linux Application",
171 "Linux DSO",
172 "Palm OS 2004",
173 "Reserved (Palm OS)",
174 "Symbian OS 2004",
175 "Reserved (Symbian OS)"};
176 return parseStringAttribute(name: "PCS_config", tag, strings: ArrayRef(strings));
177}
178
179Error ARMAttributeParser::ABI_PCS_R9_use(AttrType tag) {
180 static const char *const strings[] = {"v6", "Static Base", "TLS", "Unused"};
181 return parseStringAttribute(name: "ABI_PCS_R9_use", tag, strings: ArrayRef(strings));
182}
183
184Error ARMAttributeParser::ABI_PCS_RW_data(AttrType tag) {
185 static const char *const strings[] = {"Absolute", "PC-relative",
186 "SB-relative", "Not Permitted"};
187 return parseStringAttribute(name: "ABI_PCS_RW_data", tag, strings: ArrayRef(strings));
188}
189
190Error ARMAttributeParser::ABI_PCS_RO_data(AttrType tag) {
191 static const char *const strings[] = {"Absolute", "PC-relative",
192 "Not Permitted"};
193 return parseStringAttribute(name: "ABI_PCS_RO_data", tag, strings: ArrayRef(strings));
194}
195
196Error ARMAttributeParser::ABI_PCS_GOT_use(AttrType tag) {
197 static const char *const strings[] = {"Not Permitted", "Direct",
198 "GOT-Indirect"};
199 return parseStringAttribute(name: "ABI_PCS_GOT_use", tag, strings: ArrayRef(strings));
200}
201
202Error ARMAttributeParser::ABI_PCS_wchar_t(AttrType tag) {
203 static const char *const strings[] = {"Not Permitted", "Unknown", "2-byte",
204 "Unknown", "4-byte"};
205 return parseStringAttribute(name: "ABI_PCS_wchar_t", tag, strings: ArrayRef(strings));
206}
207
208Error ARMAttributeParser::ABI_FP_rounding(AttrType tag) {
209 static const char *const strings[] = {"IEEE-754", "Runtime"};
210 return parseStringAttribute(name: "ABI_FP_rounding", tag, strings: ArrayRef(strings));
211}
212
213Error ARMAttributeParser::ABI_FP_denormal(AttrType tag) {
214 static const char *const strings[] = {"Unsupported", "IEEE-754", "Sign Only"};
215 return parseStringAttribute(name: "ABI_FP_denormal", tag, strings: ArrayRef(strings));
216}
217
218Error ARMAttributeParser::ABI_FP_exceptions(AttrType tag) {
219 static const char *const strings[] = {"Not Permitted", "IEEE-754"};
220 return parseStringAttribute(name: "ABI_FP_exceptions", tag, strings: ArrayRef(strings));
221}
222Error ARMAttributeParser::ABI_FP_user_exceptions(AttrType tag) {
223 static const char *const strings[] = {"Not Permitted", "IEEE-754"};
224 return parseStringAttribute(name: "ABI_FP_user_exceptions", tag, strings: ArrayRef(strings));
225}
226
227Error ARMAttributeParser::ABI_FP_number_model(AttrType tag) {
228 static const char *const strings[] = {"Not Permitted", "Finite Only", "RTABI",
229 "IEEE-754"};
230 return parseStringAttribute(name: "ABI_FP_number_model", tag, strings: ArrayRef(strings));
231}
232
233Error ARMAttributeParser::ABI_align_needed(AttrType tag) {
234 static const char *const strings[] = {"Not Permitted", "8-byte alignment",
235 "4-byte alignment", "Reserved"};
236
237 uint64_t value = de.getULEB128(C&: cursor);
238
239 std::string description;
240 if (value < std::size(strings))
241 description = strings[value];
242 else if (value <= 12)
243 description = "8-byte alignment, " + utostr(X: 1ULL << value) +
244 "-byte extended alignment";
245 else
246 description = "Invalid";
247
248 printAttribute(tag, value, valueDesc: description);
249 return Error::success();
250}
251
252Error ARMAttributeParser::ABI_align_preserved(AttrType tag) {
253 static const char *strings[] = {"Not Required", "8-byte data alignment",
254 "8-byte data and code alignment", "Reserved"};
255
256 uint64_t value = de.getULEB128(C&: cursor);
257
258 std::string description;
259 if (value < std::size(strings))
260 description = std::string(strings[value]);
261 else if (value <= 12)
262 description = std::string("8-byte stack alignment, ") +
263 utostr(X: 1ULL << value) + std::string("-byte data alignment");
264 else
265 description = "Invalid";
266
267 printAttribute(tag, value, valueDesc: description);
268 return Error::success();
269}
270
271Error ARMAttributeParser::ABI_enum_size(AttrType tag) {
272 static const char *const strings[] = {"Not Permitted", "Packed", "Int32",
273 "External Int32"};
274 return parseStringAttribute(name: "ABI_enum_size", tag, strings: ArrayRef(strings));
275}
276
277Error ARMAttributeParser::ABI_HardFP_use(AttrType tag) {
278 static const char *const strings[] = {"Tag_FP_arch", "Single-Precision",
279 "Reserved", "Tag_FP_arch (deprecated)"};
280 return parseStringAttribute(name: "ABI_HardFP_use", tag, strings: ArrayRef(strings));
281}
282
283Error ARMAttributeParser::ABI_VFP_args(AttrType tag) {
284 static const char *const strings[] = {"AAPCS", "AAPCS VFP", "Custom",
285 "Not Permitted"};
286 return parseStringAttribute(name: "ABI_VFP_args", tag, strings: ArrayRef(strings));
287}
288
289Error ARMAttributeParser::ABI_WMMX_args(AttrType tag) {
290 static const char *const strings[] = {"AAPCS", "iWMMX", "Custom"};
291 return parseStringAttribute(name: "ABI_WMMX_args", tag, strings: ArrayRef(strings));
292}
293
294Error ARMAttributeParser::ABI_optimization_goals(AttrType tag) {
295 static const char *const strings[] = {
296 "None", "Speed", "Aggressive Speed",
297 "Size", "Aggressive Size", "Debugging",
298 "Best Debugging"};
299 return parseStringAttribute(name: "ABI_optimization_goals", tag, strings: ArrayRef(strings));
300}
301
302Error ARMAttributeParser::ABI_FP_optimization_goals(AttrType tag) {
303 static const char *const strings[] = {
304 "None", "Speed", "Aggressive Speed", "Size", "Aggressive Size",
305 "Accuracy", "Best Accuracy"};
306 return parseStringAttribute(name: "ABI_FP_optimization_goals", tag,
307 strings: ArrayRef(strings));
308}
309
310Error ARMAttributeParser::compatibility(AttrType tag) {
311 uint64_t integer = de.getULEB128(C&: cursor);
312 StringRef string = de.getCStrRef(C&: cursor);
313
314 if (sw) {
315 DictScope scope(*sw, "Attribute");
316 sw->printNumber(Label: "Tag", Value: tag);
317 sw->startLine() << "Value: " << integer << ", " << string << '\n';
318 sw->printString(Label: "TagName",
319 Value: ELFAttrs::attrTypeAsString(attr: tag, tagNameMap: tagToStringMap,
320 /*hasTagPrefix=*/false));
321 switch (integer) {
322 case 0:
323 sw->printString(Label: "Description", Value: StringRef("No Specific Requirements"));
324 break;
325 case 1:
326 sw->printString(Label: "Description", Value: StringRef("AEABI Conformant"));
327 break;
328 default:
329 sw->printString(Label: "Description", Value: StringRef("AEABI Non-Conformant"));
330 break;
331 }
332 }
333 return Error::success();
334}
335
336Error ARMAttributeParser::CPU_unaligned_access(AttrType tag) {
337 static const char *const strings[] = {"Not Permitted", "v6-style"};
338 return parseStringAttribute(name: "CPU_unaligned_access", tag, strings: ArrayRef(strings));
339}
340
341Error ARMAttributeParser::FP_HP_extension(AttrType tag) {
342 static const char *const strings[] = {"If Available", "Permitted"};
343 return parseStringAttribute(name: "FP_HP_extension", tag, strings: ArrayRef(strings));
344}
345
346Error ARMAttributeParser::ABI_FP_16bit_format(AttrType tag) {
347 static const char *const strings[] = {"Not Permitted", "IEEE-754", "VFPv3"};
348 return parseStringAttribute(name: "ABI_FP_16bit_format", tag, strings: ArrayRef(strings));
349}
350
351Error ARMAttributeParser::MPextension_use(AttrType tag) {
352 static const char *const strings[] = {"Not Permitted", "Permitted"};
353 return parseStringAttribute(name: "MPextension_use", tag, strings: ArrayRef(strings));
354}
355
356Error ARMAttributeParser::DIV_use(AttrType tag) {
357 static const char *const strings[] = {"If Available", "Not Permitted",
358 "Permitted"};
359 return parseStringAttribute(name: "DIV_use", tag, strings: ArrayRef(strings));
360}
361
362Error ARMAttributeParser::DSP_extension(AttrType tag) {
363 static const char *const strings[] = {"Not Permitted", "Permitted"};
364 return parseStringAttribute(name: "DSP_extension", tag, strings: ArrayRef(strings));
365}
366
367Error ARMAttributeParser::T2EE_use(AttrType tag) {
368 static const char *const strings[] = {"Not Permitted", "Permitted"};
369 return parseStringAttribute(name: "T2EE_use", tag, strings: ArrayRef(strings));
370}
371
372Error ARMAttributeParser::Virtualization_use(AttrType tag) {
373 static const char *const strings[] = {
374 "Not Permitted", "TrustZone", "Virtualization Extensions",
375 "TrustZone + Virtualization Extensions"};
376 return parseStringAttribute(name: "Virtualization_use", tag, strings: ArrayRef(strings));
377}
378
379Error ARMAttributeParser::PAC_extension(ARMBuildAttrs::AttrType tag) {
380 static const char *const strings[] = {"Not Permitted",
381 "Permitted in NOP space", "Permitted"};
382 return parseStringAttribute(name: "PAC_extension", tag, strings: ArrayRef(strings));
383}
384
385Error ARMAttributeParser::BTI_extension(ARMBuildAttrs::AttrType tag) {
386 static const char *const strings[] = {"Not Permitted",
387 "Permitted in NOP space", "Permitted"};
388 return parseStringAttribute(name: "BTI_extension", tag, strings: ArrayRef(strings));
389}
390
391Error ARMAttributeParser::PACRET_use(ARMBuildAttrs::AttrType tag) {
392 static const char *const strings[] = {"Not Used", "Used"};
393 return parseStringAttribute(name: "PACRET_use", tag, strings: ArrayRef(strings));
394}
395
396Error ARMAttributeParser::BTI_use(ARMBuildAttrs::AttrType tag) {
397 static const char *const strings[] = {"Not Used", "Used"};
398 return parseStringAttribute(name: "BTI_use", tag, strings: ArrayRef(strings));
399}
400
401Error ARMAttributeParser::nodefaults(AttrType tag) {
402 uint64_t value = de.getULEB128(C&: cursor);
403 printAttribute(tag, value, valueDesc: "Unspecified Tags UNDEFINED");
404 return Error::success();
405}
406
407Error ARMAttributeParser::also_compatible_with(AttrType tag) {
408 // Parse value as a C string first in order to print it in escaped form later.
409 // Then, parse it again to catch errors or to pretty print if Tag_CPU_arch.
410 std::optional<Error> returnValue;
411
412 SmallString<8> Description;
413 raw_svector_ostream DescStream(Description);
414
415 uint64_t InitialOffset = cursor.tell();
416 StringRef RawStringValue = de.getCStrRef(C&: cursor);
417 uint64_t FinalOffset = cursor.tell();
418 cursor.seek(NewOffSet: InitialOffset);
419 uint64_t InnerTag = de.getULEB128(C&: cursor);
420
421 bool ValidInnerTag =
422 any_of(Range&: tagToStringMap, P: [InnerTag](const TagNameItem &Item) {
423 return Item.attr == InnerTag;
424 });
425
426 if (!ValidInnerTag) {
427 returnValue =
428 createStringError(EC: errc::argument_out_of_domain,
429 S: Twine(InnerTag) + " is not a valid tag number");
430 } else {
431 switch (InnerTag) {
432 case ARMBuildAttrs::CPU_arch: {
433 uint64_t InnerValue = de.getULEB128(C&: cursor);
434 auto strings = ArrayRef(CPU_arch_strings);
435 if (InnerValue >= strings.size()) {
436 returnValue = createStringError(
437 EC: errc::argument_out_of_domain,
438 S: Twine(InnerValue) + " is not a valid " +
439 ELFAttrs::attrTypeAsString(attr: InnerTag, tagNameMap: tagToStringMap) +
440 " value");
441 } else {
442 DescStream << ELFAttrs::attrTypeAsString(attr: InnerTag, tagNameMap: tagToStringMap)
443 << " = " << InnerValue;
444 if (strings[InnerValue])
445 DescStream << " (" << strings[InnerValue] << ')';
446 }
447 break;
448 }
449 case ARMBuildAttrs::also_compatible_with:
450 returnValue = createStringError(
451 EC: errc::invalid_argument,
452 S: ELFAttrs::attrTypeAsString(attr: InnerTag, tagNameMap: tagToStringMap) +
453 " cannot be recursively defined");
454 break;
455 case ARMBuildAttrs::CPU_raw_name:
456 case ARMBuildAttrs::CPU_name:
457 case ARMBuildAttrs::compatibility:
458 case ARMBuildAttrs::conformance: {
459 StringRef InnerValue = de.getCStrRef(C&: cursor);
460 DescStream << ELFAttrs::attrTypeAsString(attr: InnerTag, tagNameMap: tagToStringMap)
461 << " = " << InnerValue;
462 break;
463 }
464 default: {
465 uint64_t InnerValue = de.getULEB128(C&: cursor);
466 DescStream << ELFAttrs::attrTypeAsString(attr: InnerTag, tagNameMap: tagToStringMap)
467 << " = " << InnerValue;
468 }
469 }
470 }
471
472 setAttributeString(tag, value: RawStringValue);
473 if (sw) {
474 DictScope scope(*sw, "Attribute");
475 sw->printNumber(Label: "Tag", Value: tag);
476 sw->printString(Label: "TagName",
477 Value: ELFAttrs::attrTypeAsString(attr: tag, tagNameMap: tagToStringMap, hasTagPrefix: false));
478 sw->printStringEscaped(Label: "Value", Value: RawStringValue);
479 if (!Description.empty()) {
480 sw->printString(Label: "Description", Value: Description);
481 }
482 }
483
484 cursor.seek(NewOffSet: FinalOffset);
485
486 return returnValue ? std::move(*returnValue) : Error::success();
487}
488
489Error ARMAttributeParser::handler(uint64_t tag, bool &handled) {
490 handled = false;
491 for (const auto &AH : displayRoutines) {
492 if (uint64_t(AH.attribute) == tag) {
493 if (Error e = (this->*AH.routine)(static_cast<AttrType>(tag)))
494 return e;
495 handled = true;
496 break;
497 }
498 }
499
500 return Error::success();
501}
502