HsiangKai updated this revision to Diff 251287.

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D74023/new/

https://reviews.llvm.org/D74023

Files:
  lld/ELF/InputFiles.cpp
  lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
  llvm/include/llvm/BinaryFormat/ELF.h
  llvm/include/llvm/Object/ELFObjectFile.h
  llvm/include/llvm/Support/ARMAttributeParser.h
  llvm/include/llvm/Support/ARMBuildAttributes.h
  llvm/include/llvm/Support/ELFAttributeParser.h
  llvm/include/llvm/Support/ELFAttributes.h
  llvm/include/llvm/Support/RISCVAttributeParser.h
  llvm/include/llvm/Support/RISCVAttributes.h
  llvm/lib/Object/ELF.cpp
  llvm/lib/Object/ELFObjectFile.cpp
  llvm/lib/ObjectYAML/ELFYAML.cpp
  llvm/lib/Support/ARMAttributeParser.cpp
  llvm/lib/Support/ARMBuildAttrs.cpp
  llvm/lib/Support/CMakeLists.txt
  llvm/lib/Support/ELFAttributeParser.cpp
  llvm/lib/Support/ELFAttributes.cpp
  llvm/lib/Support/RISCVAttributeParser.cpp
  llvm/lib/Support/RISCVAttributes.cpp
  llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
  llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
  llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
  llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp
  llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h
  llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp
  llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h
  llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
  llvm/test/CodeGen/RISCV/attributes.ll
  llvm/test/MC/RISCV/attribute-arch.s
  llvm/test/MC/RISCV/attribute-with-insts.s
  llvm/test/MC/RISCV/attribute.s
  llvm/test/MC/RISCV/invalid-attribute.s
  llvm/test/tools/llvm-objdump/RISCV/lit.local.cfg
  llvm/test/tools/llvm-objdump/RISCV/unknown-arch-attr.test
  llvm/tools/llvm-readobj/ELFDumper.cpp
  llvm/unittests/Support/ARMAttributeParser.cpp
  llvm/unittests/Support/CMakeLists.txt
  llvm/unittests/Support/ELFAttributeParserTest.cpp
  llvm/unittests/Support/RISCVAttributeParserTest.cpp

Index: llvm/unittests/Support/RISCVAttributeParserTest.cpp
===================================================================
--- /dev/null
+++ llvm/unittests/Support/RISCVAttributeParserTest.cpp
@@ -0,0 +1,69 @@
+//===----- unittests/RISCVAttributeParserTest.cpp -------------------------===//
+//
+// 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/RISCVAttributeParser.h"
+#include "llvm/Support/ARMBuildAttributes.h"
+#include "llvm/Support/ELFAttributes.h"
+#include "gtest/gtest.h"
+#include <string>
+
+using namespace llvm;
+
+struct RISCVAttributeSection {
+  unsigned Tag;
+  unsigned Value;
+
+  RISCVAttributeSection(unsigned tag, unsigned value) : Tag(tag), Value(value) {}
+
+  void write(raw_ostream &OS) {
+    OS.flush();
+    // length = length + "riscv\0" + TagFile + ByteSize + Tag + Value;
+    // length = 17 bytes
+
+    OS << 'A' << (uint8_t)17 << (uint8_t)0 << (uint8_t)0 << (uint8_t)0;
+    OS << "riscv" << '\0';
+    OS << (uint8_t)1 << (uint8_t)7 << (uint8_t)0 << (uint8_t)0 << (uint8_t)0;
+    OS << (uint8_t)Tag << (uint8_t)Value;
+  }
+};
+
+static bool testAttribute(unsigned Tag, unsigned Value, unsigned ExpectedTag,
+                   unsigned ExpectedValue) {
+  std::string buffer;
+  raw_string_ostream OS(buffer);
+  RISCVAttributeSection Section(Tag, Value);
+  Section.write(OS);
+  ArrayRef<uint8_t> Bytes(reinterpret_cast<const uint8_t *>(OS.str().c_str()),
+                          OS.str().size());
+
+  RISCVAttributeParser Parser;
+  cantFail(Parser.parse(Bytes, support::little));
+
+  Optional<unsigned> Attr = Parser.getAttributeValue(ExpectedTag);
+  return Attr.hasValue() && Attr.getValue() == ExpectedValue;
+}
+
+static bool testTagString(unsigned Tag, const char *name) {
+  return ELFAttrs::attrTypeAsString(Tag, RISCVAttrs::RISCVAttributeTags)
+             .str() == name;
+}
+
+TEST(StackAlign, testAttribute) {
+  EXPECT_TRUE(testTagString(4, "Tag_stack_align"));
+  EXPECT_TRUE(
+      testAttribute(4, 4, RISCVAttrs::STACK_ALIGN, RISCVAttrs::ALIGN_4));
+  EXPECT_TRUE(
+      testAttribute(4, 16, RISCVAttrs::STACK_ALIGN, RISCVAttrs::ALIGN_16));
+}
+
+TEST(UnalignedAccess, testAttribute) {
+  EXPECT_TRUE(testTagString(6, "Tag_unaligned_access"));
+  EXPECT_TRUE(testAttribute(6, 0, RISCVAttrs::UNALIGNED_ACCESS,
+                            RISCVAttrs::NOT_ALLOWED));
+  EXPECT_TRUE(
+      testAttribute(6, 1, RISCVAttrs::UNALIGNED_ACCESS, RISCVAttrs::ALLOWED));
+}
Index: llvm/unittests/Support/ELFAttributeParserTest.cpp
===================================================================
--- /dev/null
+++ llvm/unittests/Support/ELFAttributeParserTest.cpp
@@ -0,0 +1,63 @@
+//===----- unittests/ELFAttributeParserTest.cpp ---------------------------===//
+//
+// 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/ELFAttributeParser.h"
+#include "llvm/Support/ELFAttributes.h"
+#include "gtest/gtest.h"
+#include <string>
+
+using namespace llvm;
+
+TagNameMap emptyTagNameMap;
+
+// This class is used to test the common part of the ELF attribute section.
+class AttributeHeaderParser : public ELFAttributeParser {
+  Error handler(uint64_t tag, bool &handled) {
+    // Dummy function. There is no attribute need to be handled.
+    handled = true;
+    return Error::success();
+  }
+
+public:
+  AttributeHeaderParser(ScopedPrinter *sw)
+      : ELFAttributeParser(sw, emptyTagNameMap, "test") {}
+  AttributeHeaderParser() : ELFAttributeParser(emptyTagNameMap, "test") {}
+};
+
+static void testParseError(ArrayRef<uint8_t> bytes, const char *msg) {
+  AttributeHeaderParser parser;
+  Error e = parser.parse(bytes, support::little);
+  EXPECT_STREQ(toString(std::move(e)).c_str(), msg);
+}
+
+TEST(AttributeHeaderParser, UnrecognizedFormatVersion) {
+  static const uint8_t bytes[] = {1};
+  testParseError(bytes, "unrecognized format-version: 0x1");
+}
+
+TEST(AttributeHeaderParser, InvalidSubsectionLength) {
+  static const uint8_t bytes[] = {'A', 3, 0, 0, 0};
+  testParseError(bytes, "invalid subsection length 3 at offset 0x1");
+}
+
+TEST(AttributeHeaderParser, UnrecognizedVendorName) {
+  static const uint8_t bytes[] = {'A', 7, 0, 0, 0, 'x', 'y', 0};
+  testParseError(bytes, "unrecognized vendor-name: xy");
+}
+
+TEST(AttributeHeaderParser, UnrecognizedTag) {
+  static const uint8_t bytes[] = {'A', 14, 0, 0, 0, 't', 'e', 's',
+                                  't', 0,  4, 5, 0, 0,   0};
+  testParseError(bytes, "unrecognized tag 0x4 at offset 0xa");
+}
+
+TEST(AttributeHeaderParser, InvalidAttributeSize) {
+  static const uint8_t bytes[] = {'A', 14, 0, 0, 0, 't', 'e', 's',
+                                  't', 0,  1, 4, 0, 0,   0};
+  testParseError(bytes, "invalid attribute size 4 at offset 0xa");
+}
Index: llvm/unittests/Support/CMakeLists.txt
===================================================================
--- llvm/unittests/Support/CMakeLists.txt
+++ llvm/unittests/Support/CMakeLists.txt
@@ -28,6 +28,7 @@
   DJBTest.cpp
   EndianStreamTest.cpp
   EndianTest.cpp
+  ELFAttributeParserTest.cpp
   ErrnoTest.cpp
   ErrorOrTest.cpp
   ErrorTest.cpp
@@ -58,6 +59,7 @@
   RegexTest.cpp
   ReverseIterationTest.cpp
   ReplaceFileTest.cpp
+  RISCVAttributeParserTest.cpp
   ScaledNumberTest.cpp
   SourceMgrTest.cpp
   SpecialCaseListTest.cpp
Index: llvm/unittests/Support/ARMAttributeParser.cpp
===================================================================
--- llvm/unittests/Support/ARMAttributeParser.cpp
+++ llvm/unittests/Support/ARMAttributeParser.cpp
@@ -1,5 +1,6 @@
 #include "llvm/Support/ARMAttributeParser.h"
 #include "llvm/Support/ARMBuildAttributes.h"
+#include "llvm/Support/ELFAttributes.h"
 #include "gtest/gtest.h"
 #include <string>
 
@@ -36,8 +37,8 @@
   ARMAttributeParser Parser;
   cantFail(Parser.parse(Bytes, support::little));
 
