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