[llvm] r270491 - Add the printing the Mach-O (__LLVM, __bundle) xar archive file section "verbosely"

Kevin Enderby via llvm-commits llvm-commits at lists.llvm.org
Mon May 23 14:34:13 PDT 2016


Author: enderby
Date: Mon May 23 16:34:12 2016
New Revision: 270491

URL: http://llvm.org/viewvc/llvm-project?rev=270491&view=rev
Log:
Add the printing the Mach-O (__LLVM,__bundle) xar archive file section "verbosely"
to llvm-objdump. This section is created with -fembed-bitcode option.

This requires the use of libxar and the Cmake and lit support were crafted by
Chris Bieneman!

rdar://26202242

Added:
    llvm/trunk/test/tools/llvm-objdump/Inputs/LLVM-bundle.macho-x86_64   (with props)
    llvm/trunk/test/tools/llvm-objdump/macho-LLVM-bundle.test
Modified:
    llvm/trunk/cmake/config-ix.cmake
    llvm/trunk/include/llvm/Config/config.h.cmake
    llvm/trunk/lib/Object/CMakeLists.txt
    llvm/trunk/test/lit.cfg
    llvm/trunk/test/lit.site.cfg.in
    llvm/trunk/tools/llvm-objdump/MachODump.cpp

Modified: llvm/trunk/cmake/config-ix.cmake
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/cmake/config-ix.cmake?rev=270491&r1=270490&r2=270491&view=diff
==============================================================================
--- llvm/trunk/cmake/config-ix.cmake (original)
+++ llvm/trunk/cmake/config-ix.cmake Mon May 23 16:34:12 2016
@@ -141,6 +141,11 @@ if( NOT PURE_WINDOWS AND NOT LLVM_USE_SA
   endif()
 endif()
 
+check_library_exists(xar xar_open "" HAVE_LIBXAR)
+if(HAVE_LIBXAR)
+  set(XAR_LIB xar)
+endif()
+
 # function checks
 check_symbol_exists(arc4random "stdlib.h" HAVE_DECL_ARC4RANDOM)
 check_symbol_exists(backtrace "execinfo.h" HAVE_BACKTRACE)

Modified: llvm/trunk/include/llvm/Config/config.h.cmake
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Config/config.h.cmake?rev=270491&r1=270490&r2=270491&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Config/config.h.cmake (original)
+++ llvm/trunk/include/llvm/Config/config.h.cmake Mon May 23 16:34:12 2016
@@ -322,6 +322,9 @@
 /* Define if the setupterm() function is supported this platform. */
 #cmakedefine HAVE_TERMINFO ${HAVE_TERMINFO}
 
+/* Define if the xar_open() function is supported this platform. */
+#cmakedefine HAVE_LIBXAR ${HAVE_LIBXAR}
+
 /* Define to 1 if you have the <termios.h> header file. */
 #cmakedefine HAVE_TERMIOS_H ${HAVE_TERMIOS_H}
 

Modified: llvm/trunk/lib/Object/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Object/CMakeLists.txt?rev=270491&r1=270490&r2=270491&view=diff
==============================================================================
--- llvm/trunk/lib/Object/CMakeLists.txt (original)
+++ llvm/trunk/lib/Object/CMakeLists.txt Mon May 23 16:34:12 2016
@@ -21,4 +21,6 @@ add_llvm_library(LLVMObject
 
   DEPENDS
   intrinsics_gen
+
+  LINK_LIBS ${XAR_LIB}
   )

Modified: llvm/trunk/test/lit.cfg
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/lit.cfg?rev=270491&r1=270490&r2=270491&view=diff
==============================================================================
--- llvm/trunk/test/lit.cfg (original)
+++ llvm/trunk/test/lit.cfg Mon May 23 16:34:12 2016
@@ -497,3 +497,6 @@ except OSError:
 if re.search(r'ON', llvm_config_cmd.stdout.read().decode('ascii')):
     config.available_features.add('global-isel')
 llvm_config_cmd.wait()
+
+if config.have_libxar:
+    config.available_features.add('xar')

Modified: llvm/trunk/test/lit.site.cfg.in
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/lit.site.cfg.in?rev=270491&r1=270490&r2=270491&view=diff
==============================================================================
--- llvm/trunk/test/lit.site.cfg.in (original)
+++ llvm/trunk/test/lit.site.cfg.in Mon May 23 16:34:12 2016
@@ -34,6 +34,7 @@ config.host_ldflags = "@HOST_LDFLAGS@"
 config.llvm_use_intel_jitevents = "@LLVM_USE_INTEL_JITEVENTS@"
 config.llvm_use_sanitizer = "@LLVM_USE_SANITIZER@"
 config.have_zlib = "@HAVE_LIBZ@"
+config.have_libxar = "@HAVE_LIBXAR@"
 config.have_dia_sdk = @HAVE_DIA_SDK@
 config.enable_ffi = "@LLVM_ENABLE_FFI@"
 config.test_examples = "@ENABLE_EXAMPLES@"

Added: llvm/trunk/test/tools/llvm-objdump/Inputs/LLVM-bundle.macho-x86_64
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objdump/Inputs/LLVM-bundle.macho-x86_64?rev=270491&view=auto
==============================================================================
Binary file - no diff available.

Propchange: llvm/trunk/test/tools/llvm-objdump/Inputs/LLVM-bundle.macho-x86_64
------------------------------------------------------------------------------
    svn:executable = *

Propchange: llvm/trunk/test/tools/llvm-objdump/Inputs/LLVM-bundle.macho-x86_64
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: llvm/trunk/test/tools/llvm-objdump/macho-LLVM-bundle.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objdump/macho-LLVM-bundle.test?rev=270491&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-objdump/macho-LLVM-bundle.test (added)
+++ llvm/trunk/test/tools/llvm-objdump/macho-LLVM-bundle.test Mon May 23 16:34:12 2016
@@ -0,0 +1,60 @@
+# REQUIRES: xar
+# RUN: llvm-objdump -macho -archive-headers -section __LLVM,__bundle %p/Inputs/LLVM-bundle.macho-x86_64 | FileCheck %s
+
+# CHECK: For (__LLVM,__bundle) section: xar header
+# CHECK:                   magic XAR_HEADER_MAGIC
+# CHECK:                    size 28
+# CHECK:                 version 1
+# CHECK:   toc_length_compressed 542
+# CHECK: toc_length_uncompressed 1250
+# CHECK:               cksum_alg XAR_CKSUM_SHA1
+# CHECK: For (__LLVM,__bundle) section: xar archive files:
+# CHECK:    1664 1
+# CHECK: For (__LLVM,__bundle) section: xar table of contents:
+# CHECK: <?xml version="1.0" encoding="UTF-8"?>
+# CHECK: <xar>
+# CHECK:  <subdoc subdoc_name="Ld">
+# CHECK:   <version>1.0</version>
+# CHECK:   <architecture>x86_64</architecture>
+# CHECK:   <platform>MacOSX</platform>
+# CHECK:   <sdkversion>10.11.0</sdkversion>
+# CHECK:   <dylibs>
+# CHECK:    <lib>libSystem.dylib</lib>
+# CHECK:   </dylibs>
+# CHECK:   <link-options>
+# CHECK:    <option>-execute</option>
+# CHECK:    <option>-macosx_version_min</option>
+# CHECK:    <option>10.11.0</option>
+# CHECK:    <option>-e</option>
+# CHECK:    <option>_main</option>
+# CHECK:    <option>-executable_path</option>
+# CHECK:    <option>hello</option>
+# CHECK:   </link-options>
+# CHECK:  </subdoc>
+# CHECK:  <toc>
+# CHECK:   <checksum style="sha1">
+# CHECK:    <size>20</size>
+# CHECK:    <offset>0</offset>
+# CHECK:   </checksum>
+# CHECK:   <creation-time>2016-05-23T20:49:10</creation-time>
+# CHECK:   <file id="1">
+# CHECK:    <name>1</name>
+# CHECK:    <type>file</type>
+# CHECK:    <data>
+# CHECK:     <archived-checksum style="sha1">a319940ff5f5248ca8b44cf7b4b65e7dd49a47ab</archived-checksum>
+# CHECK:     <extracted-checksum style="sha1">a319940ff5f5248ca8b44cf7b4b65e7dd49a47ab</extracted-checksum>
+# CHECK:     <size>1664</size>
+# CHECK:     <offset>20</offset>
+# CHECK:     <encoding style="application/octet-stream"/>
+# CHECK:     <length>1664</length>
+# CHECK:    </data>
+# CHECK:    <file-type>Bitcode</file-type>
+# CHECK:    <clang>
+# CHECK:     <cmd>-triple</cmd>
+# CHECK:     <cmd>x86_64-apple-macosx10.11.0</cmd>
+# CHECK:     <cmd>-emit-obj</cmd>
+# CHECK:     <cmd>-disable-llvm-optzns</cmd>
+# CHECK:    </clang>
+# CHECK:   </file>
+# CHECK:  </toc>
+# CHECK: </xar>

Modified: llvm/trunk/tools/llvm-objdump/MachODump.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objdump/MachODump.cpp?rev=270491&r1=270490&r2=270491&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objdump/MachODump.cpp (original)
+++ llvm/trunk/tools/llvm-objdump/MachODump.cpp Mon May 23 16:34:12 2016
@@ -42,6 +42,7 @@
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/TargetRegistry.h"
 #include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/ToolOutputFile.h"
 #include "llvm/Support/raw_ostream.h"
 #include <algorithm>
 #include <cstring>
@@ -51,6 +52,12 @@
 #include <cxxabi.h>
 #endif
 
+#ifdef HAVE_LIBXAR
+extern "C" {
+#include <xar/xar.h>
+}
+#endif
+
 using namespace llvm;
 using namespace object;
 
@@ -1041,6 +1048,12 @@ static void DisassembleMachO(StringRef F
                              StringRef DisSegName, StringRef DisSectName);
 static void DumpProtocolSection(MachOObjectFile *O, const char *sect,
                                 uint32_t size, uint32_t addr);
+#ifdef HAVE_LIBXAR
+static void DumpBitcodeSection(MachOObjectFile *O, const char *sect,
+                                uint32_t size, bool verbose,
+                                bool PrintXarHeader, bool PrintXarFileHeaders,
+                                std::string XarMemberName);
+#endif // defined(HAVE_LIBXAR)
 
 static void DumpSectionContents(StringRef Filename, MachOObjectFile *O,
                                 bool verbose) {
@@ -1102,6 +1115,13 @@ static void DumpSectionContents(StringRe
             DumpProtocolSection(O, sect, sect_size, sect_addr);
             continue;
           }
+#ifdef HAVE_LIBXAR
+          if (SegName == "__LLVM" && SectName == "__bundle") {
+            DumpBitcodeSection(O, sect, sect_size, verbose, !NoSymbolicOperands,
+                               ArchiveHeaders, "");
+            continue;
+          }
+#endif // defined(HAVE_LIBXAR)
           switch (section_type) {
           case MachO::S_REGULAR:
             DumpRawSectionContents(O, sect, sect_size, sect_addr);
@@ -5645,6 +5665,369 @@ static void DumpProtocolSection(MachOObj
   }
 }
 
+#ifdef HAVE_LIBXAR
+inline void swapStruct(struct xar_header &xar) {
+  sys::swapByteOrder(xar.magic);
+  sys::swapByteOrder(xar.size);
+  sys::swapByteOrder(xar.version);
+  sys::swapByteOrder(xar.toc_length_compressed);
+  sys::swapByteOrder(xar.toc_length_uncompressed);
+  sys::swapByteOrder(xar.cksum_alg);
+}
+
+static void PrintModeVerbose(uint32_t mode) {
+  switch(mode & S_IFMT){
+  case S_IFDIR:
+    outs() << "d";
+    break;
+  case S_IFCHR:
+    outs() << "c";
+    break;
+  case S_IFBLK:
+    outs() << "b";
+    break;
+  case S_IFREG:
+    outs() << "-";
+    break;
+  case S_IFLNK:
+    outs() << "l";
+    break;
+  case S_IFSOCK:
+    outs() << "s";
+    break;
+  default:
+    outs() << "?";
+    break;
+  }
+
+  /* owner permissions */
+  if(mode & S_IREAD)
+    outs() << "r";
+  else
+    outs() << "-";
+  if(mode & S_IWRITE)
+    outs() << "w";
+  else
+    outs() << "-";
+  if(mode & S_ISUID)
+    outs() << "s";
+  else if(mode & S_IEXEC)
+    outs() << "x";
+  else
+    outs() << "-";
+
+  /* group permissions */
+  if(mode & (S_IREAD >> 3))
+    outs() << "r";
+  else
+    outs() << "-";
+  if(mode & (S_IWRITE >> 3))
+    outs() << "w";
+  else
+    outs() << "-";
+  if(mode & S_ISGID)
+    outs() << "s";
+  else if(mode & (S_IEXEC >> 3))
+    outs() << "x";
+  else
+    outs() << "-";
+
+  /* other permissions */
+  if(mode & (S_IREAD >> 6))
+    outs() << "r";
+  else
+    outs() << "-";
+  if(mode & (S_IWRITE >> 6))
+    outs() << "w";
+  else
+    outs() << "-";
+  if(mode & S_ISVTX)
+    outs() << "t";
+  else if(mode & (S_IEXEC >> 6))
+    outs() << "x";
+  else
+    outs() << "-";
+}
+
+static void PrintXarFilesSummary(const char *XarFilename, xar_t xar) {
+  xar_iter_t xi;
+  xar_file_t xf;
+  xar_iter_t xp;
+  const char *key, *type, *mode, *user, *group, *size, *mtime, *name, *m;
+  char *endp;
+  uint32_t mode_value;
+
+  xi = xar_iter_new();
+  if (!xi) {
+    errs() << "Can't obtain an xar iterator for xar archive "
+           << XarFilename << "\n";
+    return;
+  }
+
+  // Go through the xar's files.
+  for (xf = xar_file_first(xar, xi); xf; xf = xar_file_next(xi)) {
+    xp = xar_iter_new();
+    if(!xp){
+      errs() << "Can't obtain an xar iterator for xar archive "
+             << XarFilename << "\n";
+      return;
+    }
+    type = nullptr;
+    mode = nullptr;
+    user = nullptr;
+    group = nullptr;
+    size = nullptr;
+    mtime = nullptr;
+    name = nullptr;
+    for(key = xar_prop_first(xf, xp); key; key = xar_prop_next(xp)){
+      const char *val = nullptr; 
+      xar_prop_get(xf, key, &val);
+#if 0 // Useful for debugging.
+      outs() << "key: " << key << " value: " << val << "\n";
+#endif
+      if(strcmp(key, "type") == 0)
+        type = val;
+      if(strcmp(key, "mode") == 0)
+        mode = val;
+      if(strcmp(key, "user") == 0)
+        user = val;
+      if(strcmp(key, "group") == 0)
+        group = val;
+      if(strcmp(key, "data/size") == 0)
+        size = val;
+      if(strcmp(key, "mtime") == 0)
+        mtime = val;
+      if(strcmp(key, "name") == 0)
+        name = val;
+    }
+    if(mode != nullptr){
+      mode_value = strtoul(mode, &endp, 8);
+      if(*endp != '\0')
+        outs() << "(mode: \"" << mode << "\" contains non-octal chars) ";
+      if(strcmp(type, "file") == 0)
+        mode_value |= S_IFREG;
+      PrintModeVerbose(mode_value);
+      outs() << " ";
+    }
+    if(user != nullptr)
+      outs() << format("%10s/", user);
+    if(group != nullptr)
+      outs() << format("%-10s ", group);
+    if(size != nullptr)
+      outs() << format("%7s ", size);
+    if(mtime != nullptr){
+      for(m = mtime; *m != 'T' && *m != '\0'; m++)
+        outs() << *m;
+      if(*m == 'T')
+        m++;
+      outs() << " ";
+      for( ; *m != 'Z' && *m != '\0'; m++)
+        outs() << *m;
+      outs() << " ";
+    }
+    if(name != nullptr)
+      outs() << name;
+    outs() << "\n";
+  }
+}
+
+static void DumpBitcodeSection(MachOObjectFile *O, const char *sect,
+                                uint32_t size, bool verbose,
+                                bool PrintXarHeader, bool PrintXarFileHeaders,
+                                std::string XarMemberName) {
+  if(size < sizeof(struct xar_header)) {
+    outs() << "size of (__LLVM,__bundle) section too small (smaller than size "
+              "of struct xar_header)\n";
+    return;
+  }
+  struct xar_header XarHeader;
+  memcpy(&XarHeader, sect, sizeof(struct xar_header));
+  if (sys::IsLittleEndianHost)
+    swapStruct(XarHeader);
+  if (PrintXarHeader) {
+    if (!XarMemberName.empty())
+      outs() << "In xar member " << XarMemberName << ": ";
+    else
+      outs() << "For (__LLVM,__bundle) section: ";
+    outs() << "xar header\n";
+    if (XarHeader.magic == XAR_HEADER_MAGIC)
+      outs() << "                  magic XAR_HEADER_MAGIC\n";
+    else
+      outs() << "                  magic "
+             << format_hex(XarHeader.magic, 10, true)
+             << " (not XAR_HEADER_MAGIC)\n";
+    outs() << "                   size " << XarHeader.size << "\n";
+    outs() << "                version " << XarHeader.version << "\n";
+    outs() << "  toc_length_compressed " << XarHeader.toc_length_compressed
+           << "\n";
+    outs() << "toc_length_uncompressed " << XarHeader.toc_length_uncompressed
+           << "\n";
+    outs() << "              cksum_alg ";
+    switch (XarHeader.cksum_alg) {
+      case XAR_CKSUM_NONE:
+        outs() << "XAR_CKSUM_NONE\n";
+        break;
+      case XAR_CKSUM_SHA1:
+        outs() << "XAR_CKSUM_SHA1\n";
+        break;
+      case XAR_CKSUM_MD5:
+        outs() << "XAR_CKSUM_MD5\n";
+        break;
+      case XAR_CKSUM_SHA256:
+        outs() << "XAR_CKSUM_SHA256\n";
+        break;
+      case XAR_CKSUM_SHA512:
+        outs() << "XAR_CKSUM_SHA512\n";
+        break;
+      default:
+        outs() << XarHeader.cksum_alg << "\n";
+    }
+  }
+
+  SmallString<128> XarFilename;
+  int FD;
+  std::error_code XarEC =
+      sys::fs::createTemporaryFile("llvm-objdump", "xar", FD, XarFilename);
+  if (XarEC) {
+    errs() << XarEC.message() << "\n";
+    return;
+  }
+  tool_output_file XarFile(XarFilename, FD);
+  raw_fd_ostream &XarOut = XarFile.os();
+  StringRef XarContents(sect, size);
+  XarOut << XarContents;
+  XarOut.close();
+  if (XarOut.has_error())
+    return;
+
+  xar_t xar = xar_open(XarFilename.c_str(), READ);
+  if (!xar) {
+    errs() << "Can't create temporary xar archive " << XarFilename << "\n";
+    return;
+  }
+
+  SmallString<128> TocFilename;
+  std::error_code TocEC =
+      sys::fs::createTemporaryFile("llvm-objdump", "toc", TocFilename);
+  if (TocEC) {
+    errs() << TocEC.message() << "\n";
+    return;
+  }
+  xar_serialize(xar, TocFilename.c_str());
+
+  if (PrintXarFileHeaders) {
+    if (!XarMemberName.empty())
+      outs() << "In xar member " << XarMemberName << ": ";
+    else
+      outs() << "For (__LLVM,__bundle) section: ";
+    outs() << "xar archive files:\n";
+    PrintXarFilesSummary(XarFilename.c_str(), xar);
+  }
+
+  ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr =
+    MemoryBuffer::getFileOrSTDIN(TocFilename.c_str());
+  if (std::error_code EC = FileOrErr.getError()) {
+    errs() << EC.message() << "\n";
+    return;
+  }
+  std::unique_ptr<MemoryBuffer> &Buffer = FileOrErr.get();
+
+  if (!XarMemberName.empty())
+    outs() << "In xar member " << XarMemberName << ": ";
+  else
+    outs() << "For (__LLVM,__bundle) section: ";
+  outs() << "xar table of contents:\n";
+  outs() << Buffer->getBuffer() << "\n";
+
+  // TODO: Go through the xar's files.
+  xar_iter_t xi = xar_iter_new();
+  if(!xi){
+    errs() << "Can't obtain an xar iterator for xar archive "
+           << XarFilename.c_str() << "\n";
+    xar_close(xar);
+    return;
+  }
+  for(xar_file_t xf = xar_file_first(xar, xi); xf; xf = xar_file_next(xi)){
+    const char *key;
+    xar_iter_t xp;
+    const char *member_name, *member_type, *member_size_string;
+    size_t member_size;
+
+    xp = xar_iter_new();
+    if(!xp){
+      errs() << "Can't obtain an xar iterator for xar archive "
+	     << XarFilename.c_str() << "\n";
+      xar_close(xar);
+      return;
+    }
+    member_name = NULL;
+    member_type = NULL;
+    member_size_string = NULL;
+    for(key = xar_prop_first(xf, xp); key; key = xar_prop_next(xp)){
+      const char *val = nullptr; 
+      xar_prop_get(xf, key, &val);
+#if 0 // Useful for debugging.
+      outs() << "key: " << key << " value: " << val << "\n";
+#endif
+      if(strcmp(key, "name") == 0)
+	member_name = val;
+      if(strcmp(key, "type") == 0)
+	member_type = val;
+      if(strcmp(key, "data/size") == 0)
+	member_size_string = val;
+    }
+    /*
+     * If we find a file with a name, date/size and type properties
+     * and with the type being "file" see if that is a xar file.
+     */
+    if (member_name != NULL && member_type != NULL &&
+        strcmp(member_type, "file") == 0 &&
+        member_size_string != NULL){
+      // Extract the file into a buffer.
+      char *endptr;
+      member_size = strtoul(member_size_string, &endptr, 10);
+      if (*endptr == '\0' && member_size != 0) {
+	char *buffer = (char *) ::operator new (member_size);
+	if (xar_extract_tobuffersz(xar, xf, &buffer, &member_size) == 0) {
+#if 0 // Useful for debugging.
+	  outs() << "xar member: " << member_name << " extracted\n";
+#endif
+          // Set the XarMemberName we want to see printed in the header.
+	  std::string OldXarMemberName;
+	  // If XarMemberName is already set this is nested. So
+	  // save the old name and create the nested name.
+	  if (!XarMemberName.empty()) {
+	    OldXarMemberName = XarMemberName;
+            XarMemberName =
+             (Twine("[") + XarMemberName + "]" + member_name).str();
+	  } else {
+	    OldXarMemberName = "";
+	    XarMemberName = member_name;
+	  }
+	  // See if this is could be a xar file (nested).
+	  if (member_size >= sizeof(struct xar_header)) {
+#if 0 // Useful for debugging.
+	    outs() << "could be a xar file: " << member_name << "\n";
+#endif
+	    memcpy((char *)&XarHeader, buffer, sizeof(struct xar_header));
+            if (sys::IsLittleEndianHost)
+	      swapStruct(XarHeader);
+	    if(XarHeader.magic == XAR_HEADER_MAGIC)
+	      DumpBitcodeSection(O, buffer, member_size, verbose,
+                                 PrintXarHeader, PrintXarFileHeaders,
+		                 XarMemberName);
+	  }
+	  XarMemberName = OldXarMemberName;
+	}
+        delete buffer;
+      }
+    }
+    xar_iter_free(xp);
+  }
+  xar_close(xar);
+}
+#endif // defined(HAVE_LIBXAR)
+
 static void printObjcMetaData(MachOObjectFile *O, bool verbose) {
   if (O->is64Bit())
     printObjc2_64bit_MetaData(O, verbose);




More information about the llvm-commits mailing list