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