-  return (Parser.hasAttribute(ExpectedTag) &&
-    Parser.getAttributeValue(ExpectedTag) == ExpectedValue);
+  Optional<unsigned> Attr = Parser.getAttributeValue(ExpectedTag);
+  return Attr.hasValue() && Attr.getValue() == ExpectedValue;
 }
 
 void testParseError(ArrayRef<uint8_t> bytes, const char *msg) {
@@ -47,34 +48,8 @@
 }
 
 bool testTagString(unsigned Tag, const char *name) {
-  return ARMBuildAttrs::AttrTypeAsString(Tag).str() == name;
-}
-
-TEST(ARMAttributeParser, UnrecognizedFormatVersion) {
-  static const uint8_t bytes[] = {1};
-  testParseError(bytes, "unrecognized format-version: 0x1");
-}
-
-TEST(ARMAttributeParser, InvalidSubsectionLength) {
-  static const uint8_t bytes[] = {'A', 3, 0, 0, 0};
-  testParseError(bytes, "invalid subsection length 3 at offset 0x1");
-}
-
-TEST(ARMAttributeParser, UnrecognizedVendorName) {
-  static const uint8_t bytes[] = {'A', 7, 0, 0, 0, 'x', 'y', 0};
-  testParseError(bytes, "unrecognized vendor-name: xy");
-}
-
-TEST(ARMAttributeParser, InvalidAttributeSize) {
-  static const uint8_t bytes[] = {'A', 15,  0, 0, 0, 'a', 'e', 'a',
-                                  'b', 'i', 0, 4, 4, 0,   0,   0};
-  testParseError(bytes, "invalid attribute size 4 at offset 0xb");
-}
-
-TEST(ARMAttributeParser, UnrecognizedTag) {
-  static const uint8_t bytes[] = {'A', 15,  0, 0, 0, 'a', 'e', 'a',
-                                  'b', 'i', 0, 4, 5, 0,   0,   0};
-  testParseError(bytes, "unrecognized tag 0x4 at offset 0xb");
+  return ELFAttrs::attrTypeAsString(Tag, ARMBuildAttrs::ARMAttributeTags)
+             .str() == name;
 }
 
 TEST(ARMAttributeParser, UnknownCPU_arch) {
Index: llvm/tools/llvm-readobj/ELFDumper.cpp
===================================================================
--- llvm/tools/llvm-readobj/ELFDumper.cpp
+++ llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -2680,7 +2680,7 @@
 
     ArrayRef<uint8_t> Contents =
         unwrapOrError(ObjF->getFileName(), Obj->getSectionContents(&Sec));
-    if (Contents[0] != ARMBuildAttrs::Format_Version) {
+    if (Contents[0] != ELFAttrs::Format_Version) {
       errs() << "unrecognised FormatVersion: 0x"
              << Twine::utohexstr(Contents[0]) << '\n';
       continue;
Index: llvm/test/tools/llvm-objdump/RISCV/unknown-arch-attr.test
===================================================================
--- /dev/null
+++ llvm/test/tools/llvm-objdump/RISCV/unknown-arch-attr.test
@@ -0,0 +1,38 @@
+## Handle unrecognized arch attributes.
+## Encode an unrecognized arch feature into an object file and try to decode it.
+## The expected behavior is to ignore the unrecognized arch feature and
+## continue to process the following arch features.
+##
+## The object file has the "rv32i2p0_x1p0_m2p0" arch feature. "x1p0" is an
+## unrecognized architecture extension. llvm-objdump will ignore it and decode
+## "mul" instruction correctly according to "m2p0" in the arch feature.
+##
+## This test cannot be assembly because the test needs an unrecognized arch
+## feature and `llvm-mc` will filter out the unrecognized arch feature.
+
+# RUN: yaml2obj %s -D BITS=32 -o %t.32.o
+# RUN: llvm-objdump -d %t.32.o \
+# RUN:   | FileCheck %s --check-prefixes=DISASM
+# RUN: yaml2obj %s -D BITS=64 -o %t.64.o
+# RUN: llvm-objdump -d %t.64.o \
+# RUN:   | FileCheck %s --check-prefixes=DISASM
+
+# DISASM: mul a0, a1, a2
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS[[BITS]]
+  Data:    ELFDATA2LSB
+  Type:    ET_REL
+  Machine: EM_RISCV
+Sections:
+  - Name:    .text
+    Type:    SHT_PROGBITS
+    Flags:   [ SHF_ALLOC, SHF_EXECINSTR ]
+## The content is the encoding of "mul a0, a1, a2".
+## The encoding could be decoded only when the "m" extension is enabled.
+    Content: 3385C502
+  - Name:    .riscv.attributes
+    Type:    SHT_RISCV_ATTRIBUTES
+## The content is the encoding of the arch feature "rv32i2p0_x1p0_m2p0"
+    Content: 412300000072697363760001190000000572763332693270305F783170305F6D32703000
Index: llvm/test/tools/llvm-objdump/RISCV/lit.local.cfg
===================================================================
--- /dev/null
+++ llvm/test/tools/llvm-objdump/RISCV/lit.local.cfg
@@ -0,0 +1,2 @@
+if not 'RISCV' in config.root.targets:
+    config.unsupported = True
Index: llvm/test/MC/RISCV/invalid-attribute.s
===================================================================
--- /dev/null
+++ llvm/test/MC/RISCV/invalid-attribute.s
@@ -0,0 +1,31 @@
+## Negative tests:
+##  - Feed integer value to string type attribute.
+##  - Feed string value to integer type attribute.
+##  - Invalid arch string.
+
+# RUN: not llvm-mc %s -triple=riscv32 -filetype=asm 2>&1 | FileCheck %s
+# RUN: not llvm-mc %s -triple=riscv64 -filetype=asm 2>&1 | FileCheck %s
+
+.attribute arch, "foo"
+# CHECK: [[@LINE-1]]:18: error: bad arch string foo
+
+.attribute arch, "rv32i2p0_y2p0"
+# CHECK: [[@LINE-1]]:18: error: bad arch string y2p0
+
+.attribute stack_align, "16"
+# CHECK: [[@LINE-1]]:25: error: expected numeric constant
+
+.attribute unaligned_access, "0"
+# CHECK: [[@LINE-1]]:30: error: expected numeric constant
+
+.attribute priv_spec, "2"
+# CHECK: [[@LINE-1]]:23: error: expected numeric constant
+
+.attribute priv_spec_minor, "0"
+# CHECK: [[@LINE-1]]:29: error: expected numeric constant
+
+.attribute priv_spec_revision, "0"
+# CHECK: [[@LINE-1]]:32: error: expected numeric constant
+
+.attribute arch, 30
+# CHECK: [[@LINE-1]]:18: error: expected string constant
Index: llvm/test/MC/RISCV/attribute.s
===================================================================
--- /dev/null
+++ llvm/test/MC/RISCV/attribute.s
@@ -0,0 +1,22 @@
+## Test llvm-mc could handle .attribute correctly.
+
+# RUN: llvm-mc %s -triple=riscv32 -filetype=asm | FileCheck %s
+# RUN: llvm-mc %s -triple=riscv64 -filetype=asm | FileCheck %s
+
+.attribute stack_align, 16
+# CHECK: attribute      4, 16
+
+.attribute arch, "rv32i2p0_m2p0_a2p0_c2p0"
+# CHECK: attribute      5, "rv32i2p0_m2p0_a2p0_c2p0"
+
+.attribute unaligned_access, 0
+# CHECK: attribute      6, 0
+
+.attribute priv_spec, 2
+# CHECK: attribute      8, 2
+
+.attribute priv_spec_minor, 0
+# CHECK: attribute      10, 0
+
+.attribute priv_spec_revision, 0
+# CHECK: attribute      12, 0
Index: llvm/test/MC/RISCV/attribute-with-insts.s
===================================================================
--- /dev/null
+++ llvm/test/MC/RISCV/attribute-with-insts.s
@@ -0,0 +1,34 @@
+## Test .attribute effects.
+## We do not provide '-mattr=' and '.option rvc' and enable extensions through
+## '.attribute arch'.
+
+# RUN: llvm-mc -triple riscv32 -filetype=obj %s \
+# RUN:   | llvm-objdump -triple riscv32 -d -M no-aliases - \
+# RUN:   | FileCheck -check-prefix=CHECK-INST %s
+
+# RUN: llvm-mc -triple riscv64 -filetype=obj %s \
+# RUN:   | llvm-objdump -triple riscv64 -d -M no-aliases - \
+# RUN:   | FileCheck -check-prefix=CHECK-INST %s
+
+.attribute arch, "rv64i2p0_m2p0_a2p0_d2p0_c2p0"
+
+# CHECK-INST: lr.w t0, (t1)
+lr.w t0, (t1)
+
+# CHECK-INST: c.addi a3, -32
+c.addi a3, -32
+
+# CHECK-INST: fmadd.d fa0, fa1, fa2, fa3, dyn
+fmadd.d f10, f11, f12, f13, dyn
+
+# CHECK-INST: fmadd.s fa0, fa1, fa2, fa3, dyn
+fmadd.s f10, f11, f12, f13, dyn
+
+# CHECK-INST: addi ra, sp, 2
+addi ra, sp, 2
+
+# CHECK-INST: mul a4, ra, s0
+mul a4, ra, s0
+
+# CHECK-INST: addw a2, a3, a4
+addw a2, a3, a4
Index: llvm/test/MC/RISCV/attribute-arch.s
===================================================================
--- /dev/null
+++ llvm/test/MC/RISCV/attribute-arch.s
@@ -0,0 +1,38 @@
+## Arch string without version.
+
+# RUN: llvm-mc %s -triple=riscv32 -filetype=asm | FileCheck %s
+# RUN: llvm-mc %s -triple=riscv64 -filetype=asm | FileCheck %s
+
+.attribute arch, "rv32i"
+# CHECK: attribute      5, "rv32i2p0"
+
+.attribute arch, "rv32i2"
+# CHECK: attribute      5, "rv32i2p0"
+
+.attribute arch, "rv32i2p"
+# CHECK: attribute      5, "rv32i2p0"
+
+.attribute arch, "rv32i2p0"
+# CHECK: attribute      5, "rv32i2p0"
+
+.attribute arch, "rv32i2_m2"
+# CHECK: attribute      5, "rv32i2p0_m2p0"
+
+.attribute arch, "rv32i2_ma"
+# CHECK: attribute      5, "rv32i2p0_m2p0_a2p0"
+
+.attribute arch, "rv32g"
+# CHECK: attribute      5, "rv32i2p0_m2p0_a2p0_f2p0_d2p0"
+
+.attribute arch, "rv32imafdc"
+# CHECK: attribute      5, "rv32i2p0_m2p0_a2p0_f2p0_d2p0_c2p0"
+
+.attribute arch, "rv32i2p0_mafdc"
+# CHECK: attribute      5, "rv32i2p0_m2p0_a2p0_f2p0_d2p0_c2p0"
+
+.attribute arch, "rv32ima2p0_fdc"
+# CHECK: attribute      5, "rv32i2p0_m2p0_a2p0_f2p0_d2p0_c2p0"
+
+.attribute arch, "rv32ima2p_fdc"
+# CHECK: attribute      5, "rv32i2p0_m2p0_a2p0_f2p0_d2p0_c2p0"
+
Index: llvm/test/CodeGen/RISCV/attributes.ll
===================================================================
--- /dev/null
+++ llvm/test/CodeGen/RISCV/attributes.ll
@@ -0,0 +1,29 @@
+;; Generate ELF attributes from llc.
+
+; RUN: llc -mtriple=riscv32 -mattr=+m %s -o - | FileCheck --check-prefix=RV32M %s
+; RUN: llc -mtriple=riscv32 -mattr=+a %s -o - | FileCheck --check-prefix=RV32A %s
+; RUN: llc -mtriple=riscv32 -mattr=+f %s -o - | FileCheck --check-prefix=RV32F %s
+; RUN: llc -mtriple=riscv32 -mattr=+d %s -o - | FileCheck --check-prefix=RV32D %s
+; RUN: llc -mtriple=riscv32 -mattr=+c %s -o - | FileCheck --check-prefix=RV32C %s
+; RUN: llc -mtriple=riscv64 -mattr=+m %s -o - | FileCheck --check-prefix=RV64M %s
+; RUN: llc -mtriple=riscv64 -mattr=+a %s -o - | FileCheck --check-prefix=RV64A %s
+; RUN: llc -mtriple=riscv64 -mattr=+f %s -o - | FileCheck --check-prefix=RV64F %s
+; RUN: llc -mtriple=riscv64 -mattr=+d %s -o - | FileCheck --check-prefix=RV64D %s
+; RUN: llc -mtriple=riscv64 -mattr=+c %s -o - | FileCheck --check-prefix=RV64C %s
+
+; RV32M: .attribute 5, "rv32i2p0_m2p0"
+; RV32A: .attribute 5, "rv32i2p0_a2p0"
+; RV32F: .attribute 5, "rv32i2p0_f2p0"
+; RV32D: .attribute 5, "rv32i2p0_f2p0_d2p0"
+; RV32C: .attribute 5, "rv32i2p0_c2p0"
+; RV64M: .attribute 5, "rv64i2p0_m2p0"
+; RV64A: .attribute 5, "rv64i2p0_a2p0"
+; RV64F: .attribute 5, "rv64i2p0_f2p0"
+; RV64D: .attribute 5, "rv64i2p0_f2p0_d2p0"
+; RV64C: .attribute 5, "rv64i2p0_c2p0"
+
+define i32 @addi(i32 %a) nounwind {
+  %1 = add i32 %a, 1
+  ret i32 %1
+}
+
Index: llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
===================================================================
--- llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
+++ llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
@@ -11,9 +11,10 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "RISCV.h"
 #include "MCTargetDesc/RISCVInstPrinter.h"
 #include "MCTargetDesc/RISCVMCExpr.h"
+#include "MCTargetDesc/RISCVTargetStreamer.h"
+#include "RISCV.h"
 #include "RISCVTargetMachine.h"
 #include "TargetInfo/RISCVTargetInfo.h"
 #include "llvm/ADT/Statistic.h"
@@ -63,6 +64,12 @@
   bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const {
     return LowerRISCVMachineOperandToMCOperand(MO, MCOp, *this);
   }
+
+  void emitStartOfAsmFile(Module &M) override;
+  void emitEndOfAsmFile(Module &M) override;
+
+private:
+  void emitAttributes();
 };
 }
 
@@ -170,6 +177,32 @@
   return false;
 }
 
+void RISCVAsmPrinter::emitStartOfAsmFile(Module &M) {
+  if (TM.getTargetTriple().isOSBinFormatELF())
+    emitAttributes();
+}
+
+void RISCVAsmPrinter::emitEndOfAsmFile(Module &M) {
+  MCTargetStreamer &TS = *OutStreamer->getTargetStreamer();
+  RISCVTargetStreamer &RTS = static_cast<RISCVTargetStreamer &>(TS);
+
+  if (TM.getTargetTriple().isOSBinFormatELF())
+    RTS.finishAttributeSection();
+}
+
+void RISCVAsmPrinter::emitAttributes() {
+  MCTargetStreamer &TS = *OutStreamer->getTargetStreamer();
+  RISCVTargetStreamer &RTS = static_cast<RISCVTargetStreamer &>(TS);
+
+  const Triple &TT = TM.getTargetTriple();
+  StringRef CPU = TM.getTargetCPU();
+  StringRef FS = TM.getTargetFeatureString();
+  const RISCVTargetMachine &RTM = static_cast<const RISCVTargetMachine &>(TM);
+  const RISCVSubtarget STI(TT, CPU, FS, /*ABIName=*/"", RTM);
+
+  RTS.emitTargetAttributes(STI);
+}
+
 // Force static initialization.
 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVAsmPrinter() {
   RegisterAsmPrinter<RISCVAsmPrinter> X(getTheRISCV32Target());
Index: llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h
===================================================================
--- llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h
+++ llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h
@@ -10,12 +10,14 @@
 #define LLVM_LIB_TARGET_RISCV_RISCVTARGETSTREAMER_H
 
 #include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSubtargetInfo.h"
 
 namespace llvm {
 
 class RISCVTargetStreamer : public MCTargetStreamer {
 public:
   RISCVTargetStreamer(MCStreamer &S);
+  void finish() override;
 
   virtual void emitDirectiveOptionPush() = 0;
   virtual void emitDirectiveOptionPop() = 0;
@@ -23,12 +25,25 @@
   virtual void emitDirectiveOptionNoRVC() = 0;
   virtual void emitDirectiveOptionRelax() = 0;
   virtual void emitDirectiveOptionNoRelax() = 0;
+  virtual void emitAttribute(unsigned Attribute, unsigned Value) = 0;
+  virtual void finishAttributeSection() = 0;
+  virtual void emitTextAttribute(unsigned Attribute, StringRef String) = 0;
+  virtual void emitIntTextAttribute(unsigned Attribute, unsigned IntValue,
+                                    StringRef StringValue) = 0;
+
+  void emitTargetAttributes(const MCSubtargetInfo &STI);
 };
 
 // This part is for ascii assembly output
 class RISCVTargetAsmStreamer : public RISCVTargetStreamer {
   formatted_raw_ostream &OS;
 
+  void finishAttributeSection() override;
+  void emitAttribute(unsigned Attribute, unsigned Value) override;
+  void emitTextAttribute(unsigned Attribute, StringRef String) override;
+  void emitIntTextAttribute(unsigned Attribute, unsigned IntValue,
+                            StringRef StringValue) override;
+
 public:
   RISCVTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS);
 
Index: llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp
===================================================================
--- llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp
+++ llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp
@@ -11,12 +11,50 @@
 //===----------------------------------------------------------------------===//
 
 #include "RISCVTargetStreamer.h"
+#include "RISCVSubtarget.h"
 #include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/RISCVAttributes.h"
 
 using namespace llvm;
 
 RISCVTargetStreamer::RISCVTargetStreamer(MCStreamer &S) : MCTargetStreamer(S) {}
 
+void RISCVTargetStreamer::finish() { finishAttributeSection(); }
+
+void RISCVTargetStreamer::emitTargetAttributes(const MCSubtargetInfo &STI) {
+  if (STI.hasFeature(RISCV::FeatureRV32E))
+    emitAttribute(RISCVAttrs::STACK_ALIGN, RISCVAttrs::ALIGN_4);
+  else
+    emitAttribute(RISCVAttrs::STACK_ALIGN, RISCVAttrs::ALIGN_16);
+
+  std::string Arch = "rv32";
+
+  if (STI.hasFeature(RISCV::Feature64Bit))
+    Arch = "rv64";
+
+  if (STI.hasFeature(RISCV::FeatureRV32E))
+    Arch = (Twine(Arch) + "e1p9").str();
+  else
+    Arch = (Twine(Arch) + "i2p0").str();
+
+  if (STI.hasFeature(RISCV::FeatureStdExtM))
+    Arch = (Twine(Arch) + "_m2p0").str();
+
+  if (STI.hasFeature(RISCV::FeatureStdExtA))
+    Arch = (Twine(Arch) + "_a2p0").str();
+
+  if (STI.hasFeature(RISCV::FeatureStdExtF))
+    Arch = (Twine(Arch) + "_f2p0").str();
+
+  if (STI.hasFeature(RISCV::FeatureStdExtD))
+    Arch = (Twine(Arch) + "_d2p0").str();
+
+  if (STI.hasFeature(RISCV::FeatureStdExtC))
+    Arch = (Twine(Arch) + "_c2p0").str();
+
+  emitTextAttribute(RISCVAttrs::ARCH, Arch);
+}
+
 // This part is for ascii assembly output
 RISCVTargetAsmStreamer::RISCVTargetAsmStreamer(MCStreamer &S,
                                                formatted_raw_ostream &OS)
@@ -45,3 +83,18 @@
 void RISCVTargetAsmStreamer::emitDirectiveOptionNoRelax() {
   OS << "\t.option\tnorelax\n";
 }
+
+void RISCVTargetAsmStreamer::emitAttribute(unsigned Attribute, unsigned Value) {
+  OS << "\t.attribute\t" << Attribute << ", " << Twine(Value) << "\n";
+}
+
+void RISCVTargetAsmStreamer::emitTextAttribute(unsigned Attribute,
+                                               StringRef String) {
+  OS << "\t.attribute\t" << Attribute << ", \"" << String << "\"\n";
+}
+
+void RISCVTargetAsmStreamer::emitIntTextAttribute(unsigned Attribute,
+                                                  unsigned IntValue,
+                                                  StringRef StringValue) {}
+
+void RISCVTargetAsmStreamer::finishAttributeSection() {}
Index: llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h
===================================================================
--- llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h
+++ llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h
@@ -15,16 +15,92 @@
 namespace llvm {
 
 class RISCVTargetELFStreamer : public RISCVTargetStreamer {
+private:
+  enum class AttributeType { Hidden, Numeric, Text, NumericAndText };
+
+  struct AttributeItem {
+    AttributeType Type;
+    unsigned Tag;
+    unsigned IntValue;
+    std::string StringValue;
+  };
+
+  StringRef CurrentVendor;
+  SmallVector<AttributeItem, 64> Contents;
+
+  MCSection *AttributeSection = nullptr;
+
+  AttributeItem *getAttributeItem(unsigned Attribute) {
+    for (size_t i = 0; i < Contents.size(); ++i)
+      if (Contents[i].Tag == Attribute)
+        return &Contents[i];
+    return nullptr;
+  }
+
+  void setAttributeItem(unsigned Attribute, unsigned Value,
+                        bool OverwriteExisting) {
+    // Look for existing attribute item.
+    if (AttributeItem *Item = getAttributeItem(Attribute)) {
+      if (!OverwriteExisting)
+        return;
+      Item->Type = AttributeType::Numeric;
+      Item->IntValue = Value;
+      return;
+    }
+
+    // Create new attribute item.
+    Contents.push_back({AttributeType::Numeric, Attribute, Value, ""});
+  }
+
+  void setAttributeItem(unsigned Attribute, StringRef Value,
+                        bool OverwriteExisting) {
+    // Look for existing attribute item.
+    if (AttributeItem *Item = getAttributeItem(Attribute)) {
+      if (!OverwriteExisting)
+        return;
+      Item->Type = AttributeType::Text;
+      Item->StringValue = std::string(Value);
+      return;
+    }
+
+    // Create new attribute item.
+    Contents.push_back({AttributeType::Text, Attribute, 0, std::string(Value)});
+  }
+
+  void setAttributeItems(unsigned Attribute, unsigned IntValue,
+                         StringRef StringValue, bool OverwriteExisting) {
+    // Look for existing attribute item.
+    if (AttributeItem *Item = getAttributeItem(Attribute)) {
+      if (!OverwriteExisting)
+        return;
+      Item->Type = AttributeType::NumericAndText;
+      Item->IntValue = IntValue;
+      Item->StringValue = std::string(StringValue);
+      return;
+    }
+
+    // Create new attribute item.
+    Contents.push_back({AttributeType::NumericAndText, Attribute, IntValue,
+                        std::string(StringValue)});
+  }
+
+  void emitAttribute(unsigned Attribute, unsigned Value) override;
+  void emitTextAttribute(unsigned Attribute, StringRef String) override;
+  void emitIntTextAttribute(unsigned Attribute, unsigned IntValue,
+                            StringRef StringValue) override;
+  void finishAttributeSection() override;
+  size_t calculateContentSize() const;
+
 public:
   MCELFStreamer &getStreamer();
   RISCVTargetELFStreamer(MCStreamer &S, const MCSubtargetInfo &STI);
 
-  virtual void emitDirectiveOptionPush();
-  virtual void emitDirectiveOptionPop();
-  virtual void emitDirectiveOptionRVC();
-  virtual void emitDirectiveOptionNoRVC();
-  virtual void emitDirectiveOptionRelax();
-  virtual void emitDirectiveOptionNoRelax();
+  void emitDirectiveOptionPush() override;
+  void emitDirectiveOptionPop() override;
+  void emitDirectiveOptionRVC() override;
+  void emitDirectiveOptionNoRVC() override;
+  void emitDirectiveOptionRelax() override;
+  void emitDirectiveOptionNoRelax() override;
 };
 }
 #endif
Index: llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp
===================================================================
--- llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp
+++ llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp
@@ -15,14 +15,18 @@
 #include "RISCVMCTargetDesc.h"
 #include "Utils/RISCVBaseInfo.h"
 #include "llvm/BinaryFormat/ELF.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCSectionELF.h"
 #include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/RISCVAttributes.h"
 
 using namespace llvm;
 
 // This part is for ELF object output.
 RISCVTargetELFStreamer::RISCVTargetELFStreamer(MCStreamer &S,
                                                const MCSubtargetInfo &STI)
-    : RISCVTargetStreamer(S) {
+    : RISCVTargetStreamer(S), CurrentVendor("riscv") {
   MCAssembler &MCA = getStreamer().getAssembler();
   const FeatureBitset &Features = STI.getFeatureBits();
   auto &MAB = static_cast<RISCVAsmBackend &>(MCA.getBackend());
@@ -66,3 +70,98 @@
 void RISCVTargetELFStreamer::emitDirectiveOptionNoRVC() {}
 void RISCVTargetELFStreamer::emitDirectiveOptionRelax() {}
 void RISCVTargetELFStreamer::emitDirectiveOptionNoRelax() {}
+
+void RISCVTargetELFStreamer::emitAttribute(unsigned Attribute, unsigned Value) {
+  setAttributeItem(Attribute, Value, /*OverwriteExisting=*/true);
+}
+
+void RISCVTargetELFStreamer::emitTextAttribute(unsigned Attribute,
+                                               StringRef String) {
+  setAttributeItem(Attribute, String, /*OverwriteExisting=*/true);
+}
+
+void RISCVTargetELFStreamer::emitIntTextAttribute(unsigned Attribute,
+                                                  unsigned IntValue,
+                                                  StringRef StringValue) {
+  setAttributeItems(Attribute, IntValue, StringValue,
+                    /*OverwriteExisting=*/true);
+}
+
+void RISCVTargetELFStreamer::finishAttributeSection() {
+  if (Contents.empty())
+    return;
+
+  if (AttributeSection) {
+    Streamer.SwitchSection(AttributeSection);
+  } else {
+    MCAssembler &MCA = getStreamer().getAssembler();
+    AttributeSection = MCA.getContext().getELFSection(
+        ".riscv.attributes", ELF::SHT_RISCV_ATTRIBUTES, 0);
+    Streamer.SwitchSection(AttributeSection);
+
+    Streamer.emitIntValue(ELFAttrs::Format_Version, 1);
+  }
+
+  // Vendor size + Vendor name + '\0'
+  const size_t VendorHeaderSize = 4 + CurrentVendor.size() + 1;
+
+  // Tag + Tag Size
+  const size_t TagHeaderSize = 1 + 4;
+
+  const size_t ContentsSize = calculateContentSize();
+
+  Streamer.emitIntValue(VendorHeaderSize + TagHeaderSize + ContentsSize, 4);
+  Streamer.emitBytes(CurrentVendor);
+  Streamer.emitIntValue(0, 1); // '\0'
+
+  Streamer.emitIntValue(ELFAttrs::File, 1);
+  Streamer.emitIntValue(TagHeaderSize + ContentsSize, 4);
+
+  // Size should have been accounted for already, now
+  // emit each field as its type (ULEB or String).
+  for (AttributeItem item : Contents) {
+    Streamer.emitULEB128IntValue(item.Tag);
+    switch (item.Type) {
+    default:
+      llvm_unreachable("Invalid attribute type");
+    case AttributeType::Numeric:
+      Streamer.emitULEB128IntValue(item.IntValue);
+      break;
+    case AttributeType::Text:
+      Streamer.emitBytes(item.StringValue);
+      Streamer.emitIntValue(0, 1); // '\0'
+      break;
+    case AttributeType::NumericAndText:
+      Streamer.emitULEB128IntValue(item.IntValue);
+      Streamer.emitBytes(item.StringValue);
+      Streamer.emitIntValue(0, 1); // '\0'
+      break;
+    }
+  }
+
+  Contents.clear();
+}
+
+size_t RISCVTargetELFStreamer::calculateContentSize() const {
+  size_t Result = 0;
+  for (AttributeItem item : Contents) {
+    switch (item.Type) {
+    case AttributeType::Hidden:
+      break;
+    case AttributeType::Numeric:
+      Result += getULEB128Size(item.Tag);
+      Result += getULEB128Size(item.IntValue);
+      break;
+    case AttributeType::Text:
+      Result += getULEB128Size(item.Tag);
+      Result += item.StringValue.size() + 1; // string + '\0'
+      break;
+    case AttributeType::NumericAndText:
+      Result += getULEB128Size(item.Tag);
+      Result += getULEB128Size(item.IntValue);
+      Result += item.StringValue.size() + 1; // string + '\0';
+      break;
+    }
+  }
+  return Result;
+}
Index: llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
===================================================================
--- llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -32,6 +32,7 @@
 #include "llvm/MC/MCSubtargetInfo.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/MathExtras.h"
+#include "llvm/Support/RISCVAttributes.h"
 #include "llvm/Support/TargetRegistry.h"
 
 #include <limits>
@@ -146,6 +147,7 @@
   bool parseOperand(OperandVector &Operands, StringRef Mnemonic);
 
   bool parseDirectiveOption();
+  bool parseDirectiveAttribute();
 
   void setFeatureBits(uint64_t Feature, StringRef FeatureString) {
     if (!(getSTI().getFeatureBits()[Feature])) {
@@ -155,6 +157,10 @@
     }
   }
 
+  bool getFeatureBits(uint64_t Feature) {
+    return getSTI().getFeatureBits()[Feature];
+  }
+
   void clearFeatureBits(uint64_t Feature, StringRef FeatureString) {
     if (getSTI().getFeatureBits()[Feature]) {
       MCSubtargetInfo &STI = copySTI();
@@ -1579,6 +1585,8 @@
 
   if (IDVal == ".option")
     return parseDirectiveOption();
+  else if (IDVal == ".attribute")
+    return parseDirectiveAttribute();
 
   return true;
 }
@@ -1677,6 +1685,151 @@
   return false;
 }
 
+/// parseDirectiveAttribute
+///  ::= .attribute int, int [, "str"]
+///  ::= .attribute Tag_name, int [, "str"]
+bool RISCVAsmParser::parseDirectiveAttribute() {
+  MCAsmParser &Parser = getParser();
+  int64_t Tag;
+  SMLoc TagLoc;
+  TagLoc = Parser.getTok().getLoc();
+  if (Parser.getTok().is(AsmToken::Identifier)) {
+    StringRef Name = Parser.getTok().getIdentifier();
+    Optional<unsigned> Ret =
+        ELFAttrs::attrTypeFromString(Name, RISCVAttrs::RISCVAttributeTags);
+    if (!Ret.hasValue()) {
+      Error(TagLoc, "attribute name not recognised: " + Name);
+      return false;
+    }
+    Tag = Ret.getValue();
+    Parser.Lex();
+  } else {
+    const MCExpr *AttrExpr;
+
+    TagLoc = Parser.getTok().getLoc();
+    if (Parser.parseExpression(AttrExpr))
+      return true;
+
+    const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(AttrExpr);
+    if (check(!CE, TagLoc, "expected numeric constant"))
+      return true;
+
+    Tag = CE->getValue();
+  }
+
+  if (Parser.parseToken(AsmToken::Comma, "comma expected"))
+    return true;
+
+  StringRef StringValue = "";
+  int64_t IntegerValue = 0;
+  bool IsIntegerValue = true;
+
+  // RISC-V attributes have a string value if the tag number is odd
+  // and an integer value if the tag number is even.
+  if (Tag % 2)
+    IsIntegerValue = false;
+
+  SMLoc ValueExprLoc = Parser.getTok().getLoc();
+  if (IsIntegerValue) {
+    const MCExpr *ValueExpr;
+    if (Parser.parseExpression(ValueExpr))
+      return true;
+
+    const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(ValueExpr);
+    if (!CE)
+      return Error(ValueExprLoc, "expected numeric constant");
+    IntegerValue = CE->getValue();
+  } else {
+    if (Parser.getTok().isNot(AsmToken::String))
+      return Error(Parser.getTok().getLoc(), "expected string constant");
+
+    StringValue = Parser.getTok().getStringContents();
+    Parser.Lex();
+  }
+
+  if (Parser.parseToken(AsmToken::EndOfStatement,
+                        "unexpected token in '.attribute' directive"))
+    return true;
+
+  if (Tag == RISCVAttrs::ARCH) {
+    StringRef Arch = StringValue;
+    if (Arch.consume_front("rv32"))
+      clearFeatureBits(RISCV::Feature64Bit, "64bit");
+    else if (Arch.consume_front("rv64"))
+      setFeatureBits(RISCV::Feature64Bit, "64bit");
+    else
+      return Error(ValueExprLoc, "bad arch string " + Arch);
+
+    while (!Arch.empty()) {
+      if (Arch[0] == 'i')
+        clearFeatureBits(RISCV::FeatureRV32E, "e");
+      else if (Arch[0] == 'e')
+        setFeatureBits(RISCV::FeatureRV32E, "e");
+      else if (Arch[0] == 'g') {
+        clearFeatureBits(RISCV::FeatureRV32E, "e");
+        setFeatureBits(RISCV::FeatureStdExtM, "m");
+        setFeatureBits(RISCV::FeatureStdExtA, "a");
+        setFeatureBits(RISCV::FeatureStdExtF, "f");
+        setFeatureBits(RISCV::FeatureStdExtD, "d");
+      } else if (Arch[0] == 'm')
+        setFeatureBits(RISCV::FeatureStdExtM, "m");
+      else if (Arch[0] == 'a')
+        setFeatureBits(RISCV::FeatureStdExtA, "a");
+      else if (Arch[0] == 'f')
+        setFeatureBits(RISCV::FeatureStdExtF, "f");
+      else if (Arch[0] == 'd') {
+        setFeatureBits(RISCV::FeatureStdExtF, "f");
+        setFeatureBits(RISCV::FeatureStdExtD, "d");
+      } else if (Arch[0] == 'c') {
+        setFeatureBits(RISCV::FeatureStdExtC, "c");
+      } else
+        return Error(ValueExprLoc, "bad arch string " + Arch);
+
+      Arch = Arch.drop_front(1);
+      int major = 0;
+      int minor = 0;
+      Arch.consumeInteger(10, major);
+      Arch.consume_front("p");
+      Arch.consumeInteger(10, minor);
+      if (major != 0 || minor != 0) {
+        Arch = Arch.drop_until([](char c) { return c == '_' || c == '"'; });
+        Arch = Arch.drop_while([](char c) { return c == '_'; });
+      }
+    }
+  }
+
+  if (IsIntegerValue)
+    getTargetStreamer().emitAttribute(Tag, IntegerValue);
+  else {
+    if (Tag != RISCVAttrs::ARCH) {
+      getTargetStreamer().emitTextAttribute(Tag, StringValue);
+    } else {
+      std::string formalArchStr = "rv32";
+      if (getFeatureBits(RISCV::Feature64Bit))
+        formalArchStr = "rv64";
+      if (getFeatureBits(RISCV::FeatureRV32E))
+        formalArchStr = (Twine(formalArchStr) + "e1p9").str();
+      else
+        formalArchStr = (Twine(formalArchStr) + "i2p0").str();
+
+      if (getFeatureBits(RISCV::FeatureStdExtM))
+        formalArchStr = (Twine(formalArchStr) + "_m2p0").str();
+      if (getFeatureBits(RISCV::FeatureStdExtA))
+        formalArchStr = (Twine(formalArchStr) + "_a2p0").str();
+      if (getFeatureBits(RISCV::FeatureStdExtF))
+        formalArchStr = (Twine(formalArchStr) + "_f2p0").str();
+      if (getFeatureBits(RISCV::FeatureStdExtD))
+        formalArchStr = (Twine(formalArchStr) + "_d2p0").str();
+      if (getFeatureBits(RISCV::FeatureStdExtC))
+        formalArchStr = (Twine(formalArchStr) + "_c2p0").str();
+
+      getTargetStreamer().emitTextAttribute(Tag, formalArchStr);
+    }
+  }
+
+  return false;
+}
+
 void RISCVAsmParser::emitToStreamer(MCStreamer &S, const MCInst &Inst) {
   MCInst CInst;
   bool Res = compressInst(CInst, Inst, getSTI(), S.getContext());
Index: llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
===================================================================
--- llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
+++ llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
@@ -177,7 +177,8 @@
 void ARMTargetAsmStreamer::emitAttribute(unsigned Attribute, unsigned Value) {
   OS << "\t.eabi_attribute\t" << Attribute << ", " << Twine(Value);
   if (IsVerboseAsm) {
-    StringRef Name = ARMBuildAttrs::AttrTypeAsString(Attribute);
+    StringRef Name =
+        ELFAttrs::attrTypeAsString(Attribute, ARMBuildAttrs::ARMAttributeTags);
     if (!Name.empty())
       OS << "\t@ " << Name;
   }
@@ -193,7 +194,8 @@
   default:
     OS << "\t.eabi_attribute\t" << Attribute << ", \"" << String << "\"";
     if (IsVerboseAsm) {
-      StringRef Name = ARMBuildAttrs::AttrTypeAsString(Attribute);
+      StringRef Name = ELFAttrs::attrTypeAsString(
+          Attribute, ARMBuildAttrs::ARMAttributeTags);
       if (!Name.empty())
         OS << "\t@ " << Name;
     }
@@ -212,7 +214,9 @@
     if (!StringValue.empty())
       OS << ", \"" << StringValue << "\"";
     if (IsVerboseAsm)
-      OS << "\t@ " << ARMBuildAttrs::AttrTypeAsString(Attribute);
+      OS << "\t@ "
+         << ELFAttrs::attrTypeAsString(Attribute,
+                                       ARMBuildAttrs::ARMAttributeTags);
     break;
   }
   OS << "\n";
Index: llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
===================================================================
--- llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
+++ llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
@@ -11105,11 +11105,13 @@
   TagLoc = Parser.getTok().getLoc();
   if (Parser.getTok().is(AsmToken::Identifier)) {
     StringRef Name = Parser.getTok().getIdentifier();
-    Tag = ARMBuildAttrs::AttrTypeFromString(Name);
-    if (Tag == -1) {
+    Optional<unsigned> Ret =
+        ELFAttrs::attrTypeFromString(Name, ARMBuildAttrs::ARMAttributeTags);
+    if (!Ret.hasValue()) {
       Error(TagLoc, "attribute name not recognised: " + Name);
       return false;
     }
+    Tag = Ret.getValue();
     Parser.Lex();
   } else {
     const MCExpr *AttrExpr;
Index: llvm/lib/Support/RISCVAttributes.cpp
===================================================================
--- /dev/null
+++ llvm/lib/Support/RISCVAttributes.cpp
@@ -0,0 +1,21 @@
+//===-- RISCVAttributes.cpp - RISCV Attributes ----------------------------===//
+//
+// 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/RISCVAttributes.h"
+
+using namespace llvm;
+using namespace llvm::RISCVAttrs;
+
+const TagNameMap llvm::RISCVAttrs::RISCVAttributeTags = {
+    {STACK_ALIGN, "Tag_stack_align"},
+    {ARCH, "Tag_arch"},
+    {UNALIGNED_ACCESS, "Tag_unaligned_access"},
+    {PRIV_SPEC, "Tag_priv_spec"},
+    {PRIV_SPEC_MINOR, "Tag_priv_spec_minor"},
+    {PRIV_SPEC_REVISION, "Tag_priv_spec_revision"},
+};
Index: llvm/lib/Support/RISCVAttributeParser.cpp
===================================================================
--- /dev/null
+++ llvm/lib/Support/RISCVAttributeParser.cpp
@@ -0,0 +1,67 @@
+//===-- RISCVAttributeParser.cpp - RISCV Attribute Parser -----------------===//
+//
+// 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/RISCVAttributeParser.h"
+#include "llvm/ADT/StringExtras.h"
+
+using namespace llvm;
+
+const RISCVAttributeParser::DisplayHandler
+    RISCVAttributeParser::displayRoutines[] = {
+        {
+            RISCVAttrs::ARCH,
+            &ELFAttributeParser::stringAttribute,
+        },
+        {
+            RISCVAttrs::PRIV_SPEC,
+            &ELFAttributeParser::integerAttribute,
+        },
+        {
+            RISCVAttrs::PRIV_SPEC_MINOR,
+            &ELFAttributeParser::integerAttribute,
+        },
+        {
+            RISCVAttrs::PRIV_SPEC_REVISION,
+            &ELFAttributeParser::integerAttribute,
+        },
+        {
+            RISCVAttrs::STACK_ALIGN,
+            &RISCVAttributeParser::stackAlign,
+        },
+        {
+            RISCVAttrs::UNALIGNED_ACCESS,
+            &RISCVAttributeParser::unalignedAccess,
+        }};
+
+Error RISCVAttributeParser::unalignedAccess(unsigned tag) {
+  static const char *strings[] = {"No unaligned access", "Unaligned access"};
+  return parseStringAttribute("Unaligned_access", tag, makeArrayRef(strings));
+}
+
+Error RISCVAttributeParser::stackAlign(unsigned tag) {
+  uint64_t value = de.getULEB128(cursor);
+  std::string description =
+      "Stack alignment is " + utostr(value) + std::string("-bytes");
+  printAttribute(tag, value, description);
+  return Error::success();
+}
+
+Error RISCVAttributeParser::handler(uint64_t tag, bool &handled) {
+  handled = false;
+  for (unsigned AHI = 0, AHE = array_lengthof(displayRoutines); AHI != AHE;
+       ++AHI) {
+    if (uint64_t(displayRoutines[AHI].attribute) == tag) {
+      if (Error e = (this->*displayRoutines[AHI].routine)(tag))
+        return e;
+      handled = true;
+      break;
+    }
+  }
+
+  return Error::success();
+}
Index: llvm/lib/Support/ELFAttributes.cpp
===================================================================
--- /dev/null
+++ llvm/lib/Support/ELFAttributes.cpp
@@ -0,0 +1,35 @@
+//===-- ELFAttributes.cpp - ELF Attributes --------------------------------===//
+//
+// 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/ELFAttributes.h"
+#include "llvm/ADT/StringRef.h"
+
+using namespace llvm;
+
+StringRef ELFAttrs::attrTypeAsString(unsigned attr, TagNameMap tagNameMap,
+                                     bool hasTagPrefix) {
+  auto tagNameIt =
+      std::find_if(tagNameMap.begin(), tagNameMap.end(),
+                   [&](const TagNameItem &item) { return item.attr == attr; });
+  if (tagNameIt == tagNameMap.end())
+    return "";
+  StringRef tagName = tagNameIt->tagName;
+  return hasTagPrefix ? tagName : tagName.drop_front(4);
+}
+
+Optional<unsigned> ELFAttrs::attrTypeFromString(StringRef tag,
+                                                TagNameMap tagNameMap) {
+  bool hasTagPrefix = tag.startswith("Tag_");
+  auto tagNameIt = std::find_if(
+      tagNameMap.begin(), tagNameMap.end(), [&](const TagNameItem &item) {
+        return item.tagName.drop_front(hasTagPrefix ? 0 : 4) == tag;
+      });
+  if (tagNameIt == tagNameMap.end())
+    return None;
+  return tagNameIt->attr;
+}
Index: llvm/lib/Support/ELFAttributeParser.cpp
===================================================================
--- /dev/null
+++ llvm/lib/Support/ELFAttributeParser.cpp
@@ -0,0 +1,233 @@
+//===--- ELFAttributeParser.cpp - ELF Attribute Parser --------------------===//
+//
+// 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/ELFAttributeParser.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+using namespace llvm;
+using namespace llvm::ELFAttrs;
+
+static const EnumEntry<unsigned> tagNames[] = {
+    {"Tag_File", ELFAttrs::File},
+    {"Tag_Section", ELFAttrs::Section},
+    {"Tag_Symbol", ELFAttrs::Symbol},
+};
+
+Error ELFAttributeParser::parseStringAttribute(const char *name, unsigned tag,
+                                               ArrayRef<const char *> strings) {
+  uint64_t value = de.getULEB128(cursor);
+  if (value >= strings.size()) {
+    printAttribute(tag, value, "");
+    return createStringError(errc::invalid_argument,
+                             "unknown " + Twine(name) +
+                                 " value: " + Twine(value));
+  }
+  printAttribute(tag, value, strings[value]);
+  return Error::success();
+}
+
+Error ELFAttributeParser::integerAttribute(unsigned tag) {
+  StringRef tagName =
+      ELFAttrs::attrTypeAsString(tag, tagToStringMap, /*hasTagPrefix=*/false);
+  uint64_t value = de.getULEB128(cursor);
+  attributes.insert(std::make_pair(tag, value));
+
+  if (sw) {
+    DictScope scope(*sw, "Attribute");
+    sw->printNumber("Tag", tag);
+    if (!tagName.empty())
+      sw->printString("TagName", tagName);
+    sw->printNumber("Value", value);
+  }
+  return Error::success();
+}
+
+Error ELFAttributeParser::stringAttribute(unsigned tag) {
+  StringRef tagName =
+      ELFAttrs::attrTypeAsString(tag, tagToStringMap, /*hasTagPrefix=*/false);
+  StringRef desc = de.getCStrRef(cursor);
+  attributesStr.insert(std::make_pair(tag, desc));
+
+  if (sw) {
+    DictScope scope(*sw, "Attribute");
+    sw->printNumber("Tag", tag);
+    if (!tagName.empty())
+      sw->printString("TagName", tagName);
+    sw->printString("Value", desc);
+  }
+  return Error::success();
+}
+
+void ELFAttributeParser::printAttribute(unsigned tag, unsigned value,
+                                        StringRef valueDesc) {
+  attributes.insert(std::make_pair(tag, value));
+
+  if (sw) {
+    StringRef tagName = ELFAttrs::attrTypeAsString(tag, tagToStringMap,
+                                                   /*hasTagPrefix=*/false);
+    DictScope as(*sw, "Attribute");
+    sw->printNumber("Tag", tag);
+    sw->printNumber("Value", value);
+    if (!tagName.empty())
+      sw->printString("TagName", tagName);
+    if (!valueDesc.empty())
+      sw->printString("Description", valueDesc);
+  }
+}
+
+void ELFAttributeParser::parseIndexList(SmallVectorImpl<uint8_t> &indexList) {
+  for (;;) {
+    uint64_t value = de.getULEB128(cursor);
+    if (!cursor || !value)
+      break;
+    indexList.push_back(value);
+  }
+}
+
+Error ELFAttributeParser::parseAttributeList(uint32_t length) {
+  uint64_t pos;
+  uint64_t end = cursor.tell() + length;
+  while ((pos = cursor.tell()) < end) {
+    uint64_t tag = de.getULEB128(cursor);
+    bool handled;
+    if (Error e = handler(tag, handled))
+      return e;
+
+    if (!handled) {
+      if (tag < 32) {
+        return createStringError(errc::invalid_argument,
+                                 "invalid tag 0x" + Twine::utohexstr(tag) +
+                                     " at offset 0x" + Twine::utohexstr(pos));
+      }
+
+      if (tag % 2 == 0) {
+        if (Error e = integerAttribute(tag))
+          return e;
+      } else {
+        if (Error e = stringAttribute(tag))
+          return e;
+      }
+    }
+  }
+  return Error::success();
+}
+
+Error ELFAttributeParser::parseSubsection(uint32_t length) {
+  uint64_t end = cursor.tell() - sizeof(length) + length;
+  StringRef vendorName = de.getCStrRef(cursor);
+  if (sw) {
+    sw->printNumber("SectionLength", length);
+    sw->printString("Vendor", vendorName);
+  }
+
+  // Ignore unrecognized vendor-name.
+  if (vendorName.lower() != vendor)
+    return createStringError(errc::invalid_argument,
+                             "unrecognized vendor-name: " + vendorName);
+
+  while (cursor.tell() < end) {
+    /// Tag_File | Tag_Section | Tag_Symbol   uleb128:byte-size
+    uint8_t tag = de.getU8(cursor);
+    uint32_t size = de.getU32(cursor);
+    if (!cursor)
+      return cursor.takeError();
+
+    if (sw) {
+      sw->printEnum("Tag", tag, makeArrayRef(tagNames));
+      sw->printNumber("Size", size);
+    }
+    if (size < 5)
+      return createStringError(errc::invalid_argument,
+                               "invalid attribute size " + Twine(size) +
+                                   " at offset 0x" +
+                                   Twine::utohexstr(cursor.tell() - 5));
+
+    StringRef scopeName, indexName;
+    SmallVector<uint8_t, 8> indicies;
+    switch (tag) {
+    case ELFAttrs::File:
+      scopeName = "FileAttributes";
+      break;
+    case ELFAttrs::Section:
+      scopeName = "SectionAttributes";
+      indexName = "Sections";
+      parseIndexList(indicies);
+      break;
+    case ELFAttrs::Symbol:
+      scopeName = "SymbolAttributes";
+      indexName = "Symbols";
+      parseIndexList(indicies);
+      break;
+    default:
+      return createStringError(errc::invalid_argument,
+                               "unrecognized tag 0x" + Twine::utohexstr(tag) +
+                                   " at offset 0x" +
+                                   Twine::utohexstr(cursor.tell() - 5));
+    }
+
+    if (sw) {
+      DictScope scope(*sw, scopeName);
+      if (!indicies.empty())
+        sw->printList(indexName, indicies);
+      if (Error e = parseAttributeList(size - 5))
+        return e;
+    } else if (Error e = parseAttributeList(size - 5))
+      return e;
+  }
+  return Error::success();
+}
+
+Error ELFAttributeParser::parse(ArrayRef<uint8_t> section,
+                                support::endianness endian) {
+  unsigned sectionNumber = 0;
+  de = DataExtractor(section, endian == support::little, 0);
+
+  // For early returns, we have more specific errors, consume the Error in
+  // cursor.
+  struct ClearCursorError {
+    DataExtractor::Cursor &cursor;
+    ~ClearCursorError() { consumeError(cursor.takeError()); }
+  } clear{cursor};
+
+  // Unrecognized format-version.
+  uint8_t formatVersion = de.getU8(cursor);
+  if (formatVersion != 'A')
+    return createStringError(errc::invalid_argument,
+                             "unrecognized format-version: 0x" +
+                                 utohexstr(formatVersion));
+
+  while (!de.eof(cursor)) {
+    uint32_t sectionLength = de.getU32(cursor);
+    if (!cursor)
+      return cursor.takeError();
+
+    if (sw) {
+      sw->startLine() << "Section " << ++sectionNumber << " {\n";
+      sw->indent();
+    }
+
+    if (sectionLength < 4 || cursor.tell() - 4 + sectionLength > section.size())
+      return createStringError(errc::invalid_argument,
+                               "invalid subsection length " +
+                                   Twine(sectionLength) + " at offset 0x" +
+                                   utohexstr(cursor.tell() - 4));
+
+    if (Error e = parseSubsection(sectionLength))
+      return e;
+    if (sw) {
+      sw->unindent();
+      sw->startLine() << "}\n";
+    }
+  }
+
+  return cursor.takeError();
+}
Index: llvm/lib/Support/CMakeLists.txt
===================================================================
--- llvm/lib/Support/CMakeLists.txt
+++ llvm/lib/Support/CMakeLists.txt
@@ -87,6 +87,8 @@
   DeltaAlgorithm.cpp
   DAGDeltaAlgorithm.cpp
   DJB.cpp
+  ELFAttributeParser.cpp
+  ELFAttributes.cpp
   Error.cpp
   ErrorHandling.cpp
   FileCheck.cpp
@@ -121,6 +123,8 @@
   PrettyStackTrace.cpp
   RandomNumberGenerator.cpp
   Regex.cpp
+  RISCVAttributes.cpp
+  RISCVAttributeParser.cpp
   ScaledNumber.cpp
   ScopedPrinter.cpp
   SHA1.cpp
Index: llvm/lib/Support/ARMBuildAttrs.cpp
===================================================================
--- llvm/lib/Support/ARMBuildAttrs.cpp
+++ llvm/lib/Support/ARMBuildAttrs.cpp
@@ -6,16 +6,11 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "llvm/ADT/StringRef.h"
 #include "llvm/Support/ARMBuildAttributes.h"
 
 using namespace llvm;
 
-namespace {
-const struct {
-  ARMBuildAttrs::AttrType Attr;
-  StringRef TagName;
-} ARMAttributeTags[] = {
+const TagNameMap llvm::ARMBuildAttrs::ARMAttributeTags = {
   { ARMBuildAttrs::File, "Tag_File" },
   { ARMBuildAttrs::Section, "Tag_Section" },
   { ARMBuildAttrs::Symbol, "Tag_Symbol" },
@@ -67,36 +62,3 @@
   { ARMBuildAttrs::ABI_align_needed, "Tag_ABI_align8_needed" },
   { ARMBuildAttrs::ABI_align_preserved, "Tag_ABI_align8_preserved" },
 };
-}
-
-namespace llvm {
-namespace ARMBuildAttrs {
-StringRef AttrTypeAsString(unsigned Attr, bool HasTagPrefix) {
-  return AttrTypeAsString(static_cast<AttrType>(Attr), HasTagPrefix);
-}
-
-StringRef AttrTypeAsString(AttrType Attr, bool HasTagPrefix) {
-  for (unsigned TI = 0, TE = sizeof(ARMAttributeTags) / sizeof(*ARMAttributeTags);
-       TI != TE; ++TI)
-    if (ARMAttributeTags[TI].Attr == Attr) {
-      auto TagName = ARMAttributeTags[TI].TagName;
-      return HasTagPrefix ? TagName : TagName.drop_front(4);
-    }
-  return "";
-}
-
-int AttrTypeFromString(StringRef Tag) {
-  bool HasTagPrefix = Tag.startswith("Tag_");
-  for (unsigned TI = 0,
-                TE = sizeof(ARMAttributeTags) / sizeof(*ARMAttributeTags);
-       TI != TE; ++TI) {
-    auto TagName = ARMAttributeTags[TI].TagName;
-    if (TagName.drop_front(HasTagPrefix ? 0 : 4) == Tag) {
-      return ARMAttributeTags[TI].Attr;
-    }
-  }
-  return -1;
-}
-}
-}
-
Index: llvm/lib/Support/ARMAttributeParser.cpp
===================================================================
--- llvm/lib/Support/ARMAttributeParser.cpp
+++ llvm/lib/Support/ARMAttributeParser.cpp
@@ -1,4 +1,4 @@
-//===--- ARMAttributeParser.cpp - ARM Attribute Information Printer -------===//
+//===- ARMAttributeParser.cpp - ARM 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.
@@ -16,12 +16,6 @@
 using namespace llvm;
 using namespace llvm::ARMBuildAttrs;
 
-static const EnumEntry<unsigned> tagNames[] = {
-    {"Tag_File", ARMBuildAttrs::File},
-    {"Tag_Section", ARMBuildAttrs::Section},
-    {"Tag_Symbol", ARMBuildAttrs::Symbol},
-};
-
 #define ATTRIBUTE_HANDLER(attr)                                                \
   { ARMBuildAttrs::attr, &ARMAttributeParser::attr }
 
@@ -71,7 +65,8 @@
 #undef ATTRIBUTE_HANDLER
 
 Error ARMAttributeParser::stringAttribute(AttrType tag) {
-  StringRef tagName = ARMBuildAttrs::AttrTypeAsString(tag, /*TagPrefix=*/false);
+  StringRef tagName =
+      ELFAttrs::attrTypeAsString(tag, tagToStringMap, /*TagPrefix=*/false);
   StringRef desc = de.getCStrRef(cursor);
 
   if (sw) {
@@ -84,36 +79,6 @@
   return Error::success();
 }
 
-void ARMAttributeParser::printAttribute(unsigned tag, unsigned value,
-                                        StringRef valueDesc) {
-  attributes.insert(std::make_pair(tag, value));
-
-  if (sw) {
-    StringRef tagName =
-        ARMBuildAttrs::AttrTypeAsString(tag, /*TagPrefix=*/false);
-    DictScope as(*sw, "Attribute");
-    sw->printNumber("Tag", tag);
-    sw->printNumber("Value", value);
-    if (!tagName.empty())
-      sw->printString("TagName", tagName);
-    if (!valueDesc.empty())
-      sw->printString("Description", valueDesc);
-  }
-}
-
-Error ARMAttributeParser::parseStringAttribute(const char *name, AttrType tag,
-                                               ArrayRef<const char *> strings) {
-  uint64_t value = de.getULEB128(cursor);
-  if (value >= strings.size()) {
-    printAttribute(tag, value, "");
-    return createStringError(errc::invalid_argument,
-                             "unknown " + Twine(name) +
-                                 " value: " + Twine(value));
-  }
-  printAttribute(tag, value, strings[value]);
-  return Error::success();
-}
-
 Error ARMAttributeParser::CPU_arch(AttrType tag) {
   static const char *strings[] = {
     "Pre-v4", "ARM v4", "ARM v4T", "ARM v5T", "ARM v5TE", "ARM v5TEJ", "ARM v6",
@@ -323,7 +288,9 @@
     DictScope scope(*sw, "Attribute");
     sw->printNumber("Tag", tag);
     sw->startLine() << "Value: " << integer << ", " << string << '\n';
-    sw->printString("TagName", AttrTypeAsString(tag, /*TagPrefix*/ false));
+    sw->printString("TagName",
+                    ELFAttrs::attrTypeAsString(tag, tagToStringMap,
+                                               /*hasTagPrefix=*/false));
     switch (integer) {
     case 0:
       sw->printString("Description", StringRef("No Specific Requirements"));
@@ -389,167 +356,18 @@
   return Error::success();
 }
 
-void ARMAttributeParser::parseIndexList(SmallVectorImpl<uint8_t> &indexList) {
-  for (;;) {
-    uint64_t value = de.getULEB128(cursor);
-    if (!cursor || !value)
+Error ARMAttributeParser::handler(uint64_t tag, bool &handled) {
+  handled = false;
+  for (unsigned AHI = 0, AHE = array_lengthof(displayRoutines); AHI != AHE;
+       ++AHI) {
+    if (uint64_t(displayRoutines[AHI].attribute) == tag) {
+      if (Error e =
+              (this->*displayRoutines[AHI].routine)(static_cast<AttrType>(tag)))
+        return e;
+      handled = true;
       break;
-    indexList.push_back(value);
-  }
-}
-
-Error ARMAttributeParser::parseAttributeList(uint32_t length) {
-  uint64_t pos;
-  uint64_t end = cursor.tell() + length;
-  while ((pos = cursor.tell()) < end) {
-    uint64_t tag = de.getULEB128(cursor);
-    bool handled = false;
-    for (unsigned AHI = 0, AHE = array_lengthof(displayRoutines);
-         AHI != AHE && !handled; ++AHI) {
-      if (uint64_t(displayRoutines[AHI].attribute) == tag) {
-        if (Error e = (this->*displayRoutines[AHI].routine)(
-                ARMBuildAttrs::AttrType(tag)))
-          return e;
-        handled = true;
-        break;
-      }
-    }
-    if (!handled) {
-      if (tag < 32)
-        return createStringError(errc::invalid_argument,
-                                 "invalid AEABI tag 0x" +
-                                     Twine::utohexstr(tag) + " at offset 0x" +
-                                     Twine::utohexstr(pos));
-
-      if (tag % 2 == 0) {
-        uint64_t value = de.getULEB128(cursor);
-        attributes.insert(std::make_pair(tag, value));
-        if (sw)
-          sw->printNumber(ARMBuildAttrs::AttrTypeAsString(tag), value);
-      } else {
-        StringRef tagName =
-            ARMBuildAttrs::AttrTypeAsString(tag, /*TagPrefix=*/false);
-        StringRef desc = de.getCStrRef(cursor);
-
-        if (sw) {
-          DictScope scope(*sw, "Attribute");
-          sw->printNumber("Tag", tag);
-          if (!tagName.empty())
-            sw->printString("TagName", tagName);
-          sw->printString("Value", desc);
-        }
-      }
     }
   }
-  return Error::success();
-}
-
-Error ARMAttributeParser::parseSubsection(uint32_t length) {
-  uint64_t end = cursor.tell() - sizeof(length) + length;
-  StringRef vendorName = de.getCStrRef(cursor);
-  if (sw) {
-    sw->printNumber("SectionLength", length);
-    sw->printString("Vendor", vendorName);
-  }
-
-  // Ignore unrecognized vendor-name.
-  if (vendorName.lower() != "aeabi")
-    return createStringError(errc::invalid_argument,
-                             "unrecognized vendor-name: " + vendorName);
-
-  while (cursor.tell() < end) {
-    /// Tag_File | Tag_Section | Tag_Symbol   uleb128:byte-size
-    uint8_t tag = de.getU8(cursor);
-    uint32_t size = de.getU32(cursor);
-    if (!cursor)
-      return cursor.takeError();
-
-    if (sw) {
-      sw->printEnum("Tag", tag, makeArrayRef(tagNames));
-      sw->printNumber("Size", size);
-    }
-    if (size < 5)
-      return createStringError(errc::invalid_argument,
-                               "invalid attribute size " + Twine(size) +
-                                   " at offset 0x" +
-                                   Twine::utohexstr(cursor.tell() - 5));
-
-    StringRef scopeName, indexName;
-    SmallVector<uint8_t, 8> indicies;
-    switch (tag) {
-    case ARMBuildAttrs::File:
-      scopeName = "FileAttributes";
-      break;
-    case ARMBuildAttrs::Section:
-      scopeName = "SectionAttributes";
-      indexName = "Sections";
-      parseIndexList(indicies);
-      break;
-    case ARMBuildAttrs::Symbol:
-      scopeName = "SymbolAttributes";
-      indexName = "Symbols";
-      parseIndexList(indicies);
-      break;
-    default:
-      return createStringError(errc::invalid_argument,
-                               "unrecognized tag 0x" + Twine::utohexstr(tag) +
-                                   " at offset 0x" +
-                                   Twine::utohexstr(cursor.tell() - 5));
-    }
 
-    if (sw) {
-      DictScope scope(*sw, scopeName);
-      if (!indicies.empty())
-        sw->printList(indexName, indicies);
-      if (Error e = parseAttributeList(size - 5))
-        return e;
-    } else if (Error e = parseAttributeList(size - 5))
-      return e;
-  }
   return Error::success();
 }
-
-Error ARMAttributeParser::parse(ArrayRef<uint8_t> section,
-                                support::endianness endian) {
-  unsigned sectionNumber = 0;
-  de = DataExtractor(section, endian == support::little, 0);
-
-  // For early returns, we have more specific errors, consume the Error in
-  // cursor.
-  struct ClearCursorError {
-    DataExtractor::Cursor &cursor;
-    ~ClearCursorError() { consumeError(cursor.takeError()); }
-  } clear{cursor};
-
-  // Unrecognized format-version.
-  uint8_t formatVersion = de.getU8(cursor);
-  if (formatVersion != 'A')
-    return createStringError(errc::invalid_argument,
-                             "unrecognized format-version: 0x" +
-                                 utohexstr(formatVersion));
-
-  while (!de.eof(cursor)) {
-    uint32_t sectionLength = de.getU32(cursor);
-    if (!cursor)
-      return cursor.takeError();
-
-    if (sw) {
-      sw->startLine() << "Section " << ++sectionNumber << " {\n";
-      sw->indent();
-    }
-
-    if (sectionLength < 4 || cursor.tell() - 4 + sectionLength > section.size())
-      return createStringError(errc::invalid_argument,
-                               "invalid subsection length " +
-                                   Twine(sectionLength) + " at offset 0x" +
-                                   utohexstr(cursor.tell() - 4));
-    if (Error e = parseSubsection(sectionLength))
-      return e;
-    if (sw) {
-      sw->unindent();
-      sw->startLine() << "}\n";
-    }
-  }
-
-  return cursor.takeError();
-}
Index: llvm/lib/ObjectYAML/ELFYAML.cpp
===================================================================
--- llvm/lib/ObjectYAML/ELFYAML.cpp
+++ llvm/lib/ObjectYAML/ELFYAML.cpp
@@ -500,6 +500,9 @@
     ECase(SHT_MIPS_DWARF);
     ECase(SHT_MIPS_ABIFLAGS);
     break;
+  case ELF::EM_RISCV:
+    ECase(SHT_RISCV_ATTRIBUTES);
+    break;
   default:
     // Nothing to do.
     break;
Index: llvm/lib/Object/ELFObjectFile.cpp
===================================================================
--- llvm/lib/Object/ELFObjectFile.cpp
+++ llvm/lib/Object/ELFObjectFile.cpp
@@ -23,6 +23,8 @@
 #include "llvm/Support/Endian.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/MathExtras.h"
+#include "llvm/Support/RISCVAttributeParser.h"
+#include "llvm/Support/RISCVAttributes.h"
 #include "llvm/Support/TargetRegistry.h"
 #include <algorithm>
 #include <cstddef>
@@ -164,12 +166,14 @@
 
   // both ARMv7-M and R have to support thumb hardware div
   bool isV7 = false;
-  if (Attributes.hasAttribute(ARMBuildAttrs::CPU_arch))
-    isV7 = Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch)
-      == ARMBuildAttrs::v7;
-
-  if (Attributes.hasAttribute(ARMBuildAttrs::CPU_arch_profile)) {
-    switch(Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch_profile)) {
+  Optional<unsigned> Attr =
+      Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch);
+  if (Attr.hasValue())
+    isV7 = Attr.getValue() == ARMBuildAttrs::v7;
+
+  Attr = Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch_profile);
+  if (Attr.hasValue()) {
+    switch (Attr.getValue()) {
     case ARMBuildAttrs::ApplicationProfile:
       Features.AddFeature("aclass");
       break;
@@ -186,8 +190,9 @@
     }
   }
 
-  if (Attributes.hasAttribute(ARMBuildAttrs::THUMB_ISA_use)) {
-    switch(Attributes.getAttributeValue(ARMBuildAttrs::THUMB_ISA_use)) {
+  Attr = Attributes.getAttributeValue(ARMBuildAttrs::THUMB_ISA_use);
+  if (Attr.hasValue()) {
+    switch (Attr.getValue()) {
     default:
       break;
     case ARMBuildAttrs::Not_Allowed:
@@ -200,8 +205,9 @@
     }
   }
 
-  if (Attributes.hasAttribute(ARMBuildAttrs::FP_arch)) {
-    switch(Attributes.getAttributeValue(ARMBuildAttrs::FP_arch)) {
+  Attr = Attributes.getAttributeValue(ARMBuildAttrs::FP_arch);
+  if (Attr.hasValue()) {
+    switch (Attr.getValue()) {
     default:
       break;
     case ARMBuildAttrs::Not_Allowed:
@@ -223,8 +229,9 @@
     }
   }
 
-  if (Attributes.hasAttribute(ARMBuildAttrs::Advanced_SIMD_arch)) {
-    switch(Attributes.getAttributeValue(ARMBuildAttrs::Advanced_SIMD_arch)) {
+  Attr = Attributes.getAttributeValue(ARMBuildAttrs::Advanced_SIMD_arch);
+  if (Attr.hasValue()) {
+    switch (Attr.getValue()) {
     default:
       break;
     case ARMBuildAttrs::Not_Allowed:
@@ -241,8 +248,9 @@
     }
   }
 
-  if (Attributes.hasAttribute(ARMBuildAttrs::MVE_arch)) {
-    switch(Attributes.getAttributeValue(ARMBuildAttrs::MVE_arch)) {
+  Attr = Attributes.getAttributeValue(ARMBuildAttrs::MVE_arch);
+  if (Attr.hasValue()) {
+    switch (Attr.getValue()) {
     default:
       break;
     case ARMBuildAttrs::Not_Allowed:
@@ -259,8 +267,9 @@
     }
   }
 
-  if (Attributes.hasAttribute(ARMBuildAttrs::DIV_use)) {
-    switch(Attributes.getAttributeValue(ARMBuildAttrs::DIV_use)) {
+  Attr = Attributes.getAttributeValue(ARMBuildAttrs::DIV_use);
+  if (Attr.hasValue()) {
+    switch (Attr.getValue()) {
     default:
       break;
     case ARMBuildAttrs::DisallowDIV:
@@ -285,6 +294,48 @@
     Features.AddFeature("c");
   }
 
+  // Add features according to the ELF attribute section.
+  // If there are any unrecognized features, ignore them.
+  RISCVAttributeParser Attributes;
+  if (Error E = getBuildAttributes(Attributes))
+    return Features; // Keep "c" feature if there is one in PlatformFlags.
+
+  Optional<StringRef> Attr = Attributes.getAttributeString(RISCVAttrs::ARCH);
+  if (Attr.hasValue()) {
+    // The Arch pattern is [rv32|rv64][i|e]version(_[m|a|f|d|c]version)*
+    // Version string pattern is (major)p(minor). Major and minor are optional.
+    // For example, a version number could be 2p0, 2, or p92.
+    StringRef Arch = Attr.getValue();
+    if (Arch.consume_front("rv32"))
+      Features.AddFeature("64bit", false);
+    else if (Arch.consume_front("rv64"))
+      Features.AddFeature("64bit");
+
+    while (!Arch.empty()) {
+      switch (Arch[0]) {
+      default:
+        break; // Ignore unexpected features.
+      case 'i':
+        Features.AddFeature("e", false);
+        break;
+      case 'd':
+        Features.AddFeature("f"); // D-ext will imply F-ext.
+        LLVM_FALLTHROUGH;
+      case 'e':
+      case 'm':
+      case 'a':
+      case 'f':
+      case 'c':
+        Features.AddFeature(Arch.take_front());
+        break;
+      }
+
+      // FIXME: Handle version numbers.
+      Arch = Arch.drop_until([](char c) { return c == '_' || c == '\0'; });
+      Arch = Arch.drop_while([](char c) { return c == '_'; });
+    }
+  }
+
   return Features;
 }
 
@@ -320,8 +371,10 @@
   else
     Triple = "arm";
 
-  if (Attributes.hasAttribute(ARMBuildAttrs::CPU_arch)) {
-    switch(Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch)) {
+  Optional<unsigned> Attr =
+      Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch);
+  if (Attr.hasValue()) {
+    switch (Attr.getValue()) {
     case ARMBuildAttrs::v4:
       Triple += "v4";
       break;
Index: llvm/lib/Object/ELF.cpp
===================================================================
--- llvm/lib/Object/ELF.cpp
+++ llvm/lib/Object/ELF.cpp
@@ -223,6 +223,9 @@
       STRINGIFY_ENUM_CASE(ELF, SHT_MIPS_ABIFLAGS);
     }
     break;
+  case ELF::EM_RISCV:
+    switch (Type) { STRINGIFY_ENUM_CASE(ELF, SHT_RISCV_ATTRIBUTES); }
+    break;
   default:
     break;
   }
Index: llvm/include/llvm/Support/RISCVAttributes.h
===================================================================
--- /dev/null
+++ llvm/include/llvm/Support/RISCVAttributes.h
@@ -0,0 +1,50 @@
+//===-- RISCVAttributes.h - RISCV Attributes --------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains enumerations for RISCV attributes as defined in RISC-V
+// ELF psABI specification.
+//
+// RISC-V ELF psABI specification
+//
+// https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_SUPPORT_RISCVATTRIBUTES_H
+#define LLVM_SUPPORT_RISCVATTRIBUTES_H
+
+#include "llvm/Support/ELFAttributes.h"
+
+namespace llvm {
+namespace RISCVAttrs {
+
+extern const TagNameMap RISCVAttributeTags;
+
+enum AttrType : unsigned {
+  // Attribute types in ELF/.riscv.attributes.
+  STACK_ALIGN = 4,
+  ARCH = 5,
+  UNALIGNED_ACCESS = 6,
+  PRIV_SPEC = 8,
+  PRIV_SPEC_MINOR = 10,
+  PRIV_SPEC_REVISION = 12,
+};
+
+enum StackAlign {
+  ALIGN_4 = 4,
+  ALIGN_16 = 16
+};
+
+enum {
+  NOT_ALLOWED = 0,
+  ALLOWED = 1
+};
+
+} // namespace RISCVAttrs
+} // namespace llvm
+
+#endif
Index: llvm/include/llvm/Support/RISCVAttributeParser.h
===================================================================
--- /dev/null
+++ llvm/include/llvm/Support/RISCVAttributeParser.h
@@ -0,0 +1,38 @@
+//===-- RISCVAttributeParser.h - RISCV Attribute Parser ---------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_RISCVATTRIBUTEPARSER_H
+#define LLVM_SUPPORT_RISCVATTRIBUTEPARSER_H
+
+#include "ScopedPrinter.h"
+#include "llvm/Support/ELFAttributeParser.h"
+#include "llvm/Support/RISCVAttributes.h"
+
+namespace llvm {
+class RISCVAttributeParser : public ELFAttributeParser {
+  struct DisplayHandler {
+    RISCVAttrs::AttrType attribute;
+    Error (RISCVAttributeParser::*routine)(unsigned);
+  };
+  static const DisplayHandler displayRoutines[];
+
+  Error handler(uint64_t tag, bool &handled) override;
+
+  Error unalignedAccess(unsigned tag);
+  Error stackAlign(unsigned tag);
+
+public:
+  RISCVAttributeParser(ScopedPrinter *sw)
+      : ELFAttributeParser(sw, RISCVAttrs::RISCVAttributeTags, "riscv") {}
+  RISCVAttributeParser()
+      : ELFAttributeParser(RISCVAttrs::RISCVAttributeTags, "riscv") {}
+};
+
+} // namespace llvm
+
+#endif
Index: llvm/include/llvm/Support/ELFAttributes.h
===================================================================
--- /dev/null
+++ llvm/include/llvm/Support/ELFAttributes.h
@@ -0,0 +1,37 @@
+//===-- ELFAttributes.h - ELF Attributes ------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ELFATTRIBUTES_H
+#define LLVM_SUPPORT_ELFATTRIBUTES_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace llvm {
+
+struct TagNameItem {
+  unsigned attr;
+  StringRef tagName;
+};
+
+using TagNameMap = ArrayRef<TagNameItem>;
+
+namespace ELFAttrs {
+
+enum AttrType : unsigned { File = 1, Section = 2, Symbol = 3 };
+
+StringRef attrTypeAsString(unsigned attr, TagNameMap tagNameMap,
+                           bool hasTagPrefix = true);
+Optional<unsigned> attrTypeFromString(StringRef tag, TagNameMap tagNameMap);
+
+// Magic numbers for ELF attributes.
+enum AttrMagic { Format_Version = 0x41 };
+
+} // namespace ELFAttrs
+} // namespace llvm
+#endif
Index: llvm/include/llvm/Support/ELFAttributeParser.h
===================================================================
--- /dev/null
+++ llvm/include/llvm/Support/ELFAttributeParser.h
@@ -0,0 +1,72 @@
+//===- ELF AttributeParser.h - ELF Attribute Parser -------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ELFATTRIBUTEPARSER_H
+#define LLVM_SUPPORT_ELFATTRIBUTEPARSER_H
+
+#include "ELFAttributes.h"
+#include "ScopedPrinter.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/Error.h"
+
+#include <unordered_map>
+
+namespace llvm {
+class StringRef;
+
+class ELFAttributeParser {
+  StringRef vendor;
+  std::unordered_map<unsigned, unsigned> attributes;
+  std::unordered_map<unsigned, StringRef> attributesStr;
+
+  virtual Error handler(uint64_t tag, bool &handled) = 0;
+
+protected:
+  ScopedPrinter *sw;
+  TagNameMap tagToStringMap;
+  DataExtractor de{ArrayRef<uint8_t>{}, true, 0};
+  DataExtractor::Cursor cursor{0};
+
+  void printAttribute(unsigned tag, unsigned value, StringRef valueDesc);
+
+  Error parseStringAttribute(const char *name, unsigned tag,
+                             ArrayRef<const char *> strings);
+  Error parseAttributeList(uint32_t length);
+  void parseIndexList(SmallVectorImpl<uint8_t> &indexList);
+  Error parseSubsection(uint32_t length);
+
+public:
+  virtual ~ELFAttributeParser() { static_cast<void>(!cursor.takeError()); }
+  Error integerAttribute(unsigned tag);
+  Error stringAttribute(unsigned tag);
+
+  ELFAttributeParser(ScopedPrinter *sw, TagNameMap tagNameMap, StringRef vendor)
+      : vendor(vendor), sw(sw), tagToStringMap(tagNameMap) {}
+
+  ELFAttributeParser(TagNameMap tagNameMap, StringRef vendor)
+      : vendor(vendor), sw(nullptr), tagToStringMap(tagNameMap) {}
+
+  Error parse(ArrayRef<uint8_t> section, support::endianness endian);
+
+  Optional<unsigned> getAttributeValue(unsigned tag) const {
+    auto I = attributes.find(tag);
+    if (I == attributes.end())
+      return None;
+    return I->second;
+  }
+  Optional<StringRef> getAttributeString(unsigned tag) const {
+    auto I = attributesStr.find(tag);
+    if (I == attributesStr.end())
+      return None;
+    return I->second;
+  }
+};
+
+} // namespace llvm
+#endif
Index: llvm/include/llvm/Support/ARMBuildAttributes.h
===================================================================
--- llvm/include/llvm/Support/ARMBuildAttributes.h
+++ llvm/include/llvm/Support/ARMBuildAttributes.h
@@ -18,18 +18,20 @@
 #ifndef LLVM_SUPPORT_ARMBUILDATTRIBUTES_H
 #define LLVM_SUPPORT_ARMBUILDATTRIBUTES_H
 
-namespace llvm {
-class StringRef;
+#include "llvm/Support/ELFAttributes.h"
 
+namespace llvm {
 namespace ARMBuildAttrs {
 
+extern const TagNameMap ARMAttributeTags;
+
 enum SpecialAttr {
   // This is for the .cpu asm attr. It translates into one or more
   // AttrType (below) entries in the .ARM.attributes section in the ELF.
   SEL_CPU
 };
 
-enum AttrType {
+enum AttrType : unsigned {
   // Rest correspond to ELF/.ARM.attributes
   File                      = 1,
   CPU_raw_name              = 4,
@@ -82,15 +84,6 @@
   MPextension_use_old       = 70  // recoded to MPextension_use (ABI r2.08)
 };
 
-StringRef AttrTypeAsString(unsigned Attr, bool HasTagPrefix = true);
-StringRef AttrTypeAsString(AttrType Attr, bool HasTagPrefix = true);
-int AttrTypeFromString(StringRef Tag);
-
-// Magic numbers for .ARM.attributes
-enum AttrMagic {
-  Format_Version  = 0x41
-};
-
 // Legal Values for CPU_arch, (=6), uleb128
 enum CPUArch {
   Pre_v4   = 0,
Index: llvm/include/llvm/Support/ARMAttributeParser.h
===================================================================
--- llvm/include/llvm/Support/ARMAttributeParser.h
+++ llvm/include/llvm/Support/ARMAttributeParser.h
@@ -1,4 +1,4 @@
-//===--- ARMAttributeParser.h - ARM Attribute Information Printer ---------===//
+//===- ARMAttributeParser.h - ARM Attribute Information Printer -*- C++ -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -10,36 +10,24 @@
 #define LLVM_SUPPORT_ARMATTRIBUTEPARSER_H
 
 #include "ARMBuildAttributes.h"
+#include "ELFAttributeParser.h"
 #include "ScopedPrinter.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/Support/DataExtractor.h"
 #include "llvm/Support/Endian.h"
 #include "llvm/Support/Error.h"
 
-#include <map>
-
 namespace llvm {
 class StringRef;
 
-class ARMAttributeParser {
-  ScopedPrinter *sw;
-
-  std::map<unsigned, unsigned> attributes;
-  DataExtractor de{ArrayRef<uint8_t>{}, true, 0};
-  DataExtractor::Cursor cursor{0};
-
+class ARMAttributeParser : public ELFAttributeParser {
   struct DisplayHandler {
     ARMBuildAttrs::AttrType attribute;
     Error (ARMAttributeParser::*routine)(ARMBuildAttrs::AttrType);
   };
   static const DisplayHandler displayRoutines[];
 
-  Error parseAttributeList(uint32_t length);
-  void parseIndexList(SmallVectorImpl<uint8_t> &indexList);
-  Error parseSubsection(uint32_t length);
-  Error parseStringAttribute(const char *name, ARMBuildAttrs::AttrType tag,
-                             const ArrayRef<const char *> array);
-  void printAttribute(unsigned tag, unsigned value, StringRef valueDesc);
+  Error handler(uint64_t tag, bool &handled) override;
 
   Error stringAttribute(ARMBuildAttrs::AttrType tag);
 
@@ -82,20 +70,11 @@
   Error nodefaults(ARMBuildAttrs::AttrType tag);
 
 public:
-  ARMAttributeParser(ScopedPrinter *sw) : sw(sw) {}
-  ARMAttributeParser() : sw(nullptr) {}
-  ~ARMAttributeParser() { static_cast<void>(!cursor.takeError()); }
-
-  Error parse(ArrayRef<uint8_t> section, support::endianness endian);
-
-  bool hasAttribute(unsigned tag) const { return attributes.count(tag); }
-
-  unsigned getAttributeValue(unsigned tag) const {
-    return attributes.find(tag)->second;
-  }
+  ARMAttributeParser(ScopedPrinter *sw)
+      : ELFAttributeParser(sw, ARMBuildAttrs::ARMAttributeTags, "aeabi") {}
+  ARMAttributeParser()
+      : ELFAttributeParser(ARMBuildAttrs::ARMAttributeTags, "aeabi") {}
 };
-
 }
 
 #endif
-
Index: llvm/include/llvm/Object/ELFObjectFile.h
===================================================================
--- llvm/include/llvm/Object/ELFObjectFile.h
+++ llvm/include/llvm/Object/ELFObjectFile.h
@@ -28,8 +28,8 @@
 #include "llvm/Object/ObjectFile.h"
 #include "llvm/Object/SymbolicFile.h"
 #include "llvm/Support/ARMAttributeParser.h"
-#include "llvm/Support/ARMBuildAttributes.h"
 #include "llvm/Support/Casting.h"
+#include "llvm/Support/ELFAttributes.h"
 #include "llvm/Support/Endian.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/ErrorHandling.h"
@@ -64,7 +64,7 @@
   virtual uint64_t getSectionOffset(DataRefImpl Sec) const = 0;
 
   virtual Expected<int64_t> getRelocationAddend(DataRefImpl Rel) const = 0;
-  virtual Error getBuildAttributes(ARMAttributeParser &Attributes) const = 0;
+  virtual Error getBuildAttributes(ELFAttributeParser &Attributes) const = 0;
 
 public:
   using elf_symbol_iterator_range = iterator_range<elf_symbol_iterator>;
@@ -365,19 +365,20 @@
         (Visibility == ELF::STV_DEFAULT || Visibility == ELF::STV_PROTECTED));
   }
 
-  Error getBuildAttributes(ARMAttributeParser &Attributes) const override {
+  Error getBuildAttributes(ELFAttributeParser &Attributes) const override {
     auto SectionsOrErr = EF.sections();
     if (!SectionsOrErr)
       return SectionsOrErr.takeError();
 
     for (const Elf_Shdr &Sec : *SectionsOrErr) {
-      if (Sec.sh_type == ELF::SHT_ARM_ATTRIBUTES) {
+      if (Sec.sh_type == ELF::SHT_ARM_ATTRIBUTES ||
+          Sec.sh_type == ELF::SHT_RISCV_ATTRIBUTES) {
         auto ErrorOrContents = EF.getSectionContents(&Sec);
         if (!ErrorOrContents)
           return ErrorOrContents.takeError();
 
         auto Contents = ErrorOrContents.get();
-        if (Contents[0] != ARMBuildAttrs::Format_Version || Contents.size() == 1)
+        if (Contents[0] != ELFAttrs::Format_Version || Contents.size() == 1)
           return Error::success();
 
         if (Error E = Attributes.parse(Contents, ELFT::TargetEndianness))
Index: llvm/include/llvm/BinaryFormat/ELF.h
===================================================================
--- llvm/include/llvm/BinaryFormat/ELF.h
+++ llvm/include/llvm/BinaryFormat/ELF.h
@@ -880,6 +880,8 @@
 
   SHT_MSP430_ATTRIBUTES = 0x70000003U,
 
+  SHT_RISCV_ATTRIBUTES = 0x70000003U,
+
   SHT_HIPROC = 0x7fffffff,              // Highest processor arch-specific type.
   SHT_LOUSER = 0x80000000,              // Lowest type reserved for applications.
   SHT_HIUSER = 0xffffffff               // Highest type reserved for applications.
Index: lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
===================================================================
--- lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -1239,7 +1239,7 @@
   lldb::offset_t Offset = 0;
 
   uint8_t FormatVersion = data.GetU8(&Offset);
-  if (FormatVersion != llvm::ARMBuildAttrs::Format_Version)
+  if (FormatVersion != llvm::ELFAttrs::Format_Version)
     return;
 
   Offset = Offset + sizeof(uint32_t); // Section Length
Index: lld/ELF/InputFiles.cpp
===================================================================
--- lld/ELF/InputFiles.cpp
+++ lld/ELF/InputFiles.cpp
@@ -660,7 +660,9 @@
 // the input objects have been compiled.
 static void updateARMVFPArgs(const ARMAttributeParser &attributes,
                              const InputFile *f) {
-  if (!attributes.hasAttribute(ARMBuildAttrs::ABI_VFP_args))
+  Optional<unsigned> attr =
+      attributes.getAttributeValue(ARMBuildAttrs::ABI_VFP_args);
+  if (!attr.hasValue())
     // If an ABI tag isn't present then it is implicitly given the value of 0
     // which maps to ARMBuildAttrs::BaseAAPCS. However many assembler files,
     // including some in glibc that don't use FP args (and should have value 3)
@@ -668,7 +670,7 @@
     // as a clash.
     return;
 
-  unsigned vfpArgs = attributes.getAttributeValue(ARMBuildAttrs::ABI_VFP_args);
+  unsigned vfpArgs = attr.getValue();
   ARMVFPArgKind arg;
   switch (vfpArgs) {
   case ARMBuildAttrs::BaseAAPCS:
@@ -705,9 +707,11 @@
 // is compiled with an architecture that supports these features then lld is
 // permitted to use them.
 static void updateSupportedARMFeatures(const ARMAttributeParser &attributes) {
-  if (!attributes.hasAttribute(ARMBuildAttrs::CPU_arch))
+  Optional<unsigned> attr =
+      attributes.getAttributeValue(ARMBuildAttrs::CPU_arch);
+  if (!attr.hasValue())
     return;
-  auto arch = attributes.getAttributeValue(ARMBuildAttrs::CPU_arch);
+  auto arch = attr.getValue();
   switch (arch) {
   case ARMBuildAttrs::Pre_v4:
   case ARMBuildAttrs::v4:
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to