blob: e3e2df4aee0dc601f6e8441c4e1ba0f927bf6254 [file] [log] [blame]
Reid Spencer362cbf02004-11-06 08:51:45 +00001//===-- ArchiveWriter.cpp - LLVM archive writing --------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file was developed by Reid Spencerand is distributed under the
6// University of Illinois Open Source License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// Builds up standard unix archive files (.a) containing LLVM bytecode.
11//
12//===----------------------------------------------------------------------===//
13
14#include "ArchiveInternals.h"
15#include "llvm/Module.h"
16#include "llvm/Bytecode/Reader.h"
17#include "llvm/Support/FileUtilities.h"
18#include "llvm/ADT/StringExtras.h"
19#include "llvm/System/MappedFile.h"
20#include <fstream>
21#include <iostream>
22
23using namespace llvm;
24
25Archive*
26Archive::CreateEmpty(const sys::Path& Filename) {
27 Archive* result = new Archive;
28 Archive::ArchiveInternals* impl = result->impl = new Archive::ArchiveInternals;
29 impl->fname = Filename;
30 return result;
31}
32
33Archive*
34Archive::CreateFromFiles(
35 const sys::Path& Filename,
36 const PathList& Files,
37 const std::string& StripName
38) {
39 Archive* result = new Archive;
40 Archive::ArchiveInternals* impl = result->impl = new Archive::ArchiveInternals;
41 impl->fname = Filename;
42
43 try {
44 size_t strip_len = StripName.length();
45 for (PathList::const_iterator P = Files.begin(), E = Files.end(); P != E ;++P)
46 {
47 if (P->readable()) {
48 std::string name(P->get());
49 if (strip_len > 0 && StripName == name.substr(0,strip_len)) {
50 name.erase(0,strip_len);
51 }
52 if (P->isBytecodeFile()) {
53 std::vector<std::string> syms;
54 if (!GetBytecodeSymbols(*P, syms))
55 throw std::string("Can not get symbols from: ") + P->get();
56 impl->addFileMember(*P, name, &syms);
57 } else {
58 impl->addFileMember(*P, name);
59 }
60 }
61 else
62 throw std::string("Can not read: ") + P->get();
63 }
64
65 // Now that we've collected everything, write the archive
66 impl->writeArchive();
67
68 } catch(...) {
69 delete impl;
70 result->impl = 0;
71 delete result;
72 throw;
73 }
74
75 return result;
76}
77
78void
79Archive::ArchiveInternals::addFileMember(
80 const sys::Path& filePath,
81 const std::string& memberName,
82 const StrTab* symbols
83) {
84 MemberInfo info;
85 info.path = filePath;
86 info.name = memberName;
87 filePath.getStatusInfo(info.status);
88 if (symbols)
89 info.symbols = *symbols;
90 info.offset = 0;
91 members.push_back(info);
92}
93
94void
95Archive::ArchiveInternals::writeInteger(int num, std::ofstream& ARFile) {
96 char buff[4];
97 buff[0] = (num >> 24) & 255;
98 buff[1] = (num >> 16) & 255;
99 buff[2] = (num >> 8) & 255;
100 buff[3] = num & 255;
101 ARFile.write(buff, sizeof(buff));
102}
103
104void
105Archive::ArchiveInternals::writeSymbolTable( std::ofstream& ARFile ) {
106
107 // Compute the number of symbols in the symbol table and the
108 // total byte size of the string pool. While we're traversing,
109 // build the string pool for supporting long file names. Also,
110 // build the table of file offsets for the symbol table and
111 // the
112 typedef std::map<std::string,unsigned> SymbolMap;
113 StrTab stringPool;
114 SymbolMap symbolTable;
115 std::vector<unsigned> fileOffsets;
116 std::string symTabStrings;
117 unsigned fileOffset = 0;
118 unsigned spOffset = 0;
119 unsigned numSymbols = 0;
120 unsigned numSymBytes = 0;
121 for (unsigned i = 0; i < members.size(); i++ ) {
122 MemberInfo& mi = members[i];
123 StrTab& syms = mi.symbols;
124 size_t numSym = syms.size();
125 numSymbols += numSym;
126 for (unsigned j = 0; j < numSym; j++ ) {
127 numSymBytes += syms[j].size() + 1;
128 symbolTable[syms[i]] = i;
129 }
130 if (mi.name.length() > 15 || std::string::npos != mi.name.find('/')) {
131 stringPool.push_back(mi.name + "/\n");
132 mi.name = std::string("/") + utostr(spOffset);
133 spOffset += mi.name.length() + 2;
134 } else if (mi.name[mi.name.length()-1] != '/') {
135 mi.name += "/";
136 }
137 fileOffsets.push_back(fileOffset);
138 fileOffset += sizeof(ArchiveMemberHeader) + mi.status.fileSize;
139 }
140
141
142 // Compute the size of the symbol table file member
143 unsigned symTabSize = 0;
144 if (numSymbols != 0)
145 symTabSize =
146 sizeof(ArchiveMemberHeader) + // Size of the file header
147 4 + // Size of "number of entries"
148 (4 * numSymbols) + // Size of member file indices
149 numSymBytes; // Size of the string table
150
151 // Compute the size of the string pool
152 unsigned strPoolSize = 0;
153 if (spOffset != 0 )
154 strPoolSize =
155 sizeof(ArchiveMemberHeader) + // Size of the file header
156 spOffset; // Number of bytes in the string pool
157
158 // Compute the byte index offset created by symbol table and string pool
159 unsigned firstFileOffset = symTabSize + strPoolSize;
160
161 // Create header for symbol table. This must be first if there is
162 // a symbol table and must have a special name.
163 if ( symTabSize > 0 ) {
164 ArchiveMemberHeader Hdr;
165 Hdr.init();
166
167 // Name of symbol table is '/ ' but "" is passed in
168 // because the setName method always terminates with a /
169 Hdr.setName(ARFILE_SYMTAB_NAME);
170 Hdr.setDate();
171 Hdr.setSize(symTabSize - sizeof(ArchiveMemberHeader));
172 Hdr.setMode(0);
173 Hdr.setUid(0);
174 Hdr.setGid(0);
175
176 // Write header to archive file
177 ARFile.write((char*)&Hdr, sizeof(Hdr));
178
179 // Write the number of entries in the symbol table
180 this->writeInteger(numSymbols, ARFile);
181
182 // Write the file offset indices for each symbol and build the
183 // symbol table string pool
184 std::string symTabStrPool;
185 symTabStrPool.reserve(256 * 1024); // Reserve 256KBytes for symbols
186 for (SymbolMap::iterator I = symbolTable.begin(), E = symbolTable.end();
187 I != E; ++I ) {
188 this->writeInteger(firstFileOffset + fileOffsets[I->second], ARFile);
189 symTabStrPool += I->first;
190 symTabStrPool += "\0";
191 }
192
193 // Write the symbol table's string pool
194 ARFile.write(symTabStrPool.data(), symTabStrPool.size());
195 }
196
197 //============== DONE WITH SYMBOL TABLE
198
199 if (strPoolSize > 0) {
200 // Initialize the header for the string pool
201 ArchiveMemberHeader Hdr;
202 Hdr.init();
203 Hdr.setName(ARFILE_STRTAB_NAME);
204 Hdr.setDate();
205 Hdr.setSize(spOffset);
206 Hdr.setMode(0);
207 Hdr.setUid(0);
208 Hdr.setGid(0);
209
210 // Write the string pool header
211 ARFile.write((char*)&Hdr, sizeof(Hdr));
212
213 // Write the string pool
214 for (unsigned i = 0; i < stringPool.size(); i++) {
215 ARFile.write(stringPool[i].data(), stringPool[i].size());
216 }
217 }
218}
219
220void
221Archive::ArchiveInternals::writeMember(
222 const MemberInfo& member,
223 std::ofstream& ARFile
224) {
225
226 // Map the file into memory. We do this early for two reasons. First,
227 // if there's any kind of error, we want to know about it. Second, we
228 // want to ensure we're using the most recent size for this file.
229 sys::MappedFile mFile(member.path);
230 mFile.map();
231
232 // Header for the archive member
233 ArchiveMemberHeader Hdr;
234 Hdr.init();
235
236 // Set the name. If its longer than 15 chars, it will have already
237 // been reduced by the writeSymbolTable.
238 Hdr.setName(member.name);
239
240 // Set the other header members
241 Hdr.setSize( mFile.size() );
242 Hdr.setMode( member.status.mode);
243 Hdr.setUid ( member.status.user);
244 Hdr.setGid ( member.status.group);
245 Hdr.setDate( member.status.modTime.ToPosixTime() );
246
247 // Write header to archive file
248 ARFile.write((char*)&Hdr, sizeof(Hdr));
249
250 //write to archive file
251 ARFile.write(mFile.charBase(),mFile.size());
252
253 mFile.unmap();
254}
255
256void
257Archive::ArchiveInternals::writeArchive() {
258
259 // Create archive file for output.
260 std::ofstream ArchiveFile(fname.get().c_str());
261
262 // Check for errors opening or creating archive file.
263 if ( !ArchiveFile.is_open() || ArchiveFile.bad() ) {
264 throw std::string("Error opening archive file: ") + fname.get();
265 }
266
267 // Write magic string to archive.
268 ArchiveFile << ARFILE_MAGIC;
269
270 // Write the symbol table and string pool
271 writeSymbolTable(ArchiveFile);
272
273 //Loop over all member files, and add to the archive.
274 for ( unsigned i = 0; i < members.size(); ++i) {
275 if(ArchiveFile.tellp() % 2 != 0)
276 ArchiveFile << ARFILE_PAD;
277 writeMember(members[i],ArchiveFile);
278 }
279
280 //Close archive file.
281 ArchiveFile.close();
282}
283
284// vim: sw=2 ai