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/STLExtras.h"
11 #include "llvm/ADT/StringExtras.h"
12 #include "llvm/Support/Errc.h"
13 #include "llvm/Support/LEB128.h"
14 #include "llvm/Support/ScopedPrinter.h"
15 
16 using namespace llvm;
17 using namespace llvm::ARMBuildAttrs;
18 
19 static const EnumEntry<unsigned> tagNames[] = {
20     {"Tag_File", ARMBuildAttrs::File},
21     {"Tag_Section", ARMBuildAttrs::Section},
22     {"Tag_Symbol", ARMBuildAttrs::Symbol},
23 };
24 
25 #define ATTRIBUTE_HANDLER(attr)                                                \
26   { ARMBuildAttrs::attr, &ARMAttributeParser::attr }
27 
28 const ARMAttributeParser::DisplayHandler ARMAttributeParser::displayRoutines[] =
29     {
30         {ARMBuildAttrs::CPU_raw_name, &ARMAttributeParser::stringAttribute},
31         {ARMBuildAttrs::CPU_name, &ARMAttributeParser::stringAttribute},
32         ATTRIBUTE_HANDLER(CPU_arch),
33         ATTRIBUTE_HANDLER(CPU_arch_profile),
34         ATTRIBUTE_HANDLER(ARM_ISA_use),
35         ATTRIBUTE_HANDLER(THUMB_ISA_use),
36         ATTRIBUTE_HANDLER(FP_arch),
37         ATTRIBUTE_HANDLER(WMMX_arch),
38         ATTRIBUTE_HANDLER(Advanced_SIMD_arch),
39         ATTRIBUTE_HANDLER(MVE_arch),
40         ATTRIBUTE_HANDLER(PCS_config),
41         ATTRIBUTE_HANDLER(ABI_PCS_R9_use),
42         ATTRIBUTE_HANDLER(ABI_PCS_RW_data),
43         ATTRIBUTE_HANDLER(ABI_PCS_RO_data),
44         ATTRIBUTE_HANDLER(ABI_PCS_GOT_use),
45         ATTRIBUTE_HANDLER(ABI_PCS_wchar_t),
46         ATTRIBUTE_HANDLER(ABI_FP_rounding),
47         ATTRIBUTE_HANDLER(ABI_FP_denormal),
48         ATTRIBUTE_HANDLER(ABI_FP_exceptions),
49         ATTRIBUTE_HANDLER(ABI_FP_user_exceptions),
50         ATTRIBUTE_HANDLER(ABI_FP_number_model),
51         ATTRIBUTE_HANDLER(ABI_align_needed),
52         ATTRIBUTE_HANDLER(ABI_align_preserved),
53         ATTRIBUTE_HANDLER(ABI_enum_size),
54         ATTRIBUTE_HANDLER(ABI_HardFP_use),
55         ATTRIBUTE_HANDLER(ABI_VFP_args),
56         ATTRIBUTE_HANDLER(ABI_WMMX_args),
57         ATTRIBUTE_HANDLER(ABI_optimization_goals),
58         ATTRIBUTE_HANDLER(ABI_FP_optimization_goals),
59         ATTRIBUTE_HANDLER(compatibility),
60         ATTRIBUTE_HANDLER(CPU_unaligned_access),
61         ATTRIBUTE_HANDLER(FP_HP_extension),
62         ATTRIBUTE_HANDLER(ABI_FP_16bit_format),
63         ATTRIBUTE_HANDLER(MPextension_use),
64         ATTRIBUTE_HANDLER(DIV_use),
65         ATTRIBUTE_HANDLER(DSP_extension),
66         ATTRIBUTE_HANDLER(T2EE_use),
67         ATTRIBUTE_HANDLER(Virtualization_use),
68         ATTRIBUTE_HANDLER(nodefaults),
69 };
70 
71 #undef ATTRIBUTE_HANDLER
72 
73 Error ARMAttributeParser::stringAttribute(AttrType tag) {
74   StringRef tagName = ARMBuildAttrs::AttrTypeAsString(tag, /*TagPrefix=*/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 void ARMAttributeParser::printAttribute(unsigned tag, unsigned value,
88                                         StringRef valueDesc) {
89   attributes.insert(std::make_pair(tag, value));
90 
91   if (sw) {
92     StringRef tagName =
93         ARMBuildAttrs::AttrTypeAsString(tag, /*TagPrefix=*/false);
94     DictScope as(*sw, "Attribute");
95     sw->printNumber("Tag", tag);
96     sw->printNumber("Value", value);
97     if (!tagName.empty())
98       sw->printString("TagName", tagName);
99     if (!valueDesc.empty())
100       sw->printString("Description", valueDesc);
101   }
102 }
103 
104 Error ARMAttributeParser::parseStringAttribute(const char *name, AttrType tag,
105                                                ArrayRef<const char *> strings) {
106   uint64_t value = de.getULEB128(cursor);
107   if (value >= strings.size()) {
108     printAttribute(tag, value, "");
109     return createStringError(errc::invalid_argument,
110                              "unknown " + Twine(name) +
111                                  " value: " + Twine(value));
112   }
113   printAttribute(tag, value, strings[value]);
114   return Error::success();
115 }
116 
117 Error ARMAttributeParser::CPU_arch(AttrType tag) {
118   static const char *strings[] = {
119     "Pre-v4", "ARM v4", "ARM v4T", "ARM v5T", "ARM v5TE", "ARM v5TEJ", "ARM v6",
120     "ARM v6KZ", "ARM v6T2", "ARM v6K", "ARM v7", "ARM v6-M", "ARM v6S-M",
121     "ARM v7E-M", "ARM v8", nullptr,
122     "ARM v8-M Baseline", "ARM v8-M Mainline", nullptr, nullptr, nullptr,
123     "ARM v8.1-M Mainline"
124   };
125   return parseStringAttribute("CPU_arch", tag, makeArrayRef(strings));
126 }
127 
128 Error ARMAttributeParser::CPU_arch_profile(AttrType tag) {
129   uint64_t value = de.getULEB128(cursor);
130 
131   StringRef profile;
132   switch (value) {
133   default: profile = "Unknown"; break;
134   case 'A': profile = "Application"; break;
135   case 'R': profile = "Real-time"; break;
136   case 'M': profile = "Microcontroller"; break;
137   case 'S': profile = "Classic"; break;
138   case 0: profile = "None"; break;
139   }
140 
141   printAttribute(tag, value, profile);
142   return Error::success();
143 }
144 
145 Error ARMAttributeParser::ARM_ISA_use(AttrType tag) {
146   static const char *strings[] = {"Not Permitted", "Permitted"};
147   return parseStringAttribute("ARM_ISA_use", tag, makeArrayRef(strings));
148 }
149 
150 Error ARMAttributeParser::THUMB_ISA_use(AttrType tag) {
151   static const char *strings[] = {"Not Permitted", "Thumb-1", "Thumb-2"};
152   return parseStringAttribute("THUMB_ISA_use", tag, makeArrayRef(strings));
153 }
154 
155 Error ARMAttributeParser::FP_arch(AttrType tag) {
156   static const char *strings[] = {
157       "Not Permitted", "VFPv1",     "VFPv2",      "VFPv3",         "VFPv3-D16",
158       "VFPv4",         "VFPv4-D16", "ARMv8-a FP", "ARMv8-a FP-D16"};
159   return parseStringAttribute("FP_arch", tag, makeArrayRef(strings));
160 }
161 
162 Error ARMAttributeParser::WMMX_arch(AttrType tag) {
163   static const char *strings[] = {"Not Permitted", "WMMXv1", "WMMXv2"};
164   return parseStringAttribute("WMMX_arch", tag, makeArrayRef(strings));
165 }
166 
167 Error ARMAttributeParser::Advanced_SIMD_arch(AttrType tag) {
168   static const char *strings[] = {"Not Permitted", "NEONv1", "NEONv2+FMA",
169                                   "ARMv8-a NEON", "ARMv8.1-a NEON"};
170   return parseStringAttribute("Advanced_SIMD_arch", tag, makeArrayRef(strings));
171 }
172 
173 Error ARMAttributeParser::MVE_arch(AttrType tag) {
174   static const char *strings[] = {"Not Permitted", "MVE integer",
175                                   "MVE integer and float"};
176   return parseStringAttribute("MVE_arch", tag, makeArrayRef(strings));
177 }
178 
179 Error ARMAttributeParser::PCS_config(AttrType tag) {
180   static const char *strings[] = {
181     "None", "Bare Platform", "Linux Application", "Linux DSO", "Palm OS 2004",
182     "Reserved (Palm OS)", "Symbian OS 2004", "Reserved (Symbian OS)"};
183   return parseStringAttribute("PCS_config", tag, makeArrayRef(strings));
184 }
185 
186 Error ARMAttributeParser::ABI_PCS_R9_use(AttrType tag) {
187   static const char *strings[] = {"v6", "Static Base", "TLS", "Unused"};
188   return parseStringAttribute("ABI_PCS_R9_use", tag, makeArrayRef(strings));
189 }
190 
191 Error ARMAttributeParser::ABI_PCS_RW_data(AttrType tag) {
192   static const char *strings[] = {"Absolute", "PC-relative", "SB-relative",
193                                   "Not Permitted"};
194   return parseStringAttribute("ABI_PCS_RW_data", tag, makeArrayRef(strings));
195 }
196 
197 Error ARMAttributeParser::ABI_PCS_RO_data(AttrType tag) {
198   static const char *strings[] = {"Absolute", "PC-relative", "Not Permitted"};
199   return parseStringAttribute("ABI_PCS_RO_data", tag, makeArrayRef(strings));
200 }
201 
202 Error ARMAttributeParser::ABI_PCS_GOT_use(AttrType tag) {
203   static const char *strings[] = {"Not Permitted", "Direct", "GOT-Indirect"};
204   return parseStringAttribute("ABI_PCS_GOT_use", tag, makeArrayRef(strings));
205 }
206 
207 Error ARMAttributeParser::ABI_PCS_wchar_t(AttrType tag) {
208   static const char *strings[] = {"Not Permitted", "Unknown", "2-byte",
209                                   "Unknown", "4-byte"};
210   return parseStringAttribute("ABI_PCS_wchar_t", tag, makeArrayRef(strings));
211 }
212 
213 Error ARMAttributeParser::ABI_FP_rounding(AttrType tag) {
214   static const char *strings[] = {"IEEE-754", "Runtime"};
215   return parseStringAttribute("ABI_FP_rounding", tag, makeArrayRef(strings));
216 }
217 
218 Error ARMAttributeParser::ABI_FP_denormal(AttrType tag) {
219   static const char *strings[] = {"Unsupported", "IEEE-754", "Sign Only"};
220   return parseStringAttribute("ABI_FP_denormal", tag, makeArrayRef(strings));
221 }
222 
223 Error ARMAttributeParser::ABI_FP_exceptions(AttrType tag) {
224   static const char *strings[] = {"Not Permitted", "IEEE-754"};
225   return parseStringAttribute("ABI_FP_exceptions", tag, makeArrayRef(strings));
226 }
227 Error ARMAttributeParser::ABI_FP_user_exceptions(AttrType tag) {
228   static const char *strings[] = {"Not Permitted", "IEEE-754"};
229   return parseStringAttribute("ABI_FP_user_exceptions", tag,
230                               makeArrayRef(strings));
231 }
232 
233 Error ARMAttributeParser::ABI_FP_number_model(AttrType tag) {
234   static const char *strings[] = {"Not Permitted", "Finite Only", "RTABI",
235                                   "IEEE-754"};
236   return parseStringAttribute("ABI_FP_number_model", tag,
237                               makeArrayRef(strings));
238 }
239 
240 Error ARMAttributeParser::ABI_align_needed(AttrType tag) {
241   static const char *strings[] = {"Not Permitted", "8-byte alignment",
242                                   "4-byte alignment", "Reserved"};
243 
244   uint64_t value = de.getULEB128(cursor);
245 
246   std::string description;
247   if (value < array_lengthof(strings))
248     description = strings[value];
249   else if (value <= 12)
250     description = "8-byte alignment, " + utostr(1ULL << value) +
251                   "-byte extended alignment";
252   else
253     description = "Invalid";
254 
255   printAttribute(tag, value, description);
256   return Error::success();
257 }
258 
259 Error ARMAttributeParser::ABI_align_preserved(AttrType tag) {
260   static const char *strings[] = {"Not Required", "8-byte data alignment",
261                                   "8-byte data and code alignment", "Reserved"};
262 
263   uint64_t value = de.getULEB128(cursor);
264 
265   std::string description;
266   if (value < array_lengthof(strings))
267     description = std::string(strings[value]);
268   else if (value <= 12)
269     description = std::string("8-byte stack alignment, ") +
270                   utostr(1ULL << value) + std::string("-byte data alignment");
271   else
272     description = "Invalid";
273 
274   printAttribute(tag, value, description);
275   return Error::success();
276 }
277 
278 Error ARMAttributeParser::ABI_enum_size(AttrType tag) {
279   static const char *strings[] = {"Not Permitted", "Packed", "Int32",
280                                   "External Int32"};
281   return parseStringAttribute("ABI_enum_size", tag, makeArrayRef(strings));
282 }
283 
284 Error ARMAttributeParser::ABI_HardFP_use(AttrType tag) {
285   static const char *strings[] = {"Tag_FP_arch", "Single-Precision", "Reserved",
286                                   "Tag_FP_arch (deprecated)"};
287   return parseStringAttribute("ABI_HardFP_use", tag, makeArrayRef(strings));
288 }
289 
290 Error ARMAttributeParser::ABI_VFP_args(AttrType tag) {
291   static const char *strings[] = {"AAPCS", "AAPCS VFP", "Custom",
292                                   "Not Permitted"};
293   return parseStringAttribute("ABI_VFP_args", tag, makeArrayRef(strings));
294 }
295 
296 Error ARMAttributeParser::ABI_WMMX_args(AttrType tag) {
297   static const char *strings[] = {"AAPCS", "iWMMX", "Custom"};
298   return parseStringAttribute("ABI_WMMX_args", tag, makeArrayRef(strings));
299 }
300 
301 Error ARMAttributeParser::ABI_optimization_goals(AttrType tag) {
302   static const char *strings[] = {
303     "None", "Speed", "Aggressive Speed", "Size", "Aggressive Size", "Debugging",
304     "Best Debugging"
305   };
306   return parseStringAttribute("ABI_optimization_goals", tag,
307                               makeArrayRef(strings));
308 }
309 
310 Error ARMAttributeParser::ABI_FP_optimization_goals(AttrType tag) {
311   static const char *strings[] = {
312       "None",     "Speed",        "Aggressive Speed", "Size", "Aggressive Size",
313       "Accuracy", "Best Accuracy"};
314   return parseStringAttribute("ABI_FP_optimization_goals", tag,
315                               makeArrayRef(strings));
316 }
317 
318 Error ARMAttributeParser::compatibility(AttrType tag) {
319   uint64_t integer = de.getULEB128(cursor);
320   StringRef string = de.getCStrRef(cursor);
321 
322   if (sw) {
323     DictScope scope(*sw, "Attribute");
324     sw->printNumber("Tag", tag);
325     sw->startLine() << "Value: " << integer << ", " << string << '\n';
326     sw->printString("TagName", AttrTypeAsString(tag, /*TagPrefix*/ false));
327     switch (integer) {
328     case 0:
329       sw->printString("Description", StringRef("No Specific Requirements"));
330       break;
331     case 1:
332       sw->printString("Description", StringRef("AEABI Conformant"));
333       break;
334     default:
335       sw->printString("Description", StringRef("AEABI Non-Conformant"));
336       break;
337     }
338   }
339   return Error::success();
340 }
341 
342 Error ARMAttributeParser::CPU_unaligned_access(AttrType tag) {
343   static const char *strings[] = {"Not Permitted", "v6-style"};
344   return parseStringAttribute("CPU_unaligned_access", tag,
345                               makeArrayRef(strings));
346 }
347 
348 Error ARMAttributeParser::FP_HP_extension(AttrType tag) {
349   static const char *strings[] = {"If Available", "Permitted"};
350   return parseStringAttribute("FP_HP_extension", tag, makeArrayRef(strings));
351 }
352 
353 Error ARMAttributeParser::ABI_FP_16bit_format(AttrType tag) {
354   static const char *strings[] = {"Not Permitted", "IEEE-754", "VFPv3"};
355   return parseStringAttribute("ABI_FP_16bit_format", tag,
356                               makeArrayRef(strings));
357 }
358 
359 Error ARMAttributeParser::MPextension_use(AttrType tag) {
360   static const char *strings[] = {"Not Permitted", "Permitted"};
361   return parseStringAttribute("MPextension_use", tag, makeArrayRef(strings));
362 }
363 
364 Error ARMAttributeParser::DIV_use(AttrType tag) {
365   static const char *strings[] = {"If Available", "Not Permitted", "Permitted"};
366   return parseStringAttribute("DIV_use", tag, makeArrayRef(strings));
367 }
368 
369 Error ARMAttributeParser::DSP_extension(AttrType tag) {
370   static const char *strings[] = {"Not Permitted", "Permitted"};
371   return parseStringAttribute("DSP_extension", tag, makeArrayRef(strings));
372 }
373 
374 Error ARMAttributeParser::T2EE_use(AttrType tag) {
375   static const char *strings[] = {"Not Permitted", "Permitted"};
376   return parseStringAttribute("T2EE_use", tag, makeArrayRef(strings));
377 }
378 
379 Error ARMAttributeParser::Virtualization_use(AttrType tag) {
380   static const char *strings[] = {"Not Permitted", "TrustZone",
381                                   "Virtualization Extensions",
382                                   "TrustZone + Virtualization Extensions"};
383   return parseStringAttribute("Virtualization_use", tag, makeArrayRef(strings));
384 }
385 
386 Error ARMAttributeParser::nodefaults(AttrType tag) {
387   uint64_t value = de.getULEB128(cursor);
388   printAttribute(tag, value, "Unspecified Tags UNDEFINED");
389   return Error::success();
390 }
391 
392 void ARMAttributeParser::parseIndexList(SmallVectorImpl<uint8_t> &indexList) {
393   for (;;) {
394     uint64_t value = de.getULEB128(cursor);
395     if (!cursor || !value)
396       break;
397     indexList.push_back(value);
398   }
399 }
400 
401 Error ARMAttributeParser::parseAttributeList(uint32_t length) {
402   uint64_t pos;
403   uint64_t end = cursor.tell() + length;
404   while ((pos = cursor.tell()) < end) {
405     uint64_t tag = de.getULEB128(cursor);
406     bool handled = false;
407     for (unsigned AHI = 0, AHE = array_lengthof(displayRoutines);
408          AHI != AHE && !handled; ++AHI) {
409       if (uint64_t(displayRoutines[AHI].attribute) == tag) {
410         if (Error e = (this->*displayRoutines[AHI].routine)(
411                 ARMBuildAttrs::AttrType(tag)))
412           return e;
413         handled = true;
414         break;
415       }
416     }
417     if (!handled) {
418       if (tag < 32)
419         return createStringError(errc::invalid_argument,
420                                  "invalid AEABI tag 0x" +
421                                      Twine::utohexstr(tag) + " at offset 0x" +
422                                      Twine::utohexstr(pos));
423 
424       if (tag % 2 == 0) {
425         uint64_t value = de.getULEB128(cursor);
426         attributes.insert(std::make_pair(tag, value));
427         if (sw)
428           sw->printNumber(ARMBuildAttrs::AttrTypeAsString(tag), value);
429       } else {
430         StringRef tagName =
431             ARMBuildAttrs::AttrTypeAsString(tag, /*TagPrefix=*/false);
432         StringRef desc = de.getCStrRef(cursor);
433 
434         if (sw) {
435           DictScope scope(*sw, "Attribute");
436           sw->printNumber("Tag", tag);
437           if (!tagName.empty())
438             sw->printString("TagName", tagName);
439           sw->printString("Value", desc);
440         }
441       }
442     }
443   }
444   return Error::success();
445 }
446 
447 Error ARMAttributeParser::parseSubsection(uint32_t length) {
448   uint64_t end = cursor.tell() - sizeof(length) + length;
449   StringRef vendorName = de.getCStrRef(cursor);
450   if (sw) {
451     sw->printNumber("SectionLength", length);
452     sw->printString("Vendor", vendorName);
453   }
454 
455   // Ignore unrecognized vendor-name.
456   if (vendorName.lower() != "aeabi")
457     return createStringError(errc::invalid_argument,
458                              "unrecognized vendor-name: " + vendorName);
459 
460   while (cursor.tell() < end) {
461     /// Tag_File | Tag_Section | Tag_Symbol   uleb128:byte-size
462     uint8_t tag = de.getU8(cursor);
463     uint32_t size = de.getU32(cursor);
464     if (!cursor)
465       return cursor.takeError();
466 
467     if (sw) {
468       sw->printEnum("Tag", tag, makeArrayRef(tagNames));
469       sw->printNumber("Size", size);
470     }
471     if (size < 5)
472       return createStringError(errc::invalid_argument,
473                                "invalid attribute size " + Twine(size) +
474                                    " at offset 0x" +
475                                    Twine::utohexstr(cursor.tell() - 5));
476 
477     StringRef scopeName, indexName;
478     SmallVector<uint8_t, 8> indicies;
479     switch (tag) {
480     case ARMBuildAttrs::File:
481       scopeName = "FileAttributes";
482       break;
483     case ARMBuildAttrs::Section:
484       scopeName = "SectionAttributes";
485       indexName = "Sections";
486       parseIndexList(indicies);
487       break;
488     case ARMBuildAttrs::Symbol:
489       scopeName = "SymbolAttributes";
490       indexName = "Symbols";
491       parseIndexList(indicies);
492       break;
493     default:
494       return createStringError(errc::invalid_argument,
495                                "unrecognized tag 0x" + Twine::utohexstr(tag) +
496                                    " at offset 0x" +
497                                    Twine::utohexstr(cursor.tell() - 5));
498     }
499 
500     if (sw) {
501       DictScope scope(*sw, scopeName);
502       if (!indicies.empty())
503         sw->printList(indexName, indicies);
504       if (Error e = parseAttributeList(size - 5))
505         return e;
506     } else if (Error e = parseAttributeList(size - 5))
507       return e;
508   }
509   return Error::success();
510 }
511 
512 Error ARMAttributeParser::parse(ArrayRef<uint8_t> section,
513                                 support::endianness endian) {
514   unsigned sectionNumber = 0;
515   de = DataExtractor(section, endian == support::little, 0);
516 
517   // For early returns, we have more specific errors, consume the Error in
518   // cursor.
519   struct ClearCursorError {
520     DataExtractor::Cursor &cursor;
521     ~ClearCursorError() { consumeError(cursor.takeError()); }
522   } clear{cursor};
523 
524   // Unrecognized format-version.
525   uint8_t formatVersion = de.getU8(cursor);
526   if (formatVersion != 'A')
527     return createStringError(errc::invalid_argument,
528                              "unrecognized format-version: 0x" +
529                                  utohexstr(formatVersion));
530 
531   while (!de.eof(cursor)) {
532     uint32_t sectionLength = de.getU32(cursor);
533     if (!cursor)
534       return cursor.takeError();
535 
536     if (sw) {
537       sw->startLine() << "Section " << ++sectionNumber << " {\n";
538       sw->indent();
539     }
540 
541     if (sectionLength < 4 || cursor.tell() - 4 + sectionLength > section.size())
542       return createStringError(errc::invalid_argument,
543                                "invalid subsection length " +
544                                    Twine(sectionLength) + " at offset 0x" +
545                                    utohexstr(cursor.tell() - 4));
546     if (Error e = parseSubsection(sectionLength))
547       return e;
548     if (sw) {
549       sw->unindent();
550       sw->startLine() << "}\n";
551     }
552   }
553 
554   return cursor.takeError();
555 }
556