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