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
16 using namespace llvm;
17 using namespace llvm::ARMBuildAttrs;
18
19 #define ATTRIBUTE_HANDLER(attr) \
20 { ARMBuildAttrs::attr, &ARMAttributeParser::attr }
21
22 const ARMAttributeParser::DisplayHandler ARMAttributeParser::displayRoutines[] =
23 {
24 {ARMBuildAttrs::CPU_raw_name, &ARMAttributeParser::stringAttribute},
25 {ARMBuildAttrs::CPU_name, &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
stringAttribute(AttrType tag)72 Error ARMAttributeParser::stringAttribute(AttrType tag) {
73 StringRef tagName =
74 ELFAttrs::attrTypeAsString(tag, tagToStringMap, /*hasTagPrefix=*/false);
75 StringRef desc = de.getCStrRef(cursor);
76
77 if (sw) {
78 DictScope scope(*sw, "Attribute");
79 sw->printNumber("Tag", tag);
80 if (!tagName.empty())
81 sw->printString("TagName", tagName);
82 sw->printString("Value", desc);
83 }
84 return Error::success();
85 }
86
87 static 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
CPU_arch(AttrType tag)111 Error ARMAttributeParser::CPU_arch(AttrType tag) {
112 return parseStringAttribute("CPU_arch", tag, ArrayRef(CPU_arch_strings));
113 }
114
CPU_arch_profile(AttrType tag)115 Error ARMAttributeParser::CPU_arch_profile(AttrType tag) {
116 uint64_t value = de.getULEB128(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, profile);
129 return Error::success();
130 }
131
ARM_ISA_use(AttrType tag)132 Error ARMAttributeParser::ARM_ISA_use(AttrType tag) {
133 static const char *const strings[] = {"Not Permitted", "Permitted"};
134 return parseStringAttribute("ARM_ISA_use", tag, ArrayRef(strings));
135 }
136
THUMB_ISA_use(AttrType tag)137 Error ARMAttributeParser::THUMB_ISA_use(AttrType tag) {
138 static const char *const strings[] = {"Not Permitted", "Thumb-1", "Thumb-2",
139 "Permitted"};
140 return parseStringAttribute("THUMB_ISA_use", tag, ArrayRef(strings));
141 }
142
FP_arch(AttrType tag)143 Error 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("FP_arch", tag, ArrayRef(strings));
148 }
149
WMMX_arch(AttrType tag)150 Error ARMAttributeParser::WMMX_arch(AttrType tag) {
151 static const char *const strings[] = {"Not Permitted", "WMMXv1", "WMMXv2"};
152 return parseStringAttribute("WMMX_arch", tag, ArrayRef(strings));
153 }
154
Advanced_SIMD_arch(AttrType tag)155 Error 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("Advanced_SIMD_arch", tag, ArrayRef(strings));
159 }
160
MVE_arch(AttrType tag)161 Error ARMAttributeParser::MVE_arch(AttrType tag) {
162 static const char *const strings[] = {"Not Permitted", "MVE integer",
163 "MVE integer and float"};
164 return parseStringAttribute("MVE_arch", tag, ArrayRef(strings));
165 }
166
PCS_config(AttrType tag)167 Error 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("PCS_config", tag, ArrayRef(strings));
177 }
178
ABI_PCS_R9_use(AttrType tag)179 Error ARMAttributeParser::ABI_PCS_R9_use(AttrType tag) {
180 static const char *const strings[] = {"v6", "Static Base", "TLS", "Unused"};
181 return parseStringAttribute("ABI_PCS_R9_use", tag, ArrayRef(strings));
182 }
183
ABI_PCS_RW_data(AttrType tag)184 Error ARMAttributeParser::ABI_PCS_RW_data(AttrType tag) {
185 static const char *const strings[] = {"Absolute", "PC-relative",
186 "SB-relative", "Not Permitted"};
187 return parseStringAttribute("ABI_PCS_RW_data", tag, ArrayRef(strings));
188 }
189
ABI_PCS_RO_data(AttrType tag)190 Error ARMAttributeParser::ABI_PCS_RO_data(AttrType tag) {
191 static const char *const strings[] = {"Absolute", "PC-relative",
192 "Not Permitted"};
193 return parseStringAttribute("ABI_PCS_RO_data", tag, ArrayRef(strings));
194 }
195
ABI_PCS_GOT_use(AttrType tag)196 Error ARMAttributeParser::ABI_PCS_GOT_use(AttrType tag) {
197 static const char *const strings[] = {"Not Permitted", "Direct",
198 "GOT-Indirect"};
199 return parseStringAttribute("ABI_PCS_GOT_use", tag, ArrayRef(strings));
200 }
201
ABI_PCS_wchar_t(AttrType tag)202 Error 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("ABI_PCS_wchar_t", tag, ArrayRef(strings));
206 }
207
ABI_FP_rounding(AttrType tag)208 Error ARMAttributeParser::ABI_FP_rounding(AttrType tag) {
209 static const char *const strings[] = {"IEEE-754", "Runtime"};
210 return parseStringAttribute("ABI_FP_rounding", tag, ArrayRef(strings));
211 }
212
ABI_FP_denormal(AttrType tag)213 Error ARMAttributeParser::ABI_FP_denormal(AttrType tag) {
214 static const char *const strings[] = {"Unsupported", "IEEE-754", "Sign Only"};
215 return parseStringAttribute("ABI_FP_denormal", tag, ArrayRef(strings));
216 }
217
ABI_FP_exceptions(AttrType tag)218 Error ARMAttributeParser::ABI_FP_exceptions(AttrType tag) {
219 static const char *const strings[] = {"Not Permitted", "IEEE-754"};
220 return parseStringAttribute("ABI_FP_exceptions", tag, ArrayRef(strings));
221 }
ABI_FP_user_exceptions(AttrType tag)222 Error ARMAttributeParser::ABI_FP_user_exceptions(AttrType tag) {
223 static const char *const strings[] = {"Not Permitted", "IEEE-754"};
224 return parseStringAttribute("ABI_FP_user_exceptions", tag, ArrayRef(strings));
225 }
226
ABI_FP_number_model(AttrType tag)227 Error ARMAttributeParser::ABI_FP_number_model(AttrType tag) {
228 static const char *const strings[] = {"Not Permitted", "Finite Only", "RTABI",
229 "IEEE-754"};
230 return parseStringAttribute("ABI_FP_number_model", tag, ArrayRef(strings));
231 }
232
ABI_align_needed(AttrType tag)233 Error 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(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(1ULL << value) +
244 "-byte extended alignment";
245 else
246 description = "Invalid";
247
248 printAttribute(tag, value, description);
249 return Error::success();
250 }
251
ABI_align_preserved(AttrType tag)252 Error 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(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(1ULL << value) + std::string("-byte data alignment");
264 else
265 description = "Invalid";
266
267 printAttribute(tag, value, description);
268 return Error::success();
269 }
270
ABI_enum_size(AttrType tag)271 Error ARMAttributeParser::ABI_enum_size(AttrType tag) {
272 static const char *const strings[] = {"Not Permitted", "Packed", "Int32",
273 "External Int32"};
274 return parseStringAttribute("ABI_enum_size", tag, ArrayRef(strings));
275 }
276
ABI_HardFP_use(AttrType tag)277 Error 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("ABI_HardFP_use", tag, ArrayRef(strings));
281 }
282
ABI_VFP_args(AttrType tag)283 Error ARMAttributeParser::ABI_VFP_args(AttrType tag) {
284 static const char *const strings[] = {"AAPCS", "AAPCS VFP", "Custom",
285 "Not Permitted"};
286 return parseStringAttribute("ABI_VFP_args", tag, ArrayRef(strings));
287 }
288
ABI_WMMX_args(AttrType tag)289 Error ARMAttributeParser::ABI_WMMX_args(AttrType tag) {
290 static const char *const strings[] = {"AAPCS", "iWMMX", "Custom"};
291 return parseStringAttribute("ABI_WMMX_args", tag, ArrayRef(strings));
292 }
293
ABI_optimization_goals(AttrType tag)294 Error 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("ABI_optimization_goals", tag, ArrayRef(strings));
300 }
301
ABI_FP_optimization_goals(AttrType tag)302 Error 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("ABI_FP_optimization_goals", tag,
307 ArrayRef(strings));
308 }
309
compatibility(AttrType tag)310 Error ARMAttributeParser::compatibility(AttrType tag) {
311 uint64_t integer = de.getULEB128(cursor);
312 StringRef string = de.getCStrRef(cursor);
313
314 if (sw) {
315 DictScope scope(*sw, "Attribute");
316 sw->printNumber("Tag", tag);
317 sw->startLine() << "Value: " << integer << ", " << string << '\n';
318 sw->printString("TagName",
319 ELFAttrs::attrTypeAsString(tag, tagToStringMap,
320 /*hasTagPrefix=*/false));
321 switch (integer) {
322 case 0:
323 sw->printString("Description", StringRef("No Specific Requirements"));
324 break;
325 case 1:
326 sw->printString("Description", StringRef("AEABI Conformant"));
327 break;
328 default:
329 sw->printString("Description", StringRef("AEABI Non-Conformant"));
330 break;
331 }
332 }
333 return Error::success();
334 }
335
CPU_unaligned_access(AttrType tag)336 Error ARMAttributeParser::CPU_unaligned_access(AttrType tag) {
337 static const char *const strings[] = {"Not Permitted", "v6-style"};
338 return parseStringAttribute("CPU_unaligned_access", tag, ArrayRef(strings));
339 }
340
FP_HP_extension(AttrType tag)341 Error ARMAttributeParser::FP_HP_extension(AttrType tag) {
342 static const char *const strings[] = {"If Available", "Permitted"};
343 return parseStringAttribute("FP_HP_extension", tag, ArrayRef(strings));
344 }
345
ABI_FP_16bit_format(AttrType tag)346 Error ARMAttributeParser::ABI_FP_16bit_format(AttrType tag) {
347 static const char *const strings[] = {"Not Permitted", "IEEE-754", "VFPv3"};
348 return parseStringAttribute("ABI_FP_16bit_format", tag, ArrayRef(strings));
349 }
350
MPextension_use(AttrType tag)351 Error ARMAttributeParser::MPextension_use(AttrType tag) {
352 static const char *const strings[] = {"Not Permitted", "Permitted"};
353 return parseStringAttribute("MPextension_use", tag, ArrayRef(strings));
354 }
355
DIV_use(AttrType tag)356 Error ARMAttributeParser::DIV_use(AttrType tag) {
357 static const char *const strings[] = {"If Available", "Not Permitted",
358 "Permitted"};
359 return parseStringAttribute("DIV_use", tag, ArrayRef(strings));
360 }
361
DSP_extension(AttrType tag)362 Error ARMAttributeParser::DSP_extension(AttrType tag) {
363 static const char *const strings[] = {"Not Permitted", "Permitted"};
364 return parseStringAttribute("DSP_extension", tag, ArrayRef(strings));
365 }
366
T2EE_use(AttrType tag)367 Error ARMAttributeParser::T2EE_use(AttrType tag) {
368 static const char *const strings[] = {"Not Permitted", "Permitted"};
369 return parseStringAttribute("T2EE_use", tag, ArrayRef(strings));
370 }
371
Virtualization_use(AttrType tag)372 Error ARMAttributeParser::Virtualization_use(AttrType tag) {
373 static const char *const strings[] = {
374 "Not Permitted", "TrustZone", "Virtualization Extensions",
375 "TrustZone + Virtualization Extensions"};
376 return parseStringAttribute("Virtualization_use", tag, ArrayRef(strings));
377 }
378
PAC_extension(ARMBuildAttrs::AttrType tag)379 Error ARMAttributeParser::PAC_extension(ARMBuildAttrs::AttrType tag) {
380 static const char *const strings[] = {"Not Permitted",
381 "Permitted in NOP space", "Permitted"};
382 return parseStringAttribute("PAC_extension", tag, ArrayRef(strings));
383 }
384
BTI_extension(ARMBuildAttrs::AttrType tag)385 Error ARMAttributeParser::BTI_extension(ARMBuildAttrs::AttrType tag) {
386 static const char *const strings[] = {"Not Permitted",
387 "Permitted in NOP space", "Permitted"};
388 return parseStringAttribute("BTI_extension", tag, ArrayRef(strings));
389 }
390
PACRET_use(ARMBuildAttrs::AttrType tag)391 Error ARMAttributeParser::PACRET_use(ARMBuildAttrs::AttrType tag) {
392 static const char *const strings[] = {"Not Used", "Used"};
393 return parseStringAttribute("PACRET_use", tag, ArrayRef(strings));
394 }
395
BTI_use(ARMBuildAttrs::AttrType tag)396 Error ARMAttributeParser::BTI_use(ARMBuildAttrs::AttrType tag) {
397 static const char *const strings[] = {"Not Used", "Used"};
398 return parseStringAttribute("BTI_use", tag, ArrayRef(strings));
399 }
400
nodefaults(AttrType tag)401 Error ARMAttributeParser::nodefaults(AttrType tag) {
402 uint64_t value = de.getULEB128(cursor);
403 printAttribute(tag, value, "Unspecified Tags UNDEFINED");
404 return Error::success();
405 }
406
also_compatible_with(AttrType tag)407 Error 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(cursor);
417 uint64_t FinalOffset = cursor.tell();
418 cursor.seek(InitialOffset);
419 uint64_t InnerTag = de.getULEB128(cursor);
420
421 bool ValidInnerTag =
422 any_of(tagToStringMap, [InnerTag](const TagNameItem &Item) {
423 return Item.attr == InnerTag;
424 });
425
426 if (!ValidInnerTag) {
427 returnValue =
428 createStringError(errc::argument_out_of_domain,
429 Twine(InnerTag) + " is not a valid tag number");
430 } else {
431 switch (InnerTag) {
432 case ARMBuildAttrs::CPU_arch: {
433 uint64_t InnerValue = de.getULEB128(cursor);
434 auto strings = ArrayRef(CPU_arch_strings);
435 if (InnerValue >= strings.size()) {
436 returnValue = createStringError(
437 errc::argument_out_of_domain,
438 Twine(InnerValue) + " is not a valid " +
439 ELFAttrs::attrTypeAsString(InnerTag, tagToStringMap) +
440 " value");
441 } else {
442 DescStream << ELFAttrs::attrTypeAsString(InnerTag, 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 errc::invalid_argument,
452 ELFAttrs::attrTypeAsString(InnerTag, 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(cursor);
460 DescStream << ELFAttrs::attrTypeAsString(InnerTag, tagToStringMap)
461 << " = " << InnerValue;
462 break;
463 }
464 default: {
465 uint64_t InnerValue = de.getULEB128(cursor);
466 DescStream << ELFAttrs::attrTypeAsString(InnerTag, tagToStringMap)
467 << " = " << InnerValue;
468 }
469 }
470 }
471
472 setAttributeString(tag, RawStringValue);
473 if (sw) {
474 DictScope scope(*sw, "Attribute");
475 sw->printNumber("Tag", tag);
476 sw->printString("TagName",
477 ELFAttrs::attrTypeAsString(tag, tagToStringMap, false));
478 sw->printStringEscaped("Value", RawStringValue);
479 if (!Description.empty()) {
480 sw->printString("Description", Description);
481 }
482 }
483
484 cursor.seek(FinalOffset);
485
486 return returnValue ? std::move(*returnValue) : Error::success();
487 }
488
handler(uint64_t tag,bool & handled)489 Error 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