Make sure to print a stack trace whenever an error signal is delivered to the
[oota-llvm.git] / tools / llvm-ar / llvm-ar.cpp
1 //===-- 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 "llvm/Module.h"
15 #include "llvm/Bytecode/Reader.h"
16 #include "Support/CommandLine.h"
17 #include "Support/FileUtilities.h"
18 #include "Support/Signals.h"
19 #include <string>
20 #include <fstream>
21 #include <cstdio>
22 #include <sys/stat.h>
23 #include <sys/types.h> 
24 #include <fcntl.h>
25 #include <unistd.h>
26 #include <sys/mman.h>
27 using namespace llvm;
28
29 using std::string;
30
31
32 #define  ARFMAG    "\n"      /* header trailer string */ 
33 #define  ARMAG   "!<arch>\n"  /* magic string */ 
34 #define  SARMAG  8            /* length of magic string */ 
35 #define VERSION "llvm-ar is a part of the LLVM compiler infrastructure.\nPlease see http://llvm.cs.uiuc.edu for more information.\n";
36
37
38 // Each file member is preceded by a file member header. Which is
39 // of the following format:
40 //
41 // char ar_name[16]  - '/' terminated file member name. 
42 //                     If the file name does not fit, a dummy name is used.
43 // char ar_date[12]  - file date in decimal
44 // char ar_uid[6]    - User id of file owner in decimal.
45 // char ar_gid[6]    - Group ID file belongs to in decimal.
46 // char ar_mode[8]   - File mode in octal.
47 // char ar_size[10]  - Size of file in decimal.
48 // char ar_fmag[2]   - Trailer of header file, a newline.
49 struct ar_hdr {
50   char name[16];
51   char date[12];
52   char uid[6];
53   char gid[6];
54   char mode[8];
55   char size[10];
56   char fmag[2]; 
57   void init() {
58     memset(name,' ',16);
59     memset(date,' ',12);
60     memset(uid,' ',6);
61     memset(gid,' ',6);
62     memset(mode,' ',8);
63     memset(size,' ',10);
64     memset(fmag,' ',2);
65     }
66 };
67
68
69 //Option for X32_64, not used but must allow it to be present.
70 cl::opt<bool> X32Option ("X32_64", cl::desc("Ignored option spelt -X32_64, for compatibility with AIX"), cl::Optional);
71
72 //llvm-ar options
73 cl::opt<string> Options(cl::Positional, cl::desc("{dmpqrstx}[abcfilNoPsSuvV] "), cl::Required);
74
75 //llvm-ar options
76 cl::list<string> RestofArgs(cl::Positional, cl::desc("[relpos] [count]] <archive-file> [members..]"), cl::Optional);
77
78 //booleans to represent Operation, only one can be preformed at a time
79 bool Print, Delete, Move, QuickAppend, InsertWithReplacement, DisplayTable;
80 bool Extract;
81
82 //Modifiers to follow operation to vary behavior
83 bool AddAfter, AddBefore, Create, TruncateNames, InsertBefore, UseCount;
84 bool OriginalDates,  FullPath, SymTable, OnlyUpdate, Verbose;
85
86 //Realtive Pos Arg
87 string RelPos;
88
89 //Count, use for multiple entries in the archive with the same name
90 int Count;
91
92 //Archive
93 string Archive;
94
95 //Member Files
96 std::vector<string> Members;
97
98
99 // WriteSymbolTable - Writes symbol table to ArchiveFile, return false
100 // on errors. Also returns by reference size of symbol table.
101 //
102 // Overview of method:
103 // 1) Generate the header for the symbol table. This is a normal
104 //    archive member header, but it has a zero length name.
105 // 2) For each archive member file, stat the file and parse the bytecode
106 //    Store cumulative offset (file size + header size).
107 // 3) Loop over all the symbols for the current member file, 
108 //    add offset entry to offset vector, and add symbol name to its vector.
109 //    Note: The symbol name vector is a vector of chars to speed up calculating
110 //    the total size of the symbol table.
111 // 4) Update offset vector once we know the total size of symbol table. This is
112 //    because the symbol table appears before all archive member file contents.
113 //    We add the size of magic string, and size of symbol table to each offset.
114 // 5) If the new updated offset it not even, we add 1 byte to offset because
115 //    a newline will be inserted when writing member files. This adjustment is
116 //    cummulative (ie. each time we have an odd offset we add 1 to total adjustment).
117 // 6) Lastly, write symbol table to file.
118 //
119 bool WriteSymbolTable(std::ofstream &ArchiveFile) {
120  
121   //Create header for symbol table. This is essentially an empty header with the
122   //name set to a '/' to indicate its a symbol table.
123   ar_hdr Hdr;
124   Hdr.init();
125
126   //Name of symbol table is '/'
127   Hdr.name[0] = '/';
128   Hdr.name[1] = '\0';
129   
130   //Set the header trailer to a newline
131   memcpy(Hdr.fmag,ARFMAG,sizeof(ARFMAG));
132
133   
134   //Write header to archive file
135   ArchiveFile.write((char*)&Hdr, sizeof(Hdr));
136   
137
138   unsigned memoff = 0;  //Keep Track of total size of files added to archive
139   std::vector<unsigned> offsets; //Vector of offsets into archive file
140   std::vector<char> names; //Vector of characters that are the symbol names. 
141
142   //Loop over archive member files, parse bytecode, and generate symbol table.
143   for(unsigned i=0; i<Members.size(); ++i) { 
144     
145     //Open Member file for reading and copy to buffer
146     int FD = open(Members[i].c_str(),O_RDONLY);
147     
148     //Check for errors opening the file.
149     if (FD == -1) {
150       std::cerr << "Error opening file!\n";
151       return false;
152     }
153
154     // Size of file
155     unsigned Length = getFileSize(Members[i]);
156     if (Length == (unsigned)-1) {
157       std::cerr << "Error stating file\n";
158       return false;
159     }
160     
161     //Read in file into a buffer.
162     unsigned char *buf = (unsigned char*)mmap(0, Length,PROT_READ,
163                                               MAP_PRIVATE, FD, 0);
164   
165     //Check if mmap failed.
166     if (buf == (unsigned char*)MAP_FAILED) {
167       std::cerr << "Error mmapping file!\n";
168       return false;
169     }
170     
171     //Parse the bytecode file and get all the symbols.
172     string ErrorStr;
173     Module *M = ParseBytecodeBuffer(buf,Length,Members[i],&ErrorStr);
174     
175     //Check for errors parsing bytecode.
176     //if(ErrorStr) {
177     //std::cerr << "Error Parsing Bytecode\n";
178     //return false;
179     //}
180
181     //Loop over function names and global vars and add to symbol maps
182     for(Module::iterator I = M->begin(), E=M->end(); I != E; ++I) {
183       
184       //get function name
185       string NM = ((Function*)I)->getName();
186             
187       //Loop over the characters in the name and add to symbol name vector
188       for(unsigned i=0; i<NM.size(); ++i)
189         names.push_back(NM[i]);
190
191       //Each symbol is null terminated.
192       names.push_back('\0');
193
194       //Add offset to vector of offsets
195       offsets.push_back(memoff);
196     }
197
198     memoff += Length + sizeof(Hdr);
199   }
200
201   //Determine how large our symbol table is.
202   unsigned symbolTableSize = sizeof(Hdr) + 4 + 4*(offsets.size()) + names.size();
203   std::cout << "Symbol Table Size: " << symbolTableSize << "\n";
204
205   //Number of symbols should be in network byte order as well
206   char num[4];
207   unsigned temp = offsets.size();
208   num[0] = (temp >> 24) & 255;
209   num[1] = (temp >> 16) & 255;
210   num[2] = (temp >> 8) & 255;
211   num[3] = temp & 255;
212
213   //Write number of symbols to archive file
214   ArchiveFile.write(num,4);
215
216   //Adjustment to offset to start files on even byte boundaries
217   unsigned adjust = 0;
218   
219   //Update offsets write symbol table to archive.
220   for(unsigned i=0; i<offsets.size(); ++i) {
221     char output[4];
222     offsets[i] = offsets[i] + symbolTableSize + SARMAG;
223     offsets[i] += adjust;
224     if((offsets[i] % 2 != 0)) {
225       adjust++;
226       offsets[i] += adjust;
227     }
228     
229     std::cout << "Offset: " << offsets[i] << "\n";
230     output[0] = (offsets[i] >> 24) & 255;
231     output[1] = (offsets[i] >> 16) & 255;
232     output[2] = (offsets[i] >> 8) & 255;
233     output[3] = offsets[i] & 255;
234     ArchiveFile.write(output,4);
235   }
236
237
238   //Write out symbol name vector.
239   for(unsigned i=0; i<names.size(); ++i)
240     ArchiveFile << names[i];
241
242   return true;
243 }
244
245 // AddMemberToArchive - Writes member file to archive. Returns false on errors.
246 // 
247 // Overview of method: 
248 // 1) Open file, and stat it.  
249 // 2) Fill out header using stat information. If name is longer then 15 
250 //    characters, use "dummy" name.
251 // 3) Write header and file contents to disk.
252 // 4) Keep track of total offset into file, and insert a newline if it is odd.
253 //
254 bool AddMemberToArchive(string Member, std::ofstream &ArchiveFile) {
255
256   std::cout << "Member File Start: " << ArchiveFile.tellp() << "\n";
257
258   ar_hdr Hdr; //Header for archive member file.
259
260   //stat the file to get info
261   struct stat StatBuf;
262   if (stat(Member.c_str(), &StatBuf) == -1 || StatBuf.st_size == 0)
263     return false;
264
265   //fill in header
266   
267   //set name to white spaces
268   memset(Hdr.name,' ', sizeof(Hdr.name));
269
270   //check the size of the name, if less than 15, we can copy it directly
271   //otherwise we give it a dummy name for now
272   if(Member.length() < 16)
273     memcpy(Hdr.name,Member.c_str(),Member.length());
274   else
275     memcpy(Hdr.name, "Dummy", 5);
276
277   //terminate name with forward slash
278   Hdr.name[15] = '/';
279
280   //file member size in decimal
281   unsigned Length = StatBuf.st_size;
282   sprintf(Hdr.size,"%d", Length);
283   std::cout << "Size: " << Length << "\n";
284
285   //file member user id in decimal
286   sprintf(Hdr.uid, "%d", StatBuf.st_uid);
287
288   //file member group id in decimal
289   sprintf(Hdr.gid, "%d", StatBuf.st_gid);
290
291   //file member date in decimal
292   sprintf(Hdr.date,"%d", (int)StatBuf.st_mtime);
293   
294   //file member mode in OCTAL
295   sprintf(Hdr.mode,"%d", StatBuf.st_mode);
296  
297   //add our header trailer
298   memcpy(Hdr.fmag,ARFMAG,sizeof(ARFMAG));
299
300   //write header to archive file
301   ArchiveFile.write((char*)&Hdr, sizeof(Hdr));
302   
303   //open Member file for reading and copy to buffer
304   int FD = open(Member.c_str(),O_RDONLY);
305   if (FD == -1) {
306     std::cerr << "Error opening file!\n";
307     return false;
308   }
309
310   unsigned char *buf = (unsigned char*)mmap(0, Length,PROT_READ,
311                           MAP_PRIVATE, FD, 0);
312   
313   //check if mmap failed
314   if (buf == (unsigned char*)MAP_FAILED) {
315     std::cerr << "Error mmapping file!\n";
316     return false;
317   }
318
319   //write to archive file
320   ArchiveFile.write((char*)buf,Length);
321   
322   // Unmmap the memberfile
323   munmap((char*)buf, Length);
324   
325   std::cout << "Member File End: " << ArchiveFile.tellp() << "\n";
326
327   return true;
328 }
329
330
331 // CreateArchive - Generates archive with or without symbol table.
332 //
333 void CreateArchive() {
334   
335   std::cerr << "Archive File: " << Archive << "\n";
336
337   //Create archive file for output.
338   std::ofstream ArchiveFile(Archive.c_str());
339   
340   //Check for errors opening or creating archive file.
341   if(!ArchiveFile.is_open() || ArchiveFile.bad() ) {
342     std::cerr << "Error opening Archive File\n";
343     exit(1);
344   }
345
346   //Write magic string to archive.
347   ArchiveFile << ARMAG;
348
349   //If the '-s' option was specified, generate symbol table.
350   if(SymTable) {
351     std::cout << "Symbol Table Start: " << ArchiveFile.tellp() << "\n";
352     if(!WriteSymbolTable(ArchiveFile)) {
353       std::cerr << "Error creating symbol table. Exiting program.";
354       exit(1);
355     }
356     std::cout << "Symbol Table End: " << ArchiveFile.tellp() << "\n";
357   }
358   //Loop over all member files, and add to the archive.
359   for(unsigned i=0; i < Members.size(); ++i) {
360     if(ArchiveFile.tellp() % 2 != 0)
361       ArchiveFile << ARFMAG;
362     if(AddMemberToArchive(Members[i],ArchiveFile) != true) {
363       std::cerr << "Error adding " << Members[i] << "to archive. Exiting program.\n";
364       exit(1);
365     }
366   }
367   
368   //Close archive file.
369   ArchiveFile.close();
370 }
371
372 //Print out usage for errors in command line
373 void printUse() {
374   std::cout << "USAGE: ar [-X32_64] [-]{dmpqrstx}[abcfilNoPsSuvV] [member-name] [count] archive-file [files..]\n\n";
375
376   std::cout << "commands:\n" <<
377     "d            - delete file(s) from the archive\n"
378   << "m[ab]        - move file(s) in the archive\n"
379   << "p            - print file(s) found in the archive\n"
380   << "q[f]         - quick append file(s) to the archive\n"
381   << "r[ab][f][u]  - replace existing or insert new file(s) into the archive\n"
382   << "t            - display contents of archive\n"
383   << "x[o]         - extract file(s) from the archive\n";
384
385   std::cout << "\ncommand specific modifiers:\n"
386             << "[a]          - put file(s) after [member-name]\n"
387             << "[b]          - put file(s) before [member-name] (same as [i])\n"
388             << "[N]          - use instance [count] of name\n"
389             << "[f]          - truncate inserted file names\n"
390             << "[P]          - use full path names when matching\n"
391             << "[o]          - preserve original dates\n"
392             << "[u]          - only replace files that are newer than current archive contents\n";
393
394   std::cout << "generic modifiers:\n"
395             << "[c]          - do not warn if the library had to be created\n"
396             << "[s]          - create an archive index (cf. ranlib)\n"
397             << "[S]          - do not build a symbol table\n"
398             << "[v]          - be verbose\n"
399             << "[V]          - display the version number\n";
400   exit(1);
401 }
402
403
404 //Print version
405 void printVersion() {
406   std::cout << VERSION;
407   exit(0);
408 }
409
410 //Extract the memberfile name from the command line
411 void getRelPos() {
412   if(RestofArgs.size() > 0) {
413     RelPos = RestofArgs[0];
414     RestofArgs.erase(RestofArgs.begin());
415   }
416   //Throw error if needed and not present
417   else
418     printUse();
419 }
420
421 //Extract count from the command line
422 void getCount() {
423   if(RestofArgs.size() > 0) {
424     Count = atoi(RestofArgs[0].c_str());
425     RestofArgs.erase(RestofArgs.begin());
426   }
427   //Throw error if needed and not present
428   else
429     printUse();
430 }
431
432 //Get the Archive File Name from the command line
433 void getArchive() {
434   std::cerr << RestofArgs.size() << "\n";
435   if(RestofArgs.size() > 0) {
436     Archive = RestofArgs[0];
437     RestofArgs.erase(RestofArgs.begin());
438   }
439   //Throw error if needed and not present
440   else
441     printUse();
442 }
443
444
445 //Copy over remaining items in RestofArgs to our Member File vector.
446 //This is just for clarity.
447 void getMembers() {
448   std::cerr << RestofArgs.size() << "\n";
449   if(RestofArgs.size() > 0)
450     Members = std::vector<string>(RestofArgs); 
451 }
452
453 // Parse the operations and operation modifiers
454 // FIXME: Not all of these options has been implemented, but we still
455 // do all the command line parsing for them.
456 void parseCL() {
457
458   //Keep track of number of operations. We can only specify one
459   //per execution
460   unsigned NumOperations = 0;
461
462   for(unsigned i=0; i<Options.size(); ++i) {
463     switch(Options[i]) {
464     case 'd':
465       ++NumOperations;
466       Delete = true;
467       break;
468     case 'm':
469       ++NumOperations;
470       Move = true;
471       break;
472     case 'p':
473       ++NumOperations;
474       Print = true;
475       break;
476     case 'r':
477       ++NumOperations;
478       InsertWithReplacement = true;
479       break;
480     case 't':
481       ++NumOperations;
482       DisplayTable = true;
483       break;
484     case 'x':
485       ++NumOperations;
486       Extract = true;
487       break;
488     case 'a':
489       AddAfter = true;
490       getRelPos();
491       break;
492     case 'b':
493       AddBefore = true;
494       getRelPos();
495       break;
496     case 'c':
497       Create = true;
498       break;
499     case 'f':
500       TruncateNames = true;
501       break;
502     case 'i':
503       InsertBefore = true;
504       getRelPos();
505       break;
506     case 'l':
507       break;
508     case 'N':
509       UseCount = true;
510       getCount();
511       break;
512     case 'o':
513       OriginalDates = true;
514       break;
515     case 'P':
516       FullPath = true;
517       break;
518     case 's':
519       SymTable = true;
520       break;
521     case 'S':
522       SymTable = false;
523       break;
524     case 'u':
525       OnlyUpdate = true;
526       break;
527     case 'v':
528       Verbose = true;
529       break;
530     case 'V':
531       printVersion();
532       break;
533     default:
534       printUse();
535     }
536   }
537
538   //Check that only one operation has been specified
539   if(NumOperations > 1)
540     printUse();
541
542   getArchive();
543   getMembers();
544
545 }
546
547 int main(int argc, char **argv) {
548   cl::ParseCommandLineOptions(argc, argv);
549   PrintStackTraceOnErrorSignal();
550
551   parseCL();
552
553   //Create archive!
554   if(Create)
555     CreateArchive();
556
557   return 0;
558 }
559