xref: /llvm-project/llvm/lib/Support/ARMAttributeParser.cpp (revision 1c1b8c20c2d58b6a307e6fdc6db271e81ee8d603)
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 
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 
111 Error ARMAttributeParser::CPU_arch(AttrType tag) {
112   return parseStringAttribute("CPU_arch", tag, ArrayRef(CPU_arch_strings));
113 }
114 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 }
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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