[llvm-commits] [llvm] r140626 - in /llvm/trunk: include/llvm/Object/Archive.h lib/Object/Archive.cpp lib/Object/Binary.cpp lib/Object/CMakeLists.txt

Michael J. Spencer bigcheesegs at gmail.com
Tue Sep 27 12:36:56 PDT 2011


Author: mspencer
Date: Tue Sep 27 14:36:55 2011
New Revision: 140626

URL: http://llvm.org/viewvc/llvm-project?rev=140626&view=rev
Log:
Object: Add archive support.

Added:
    llvm/trunk/include/llvm/Object/Archive.h
    llvm/trunk/lib/Object/Archive.cpp
Modified:
    llvm/trunk/lib/Object/Binary.cpp
    llvm/trunk/lib/Object/CMakeLists.txt

Added: llvm/trunk/include/llvm/Object/Archive.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Object/Archive.h?rev=140626&view=auto
==============================================================================
--- llvm/trunk/include/llvm/Object/Archive.h (added)
+++ llvm/trunk/include/llvm/Object/Archive.h Tue Sep 27 14:36:55 2011
@@ -0,0 +1,90 @@
+//===- Archive.h - ar archive file format -----------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the ar archive file format class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OBJECT_ARCHIVE_H
+#define LLVM_OBJECT_ARCHIVE_H
+
+#include "llvm/Object/Binary.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/DataTypes.h"
+
+namespace llvm {
+namespace object {
+
+class Archive : public Binary {
+public:
+  class Child {
+    Archive *Parent;
+    StringRef Data;
+
+  public:
+    Child(Archive *p, StringRef d) : Parent(p), Data(d) {}
+
+    bool operator ==(const Child &other) const {
+      return (Parent == other.Parent) && (Data.begin() == other.Data.begin());
+    }
+
+    Child getNext() const;
+    error_code getName(StringRef &Result) const;
+    int getLastModified() const;
+    int getUID() const;
+    int getGID() const;
+    int getAccessMode() const;
+    ///! Return the size of the archive member without the header or padding.
+    uint64_t getSize() const;
+
+    MemoryBuffer *getBuffer() const;
+    error_code getAsBinary(OwningPtr<Binary> &Result) const;
+  };
+
+  class child_iterator {
+    Child child;
+  public:
+    child_iterator(const Child &c) : child(c) {}
+    const Child* operator->() const {
+      return &child;
+    }
+
+    bool operator==(const child_iterator &other) const {
+      return child == other.child;
+    }
+
+    bool operator!=(const child_iterator &other) const {
+      return !(*this == other);
+    }
+
+    child_iterator& operator++() {  // Preincrement
+      child = child.getNext();
+      return *this;
+    }
+  };
+
+  Archive(MemoryBuffer *source, error_code &ec);
+
+  child_iterator begin_children();
+  child_iterator end_children();
+
+  // Cast methods.
+  static inline bool classof(Archive const *v) { return true; }
+  static inline bool classof(Binary const *v) {
+    return v->getType() == Binary::isArchive;
+  }
+
+private:
+  child_iterator StringTable;
+};
+
+}
+}
+
+#endif

Added: llvm/trunk/lib/Object/Archive.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Object/Archive.cpp?rev=140626&view=auto
==============================================================================
--- llvm/trunk/lib/Object/Archive.cpp (added)
+++ llvm/trunk/lib/Object/Archive.cpp Tue Sep 27 14:36:55 2011
@@ -0,0 +1,172 @@
+//===- Archive.cpp - ar File Format implementation --------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the ArchiveObjectFile class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/Archive.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+using namespace llvm;
+using namespace object;
+
+namespace {
+const StringRef Magic = "!<arch>\n";
+
+struct ArchiveMemberHeader {
+  char Name[16];
+  char LastModified[12];
+  char UID[6];
+  char GID[6];
+  char AccessMode[8];
+  char Size[10]; //< Size of data, not including header or padding.
+  char Terminator[2];
+
+  ///! Get the name without looking up long names.
+  StringRef getName() const {
+    char EndCond = Name[0] == '/' ? ' ' : '/';
+    StringRef::size_type end = StringRef(Name, sizeof(Name)).find(EndCond);
+    if (end == StringRef::npos)
+      end = sizeof(Name);
+    assert(end <= sizeof(Name) && end > 0);
+    // Don't include the EndCond if there is one.
+    return StringRef(Name, end);
+  }
+
+  uint64_t getSize() const {
+    APInt ret;
+    StringRef(Size, sizeof(Size)).getAsInteger(10, ret);
+    return ret.getZExtValue();
+  }
+};
+
+const ArchiveMemberHeader *ToHeader(const char *base) {
+  return reinterpret_cast<const ArchiveMemberHeader *>(base);
+}
+}
+
+Archive::Child Archive::Child::getNext() const {
+  size_t SpaceToSkip = sizeof(ArchiveMemberHeader) +
+    ToHeader(Data.data())->getSize();
+  // If it's odd, add 1 to make it even.
+  if (SpaceToSkip & 1)
+    ++SpaceToSkip;
+
+  const char *NextLoc = Data.data() + SpaceToSkip;
+
+  // Check to see if this is past the end of the archive.
+  if (NextLoc >= Parent->Data->getBufferEnd())
+    return Child(Parent, StringRef(0, 0));
+
+  size_t NextSize = sizeof(ArchiveMemberHeader) +
+    ToHeader(NextLoc)->getSize();
+
+  return Child(Parent, StringRef(NextLoc, NextSize));
+}
+
+error_code Archive::Child::getName(StringRef &Result) const {
+  StringRef name = ToHeader(Data.data())->getName();
+  // Check if it's a special name.
+  if (name[0] == '/') {
+    if (name.size() == 1) { // Linker member.
+      Result = name;
+      return object_error::success;
+    }
+    if (name.size() == 2 && name[1] == '/') { // String table.
+      Result = name;
+      return object_error::success;
+    }
+    // It's a long name.
+    // Get the offset.
+    APInt offset;
+    name.substr(1).getAsInteger(10, offset);
+    const char *addr = Parent->StringTable->Data.begin()
+                       + sizeof(ArchiveMemberHeader)
+                       + offset.getZExtValue();
+    // Verify it.
+    if (Parent->StringTable == Parent->end_children()
+        || addr < (Parent->StringTable->Data.begin()
+                   + sizeof(ArchiveMemberHeader))
+        || addr > (Parent->StringTable->Data.begin()
+                   + sizeof(ArchiveMemberHeader)
+                   + Parent->StringTable->getSize()))
+      return object_error::parse_failed;
+    Result = addr;
+    return object_error::success;
+  }
+  // It's a simple name.
+  if (name[name.size() - 1] == '/')
+    Result = name.substr(0, name.size() - 1);
+  else
+    Result = name;
+  return object_error::success;
+}
+
+uint64_t Archive::Child::getSize() const {
+  return ToHeader(Data.data())->getSize();
+}
+
+MemoryBuffer *Archive::Child::getBuffer() const {
+  StringRef name;
+  if (getName(name)) return NULL;
+  return MemoryBuffer::getMemBuffer(Data.substr(sizeof(ArchiveMemberHeader),
+                                                getSize()),
+                                    name,
+                                    false);
+}
+
+error_code Archive::Child::getAsBinary(OwningPtr<Binary> &Result) const {
+  OwningPtr<Binary> ret;
+  if (error_code ec =
+    createBinary(getBuffer(), ret))
+    return ec;
+  Result.swap(ret);
+  return object_error::success;
+}
+
+Archive::Archive(MemoryBuffer *source, error_code &ec)
+  : Binary(Binary::isArchive, source)
+  , StringTable(Child(this, StringRef(0, 0))) {
+  // Check for sufficient magic.
+  if (!source || source->getBufferSize()
+                 < (8 + sizeof(ArchiveMemberHeader) + 2) // Smallest archive.
+              || StringRef(source->getBufferStart(), 8) != Magic) {
+    ec = object_error::invalid_file_type;
+    return;
+  }
+
+  // Get the string table. It's the 3rd member.
+  child_iterator StrTable = begin_children();
+  child_iterator e = end_children();
+  for (int i = 0; StrTable != e && i < 2; ++StrTable, ++i);
+
+  // Check to see if there were 3 members, or the 3rd member wasn't named "//".
+  StringRef name;
+  if (StrTable != e && !StrTable->getName(name) && name == "//")
+    StringTable = StrTable;
+
+  ec = object_error::success;
+}
+
+Archive::child_iterator Archive::begin_children() {
+  const char *Loc = Data->getBufferStart() + Magic.size();
+  size_t Size = sizeof(ArchiveMemberHeader) +
+    ToHeader(Loc)->getSize();
+  return Child(this, StringRef(Loc, Size));
+}
+
+Archive::child_iterator Archive::end_children() {
+  return Child(this, StringRef(0, 0));
+}
+
+namespace llvm {
+
+} // end namespace llvm

Modified: llvm/trunk/lib/Object/Binary.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Object/Binary.cpp?rev=140626&r1=140625&r2=140626&view=diff
==============================================================================
--- llvm/trunk/lib/Object/Binary.cpp (original)
+++ llvm/trunk/lib/Object/Binary.cpp Tue Sep 27 14:36:55 2011
@@ -17,8 +17,9 @@
 #include "llvm/Support/Path.h"
 
 // Include headers for createBinary.
-#include "llvm/Object/ObjectFile.h"
+#include "llvm/Object/Archive.h"
 #include "llvm/Object/COFF.h"
+#include "llvm/Object/ObjectFile.h"
 
 using namespace llvm;
 using namespace object;
@@ -50,6 +51,12 @@
                                 static_cast<unsigned>(Source->getBufferSize()));
   error_code ec;
   switch (type) {
+    case sys::Archive_FileType: {
+      OwningPtr<Binary> ret(new Archive(scopedSource.take(), ec));
+      if (ec) return ec;
+      Result.swap(ret);
+      return object_error::success;
+    }
     case sys::ELF_Relocatable_FileType:
     case sys::ELF_Executable_FileType:
     case sys::ELF_SharedObject_FileType:

Modified: llvm/trunk/lib/Object/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Object/CMakeLists.txt?rev=140626&r1=140625&r2=140626&view=diff
==============================================================================
--- llvm/trunk/lib/Object/CMakeLists.txt (original)
+++ llvm/trunk/lib/Object/CMakeLists.txt Tue Sep 27 14:36:55 2011
@@ -1,4 +1,5 @@
 add_llvm_library(LLVMObject
+  Archive.cpp
   Binary.cpp
   COFFObjectFile.cpp
   ELFObjectFile.cpp





More information about the llvm-commits mailing list