[lld] [llvm] [readobj][Arm][AArch64] Refactor Build Attributes parsing under ELFAtributeParser and add support for AArch64 Build Attributes (PR #128727)

Oliver Stannard via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 26 02:40:01 PST 2025


================
@@ -0,0 +1,176 @@
+//===-ELFAttrParserExtended.cpp-ELF Extended Attribute Information Printer-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM
+// Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===------------------------------------------------------------------===//
+
+#include "llvm/Support/ELFAttrParserExtended.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/AArch64BuildAttributes.h"
+#include "llvm/Support/ELFAttributes.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstdint>
+
+using namespace llvm;
+using namespace ELFAttrs;
+
+std::optional<unsigned>
+ELFExtendedAttrParser::getAttributeValue(StringRef BuildAttrSubsectionName,
+                                         unsigned Tag) const {
+  for (auto SubSection : SubSectionVec) {
+    if (BuildAttrSubsectionName == SubSection.Name)
+      for (auto BAItem : SubSection.Content) {
+        if (Tag == BAItem.Tag)
+          return std::optional<unsigned>(BAItem.IntValue);
+      }
+  }
+  return std::nullopt;
+}
+
+std::optional<StringRef>
+ELFExtendedAttrParser::getAttributeString(StringRef BuildAttrSubsectionName,
+                                          unsigned Tag) const {
+  for (auto SubSection : SubSectionVec) {
+    if (BuildAttrSubsectionName == SubSection.Name)
+      for (auto BAItem : SubSection.Content) {
+        if (Tag == BAItem.Tag)
+          return std::optional<StringRef>(BAItem.StringValue);
+      }
+  }
+  return std::nullopt;
+}
+
+StringRef ELFExtendedAttrParser::getTagName(const StringRef &s,
+                                            const unsigned i) {
+  for (const auto &entry : TagsNamesMap) {
+    if (s == entry.SubsectionName) {
+      if (i == entry.Tag) {
+        return entry.TagName;
+      }
+    }
+  }
+  return "";
+}
+
+Error ELFExtendedAttrParser::parse(ArrayRef<uint8_t> Section,
+                                   llvm::endianness Endian) {
+
+  unsigned SectionNumber = 0;
+  De = DataExtractor(Section, Endian == llvm::endianness::little, 0);
+
+  // Early returns have specific errors. Consume the Error in Cursor.
+  struct ClearCursorError {
+    DataExtractor::Cursor &Cursor;
+    ~ClearCursorError() { consumeError(Cursor.takeError()); }
+  } Clear{Cursor};
+
+  /*
+      ELF Extended Build Attributes Layout:
+      <format-version: ‘A’> --> Currently, there is only one version: 'A' (0x41)
+      [ <uint32: subsection-length> <NTBS: vendor-name> <bytes: vendor-data> ]
+        --> subsection-length: Offset from the start of this subsection to the
+     start of the next one.
+        --> vendor-name: Null-terminated byte string.
+        --> vendor-data expands to:
+          [ <uint8: optional> <uint8: parameter type> <attribute>* ]
+            --> optional: 0 = required, 1 = optional.
+            --> parameter type: 0 = ULEB128, 1 = NTBS.
+            --> attribute: <tag, value>* pair. Tag is ULEB128, value is of
+     <parameter type>.
+  */
+
+  // Get format-version
+  uint8_t FormatVersion = De.getU8(Cursor);
+  if (ELFAttrs::Format_Version != FormatVersion)
+    return createStringError(errc::invalid_argument,
+                             "unrecognized format-version: 0x" +
+                                 utohexstr(FormatVersion));
+
+  while (!De.eof(Cursor)) {
+    uint32_t ExtBASubsectionLength = De.getU32(Cursor);
+    // Minimal valid Extended Build Attributes subsection header size is at
+    // least 8: length(4) name(at least a single char + null) optionality(1) and
+    // type(1)
+    if (ExtBASubsectionLength < 8)
+      return createStringError(
+          errc::invalid_argument,
+          "invalid Extended Build Attributes subsection size at offset: " +
+              utohexstr(Cursor.tell() - 4));
+
+    StringRef VendorName = De.getCStrRef(Cursor);
+    uint8_t IsOptional = De.getU8(Cursor);
+    StringRef IsOptionalStr = IsOptional ? "optional" : "required";
+    uint8_t Type = De.getU8(Cursor);
+    StringRef TypeStr = Type ? "ntbs" : "uleb128";
+
+    BuildAttributeSubSection BASubSection;
+    BASubSection.Name = VendorName;
+    BASubSection.IsOptional = IsOptional;
+    BASubSection.ParameterType = Type;
+
+    if (Sw) {
+      Sw->startLine() << "Section " << ++SectionNumber << " {\n";
+      Sw->indent();
+      Sw->printNumber("SectionLength", ExtBASubsectionLength);
+      Sw->startLine() << "VendorName" << ": " << VendorName
+                      << " Optionality: " << IsOptionalStr
+                      << " Type: " << TypeStr << "\n";
+      Sw->startLine() << "Attributes {\n";
+      Sw->indent();
+    }
+
+    // Offset in Section
+    uint64_t OffsetInSection = Cursor.tell();
+    // Size: 4 bytes, Vendor Name: VendorName.size() + 1 (null termination),
+    // optionality: 1, size: 1
+    uint32_t BytesAllButAttributes = 4 + (VendorName.size() + 1) + 1 + 1;
+    while (Cursor.tell() <
+           (OffsetInSection + ExtBASubsectionLength - BytesAllButAttributes)) {
+
+      uint64_t Tag = De.getULEB128(Cursor);
+      std::string Str = utostr(Tag);
+      StringRef TagStr(Str);
+
+      StringRef TagAsString = getTagName(VendorName, Tag);
+      if ("" != TagAsString)
+        TagStr = TagAsString;
+
+      uint64_t ValueInt = 0;
----------------
ostannard wrote:

These aren't modified, and we always construct the `BuildAttributeItem` below with the default values.

https://github.com/llvm/llvm-project/pull/128727


More information about the llvm-commits mailing list