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