[llvm-commits] [llvm] r151785 - in /llvm/trunk: include/llvm/Object/ lib/Object/ test/Object/ test/Object/Inputs/ tools/ tools/llvm-readobj/

Chandler Carruth chandlerc at google.com
Thu Mar 1 17:51:52 PST 2012


On Wed, Feb 29, 2012 at 5:36 PM, David Meyer <pdox at google.com> wrote:

> Author: pdox
> Date: Wed Feb 29 19:36:50 2012
> New Revision: 151785
>
> URL: http://llvm.org/viewvc/llvm-project?rev=151785&view=rev
> Log:
> [Object]
> * Add begin_dynamic_table() / end_dynamic_table() private interface to
> ELFObjectFile.
> * Add begin_libraries_needed() / end_libraries_needed() interface to
> ObjectFile, for grabbing the list of needed libraries for a shared object
> or dynamic executable.
> * Implement this new interface completely for ELF, leave stubs for COFF
> and MachO.
> * Add 'llvm-readobj' tool for dumping ObjectFile information.
>

In the future, I might break this large of a patch into a few separate
commits... I have several comments inline. Sorry if I missed a subsequent
patch from you addressing these things, but I'm responding to what I see
here.

There are a lot of style issues with this patch. I don't know how many are
due to inherent style issues permeating the Object library, but I'd really
like to at least stop making things worse and preferably start improving
the consistency and style of this library w.r.t. other libraries in LLVM.
See comments inline.

Added:
>    llvm/trunk/test/Object/readobj-shared-object.test
>    llvm/trunk/tools/llvm-readobj/
>    llvm/trunk/tools/llvm-readobj/CMakeLists.txt
>    llvm/trunk/tools/llvm-readobj/LLVMBuild.txt
>    llvm/trunk/tools/llvm-readobj/Makefile
>    llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp
> Modified:
>    llvm/trunk/include/llvm/Object/COFF.h
>    llvm/trunk/include/llvm/Object/ELF.h
>    llvm/trunk/include/llvm/Object/MachO.h
>    llvm/trunk/include/llvm/Object/ObjectFile.h
>    llvm/trunk/lib/Object/COFFObjectFile.cpp
>    llvm/trunk/lib/Object/MachOObjectFile.cpp
>    llvm/trunk/test/Object/Inputs/shared-object-test.elf-i386   (contents,
> props changed)
>    llvm/trunk/test/Object/Inputs/shared-object-test.elf-x86-64
> (contents, props changed)
>    llvm/trunk/test/Object/Inputs/shared.ll
>    llvm/trunk/tools/CMakeLists.txt
>    llvm/trunk/tools/Makefile
>
> Modified: llvm/trunk/include/llvm/Object/COFF.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Object/COFF.h?rev=151785&r1=151784&r2=151785&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/Object/COFF.h (original)
> +++ llvm/trunk/include/llvm/Object/COFF.h Wed Feb 29 19:36:50 2012
> @@ -145,12 +145,19 @@
>   virtual error_code getRelocationValueString(DataRefImpl Rel,
>                                            SmallVectorImpl<char> &Result)
> const;
>
> +  virtual error_code getLibraryNext(DataRefImpl LibData,
> +                                    LibraryRef &Result) const;
> +  virtual error_code getLibraryPath(DataRefImpl LibData,
> +                                    StringRef &Result) const;
> +
>  public:
>   COFFObjectFile(MemoryBuffer *Object, error_code &ec);
>   virtual symbol_iterator begin_symbols() const;
>   virtual symbol_iterator end_symbols() const;
>   virtual symbol_iterator begin_dynamic_symbols() const;
>   virtual symbol_iterator end_dynamic_symbols() const;
> +  virtual library_iterator begin_libraries_needed() const;
> +  virtual library_iterator end_libraries_needed() const;
>   virtual section_iterator begin_sections() const;
>   virtual section_iterator end_sections() const;
>
>
> Modified: llvm/trunk/include/llvm/Object/ELF.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Object/ELF.h?rev=151785&r1=151784&r2=151785&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/Object/ELF.h (original)
> +++ llvm/trunk/include/llvm/Object/ELF.h Wed Feb 29 19:36:50 2012
> @@ -176,6 +176,71 @@
>   }
>  };
>
> +// Elf_Dyn: Entry in the dynamic table
>

This is a terrible comment. This is Elf_Dyn_Base. What is it? Please write
complete English sentences, and make the comments doxygen comments. This
isn't just an implementation detail either, this is in a major public
header of the Object library.


> +template<support::endianness target_endianness, bool is64Bits>
> +struct Elf_Dyn_Base;
> +
> +template<support::endianness target_endianness>
> +struct Elf_Dyn_Base<target_endianness, false> {
> +  LLVM_ELF_IMPORT_TYPES(target_endianness, false)
> +  Elf_Sword d_tag;
>

Is this really the prevailing style of this file? it doesn't at all match
the style of LLVM generally.


> +  union {
> +    Elf_Word d_val;
> +    Elf_Addr d_ptr;
> +  } d_un;
> +};
> +
> +template<support::endianness target_endianness>
> +struct Elf_Dyn_Base<target_endianness, true> {
> +  LLVM_ELF_IMPORT_TYPES(target_endianness, true)
> +  Elf_Sxword d_tag;
> +  union {
> +    Elf_Xword d_val;
> +    Elf_Addr d_ptr;
> +  } d_un;
> +};
> +
> +template<support::endianness target_endianness, bool is64Bits>
> +struct Elf_Dyn_Impl : Elf_Dyn_Base<target_endianness, is64Bits> {
> +  using Elf_Dyn_Base<target_endianness, is64Bits>::d_tag;
> +  using Elf_Dyn_Base<target_endianness, is64Bits>::d_un;
> +  int64_t getTag() const { return d_tag; }
> +  uint64_t getVal() const { return d_un.d_val; }
> +  uint64_t getPtr() const { return d_un.ptr; }
> +};
> +
> +template<support::endianness target_endianness, bool is64Bits>
> +class ELFObjectFile;
> +
> +// DynRefImpl: Reference to an entry in the dynamic table
> +// This is an ELF-specific interface.
> +template<support::endianness target_endianness, bool is64Bits>
> +class DynRefImpl {
> +  typedef Elf_Dyn_Impl<target_endianness, is64Bits> Elf_Dyn;
> +  typedef ELFObjectFile<target_endianness, is64Bits> OwningType;
> +
> +  DataRefImpl DynPimpl;
> +  const OwningType *OwningObject;
> +
> +public:
> +  DynRefImpl() : OwningObject(NULL) {
> +    std::memset(&DynPimpl, 0, sizeof(DynPimpl));
> +  }
> +
> +  DynRefImpl(DataRefImpl DynP, const OwningType *Owner);
> +
> +  bool operator==(const DynRefImpl &Other) const;
> +  bool operator <(const DynRefImpl &Other) const;
> +
> +  error_code getNext(DynRefImpl &Result) const;
> +  int64_t getTag() const;
> +  uint64_t getVal() const;
> +  uint64_t getPtr() const;
> +
> +  DataRefImpl getRawDataRefImpl() const;
> +};
> +
> +// Elf_Rel: Elf Relocation
>

