Support --build-id=0x<hexstring>.

If you specify the option in the form of --build-id=0x<hexstring>,
that hexstring is set as a build ID. We observed that the feature
is actually in use in some builds, so we want this feature.

llvm-svn: 269495
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index 120df31..2261cfe 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -30,7 +30,7 @@
   ELF64BEKind
 };
 
-enum class BuildIdKind { None, Fnv1, Md5, Sha1 };
+enum class BuildIdKind { None, Fnv1, Md5, Sha1, Hexstring };
 
 // This struct contains the global configuration for the linker.
 // Most fields are direct mapping from the command line options
@@ -53,6 +53,7 @@
   std::vector<llvm::StringRef> SearchPaths;
   std::vector<llvm::StringRef> Undefined;
   std::vector<llvm::StringRef> VersionScriptGlobals;
+  std::vector<uint8_t> BuildIdVector;
   bool AllowMultipleDefinition;
   bool AsNeeded = false;
   bool Bsymbolic;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 4b11472..c73f280 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -386,14 +386,18 @@
     Config->BuildId = BuildIdKind::Fnv1;
   if (auto *Arg = Args.getLastArg(OPT_build_id_eq)) {
     StringRef S = Arg->getValue();
-    if (S == "md5")
+    if (S == "md5") {
       Config->BuildId = BuildIdKind::Md5;
-    else if (S == "sha1")
+    } else if (S == "sha1") {
       Config->BuildId = BuildIdKind::Sha1;
-    else if (S == "none")
+    } else if (S == "none") {
       Config->BuildId = BuildIdKind::None;
-    else
+    } else if (S.startswith("0x")) {
+      Config->BuildId = BuildIdKind::Hexstring;
+      Config->BuildIdVector = parseHexstring(S.substr(2));
+    } else {
       error("unknown --build-id style: " + S);
+    }
   }
 
   for (auto *Arg : Args.filtered(OPT_undefined))
diff --git a/lld/ELF/Driver.h b/lld/ELF/Driver.h
index 3a23827..1412ec9 100644
--- a/lld/ELF/Driver.h
+++ b/lld/ELF/Driver.h
@@ -72,6 +72,7 @@
 
 void printHelp(const char *Argv0);
 void printVersion();
+std::vector<uint8_t> parseHexstring(StringRef S);
 
 void createResponseFile(const llvm::opt::InputArgList &Args);
 void maybeCopyInputFile(StringRef Path, StringRef Buffer);
diff --git a/lld/ELF/DriverUtils.cpp b/lld/ELF/DriverUtils.cpp
index 06b0b65..801a906 100644
--- a/lld/ELF/DriverUtils.cpp
+++ b/lld/ELF/DriverUtils.cpp
@@ -88,6 +88,22 @@
   outs() << "\n";
 }
 
+// Converts a hex string (e.g. "0x123456") to a vector.
+std::vector<uint8_t> elf::parseHexstring(StringRef S) {
+  if (S.find_first_not_of("0123456789abcdefABCDEF") != StringRef::npos ||
+      S.size() % 2) {
+    error("malformed hexstring: " + S);
+    return {};
+  }
+  std::vector<uint8_t> V;
+  for (; !S.empty(); S = S.substr(2)) {
+    int I;
+    S.substr(0, 2).getAsInteger(16, I);
+    V.push_back(I);
+  }
+  return V;
+}
+
 // Makes a given pathname an absolute path first, and then remove
 // beginning /. For example, "../foo.o" is converted to "home/john/foo.o",
 // assuming that the current directory is "/home/john/bar".
diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp
index 76e5cd7..b4b5d80 100644
--- a/lld/ELF/OutputSections.cpp
+++ b/lld/ELF/OutputSections.cpp
@@ -1687,6 +1687,16 @@
 }
 
 template <class ELFT>
+BuildIdHexstring<ELFT>::BuildIdHexstring()
+    : BuildIdSection<ELFT>(Config->BuildIdVector.size()) {}
+
+template <class ELFT>
+void BuildIdHexstring<ELFT>::writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) {
+  memcpy(this->HashBuf, Config->BuildIdVector.data(),
+         Config->BuildIdVector.size());
+}
+
+template <class ELFT>
 MipsReginfoOutputSection<ELFT>::MipsReginfoOutputSection()
     : OutputSectionBase<ELFT>(".reginfo", SHT_MIPS_REGINFO, SHF_ALLOC) {
   this->Header.sh_addralign = 4;
@@ -1852,5 +1862,10 @@
 template class BuildIdSha1<ELF32BE>;
 template class BuildIdSha1<ELF64LE>;
 template class BuildIdSha1<ELF64BE>;
+
+template class BuildIdHexstring<ELF32LE>;
+template class BuildIdHexstring<ELF32BE>;
+template class BuildIdHexstring<ELF64LE>;
+template class BuildIdHexstring<ELF64BE>;
 }
 }
diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h
index b94f765..6d0b521 100644
--- a/lld/ELF/OutputSections.h
+++ b/lld/ELF/OutputSections.h
@@ -581,6 +581,13 @@
   void writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) override;
 };
 
+template <class ELFT>
+class BuildIdHexstring final : public BuildIdSection<ELFT> {
+public:
+  BuildIdHexstring();
+  void writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) override;
+};
+
 // All output sections that are hadnled by the linker specially are
 // globally accessible. Writer initializes them, so don't use them
 // until Writer is initialized.
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index d1604a2..0d6925b 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -163,6 +163,8 @@
     BuildId.reset(new BuildIdMd5<ELFT>);
   else if (Config->BuildId == BuildIdKind::Sha1)
     BuildId.reset(new BuildIdSha1<ELFT>);
+  else if (Config->BuildId == BuildIdKind::Hexstring)
+    BuildId.reset(new BuildIdHexstring<ELFT>);
 
   if (Config->GnuHash)
     GnuHashTab.reset(new GnuHashTableSection<ELFT>);
diff --git a/lld/test/ELF/build-id.s b/lld/test/ELF/build-id.s
index 9230063..f1eac42 100644
--- a/lld/test/ELF/build-id.s
+++ b/lld/test/ELF/build-id.s
@@ -7,6 +7,8 @@
 # RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=MD5 %s
 # RUN: ld.lld --build-id=sha1 %t -o %t2
 # RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=SHA1 %s
+# RUN: ld.lld --build-id=0x12345678 %t -o %t2
+# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=HEX %s
 # RUN: ld.lld %t -o %t2
 # RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=NONE %s
 # RUN: ld.lld --build-id=md5 --build-id=none %t -o %t2
@@ -29,4 +31,8 @@
 # SHA1:      Contents of section .note.gnu.build-id:
 # SHA1-NEXT: 04000000 14000000 03000000 474e5500  ............GNU.
 
+# HEX:      Contents of section .note.gnu.build-id:
+# HEX-NEXT: 04000000 04000000 03000000 474e5500  ............GNU.
+# HEX-NEXT: 12345678
+
 # NONE-NOT: Contents of section .note.gnu.build-id: