diff options
author | Michael J. Spencer <bigcheesegs@gmail.com> | 2011-09-27 19:36:55 +0000 |
---|---|---|
committer | Michael J. Spencer <bigcheesegs@gmail.com> | 2011-09-27 19:36:55 +0000 |
commit | a51d7d97b0b8187ed68d4cbad2374f514d2cd168 (patch) | |
tree | 6903f55118203a052fd7761c8fe7b55392f902f4 | |
parent | 040bff0bc23bd38ad68b2de8dff8bb41706180e0 (diff) | |
download | external_llvm-a51d7d97b0b8187ed68d4cbad2374f514d2cd168.zip external_llvm-a51d7d97b0b8187ed68d4cbad2374f514d2cd168.tar.gz external_llvm-a51d7d97b0b8187ed68d4cbad2374f514d2cd168.tar.bz2 |
Object: Add archive support.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@140626 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/llvm/Object/Archive.h | 90 | ||||
-rw-r--r-- | lib/Object/Archive.cpp | 172 | ||||
-rw-r--r-- | lib/Object/Binary.cpp | 9 | ||||
-rw-r--r-- | lib/Object/CMakeLists.txt | 1 |
4 files changed, 271 insertions, 1 deletions
diff --git a/include/llvm/Object/Archive.h b/include/llvm/Object/Archive.h new file mode 100644 index 0000000..c6b6ed0 --- /dev/null +++ b/include/llvm/Object/Archive.h @@ -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 diff --git a/lib/Object/Archive.cpp b/lib/Object/Archive.cpp new file mode 100644 index 0000000..80343e3 --- /dev/null +++ b/lib/Object/Archive.cpp @@ -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 diff --git a/lib/Object/Binary.cpp b/lib/Object/Binary.cpp index 4b31c75..3b00beb 100644 --- a/lib/Object/Binary.cpp +++ b/lib/Object/Binary.cpp @@ -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 @@ error_code object::createBinary(MemoryBuffer *Source, 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: diff --git a/lib/Object/CMakeLists.txt b/lib/Object/CMakeLists.txt index 8111393..86eb51a 100644 --- a/lib/Object/CMakeLists.txt +++ b/lib/Object/CMakeLists.txt @@ -1,4 +1,5 @@ add_llvm_library(LLVMObject + Archive.cpp Binary.cpp COFFObjectFile.cpp ELFObjectFile.cpp |