Same comment about this comment. Please go through and fix the commenting
throughout this file.


>  template<support::endianness target_endianness, bool is64Bits, bool
> isRela>
>

WTF is 'isRela'?


>  struct Elf_Rel_Base;
>
> @@ -255,8 +320,11 @@
>
>   typedef Elf_Shdr_Impl<target_endianness, is64Bits> Elf_Shdr;
>   typedef Elf_Sym_Impl<target_endianness, is64Bits> Elf_Sym;
> +  typedef Elf_Dyn_Impl<target_endianness, is64Bits> Elf_Dyn;
>   typedef Elf_Rel_Impl<target_endianness, is64Bits, false> Elf_Rel;
>   typedef Elf_Rel_Impl<target_endianness, is64Bits, true> Elf_Rela;
> +  typedef DynRefImpl<target_endianness, is64Bits> DynRef;
> +  typedef content_iterator<DynRef> dyn_iterator;
>
>  protected:
>   struct Elf_Ehdr {
> @@ -300,6 +368,8 @@
>   IndexMap_t SymbolTableSectionsIndexMap;
>   DenseMap<const Elf_Sym*, ELF::Elf64_Word> ExtendedSymbolTable;
>
> +  const Elf_Shdr *dot_dynamic_sec; // .dynamic
>

Please use CamelCase rather than under_scores.


> +
>   /// @brief Map sections to an array of relocation sections that reference
>   ///        them sorted by section index.
>   RelocMap_t SectionRelocMap;
> @@ -329,6 +399,9 @@
>   const Elf_Sym  *getSymbol(DataRefImpl Symb) const; // FIXME: Should be
> private?
>   void            validateSymbol(DataRefImpl Symb) const;
>
> +public:
> +  const Elf_Dyn  *getDyn(DataRefImpl DynData) const;
> +
>  protected:
>   virtual error_code getSymbolNext(DataRefImpl Symb, SymbolRef &Res) const;
>   virtual error_code getSymbolName(DataRefImpl Symb, StringRef &Res) const;
> @@ -341,6 +414,12 @@
>   virtual error_code getSymbolSection(DataRefImpl Symb,
>                                       section_iterator &Res) const;
>
> +  friend class DynRefImpl<target_endianness, is64Bits>;
> +  virtual error_code getDynNext(DataRefImpl DynData, DynRef &Result)
> const;
> +
> +  virtual error_code getLibraryNext(DataRefImpl Data, LibraryRef &Result)
> const;
> +  virtual error_code getLibraryPath(DataRefImpl Data, StringRef &Res)
> const;
> +
>   virtual error_code getSectionNext(DataRefImpl Sec, SectionRef &Res)
> const;
>   virtual error_code getSectionName(DataRefImpl Sec, StringRef &Res) const;
>   virtual error_code getSectionAddress(DataRefImpl Sec, uint64_t &Res)
> const;
> @@ -376,11 +455,19 @@
>   ELFObjectFile(MemoryBuffer *Object, error_code &ec);
>   virtual symbol_iterator begin_symbols() const;
>   virtual symbol_iterator end_symbols() const;
> +
>   virtual symbol_iterator begin_dynamic_symbols() const;
>   virtual symbol_iterator end_dynamic_symbols() const;
> +
>   virtual section_iterator begin_sections() const;
>   virtual section_iterator end_sections() const;
>
> +  virtual library_iterator begin_libraries_needed() const;
> +  virtual library_iterator end_libraries_needed() const;
> +
> +  virtual dyn_iterator begin_dynamic_table() const;
> +  virtual dyn_iterator end_dynamic_table() const;
> +
>   virtual uint8_t getBytesInAddress() const;
>   virtual StringRef getFileFormatName() const;
>   virtual unsigned getArch() const;
> @@ -1171,7 +1258,8 @@
>   , SectionHeaderTable(0)
>   , dot_shstrtab_sec(0)
>   , dot_strtab_sec(0)
> -  , dot_dynstr_sec(0) {
> +  , dot_dynstr_sec(0)
> +  , dot_dynamic_sec(0) {
>
>   const uint64_t FileSize = Data->getBufferSize();
>
> @@ -1227,6 +1315,12 @@
>     if (sh->sh_type == ELF::SHT_REL || sh->sh_type == ELF::SHT_RELA) {
>       SectionRelocMap[getSection(sh->sh_info)].push_back(i);
>     }
> +    if (sh->sh_type == ELF::SHT_DYNAMIC) {
> +      if (dot_dynamic_sec != NULL)
> +        // FIXME: Proper error handling.
> +        report_fatal_error("More than one .dynamic!");
> +      dot_dynamic_sec = sh;
> +    }
>     ++sh;
>   }
>
> @@ -1353,6 +1447,121 @@
>  }
>
>  template<support::endianness target_endianness, bool is64Bits>
> +typename ELFObjectFile<target_endianness, is64Bits>::dyn_iterator
> +ELFObjectFile<target_endianness, is64Bits>::begin_dynamic_table() const {
> +  DataRefImpl DynData;
> +  memset(&DynData, 0, sizeof(DynData));
> +  if (dot_dynamic_sec == NULL || dot_dynamic_sec->sh_size == 0) {
> +    DynData.d.a = std::numeric_limits<uint32_t>::max();
> +  } else {
> +    DynData.d.a = 0;
> +  }
> +  return dyn_iterator(DynRef(DynData, this));
> +}
> +
> +template<support::endianness target_endianness, bool is64Bits>
> +typename ELFObjectFile<target_endianness, is64Bits>::dyn_iterator
> +ELFObjectFile<target_endianness, is64Bits>
> +                          ::end_dynamic_table() const {
> +  DataRefImpl DynData;
> +  memset(&DynData, 0, sizeof(DynData));
> +  DynData.d.a = std::numeric_limits<uint32_t>::max();
> +  return dyn_iterator(DynRef(DynData, this));
> +}
> +
> +template<support::endianness target_endianness, bool is64Bits>
> +error_code ELFObjectFile<target_endianness, is64Bits>
> +                        ::getDynNext(DataRefImpl DynData,
> +                                     DynRef &Result) const {
> +  ++DynData.d.a;
> +
> +  // Check to see if we are at the end of .dynamic
> +  if (DynData.d.a >= dot_dynamic_sec->getEntityCount()) {
> +    // We are at the end. Return the terminator.
> +    DynData.d.a = std::numeric_limits<uint32_t>::max();
> +  }
> +
> +  Result = DynRef(DynData, this);
> +  return object_error::success;
> +}
> +
> +template<support::endianness target_endianness, bool is64Bits>
> +library_iterator ELFObjectFile<target_endianness, is64Bits>
> +                             ::begin_libraries_needed() const {
> +  // Find the first DT_NEEDED entry
> +  dyn_iterator i = begin_dynamic_table();
> +  dyn_iterator e = end_dynamic_table();
> +  error_code ec;
> +  while (i != e) {
> +    if (i->getTag() == ELF::DT_NEEDED)
> +      break;
> +    i.increment(ec);
> +    if (ec)
> +      report_fatal_error("dynamic table iteration failed");
> +  }
> +  // Use the same DataRefImpl format as DynRef.
> +  return library_iterator(LibraryRef(i->getRawDataRefImpl(), this));
> +}
> +
> +template<support::endianness target_endianness, bool is64Bits>
> +error_code ELFObjectFile<target_endianness, is64Bits>
> +                        ::getLibraryNext(DataRefImpl Data,
> +                                         LibraryRef &Result) const {
> +  // Use the same DataRefImpl format as DynRef.
> +  dyn_iterator i = dyn_iterator(DynRef(Data, this));
> +  dyn_iterator e = end_dynamic_table();
>

Please follow LLVM conventions for naming iterators: I and E. Here, and
throughout this file.


> +
> +  // Skip the current dynamic table entry.
> +  error_code ec;
> +  if (i != e) {
> +    i.increment(ec);
> +    // TODO: proper error handling
> +    if (ec)
> +      report_fatal_error("dynamic table iteration failed");
> +  }
> +
> +  // Find the next DT_NEEDED entry.
> +  while (i != e) {
> +    if (i->getTag() == ELF::DT_NEEDED)
> +      break;
> +    i.increment(ec);
> +    if (ec)
> +      report_fatal_error("dynamic table iteration failed");
> +  }
> +  Result = LibraryRef(i->getRawDataRefImpl(), this);
> +  return object_error::success;
> +}
> +
> +template<support::endianness target_endianness, bool is64Bits>
> +error_code ELFObjectFile<target_endianness, is64Bits>
> +         ::getLibraryPath(DataRefImpl Data, StringRef &Res) const {
> +  dyn_iterator i = dyn_iterator(DynRef(Data, this));
> +  if (i == end_dynamic_table())
> +    report_fatal_error("getLibraryPath() called on iterator end");
> +
> +  if (i->getTag() != ELF::DT_NEEDED)
> +    report_fatal_error("Invalid library_iterator");
> +
> +  // This uses .dynstr to lookup the name of the DT_NEEDED entry.
> +  // THis works as long as DT_STRTAB == .dynstr. This is true most of
> +  // the time, but the specification allows exceptions.
> +  // TODO: This should really use DT_STRTAB instead. Doing this requires
> +  // reading the program headers.
> +  if (dot_dynstr_sec == NULL)
> +    report_fatal_error("Dynamic string table is missing");
> +  Res = getString(dot_dynstr_sec, i->getVal());
> +  return object_error::success;
> +}
> +
> +template<support::endianness target_endianness, bool is64Bits>
> +library_iterator ELFObjectFile<target_endianness, is64Bits>
> +                             ::end_libraries_needed() const {
> +  dyn_iterator e = end_dynamic_table();
> +  // Use the same DataRefImpl format as DynRef.
> +  return library_iterator(LibraryRef(e->getRawDataRefImpl(), this));
> +}
> +
> +template<support::endianness target_endianness, bool is64Bits>
>  uint8_t ELFObjectFile<target_endianness, is64Bits>::getBytesInAddress()
> const {
>   return is64Bits ? 8 : 4;
>  }
> @@ -1450,6 +1659,12 @@
>  }
>
>  template<support::endianness target_endianness, bool is64Bits>
> +const typename ELFObjectFile<target_endianness, is64Bits>::Elf_Dyn *
> +ELFObjectFile<target_endianness, is64Bits>::getDyn(DataRefImpl DynData)
> const {
> +  return getEntry<Elf_Dyn>(dot_dynamic_sec, DynData.d.a);
> +}
> +
> +template<support::endianness target_endianness, bool is64Bits>
>  const typename ELFObjectFile<target_endianness, is64Bits>::Elf_Rel *
>  ELFObjectFile<target_endianness, is64Bits>::getRel(DataRefImpl Rel) const
> {
>   return getEntry<Elf_Rel>(Rel.w.b, Rel.w.c);
> @@ -1527,6 +1742,54 @@
>   return object_error::success;
>  }
>
> +template<support::endianness target_endianness, bool is64Bits>
> +inline DynRefImpl<target_endianness, is64Bits>
> +                 ::DynRefImpl(DataRefImpl DynP, const OwningType *Owner)
> +  : DynPimpl(DynP)
> +  , OwningObject(Owner) {}
> +
> +template<support::endianness target_endianness, bool is64Bits>
> +inline bool DynRefImpl<target_endianness, is64Bits>
> +                      ::operator==(const DynRefImpl &Other) const {
> +  return DynPimpl == Other.DynPimpl;
> +}
> +
> +template<support::endianness target_endianness, bool is64Bits>
> +inline bool DynRefImpl<target_endianness, is64Bits>
> +                      ::operator <(const DynRefImpl &Other) const {
> +  return DynPimpl < Other.DynPimpl;
> +}
> +
> +template<support::endianness target_endianness, bool is64Bits>
> +inline error_code DynRefImpl<target_endianness, is64Bits>
> +                            ::getNext(DynRefImpl &Result) const {
> +  return OwningObject->getDynNext(DynPimpl, Result);
> +}
> +
> +template<support::endianness target_endianness, bool is64Bits>
> +inline int64_t DynRefImpl<target_endianness, is64Bits>
> +                            ::getTag() const {
> +  return OwningObject->getDyn(DynPimpl)->d_tag;
> +}
> +
> +template<support::endianness target_endianness, bool is64Bits>
> +inline uint64_t DynRefImpl<target_endianness, is64Bits>
> +                            ::getVal() const {
> +  return OwningObject->getDyn(DynPimpl)->d_un.d_val;
> +}
> +
> +template<support::endianness target_endianness, bool is64Bits>
> +inline uint64_t DynRefImpl<target_endianness, is64Bits>
> +                            ::getPtr() const {
> +  return OwningObject->getDyn(DynPimpl)->d_un.d_ptr;
> +}
> +
> +template<support::endianness target_endianness, bool is64Bits>
> +inline DataRefImpl DynRefImpl<target_endianness, is64Bits>
> +                             ::getRawDataRefImpl() const {
> +  return DynPimpl;
> +}
> +
>  }
>  }
>
>
> Modified: llvm/trunk/include/llvm/Object/MachO.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Object/MachO.h?rev=151785&r1=151784&r2=151785&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/Object/MachO.h (original)
> +++ llvm/trunk/include/llvm/Object/MachO.h Wed Feb 29 19:36:50 2012
> @@ -34,6 +34,8 @@
>   virtual symbol_iterator end_symbols() const;
>   virtual symbol_iterator begin_dynamic_symbols() const;
>   virtual symbol_iterator end_dynamic_symbols() const;
> +  virtual library_iterator begin_libraries_needed() const;
> +  virtual library_iterator end_libraries_needed() const;
>   virtual section_iterator begin_sections() const;
>   virtual section_iterator end_sections() const;
>
> @@ -92,6 +94,9 @@
>                                            SmallVectorImpl<char> &Result)
> const;
>   virtual error_code getRelocationHidden(DataRefImpl Rel, bool &Result)
> const;
>
> +  virtual error_code getLibraryNext(DataRefImpl LibData, LibraryRef &Res)
> const;
> +  virtual error_code getLibraryPath(DataRefImpl LibData, StringRef &Res)
> const;
> +
>  private:
>   MachOObject *MachOObj;
>   mutable uint32_t RegisteredStringTable;
>
> Modified: llvm/trunk/include/llvm/Object/ObjectFile.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Object/ObjectFile.h?rev=151785&r1=151784&r2=151785&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/Object/ObjectFile.h (original)
> +++ llvm/trunk/include/llvm/Object/ObjectFile.h Wed Feb 29 19:36:50 2012
> @@ -228,6 +228,32 @@
>  };
>  typedef content_iterator<SymbolRef> symbol_iterator;
>
> +/// LibraryRef - This is a value type class that represents a single
> library in
> +/// the list of libraries needed by a shared or dynamic object.
>

