Removed extraneous comment line.
[oota-llvm.git] / tools / llvm-ar / llvm-ar.cpp
1 //===-- tools/llvm-ar/llvm-ar.cpp - LLVM archive librarian utility --------===//
2 // 
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file was developed by the LLVM research group and is distributed under
6 // the 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 "Support/CommandLine.h"
15 #include "llvm/Bytecode/Reader.h"
16 #include "llvm/Module.h"
17 #include <string>
18 #include <iostream>
19 #include <fstream>
20 #include <vector>
21 #include <sys/stat.h>
22 #include <cstdio>
23 #include <sys/types.h> 
24 #include <fcntl.h>
25 #include <unistd.h>
26 #include <sys/mman.h>
27
28 using std::string;
29 using std::vector;
30 using std::cout;
31
32
33 #define  ARFMAG    "\n"      /* header trailer string */ 
34 #define  ARMAG   "!<arch>\n"  /* magic string */ 
35 #define  SARMAG  8            /* length of magic string */ 
36
37 namespace {
38
39   // Each file member is preceded by a file member header. Which is
40   // of the following format:
41   //
42   // char ar_name[16]  - '/' terminated file member name. 
43   //                     If the file name does not fit, a dummy name is used.
44   // char ar_date[12]  - file date in decimal
45   // char ar_uid[6]    - User id of file owner in decimal.
46   // char ar_gid[6]    - Group ID file belongs to in decimal.
47   // char ar_mode[8]   - File mode in octal.
48   // char ar_size[10]  - Size of file in decimal.
49   // char ar_fmag[2]   - Trailer of header file, a newline.
50   struct ar_hdr {
51     char name[16];
52     char date[12];
53     char uid[6];
54     char gid[6];
55     char mode[8];
56     char size[10];
57     char fmag[2]; 
58     void init() {
59       memset(name,' ',16);
60       memset(date,' ',12);
61       memset(uid,' ',6);
62       memset(gid,' ',6);
63       memset(mode,' ',8);
64       memset(size,' ',10);
65       memset(fmag,' ',2);
66     }
67   };
68 }
69
70 //Option to generate symbol table or not
71 //running llvm-ar -s is the same as ranlib
72 cl::opt<bool> SymbolTable ("s", cl::desc("Generate an archive symbol table"));
73
74 //Archive name
75 cl::opt<string> Archive (cl::Positional, cl::desc("<archive file>"), 
76                          cl::Required);
77
78 //For now we require one or more member files, this should change so
79 //we can just run llvm-ar -s on an archive to generate the symbol
80 //table
81 cl::list<string> Members(cl::ConsumeAfter, cl::desc("<archive members>..."));
82
83
84 static inline bool Error(std::string *ErrorStr, const char *Message) {
85   if (ErrorStr) *ErrorStr = Message;
86   return true;
87 }
88
89
90 // WriteSymbolTable - Writes symbol table to ArchiveFile, return false
91 // on errors. Also returns by reference size of symbol table.
92 //
93 // Overview of method:
94 // 1) Generate the header for the symbol table. This is a normal
95 //    archive member header, but it has a zero length name.
96 // 2) For each archive member file, stat the file and parse the bytecode
97 //    Store cumulative offset (file size + header size).
98 // 3) Loop over all the symbols for the current member file, 
99 //    add offset entry to offset vector, and add symbol name to its vector.
100 //    Note: The symbol name vector is a vector of chars to speed up calculating
101 //    the total size of the symbol table.
102 // 4) Update offset vector once we know the total size of symbol table. This is
103 //    because the symbol table appears before all archive member file contents.
104 //    We add the size of magic string, and size of symbol table to each offset.
105 // 5) If the new updated offset it not even, we add 1 byte to offset because
106 //    a newline will be inserted when writing member files. This adjustment is
107 //    cummulative (ie. each time we have an odd offset we add 1 to total adjustment).
108 // 6) Lastly, write symbol table to file.
109 //
110 bool WriteSymbolTable(std::ofstream &ArchiveFile) {
111  
112   //Create header for symbol table. This is essentially an empty header with the
113   //name set to a '/' to indicate its a symbol table.
114   ar_hdr Hdr;
115   Hdr.init();
116
117   //Name of symbol table is '/'
118   Hdr.name[0] = '/';
119   Hdr.name[1] = '\0';
120   
121   //Set the header trailer to a newline
122   memcpy(Hdr.fmag,ARFMAG,sizeof(ARFMAG));
123
124   
125   //Write header to archive file
126   ArchiveFile.write((char*)&Hdr, sizeof(Hdr));
127   
128
129   unsigned memoff = 0;  //Keep Track of total size of files added to archive
130   vector<unsigned> offsets; //Vector of offsets into archive file
131   vector<char> names; //Vector of characters that are the symbol names. 
132
133   //Loop over archive member files, parse bytecode, and generate symbol table.
134   for(unsigned i=0; i<Members.size(); ++i) { 
135     
136     //Open Member file for reading and copy to buffer
137     int FD = open(Members[i].c_str(),O_RDONLY);
138     
139     //Check for errors opening the file.
140     if (FD == -1) {
141       std::cerr << "Error opening file!\n";
142       return false;
143     }
144
145     //Stat the file to get its size.
146     struct stat StatBuf;
147     if (stat(Members[i].c_str(), &StatBuf) == -1 || StatBuf.st_size == 0) {
148       std::cerr << "Error stating file\n";
149       return false;
150     }
151
152     //Size of file
153     unsigned Length = StatBuf.st_size;
154     
155     //Read in file into a buffer.
156     unsigned char *buf = (unsigned char*)mmap(0, Length,PROT_READ,
157                                               MAP_PRIVATE, FD, 0);
158   
159     //Check if mmap failed.
160     if (buf == (unsigned char*)MAP_FAILED) {
161       std::cerr << "Error mmapping file!\n";
162       return false;
163     }
164     
165     //Parse the bytecode file and get all the symbols.
166     string ErrorStr;
167     Module *M = ParseBytecodeBuffer(buf,Length,Members[i],&ErrorStr);
168     
169     //Check for errors parsing bytecode.
170     //if(ErrorStr) {
171     //std::cerr << "Error Parsing Bytecode\n";
172     //return false;
173     //}
174
175     //Loop over function names and global vars and add to symbol maps
176     for(Module::iterator I = M->begin(), E=M->end(); I != E; ++I) {
177       
178       //get function name
179       string NM = ((Function*)I)->getName();
180             
181       //Loop over the characters in the name and add to symbol name vector
182       for(unsigned i=0; i<NM.size(); ++i)
183         names.push_back(NM[i]);
184
185       //Each symbol is null terminated.
186       names.push_back('\0');
187
188       //Add offset to vector of offsets
189       offsets.push_back(memoff);
190     }
191
192     memoff += Length + sizeof(Hdr);
193   }
194
195   //Determine how large our symbol table is.
196   unsigned symbolTableSize = sizeof(Hdr) + 4 + 4*(offsets.size()) + names.size();
197   cout << "Symbol Table Size: " << symbolTableSize << "\n";
198
199   //Number of symbols should be in network byte order as well
200   char num[4];
201   unsigned temp = offsets.size();
202   num[0] = (temp >> 24) & 255;
203   num[1] = (temp >> 16) & 255;
204   num[2] = (temp >> 8) & 255;
205   num[3] = temp & 255;
206
207   //Write number of symbols to archive file
208   ArchiveFile.write(num,4);
209
210   //Adjustment to offset to start files on even byte boundaries
211   unsigned adjust = 0;
212   
213   //Update offsets write symbol table to archive.
214   for(unsigned i=0; i<offsets.size(); ++i) {
215     char output[4];
216     offsets[i] = offsets[i] + symbolTableSize + SARMAG;
217     offsets[i] += adjust;
218     if((offsets[i] % 2 != 0)) {
219       adjust++;
220       offsets[i] += adjust;
221     }
222     
223     cout << "Offset: " << offsets[i] << "\n";
224     output[0] = (offsets[i] >> 24) & 255;
225     output[1] = (offsets[i] >> 16) & 255;
226     output[2] = (offsets[i] >> 8) & 255;
227     output[3] = offsets[i] & 255;
228     ArchiveFile.write(output,4);
229   }
230
231
232   //Write out symbol name vector.
233   for(unsigned i=0; i<names.size(); ++i)
234     ArchiveFile << names[i];
235
236   return true;
237 }
238
239 // AddMemberToArchive - Writes member file to archive. Returns false on errors.
240 // 
241 // Overview of method: 
242 // 1) Open file, and stat it.  
243 // 2) Fill out header using stat information. If name is longer then 15 
244 //    characters, use "dummy" name.
245 // 3) Write header and file contents to disk.
246 // 4) Keep track of total offset into file, and insert a newline if it is odd.
247 //
248 bool AddMemberToArchive(string Member, std::ofstream &ArchiveFile) {
249   
250   ar_hdr Hdr; //Header for archive member file.
251   
252   //stat the file to get info
253   struct stat StatBuf;
254   if (stat(Member.c_str(), &StatBuf) == -1 || StatBuf.st_size == 0)
255     cout << "ERROR\n";
256
257   //fill in header
258   
259   //set name to white spaces
260   memset(Hdr.name,' ', sizeof(Hdr.name));
261
262   //check the size of the name, if less than 15, we can copy it directly
263   //otherwise we give it a dummy name for now
264   if(Member.length() < 16)
265     memcpy(Hdr.name,Member.c_str(),Member.length());
266   else
267     memcpy(Hdr.name, "Dummy", 5);
268
269   //terminate name with forward slash
270   Hdr.name[15] = '/';
271
272   //file member size in decimal
273   unsigned Length = StatBuf.st_size;
274   sprintf(Hdr.size,"%d", Length);
275   cout << "Size: " << Length << "\n";
276
277   //file member user id in decimal
278   sprintf(Hdr.uid, "%d", StatBuf.st_uid);
279
280   //file member group id in decimal
281   sprintf(Hdr.gid, "%d", StatBuf.st_gid);
282
283   //file member date in decimal
284   sprintf(Hdr.date,"%d", (int)StatBuf.st_mtime);
285   
286   //file member mode in OCTAL
287   sprintf(Hdr.mode,"%d", StatBuf.st_mode);
288  
289   //add our header trailer
290   memcpy(Hdr.fmag,ARFMAG,sizeof(ARFMAG));
291
292   //write header to archive file
293   ArchiveFile.write((char*)&Hdr, sizeof(Hdr));
294   
295   //open Member file for reading and copy to buffer
296   int FD = open(Member.c_str(),O_RDONLY);
297   if (FD == -1) {
298     std::cerr << "Error opening file!\n";
299     return false;
300   }
301
302   unsigned char *buf = (unsigned char*)mmap(0, Length,PROT_READ,
303                           MAP_PRIVATE, FD, 0);
304   
305   //check if mmap failed
306   if (buf == (unsigned char*)MAP_FAILED) {
307     std::cerr << "Error mmapping file!\n";
308     return false;
309   }
310
311   //write to archive file
312   ArchiveFile.write((char*)buf,Length);
313     
314   // Unmmap the memberfile
315   munmap((char*)buf, Length);
316
317   return true;
318 }
319
320
321 // CreateArchive - Generates archive with or without symbol table.
322 //
323 void CreateArchive() {
324   
325   //Create archive file for output.
326   std::ofstream ArchiveFile(Archive.c_str());
327   
328   //Check for errors opening or creating archive file.
329   if(!ArchiveFile.is_open() || ArchiveFile.bad() ) {
330     std::cerr << "Error opening Archive File\n";
331     exit(1);
332   }
333
334   //Write magic string to archive.
335   ArchiveFile << ARMAG;
336
337   //If the '-s' option was specified, generate symbol table.
338   if(SymbolTable) {
339     cout << "Symbol Table Start: " << ArchiveFile.tellp() << "\n";
340     if(!WriteSymbolTable(ArchiveFile)) {
341       std::cerr << "Error creating symbol table. Exiting program.";
342       exit(1);
343     }
344     cout << "Symbol Table End: " << ArchiveFile.tellp() << "\n";
345   }
346   //Loop over all member files, and add to the archive.
347   for(unsigned i=0; i<Members.size(); ++i) {
348     if(ArchiveFile.tellp() % 2 != 0)
349       ArchiveFile << ARFMAG;
350
351     cout << "Member File Start: " << ArchiveFile.tellp() << "\n";
352
353     if(AddMemberToArchive(Members[i],ArchiveFile) != true) {
354       std::cerr << "Error adding file to archive. Exiting program.";
355       exit(1);
356     }
357     cout << "Member File End: " << ArchiveFile.tellp() << "\n";
358   }
359   
360   //Close archive file.
361   ArchiveFile.close();
362 }
363
364
365 int main(int argc, char **argv) {
366
367   //Parse Command line options
368   cl::ParseCommandLineOptions(argc, argv, " llvm-ar\n");
369
370   //Create archive!
371   CreateArchive();
372
373   return 0;
374 }