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