llvm.org GIT mirror llvm / a51d7d9
Object: Add archive support. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@140626 91177308-0d34-0410-b5e6-96231b3b80d8 Michael J. Spencer 8 years ago
4 changed file(s) with 271 addition(s) and 1 deletion(s). Raw diff Collapse all Expand all
0 //===- Archive.h - ar archive file format -----------------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file declares the ar archive file format class.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #ifndef LLVM_OBJECT_ARCHIVE_H
14 #define LLVM_OBJECT_ARCHIVE_H
15
16 #include "llvm/Object/Binary.h"
17 #include "llvm/ADT/StringRef.h"
18 #include "llvm/Support/DataTypes.h"
19
20 namespace llvm {
21 namespace object {
22
23 class Archive : public Binary {
24 public:
25 class Child {
26 Archive *Parent;
27 StringRef Data;
28
29 public:
30 Child(Archive *p, StringRef d) : Parent(p), Data(d) {}
31
32 bool operator ==(const Child &other) const {
33 return (Parent == other.Parent) && (Data.begin() == other.Data.begin());
34 }
35
36 Child getNext() const;
37 error_code getName(StringRef &Result) const;
38 int getLastModified() const;
39 int getUID() const;
40 int getGID() const;
41 int getAccessMode() const;
42 ///! Return the size of the archive member without the header or padding.
43 uint64_t getSize() const;
44
45 MemoryBuffer *getBuffer() const;
46 error_code getAsBinary(OwningPtr &Result) const;
47 };
48
49 class child_iterator {
50 Child child;
51 public:
52 child_iterator(const Child &c) : child(c) {}
53 const Child* operator->() const {
54 return &child;
55 }
56
57 bool operator==(const child_iterator &other) const {
58 return child == other.child;
59 }
60
61 bool operator!=(const child_iterator &other) const {
62 return !(*this == other);
63 }
64
65 child_iterator& operator++() { // Preincrement
66 child = child.getNext();
67 return *this;
68 }
69 };
70
71 Archive(MemoryBuffer *source, error_code &ec);
72
73 child_iterator begin_children();
74 child_iterator end_children();
75
76 // Cast methods.
77 static inline bool classof(Archive const *v) { return true; }
78 static inline bool classof(Binary const *v) {
79 return v->getType() == Binary::isArchive;
80 }
81
82 private:
83 child_iterator StringTable;
84 };
85
86 }
87 }
88
89 #endif
0 //===- Archive.cpp - ar File Format implementation --------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines the ArchiveObjectFile class.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #include "llvm/Object/Archive.h"
14 #include "llvm/ADT/APInt.h"
15 #include "llvm/Support/MemoryBuffer.h"
16
17 using namespace llvm;
18 using namespace object;
19
20 namespace {
21 const StringRef Magic = "!\n";
22
23 struct ArchiveMemberHeader {
24 char Name[16];
25 char LastModified[12];
26 char UID[6];
27 char GID[6];
28 char AccessMode[8];
29 char Size[10]; //< Size of data, not including header or padding.
30 char Terminator[2];
31
32 ///! Get the name without looking up long names.
33 StringRef getName() const {
34 char EndCond = Name[0] == '/' ? ' ' : '/';
35 StringRef::size_type end = StringRef(Name, sizeof(Name)).find(EndCond);
36 if (end == StringRef::npos)
37 end = sizeof(Name);
38 assert(end <= sizeof(Name) && end > 0);
39 // Don't include the EndCond if there is one.
40 return StringRef(Name, end);
41 }
42
43 uint64_t getSize() const {
44 APInt ret;
45 StringRef(Size, sizeof(Size)).getAsInteger(10, ret);
46 return ret.getZExtValue();
47 }
48 };
49
50 const ArchiveMemberHeader *ToHeader(const char *base) {
51 return reinterpret_cast(base);
52 }
53 }
54
55 Archive::Child Archive::Child::getNext() const {
56 size_t SpaceToSkip = sizeof(ArchiveMemberHeader) +
57 ToHeader(Data.data())->getSize();
58 // If it's odd, add 1 to make it even.
59 if (SpaceToSkip & 1)
60 ++SpaceToSkip;
61
62 const char *NextLoc = Data.data() + SpaceToSkip;
63
64 // Check to see if this is past the end of the archive.
65 if (NextLoc >= Parent->Data->getBufferEnd())
66 return Child(Parent, StringRef(0, 0));
67
68 size_t NextSize = sizeof(ArchiveMemberHeader) +
69 ToHeader(NextLoc)->getSize();
70
71 return Child(Parent, StringRef(NextLoc, NextSize));
72 }
73
74 error_code Archive::Child::getName(StringRef &Result) const {
75 StringRef name = ToHeader(Data.data())->getName();
76 // Check if it's a special name.
77 if (name[0] == '/') {
78 if (name.size() == 1) { // Linker member.
79 Result = name;
80 return object_error::success;
81 }
82 if (name.size() == 2 && name[1] == '/') { // String table.
83 Result = name;
84 return object_error::success;
85 }
86 // It's a long name.
87 // Get the offset.
88 APInt offset;
89 name.substr(1).getAsInteger(10, offset);
90 const char *addr = Parent->StringTable->Data.begin()
91 + sizeof(ArchiveMemberHeader)
92 + offset.getZExtValue();
93 // Verify it.
94 if (Parent->StringTable == Parent->end_children()
95 || addr < (Parent->StringTable->Data.begin()
96 + sizeof(ArchiveMemberHeader))
97 || addr > (Parent->StringTable->Data.begin()
98 + sizeof(ArchiveMemberHeader)
99 + Parent->StringTable->getSize()))
100 return object_error::parse_failed;
101 Result = addr;
102 return object_error::success;
103 }
104 // It's a simple name.
105 if (name[name.size() - 1] == '/')
106 Result = name.substr(0, name.size() - 1);
107 else
108 Result = name;
109 return object_error::success;
110 }
111
112 uint64_t Archive::Child::getSize() const {
113 return ToHeader(Data.data())->getSize();
114 }
115
116 MemoryBuffer *Archive::Child::getBuffer() const {
117 StringRef name;
118 if (getName(name)) return NULL;
119 return MemoryBuffer::getMemBuffer(Data.substr(sizeof(ArchiveMemberHeader),
120 getSize()),
121 name,
122 false);
123 }
124
125 error_code Archive::Child::getAsBinary(OwningPtr &Result) const {
126 OwningPtr ret;
127 if (error_code ec =
128 createBinary(getBuffer(), ret))
129 return ec;
130 Result.swap(ret);
131 return object_error::success;
132 }
133
134 Archive::Archive(MemoryBuffer *source, error_code &ec)
135 : Binary(Binary::isArchive, source)
136 , StringTable(Child(this, StringRef(0, 0))) {
137 // Check for sufficient magic.
138 if (!source || source->getBufferSize()
139 < (8 + sizeof(ArchiveMemberHeader) + 2) // Smallest archive.
140 || StringRef(source->getBufferStart(), 8) != Magic) {
141 ec = object_error::invalid_file_type;
142 return;
143 }
144
145 // Get the string table. It's the 3rd member.
146 child_iterator StrTable = begin_children();
147 child_iterator e = end_children();
148 for (int i = 0; StrTable != e && i < 2; ++StrTable, ++i);
149
150 // Check to see if there were 3 members, or the 3rd member wasn't named "//".
151 StringRef name;
152 if (StrTable != e && !StrTable->getName(name) && name == "//")
153 StringTable = StrTable;
154
155 ec = object_error::success;
156 }
157
158 Archive::child_iterator Archive::begin_children() {
159 const char *Loc = Data->getBufferStart() + Magic.size();
160 size_t Size = sizeof(ArchiveMemberHeader) +
161 ToHeader(Loc)->getSize();
162 return Child(this, StringRef(Loc, Size));
163 }
164
165 Archive::child_iterator Archive::end_children() {
166 return Child(this, StringRef(0, 0));
167 }
168
169 namespace llvm {
170
171 } // end namespace llvm
1616 #include "llvm/Support/Path.h"
1717
1818 // Include headers for createBinary.
19 #include "llvm/Object/Archive.h"
20 #include "llvm/Object/COFF.h"
1921 #include "llvm/Object/ObjectFile.h"
20 #include "llvm/Object/COFF.h"
2122
2223 using namespace llvm;
2324 using namespace object;
4950 static_cast(Source->getBufferSize()));
5051 error_code ec;
5152 switch (type) {
53 case sys::Archive_FileType: {
54 OwningPtr ret(new Archive(scopedSource.take(), ec));
55 if (ec) return ec;
56 Result.swap(ret);
57 return object_error::success;
58 }
5259 case sys::ELF_Relocatable_FileType:
5360 case sys::ELF_Executable_FileType:
5461 case sys::ELF_SharedObject_FileType:
0 add_llvm_library(LLVMObject
1 Archive.cpp
12 Binary.cpp
23 COFFObjectFile.cpp
34 ELFObjectFile.cpp