While it's good to actually have a doxygen comment here, you don't have any
on the rest of the methods, and this one is pretty light on detail.


> +class LibraryRef {
> +  friend class SectionRef;
> +  DataRefImpl LibraryPimpl;
> +  const ObjectFile *OwningObject;
> +
> +public:
> +  LibraryRef() : OwningObject(NULL) {
> +    std::memset(&LibraryPimpl, 0, sizeof(LibraryPimpl));
> +  }
> +
> +  LibraryRef(DataRefImpl LibraryP, const ObjectFile *Owner);
> +
> +  bool operator==(const LibraryRef &Other) const;
> +  bool operator <(const LibraryRef &Other) const;
> +
> +  error_code getNext(LibraryRef &Result) const;
> +
> +  // Get the path to this library, as stored in the object file.
> +  error_code getPath(StringRef &Result) const;
> +
> +  DataRefImpl getRawDataRefImpl() const;
> +};
> +typedef content_iterator<LibraryRef> library_iterator;
> +
>  const uint64_t UnknownAddressOrSize = ~0ULL;
>
>  /// ObjectFile - This class is the base class for all object file types.
> @@ -307,6 +333,11 @@
>     return object_error::success;
>   }
>
> +  // Same for LibraryRef
> +  friend class LibraryRef;
> +  virtual error_code getLibraryNext(DataRefImpl Lib, LibraryRef &Res)
> const = 0;
> +  virtual error_code getLibraryPath(DataRefImpl Lib, StringRef &Res)
> const = 0;
> +
>  public:
>
>   virtual symbol_iterator begin_symbols() const = 0;
> @@ -318,6 +349,9 @@
>   virtual section_iterator begin_sections() const = 0;
>   virtual section_iterator end_sections() const = 0;
>
> +  virtual library_iterator begin_libraries_needed() const = 0;
> +  virtual library_iterator end_libraries_needed() const = 0;
> +
>   /// @brief The number of bytes used to represent an address in this
> object
>   ///        file format.
>   virtual uint8_t getBytesInAddress() const = 0;
> @@ -509,6 +543,26 @@
>  inline error_code RelocationRef::getHidden(bool &Result) const {
>   return OwningObject->getRelocationHidden(RelocationPimpl, Result);
>  }
> +// Inline function definitions.
> +inline LibraryRef::LibraryRef(DataRefImpl LibraryP, const ObjectFile
> *Owner)
> +  : LibraryPimpl(LibraryP)
> +  , OwningObject(Owner) {}
> +
> +inline bool LibraryRef::operator==(const LibraryRef &Other) const {
> +  return LibraryPimpl == Other.LibraryPimpl;
> +}
> +
> +inline bool LibraryRef::operator <(const LibraryRef &Other) const {
> +  return LibraryPimpl < Other.LibraryPimpl;
> +}
> +
> +inline error_code LibraryRef::getNext(LibraryRef &Result) const {
> +  return OwningObject->getLibraryNext(LibraryPimpl, Result);
> +}
> +
> +inline error_code LibraryRef::getPath(StringRef &Result) const {
> +  return OwningObject->getLibraryPath(LibraryPimpl, Result);
> +}
>
>  } // end namespace object
>  } // end namespace llvm
>
> Modified: llvm/trunk/lib/Object/COFFObjectFile.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Object/COFFObjectFile.cpp?rev=151785&r1=151784&r2=151785&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/Object/COFFObjectFile.cpp (original)
> +++ llvm/trunk/lib/Object/COFFObjectFile.cpp Wed Feb 29 19:36:50 2012
> @@ -515,6 +515,16 @@
>   report_fatal_error("Dynamic symbols unimplemented in COFFObjectFile");
>  }
>
> +library_iterator COFFObjectFile::begin_libraries_needed() const {
> +  // TODO: implement
> +  report_fatal_error("Libraries needed unimplemented in COFFObjectFile");
> +}
> +
> +library_iterator COFFObjectFile::end_libraries_needed() const {
> +  // TODO: implement
> +  report_fatal_error("Libraries needed unimplemented in COFFObjectFile");
> +}
> +
>  section_iterator COFFObjectFile::begin_sections() const {
>   DataRefImpl ret;
>   std::memset(&ret, 0, sizeof(DataRefImpl));
> @@ -726,6 +736,16 @@
>   return object_error::success;
>  }
>
> +error_code COFFObjectFile::getLibraryNext(DataRefImpl LibData,
> +                                          LibraryRef &Result) const {
> +  report_fatal_error("getLibraryNext not implemented in COFFObjectFile");
> +}
> +
> +error_code COFFObjectFile::getLibraryPath(DataRefImpl LibData,
> +                                          StringRef &Result) const {
> +  report_fatal_error("getLibraryPath not implemented in COFFObjectFile");
> +}
> +
>  namespace llvm {
>
>   ObjectFile *ObjectFile::createCOFFObjectFile(MemoryBuffer *Object) {
>
> Modified: llvm/trunk/lib/Object/MachOObjectFile.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Object/MachOObjectFile.cpp?rev=151785&r1=151784&r2=151785&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/Object/MachOObjectFile.cpp (original)
> +++ llvm/trunk/lib/Object/MachOObjectFile.cpp Wed Feb 29 19:36:50 2012
> @@ -377,6 +377,16 @@
>   report_fatal_error("Dynamic symbols unimplemented in MachOObjectFile");
>  }
>
> +library_iterator MachOObjectFile::begin_libraries_needed() const {
> +  // TODO: implement
> +  report_fatal_error("Needed libraries unimplemented in MachOObjectFile");
> +}
> +
> +library_iterator MachOObjectFile::end_libraries_needed() const {
> +  // TODO: implement
> +  report_fatal_error("Needed libraries unimplemented in MachOObjectFile");
> +}
> +
>  /*===-- Sections
> ----------------------------------------------------------===*/
>
>  void MachOObjectFile::moveToNextSection(DataRefImpl &DRI) const {
> @@ -1175,6 +1185,17 @@
>   return object_error::success;
>  }
>
> +error_code MachOObjectFile::getLibraryNext(DataRefImpl LibData,
> +                                           LibraryRef &Res) const {
> +  report_fatal_error("Needed libraries unimplemented in MachOObjectFile");
> +}
> +
> +error_code MachOObjectFile::getLibraryPath(DataRefImpl LibData,
> +                                           StringRef &Res) const {
> +  report_fatal_error("Needed libraries unimplemented in MachOObjectFile");
> +}
> +
> +
>  /*===-- Miscellaneous
> -----------------------------------------------------===*/
>
>  uint8_t MachOObjectFile::getBytesInAddress() const {
>
> Modified: llvm/trunk/test/Object/Inputs/shared-object-test.elf-i386
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/Inputs/shared-object-test.elf-i386?rev=151785&r1=151784&r2=151785&view=diff
>
> ==============================================================================
> Binary files - no diff available.
>
> Propchange: llvm/trunk/test/Object/Inputs/shared-object-test.elf-i386
>
> ------------------------------------------------------------------------------
>    svn:mime-type = application/x-object-file
>
> Modified: llvm/trunk/test/Object/Inputs/shared-object-test.elf-x86-64
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/Inputs/shared-object-test.elf-x86-64?rev=151785&r1=151784&r2=151785&view=diff
>
> ==============================================================================
> Binary files - no diff available.
>
> Propchange: llvm/trunk/test/Object/Inputs/shared-object-test.elf-x86-64
>
> ------------------------------------------------------------------------------
>    svn:mime-type = application/x-object-file
>
> Modified: llvm/trunk/test/Object/Inputs/shared.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/Inputs/shared.ll?rev=151785&r1=151784&r2=151785&view=diff
>
> ==============================================================================
> --- llvm/trunk/test/Object/Inputs/shared.ll (original)
> +++ llvm/trunk/test/Object/Inputs/shared.ll Wed Feb 29 19:36:50 2012
> @@ -1,12 +1,14 @@
>  ; How to make the shared objects from this file:
>  ;
> +; LDARGS="--unresolved-symbols=ignore-all -soname=libfoo.so
> --no-as-needed -lc -lm"
> +;
>  ; X86-32 ELF:
>  ;   llc -mtriple=i386-linux-gnu shared.ll -filetype=obj -o tmp32.o
> -relocation-model=pic
> -;   ld -melf_i386 -shared tmp32.o -o shared-object-test.elf-i386
> --unresolved-symbols=ignore-all
> +;   ld -melf_i386 -shared tmp32.o -o shared-object-test.elf-i386 $LDARGS
>  ;
>  ; X86-64 ELF:
>  ;   llc -mtriple=x86_64-linux-gnu shared.ll -filetype=obj -o tmp64.o
> -relocation-model=pic
> -;   ld -melf_x86_64 -shared tmp64.o -o shared-object-test.elf-x86-64
> --unresolved-symbols=ignore-all
> +;   ld -melf_x86_64 -shared tmp64.o -o shared-object-test.elf-x86-64
> $LDARGS
>
>  @defined_sym = global i32 1, align 4
>
>
> Added: llvm/trunk/test/Object/readobj-shared-object.test
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/readobj-shared-object.test?rev=151785&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/Object/readobj-shared-object.test (added)
> +++ llvm/trunk/test/Object/readobj-shared-object.test Wed Feb 29 19:36:50
> 2012
> @@ -0,0 +1,44 @@
> +RUN: llvm-readobj %p/Inputs/shared-object-test.elf-i386 \
> +RUN:         | FileCheck %s -check-prefix ELF
> +RUN: llvm-readobj %p/Inputs/shared-object-test.elf-x86-64 \
> +RUN:         | FileCheck %s -check-prefix ELF
> +
> +ELF:Symbols:
> +ELF:  .dynsym                DBG             {{[0-9a-f]+}}  {{[0-9a-f]+}}
>  {{[0-9a-f]+}}  formatspecific
> +ELF:  .dynstr                DBG             {{[0-9a-f]+}}  {{[0-9a-f]+}}
>  {{[0-9a-f]+}}  formatspecific
> +ELF:  .text                  DBG             {{[0-9a-f]+}}  {{[0-9a-f]+}}
>  {{[0-9a-f]+}}  formatspecific
> +ELF:  .eh_frame              DBG             {{[0-9a-f]+}}  {{[0-9a-f]+}}
>  {{[0-9a-f]+}}  formatspecific
> +ELF:  .tdata                 DBG             {{[0-9a-f]+}}  {{[0-9a-f]+}}
>  {{[0-9a-f]+}}  formatspecific
> +ELF:  .dynamic               DBG             {{[0-9a-f]+}}  {{[0-9a-f]+}}
>  {{[0-9a-f]+}}  formatspecific
> +ELF:  .got.plt               DBG             {{[0-9a-f]+}}  {{[0-9a-f]+}}
>  {{[0-9a-f]+}}  formatspecific
> +ELF:  .data                  DBG             {{[0-9a-f]+}}  {{[0-9a-f]+}}
>  {{[0-9a-f]+}}  formatspecific
> +ELF:  .bss                   DBG             {{[0-9a-f]+}}  {{[0-9a-f]+}}
>  {{[0-9a-f]+}}  formatspecific
> +ELF:  shared.ll              FILE            {{[0-9a-f]+}}  {{[0-9a-f]+}}
>  {{[0-9a-f]+}}  absolute,formatspecific
> +ELF:  local_func             FUNC            {{[0-9a-f]+}}  {{[0-9a-f]+}}
>  {{[0-9a-f]+}}
> +ELF:  _GLOBAL_OFFSET_TABLE_  DATA            {{[0-9a-f]+}}  {{[0-9a-f]+}}
>  {{[0-9a-f]+}}  absolute
> +ELF:  _DYNAMIC               DATA            {{[0-9a-f]+}}  {{[0-9a-f]+}}
>  {{[0-9a-f]+}}  absolute
> +ELF:  common_sym             DATA            {{[0-9a-f]+}}  {{[0-9a-f]+}}
>  {{[0-9a-f]+}}  global
> +ELF:  tls_sym                DATA            {{[0-9a-f]+}}  {{[0-9a-f]+}}
>  {{[0-9a-f]+}}  global,threadlocal
> +ELF:  defined_sym            DATA            {{[0-9a-f]+}}  {{[0-9a-f]+}}
>  {{[0-9a-f]+}}  global
> +ELF:  __bss_start            ?               {{[0-9a-f]+}}  {{[0-9a-f]+}}
>  {{[0-9a-f]+}}  global,absolute
> +ELF:  _end                   ?               {{[0-9a-f]+}}  {{[0-9a-f]+}}
>  {{[0-9a-f]+}}  global,absolute
> +ELF:  global_func            FUNC            {{[0-9a-f]+}}  {{[0-9a-f]+}}
>  {{[0-9a-f]+}}  global
> +ELF:  _edata                 ?               {{[0-9a-f]+}}  {{[0-9a-f]+}}
>  {{[0-9a-f]+}}  global,absolute
> +ELF:  Total: 21
> +
> +ELF:Dynamic Symbols:
> +ELF:  common_sym             DATA            {{[0-9a-f]+}}  {{[0-9a-f]+}}
>  {{[0-9a-f]+}}  global
> +ELF:  tls_sym                DATA            {{[0-9a-f]+}}  {{[0-9a-f]+}}
>  {{[0-9a-f]+}}  global,threadlocal
> +ELF:  defined_sym            DATA            {{[0-9a-f]+}}  {{[0-9a-f]+}}
>  {{[0-9a-f]+}}  global
> +ELF:  __bss_start            ?               {{[0-9a-f]+}}  {{[0-9a-f]+}}
>  {{[0-9a-f]+}}  global,absolute
> +ELF:  _end                   ?               {{[0-9a-f]+}}  {{[0-9a-f]+}}
>  {{[0-9a-f]+}}  global,absolute
> +ELF:  global_func            FUNC            {{[0-9a-f]+}}  {{[0-9a-f]+}}
>  {{[0-9a-f]+}}  global
> +ELF:  _edata                 ?               {{[0-9a-f]+}}  {{[0-9a-f]+}}
>  {{[0-9a-f]+}}  global,absolute
> +ELF:  Total: {{[0-9a-f]+}}
> +
> +ELF:Libraries needed:
> +ELF:  libc.so.6
> +ELF:  libm.so.6
> +ELF:  Total: 2
> +
> +
>
> Modified: llvm/trunk/tools/CMakeLists.txt
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/CMakeLists.txt?rev=151785&r1=151784&r2=151785&view=diff
>
> ==============================================================================
> --- llvm/trunk/tools/CMakeLists.txt (original)
> +++ llvm/trunk/tools/CMakeLists.txt Wed Feb 29 19:36:50 2012
> @@ -37,6 +37,7 @@
>  add_subdirectory(llvm-diff)
>  add_subdirectory(macho-dump)
>  add_subdirectory(llvm-objdump)
> +add_subdirectory(llvm-readobj)
>  add_subdirectory(llvm-rtdyld)
>  add_subdirectory(llvm-dwarfdump)
>
>
> Modified: llvm/trunk/tools/Makefile
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/Makefile?rev=151785&r1=151784&r2=151785&view=diff
>
> ==============================================================================
> --- llvm/trunk/tools/Makefile (original)
> +++ llvm/trunk/tools/Makefile Wed Feb 29 19:36:50 2012
> @@ -32,7 +32,7 @@
>                  llvm-ld llvm-prof llvm-link \
>                  lli llvm-extract llvm-mc \
>                  bugpoint llvm-bcanalyzer llvm-stub \
> -                 llvm-diff macho-dump llvm-objdump \
> +                 llvm-diff macho-dump llvm-objdump llvm-readobj \
>                 llvm-rtdyld llvm-dwarfdump llvm-cov \
>                 llvm-size llvm-stress
>
>
> Added: llvm/trunk/tools/llvm-readobj/CMakeLists.txt
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/CMakeLists.txt?rev=151785&view=auto
>
> ==============================================================================
> --- llvm/trunk/tools/llvm-readobj/CMakeLists.txt (added)
> +++ llvm/trunk/tools/llvm-readobj/CMakeLists.txt Wed Feb 29 19:36:50 2012
> @@ -0,0 +1,5 @@
> +set(LLVM_LINK_COMPONENTS archive bitreader object)
> +
> +add_llvm_tool(llvm-readobj
> +  llvm-readobj.cpp
> +  )
>
> Added: llvm/trunk/tools/llvm-readobj/LLVMBuild.txt
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/LLVMBuild.txt?rev=151785&view=auto
>
> ==============================================================================
> --- llvm/trunk/tools/llvm-readobj/LLVMBuild.txt (added)
> +++ llvm/trunk/tools/llvm-readobj/LLVMBuild.txt Wed Feb 29 19:36:50 2012
> @@ -0,0 +1,22 @@
> +;===- ./tools/llvm-readobj/LLVMBuild.txt ---------------------------*-
> Conf -*--===;
> +;
> +;                     The LLVM Compiler Infrastructure
> +;
> +; This file is distributed under the University of Illinois Open Source
> +; License. See LICENSE.TXT for details.
> +;
>
> +;===------------------------------------------------------------------------===;
> +;
> +; This is an LLVMBuild description file for the components in this
> subdirectory.
> +;
> +; For more information on the LLVMBuild system, please see:
> +;
> +;   http://llvm.org/docs/LLVMBuild.html
> +;
>
> +;===------------------------------------------------------------------------===;
> +
> +[component_0]
> +type = Tool
> +name = llvm-readobj
> +parent = Tools
> +required_libraries = Archive BitReader Object
>
> Added: llvm/trunk/tools/llvm-readobj/Makefile
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/Makefile?rev=151785&view=auto
>
> ==============================================================================
> --- llvm/trunk/tools/llvm-readobj/Makefile (added)
> +++ llvm/trunk/tools/llvm-readobj/Makefile Wed Feb 29 19:36:50 2012
> @@ -0,0 +1,18 @@
> +##===- tools/llvm-readobj/Makefile -----------------------------*-
> Makefile -*-===##
> +#
> +#                     The LLVM Compiler Infrastructure
> +#
> +# This file is distributed under the University of Illinois Open Source
> +# License. See LICENSE.TXT for details.
> +#
>
> +##===----------------------------------------------------------------------===##
> +
> +LEVEL := ../..
> +TOOLNAME := llvm-readobj
> +LINK_COMPONENTS := archive bitreader object
> +
> +# This tool has no plugins, optimize startup time.
> +TOOL_NO_EXPORTS := 1
> +
> +include $(LEVEL)/Makefile.common
> +
>
> Added: llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp?rev=151785&view=auto
>
> ==============================================================================
> --- llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp (added)
> +++ llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp Wed Feb 29 19:36:50 2012
> @@ -0,0 +1,188 @@
> +/*===- pso-stub.c - Stub executable to run llvm bitcode files
> -------------===//
>

Uh, pso-stub.c??? Please fix this comment.


> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
>

Also, where did this comment go??? You can't just add a tool with zero
documentation. ;] You also need to add this tool to the commandline tools
documentation webpages, manual pages, etc. Also, please add something to
the release notes about this work.


>
> +//===----------------------------------------------------------------------===*/
>

And remember that it doesn't need to be a C-style comment any now.


> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
>

LLVM orders these after LLVM headers, and uses the C++ naming (cstdio,
cstdlib, etc).


> +#include "llvm/Object/ObjectFile.h"
> +#include "llvm/Analysis/Verifier.h"
> +#include "llvm/Support/Format.h"
> +#include "llvm/Support/CommandLine.h"
> +#include "llvm/Support/PrettyStackTrace.h"
> +#include "llvm/Support/Debug.h"
> +#include "llvm/Support/Signals.h"
> +#include "llvm/Support/FormattedStream.h"
> +
> +using namespace llvm;
> +using namespace llvm::object;
> +
> +static cl::opt<std::string>
> +InputFilename(cl::Positional, cl::desc("<input object>"), cl::init(""));
> +
> +void DumpSymbolHeader() {
> +  outs() << format("  %-32s", (const char*)"Name")
> +         << format("  %-4s", (const char*)"Type")
> +         << format("  %-16s", (const char*)"Address")
> +         << format("  %-16s", (const char*)"Size")
> +         << format("  %-16s", (const char*)"FileOffset")
> +         << format("  %-26s", (const char*)"Flags")
> +         << "\n";
> +}
> +
> +const char *GetTypeStr(SymbolRef::Type Type) {
> +  switch (Type) {
> +  case SymbolRef::ST_Unknown: return "?";
> +  case SymbolRef::ST_Data: return "DATA";
> +  case SymbolRef::ST_Debug: return "DBG";
> +  case SymbolRef::ST_File: return "FILE";
> +  case SymbolRef::ST_Function: return "FUNC";
> +  case SymbolRef::ST_Other: return "-";
> +  }
> +  return "INV";
> +}
> +
> +std::string GetFlagStr(uint32_t Flags) {
> +  std::string result;
> +  if (Flags & SymbolRef::SF_Undefined)
> +    result += "undef,";
> +  if (Flags & SymbolRef::SF_Global)
> +    result += "global,";
> +  if (Flags & SymbolRef::SF_Weak)
> +    result += "weak,";
> +  if (Flags & SymbolRef::SF_Absolute)
> +    result += "absolute,";
> +  if (Flags & SymbolRef::SF_ThreadLocal)
> +    result += "threadlocal,";
> +  if (Flags & SymbolRef::SF_Common)
> +    result += "common,";
> +  if (Flags & SymbolRef::SF_FormatSpecific)
> +    result += "formatspecific,";
> +
> +  // Remove trailing comma
> +  if (result.size() > 0) {
> +    result.erase(result.size() - 1);
> +  }
> +  return result;
> +}
> +
> +void DumpSymbol(const SymbolRef &sym) {
> +    StringRef Name;
> +    SymbolRef::Type Type;
> +    uint32_t Flags;
> +    uint64_t Address;
> +    uint64_t Size;
> +    uint64_t FileOffset;
> +    sym.getName(Name);
> +    sym.getAddress(Address);
> +    sym.getSize(Size);
> +    sym.getFileOffset(FileOffset);
> +    sym.getType(Type);
> +    sym.getFlags(Flags);
> +
> +    // format() can't handle StringRefs
> +    outs() << format("  %-32s", Name.str().c_str())
> +           << format("  %-4s", GetTypeStr(Type))
> +           << format("  %16"PRIx64, Address)
> +           << format("  %16"PRIx64, Size)
> +           << format("  %16"PRIx64, FileOffset)
> +           << "  " << GetFlagStr(Flags)
> +           << "\n";
> +}
> +
> +
> +// Iterate through the normal symbols in the ObjectFile
> +void DumpSymbols(const ObjectFile *obj) {
> +  error_code ec;
> +  uint32_t count = 0;
> +  outs() << "Symbols:\n";
> +  symbol_iterator it = obj->begin_symbols();
> +  symbol_iterator ie = obj->end_symbols();
> +  while (it != ie) {
> +    DumpSymbol(*it);
> +    it.increment(ec);
> +    if (ec)
> +      report_fatal_error("Symbol iteration failed");
> +    ++count;
> +  }
> +  outs() << "  Total: " << count << "\n\n";
> +}
> +
> +// Iterate through the dynamic symbols in the ObjectFile.
> +void DumpDynamicSymbols(const ObjectFile *obj) {
> +  error_code ec;
> +  uint32_t count = 0;
> +  outs() << "Dynamic Symbols:\n";
> +  symbol_iterator it = obj->begin_dynamic_symbols();
> +  symbol_iterator ie = obj->end_dynamic_symbols();
> +  while (it != ie) {
> +    DumpSymbol(*it);
> +    it.increment(ec);
> +    if (ec)
> +      report_fatal_error("Symbol iteration failed");
> +    ++count;
> +  }
> +  outs() << "  Total: " << count << "\n\n";
> +}
> +
> +void DumpLibrary(const LibraryRef &lib) {
> +  StringRef path;
> +  lib.getPath(path);
> +  outs() << "  " << path << "\n";
> +}
> +
> +// Iterate through needed libraries
> +void DumpLibrariesNeeded(const ObjectFile *obj) {
> +  error_code ec;
> +  uint32_t count = 0;
> +  library_iterator it = obj->begin_libraries_needed();
> +  library_iterator ie = obj->end_libraries_needed();
> +  outs() << "Libraries needed:\n";
> +  while (it != ie) {
> +    DumpLibrary(*it);
> +    it.increment(ec);
> +    if (ec)
> +      report_fatal_error("Needed libraries iteration failed");
> +    ++count;
> +  }
> +  outs() << "  Total: " << count << "\n\n";
> +}
> +
> +int main(int argc, char** argv) {
> +  error_code ec;
> +  sys::PrintStackTraceOnErrorSignal();
> +  PrettyStackTraceProgram X(argc, argv);
> +
> +  cl::ParseCommandLineOptions(argc, argv,
> +                              "LLVM Object Reader\n");
> +
> +  if (InputFilename.empty()) {
> +    errs() << "Please specify an input filename\n";
> +    return 1;
> +  }
> +
> +  // Open the object file
> +  OwningPtr<MemoryBuffer> File;
> +  if (MemoryBuffer::getFile(InputFilename, File)) {
> +    errs() << InputFilename << ": Open failed\n";
> +    return 1;
> +  }
> +
> +  ObjectFile *obj = ObjectFile::createObjectFile(File.take());
> +  if (!obj) {
> +    errs() << InputFilename << ": Object type not recognized\n";
> +  }
> +
> +  DumpSymbols(obj);
> +  DumpDynamicSymbols(obj);
> +  DumpLibrariesNeeded(obj);
> +  return 0;
> +}
> +
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20120301/2eedef0e/attachment.html>


More information about the llvm-commits mailing list