|
| 1 | +//===-AArch64AttributeParser.cpp-AArch64 Attribute Information Printer-===// |
| 2 | +// |
| 3 | +// Part of the LLVM Project, under the Apache License v2.0 with LLVM |
| 4 | +// Exceptions. |
| 5 | +// See https://llvm.org/LICENSE.txt for license information. |
| 6 | +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 7 | +// |
| 8 | +//===------------------------------------------------------------------===// |
| 9 | + |
| 10 | +#include "llvm/Support/AArch64AttributeParser.h" |
| 11 | +#include "llvm/ADT/StringExtras.h" |
| 12 | +#include "llvm/ADT/StringRef.h" |
| 13 | +#include "llvm/Support/AArch64BuildAttributes.h" |
| 14 | +#include "llvm/Support/Errc.h" |
| 15 | +#include "llvm/Support/Error.h" |
| 16 | +#include "llvm/Support/ScopedPrinter.h" |
| 17 | +#include "llvm/Support/raw_ostream.h" |
| 18 | +#include <cstdint> |
| 19 | + |
| 20 | +using namespace llvm; |
| 21 | + |
| 22 | +Error AArch64AttributeParser::parse(ArrayRef<uint8_t> Section, |
| 23 | + llvm::endianness Endian) { |
| 24 | + |
| 25 | + unsigned SectionNumber = 0; |
| 26 | + de = DataExtractor(Section, Endian == llvm::endianness::little, 0); |
| 27 | + |
| 28 | + // Early returns have specific errors. Consume the Error in cursor. |
| 29 | + struct ClearCursorError { |
| 30 | + DataExtractor::Cursor &Cursor; |
| 31 | + ~ClearCursorError() { consumeError(Cursor.takeError()); } |
| 32 | + } Clear{cursor}; |
| 33 | + |
| 34 | + /* |
| 35 | + AArch64 build attributes layout: |
| 36 | + <format-version: ‘A’> --> There is only one version, 'A' (0x41) |
| 37 | + [ <uint32: subsection-length> <NTBS: vendor-name> <bytes: vendor-data> ] |
| 38 | + --> subsection-length: the offset from the start of this subsection to the |
| 39 | + start of the next one. |
| 40 | + --> vendor-name: NUL-terminated byte string. |
| 41 | + --> vendor-data expands to: |
| 42 | + [ <uint8: optional> <uint8: parameter type> <attribute>*] |
| 43 | + --> optional: 0- required, 1- optional |
| 44 | + --> type: 0- ULEB128, 1- NTBS |
| 45 | + --> attribute: <tag, value>* pair. Tag is ULEB128, value is <parameter |
| 46 | + type> type. |
| 47 | + */ |
| 48 | + |
| 49 | + // Get format-version |
| 50 | + uint8_t FormatVersion = de.getU8(cursor); |
| 51 | + if (ELFAttrs::Format_Version != FormatVersion) |
| 52 | + return createStringError(errc::invalid_argument, |
| 53 | + "unrecognized format-version: 0x" + |
| 54 | + utohexstr(FormatVersion)); |
| 55 | + |
| 56 | + while (!de.eof(cursor)) { |
| 57 | + uint32_t BASubsectionLength = de.getU32(cursor); |
| 58 | + // Minimal valid BA subsection header size is at least 8: length(4) name(at |
| 59 | + // least a single char + null) optionality(1) and type(1) |
| 60 | + if (BASubsectionLength < 8) |
| 61 | + return createStringError( |
| 62 | + errc::invalid_argument, |
| 63 | + "invalid AArch64 build attribute subsection size at offset: " + |
| 64 | + utohexstr(cursor.tell() - 4)); |
| 65 | + |
| 66 | + StringRef VendorName = de.getCStrRef(cursor); |
| 67 | + // The layout of a private subsection (--> vendor name does not starts with |
| 68 | + // 'aeabi') is unknown, skip) |
| 69 | + if (!VendorName.starts_with("aeabi")) { |
| 70 | + sw->startLine() |
| 71 | + << "** Skipping private AArch64 build attributes subsection: " |
| 72 | + << VendorName << "\n"; |
| 73 | + // Offset in Section |
| 74 | + uint64_t OffsetInSection = cursor.tell(); |
| 75 | + // Size: 4 bytes, Vendor Name: VendorName.size() + 1 (null termination) |
| 76 | + uint32_t BytesForLengthName = 4 + (VendorName.size() + 1); |
| 77 | + cursor.seek(OffsetInSection + BASubsectionLength - BytesForLengthName); |
| 78 | + continue; |
| 79 | + } |
| 80 | + // All public subsections names must be known |
| 81 | + if (VendorName.starts_with("aeabi")) { |
| 82 | + if (!("aeabi_feature_and_bits" == VendorName || |
| 83 | + "aeabi_pauthabi" == VendorName)) { |
| 84 | + return createStringError( |
| 85 | + errc::invalid_argument, |
| 86 | + "unknown public AArch64 build attribute subsection name at " |
| 87 | + "offset: " + |
| 88 | + utohexstr(cursor.tell() - (VendorName.size() + 1))); |
| 89 | + } |
| 90 | + } |
| 91 | + |
| 92 | + uint8_t IsOptional = de.getU8(cursor); |
| 93 | + StringRef IsOptionalStr = IsOptional ? "optional" : "required"; |
| 94 | + uint8_t Type = de.getU8(cursor); |
| 95 | + StringRef TypeStr = Type ? "ntbs" : "uleb128"; |
| 96 | + |
| 97 | + if (sw) { |
| 98 | + sw->startLine() << "Section " << ++SectionNumber << " {\n"; |
| 99 | + sw->indent(); |
| 100 | + sw->printNumber("SectionLength", BASubsectionLength); |
| 101 | + sw->startLine() << "VendorName" << ": " << VendorName |
| 102 | + << " Optionality: " << IsOptionalStr |
| 103 | + << " Type: " << TypeStr << "\n"; |
| 104 | + sw->startLine() << "Attributes {\n"; |
| 105 | + sw->indent(); |
| 106 | + } |
| 107 | + |
| 108 | + // Offset in Section |
| 109 | + uint64_t OffsetInSection = cursor.tell(); |
| 110 | + // Size: 4 bytes, Vendor Name: VendorName.size() + 1 (null termination), |
| 111 | + // optionality: 1, size: 1 |
| 112 | + uint32_t BytesAllButAttributes = 4 + (VendorName.size() + 1) + 1 + 1; |
| 113 | + while (cursor.tell() < |
| 114 | + (OffsetInSection + BASubsectionLength - BytesAllButAttributes)) { |
| 115 | + |
| 116 | + uint64_t Tag = de.getULEB128(cursor); |
| 117 | + std::string Str = utostr(Tag); |
| 118 | + StringRef TagStr(Str); |
| 119 | + if ("aeabi_feature_and_bits" == VendorName) { |
| 120 | + StringRef TagAsString = |
| 121 | + AArch64BuildAttributes::getFeatureAndBitsTagsStr(Tag); |
| 122 | + if ("" != TagAsString) |
| 123 | + TagStr = TagAsString; |
| 124 | + } |
| 125 | + if ("aeabi_pauthabi" == VendorName) { |
| 126 | + StringRef TagAsString = AArch64BuildAttributes::getPauthABITagsStr(Tag); |
| 127 | + if ("" != TagAsString) |
| 128 | + TagStr = TagAsString; |
| 129 | + } |
| 130 | + |
| 131 | + if (Type) { // type==1 --> ntbs |
| 132 | + StringRef Value = de.getCStrRef(cursor); |
| 133 | + if (sw) |
| 134 | + sw->printString(TagStr, Value); |
| 135 | + } else { // type==0 --> uleb128 |
| 136 | + uint64_t Value = de.getULEB128(cursor); |
| 137 | + if (sw) |
| 138 | + sw->printNumber(TagStr, Value); |
| 139 | + } |
| 140 | + } |
| 141 | + if (sw) { |
| 142 | + // Close 'Attributes' |
| 143 | + sw->unindent(); |
| 144 | + sw->startLine() << "}\n"; |
| 145 | + // Close 'Section' |
| 146 | + sw->unindent(); |
| 147 | + sw->startLine() << "}\n"; |
| 148 | + } |
| 149 | + } |
| 150 | + |
| 151 | + return cursor.takeError(); |
| 152 | +} |
0 commit comments