llvm-ar.cpp revision af02bf4a581dc9548ba3160b9d654a4893a12491
1//===-- llvm-ar.cpp - LLVM archive librarian utility ----------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// Builds up (relatively) standard unix archive files (.a) containing LLVM 11// bitcode or other files. 12// 13//===----------------------------------------------------------------------===// 14 15#include "llvm/IR/LLVMContext.h" 16#include "llvm/IR/Module.h" 17#include "llvm/Object/Archive.h" 18#include "llvm/Object/ObjectFile.h" 19#include "llvm/Support/CommandLine.h" 20#include "llvm/Support/FileSystem.h" 21#include "llvm/Support/Format.h" 22#include "llvm/Support/ManagedStatic.h" 23#include "llvm/Support/MemoryBuffer.h" 24#include "llvm/Support/PrettyStackTrace.h" 25#include "llvm/Support/Signals.h" 26#include "llvm/Support/ToolOutputFile.h" 27#include "llvm/Support/raw_ostream.h" 28#include <algorithm> 29#include <cstdlib> 30#include <memory> 31 32#if !defined(_MSC_VER) && !defined(__MINGW32__) 33#include <unistd.h> 34#else 35#include <io.h> 36#endif 37 38using namespace llvm; 39 40// The name this program was invoked as. 41static StringRef ToolName; 42 43static const char *TemporaryOutput; 44static int TmpArchiveFD = -1; 45 46// fail - Show the error message and exit. 47LLVM_ATTRIBUTE_NORETURN static void fail(Twine Error) { 48 outs() << ToolName << ": " << Error << ".\n"; 49 if (TmpArchiveFD != -1) 50 close(TmpArchiveFD); 51 if (TemporaryOutput) 52 sys::fs::remove(TemporaryOutput); 53 exit(1); 54} 55 56static void failIfError(error_code EC, Twine Context = "") { 57 if (!EC) 58 return; 59 60 std::string ContextStr = Context.str(); 61 if (ContextStr == "") 62 fail(EC.message()); 63 fail(Context + ": " + EC.message()); 64} 65 66// Option for compatibility with AIX, not used but must allow it to be present. 67static cl::opt<bool> 68X32Option ("X32_64", cl::Hidden, 69 cl::desc("Ignored option for compatibility with AIX")); 70 71// llvm-ar operation code and modifier flags. This must come first. 72static cl::opt<std::string> 73Options(cl::Positional, cl::Required, cl::desc("{operation}[modifiers]...")); 74 75// llvm-ar remaining positional arguments. 76static cl::list<std::string> 77RestOfArgs(cl::Positional, cl::OneOrMore, 78 cl::desc("[relpos] [count] <archive-file> [members]...")); 79 80// MoreHelp - Provide additional help output explaining the operations and 81// modifiers of llvm-ar. This object instructs the CommandLine library 82// to print the text of the constructor when the --help option is given. 83static cl::extrahelp MoreHelp( 84 "\nOPERATIONS:\n" 85 " d[NsS] - delete file(s) from the archive\n" 86 " m[abiSs] - move file(s) in the archive\n" 87 " p[kN] - print file(s) found in the archive\n" 88 " q[ufsS] - quick append file(s) to the archive\n" 89 " r[abfiuRsS] - replace or insert file(s) into the archive\n" 90 " t - display contents of archive\n" 91 " x[No] - extract file(s) from the archive\n" 92 "\nMODIFIERS (operation specific):\n" 93 " [a] - put file(s) after [relpos]\n" 94 " [b] - put file(s) before [relpos] (same as [i])\n" 95 " [i] - put file(s) before [relpos] (same as [b])\n" 96 " [N] - use instance [count] of name\n" 97 " [o] - preserve original dates\n" 98 " [s] - create an archive index (cf. ranlib)\n" 99 " [S] - do not build a symbol table\n" 100 " [u] - update only files newer than archive contents\n" 101 "\nMODIFIERS (generic):\n" 102 " [c] - do not warn if the library had to be created\n" 103 " [v] - be verbose about actions taken\n" 104); 105 106// This enumeration delineates the kinds of operations on an archive 107// that are permitted. 108enum ArchiveOperation { 109 Print, ///< Print the contents of the archive 110 Delete, ///< Delete the specified members 111 Move, ///< Move members to end or as given by {a,b,i} modifiers 112 QuickAppend, ///< Quickly append to end of archive 113 ReplaceOrInsert, ///< Replace or Insert members 114 DisplayTable, ///< Display the table of contents 115 Extract ///< Extract files back to file system 116}; 117 118// Modifiers to follow operation to vary behavior 119static bool AddAfter = false; ///< 'a' modifier 120static bool AddBefore = false; ///< 'b' modifier 121static bool Create = false; ///< 'c' modifier 122static bool OriginalDates = false; ///< 'o' modifier 123static bool OnlyUpdate = false; ///< 'u' modifier 124static bool Verbose = false; ///< 'v' modifier 125static bool Symtab = true; ///< 's' modifier 126 127// Relative Positional Argument (for insert/move). This variable holds 128// the name of the archive member to which the 'a', 'b' or 'i' modifier 129// refers. Only one of 'a', 'b' or 'i' can be specified so we only need 130// one variable. 131static std::string RelPos; 132 133// This variable holds the name of the archive file as given on the 134// command line. 135static std::string ArchiveName; 136 137// This variable holds the list of member files to proecess, as given 138// on the command line. 139static std::vector<std::string> Members; 140 141// show_help - Show the error message, the help message and exit. 142LLVM_ATTRIBUTE_NORETURN static void 143show_help(const std::string &msg) { 144 errs() << ToolName << ": " << msg << "\n\n"; 145 cl::PrintHelpMessage(); 146 std::exit(1); 147} 148 149// getRelPos - Extract the member filename from the command line for 150// the [relpos] argument associated with a, b, and i modifiers 151static void getRelPos() { 152 if(RestOfArgs.size() == 0) 153 show_help("Expected [relpos] for a, b, or i modifier"); 154 RelPos = RestOfArgs[0]; 155 RestOfArgs.erase(RestOfArgs.begin()); 156} 157 158// getArchive - Get the archive file name from the command line 159static void getArchive() { 160 if(RestOfArgs.size() == 0) 161 show_help("An archive name must be specified"); 162 ArchiveName = RestOfArgs[0]; 163 RestOfArgs.erase(RestOfArgs.begin()); 164} 165 166// getMembers - Copy over remaining items in RestOfArgs to our Members vector 167// This is just for clarity. 168static void getMembers() { 169 if(RestOfArgs.size() > 0) 170 Members = std::vector<std::string>(RestOfArgs); 171} 172 173// parseCommandLine - Parse the command line options as presented and return the 174// operation specified. Process all modifiers and check to make sure that 175// constraints on modifier/operation pairs have not been violated. 176static ArchiveOperation parseCommandLine() { 177 178 // Keep track of number of operations. We can only specify one 179 // per execution. 180 unsigned NumOperations = 0; 181 182 // Keep track of the number of positional modifiers (a,b,i). Only 183 // one can be specified. 184 unsigned NumPositional = 0; 185 186 // Keep track of which operation was requested 187 ArchiveOperation Operation; 188 189 for(unsigned i=0; i<Options.size(); ++i) { 190 switch(Options[i]) { 191 case 'd': ++NumOperations; Operation = Delete; break; 192 case 'm': ++NumOperations; Operation = Move ; break; 193 case 'p': ++NumOperations; Operation = Print; break; 194 case 'q': ++NumOperations; Operation = QuickAppend; break; 195 case 'r': ++NumOperations; Operation = ReplaceOrInsert; break; 196 case 't': ++NumOperations; Operation = DisplayTable; break; 197 case 'x': ++NumOperations; Operation = Extract; break; 198 case 'c': Create = true; break; 199 case 'l': /* accepted but unused */ break; 200 case 'o': OriginalDates = true; break; 201 case 's': 202 Symtab = true; 203 break; 204 case 'S': 205 Symtab = false; 206 break; 207 case 'u': OnlyUpdate = true; break; 208 case 'v': Verbose = true; break; 209 case 'a': 210 getRelPos(); 211 AddAfter = true; 212 NumPositional++; 213 break; 214 case 'b': 215 getRelPos(); 216 AddBefore = true; 217 NumPositional++; 218 break; 219 case 'i': 220 getRelPos(); 221 AddBefore = true; 222 NumPositional++; 223 break; 224 default: 225 cl::PrintHelpMessage(); 226 } 227 } 228 229 // At this point, the next thing on the command line must be 230 // the archive name. 231 getArchive(); 232 233 // Everything on the command line at this point is a member. 234 getMembers(); 235 236 // Perform various checks on the operation/modifier specification 237 // to make sure we are dealing with a legal request. 238 if (NumOperations == 0) 239 show_help("You must specify at least one of the operations"); 240 if (NumOperations > 1) 241 show_help("Only one operation may be specified"); 242 if (NumPositional > 1) 243 show_help("You may only specify one of a, b, and i modifiers"); 244 if (AddAfter || AddBefore) { 245 if (Operation != Move && Operation != ReplaceOrInsert) 246 show_help("The 'a', 'b' and 'i' modifiers can only be specified with " 247 "the 'm' or 'r' operations"); 248 } 249 if (OriginalDates && Operation != Extract) 250 show_help("The 'o' modifier is only applicable to the 'x' operation"); 251 if (OnlyUpdate && Operation != ReplaceOrInsert) 252 show_help("The 'u' modifier is only applicable to the 'r' operation"); 253 254 // Return the parsed operation to the caller 255 return Operation; 256} 257 258// Implements the 'p' operation. This function traverses the archive 259// looking for members that match the path list. 260static void doPrint(StringRef Name, object::Archive::child_iterator I) { 261 if (Verbose) 262 outs() << "Printing " << Name << "\n"; 263 264 StringRef Data = I->getBuffer(); 265 outs().write(Data.data(), Data.size()); 266} 267 268// putMode - utility function for printing out the file mode when the 't' 269// operation is in verbose mode. 270static void printMode(unsigned mode) { 271 if (mode & 004) 272 outs() << "r"; 273 else 274 outs() << "-"; 275 if (mode & 002) 276 outs() << "w"; 277 else 278 outs() << "-"; 279 if (mode & 001) 280 outs() << "x"; 281 else 282 outs() << "-"; 283} 284 285// Implement the 't' operation. This function prints out just 286// the file names of each of the members. However, if verbose mode is requested 287// ('v' modifier) then the file type, permission mode, user, group, size, and 288// modification time are also printed. 289static void doDisplayTable(StringRef Name, object::Archive::child_iterator I) { 290 if (Verbose) { 291 sys::fs::perms Mode = I->getAccessMode(); 292 printMode((Mode >> 6) & 007); 293 printMode((Mode >> 3) & 007); 294 printMode(Mode & 007); 295 outs() << ' ' << I->getUID(); 296 outs() << '/' << I->getGID(); 297 outs() << ' ' << format("%6llu", I->getSize()); 298 outs() << ' ' << I->getLastModified().str(); 299 outs() << ' '; 300 } 301 outs() << Name << "\n"; 302} 303 304// Implement the 'x' operation. This function extracts files back to the file 305// system. 306static void doExtract(StringRef Name, object::Archive::child_iterator I) { 307 // Retain the original mode. 308 sys::fs::perms Mode = I->getAccessMode(); 309 SmallString<128> Storage = Name; 310 311 int FD; 312 failIfError( 313 sys::fs::openFileForWrite(Storage.c_str(), FD, sys::fs::F_Binary, Mode), 314 Storage.c_str()); 315 316 { 317 raw_fd_ostream file(FD, false); 318 319 // Get the data and its length 320 StringRef Data = I->getBuffer(); 321 322 // Write the data. 323 file.write(Data.data(), Data.size()); 324 } 325 326 // If we're supposed to retain the original modification times, etc. do so 327 // now. 328 if (OriginalDates) 329 failIfError( 330 sys::fs::setLastModificationAndAccessTime(FD, I->getLastModified())); 331 332 if (close(FD)) 333 fail("Could not close the file"); 334} 335 336static bool shouldCreateArchive(ArchiveOperation Op) { 337 switch (Op) { 338 case Print: 339 case Delete: 340 case Move: 341 case DisplayTable: 342 case Extract: 343 return false; 344 345 case QuickAppend: 346 case ReplaceOrInsert: 347 return true; 348 } 349 350 llvm_unreachable("Missing entry in covered switch."); 351} 352 353static void performReadOperation(ArchiveOperation Operation, 354 object::Archive *OldArchive) { 355 for (object::Archive::child_iterator I = OldArchive->begin_children(), 356 E = OldArchive->end_children(); 357 I != E; ++I) { 358 StringRef Name; 359 failIfError(I->getName(Name)); 360 361 if (!Members.empty() && 362 std::find(Members.begin(), Members.end(), Name) == Members.end()) 363 continue; 364 365 switch (Operation) { 366 default: 367 llvm_unreachable("Not a read operation"); 368 case Print: 369 doPrint(Name, I); 370 break; 371 case DisplayTable: 372 doDisplayTable(Name, I); 373 break; 374 case Extract: 375 doExtract(Name, I); 376 break; 377 } 378 } 379} 380 381namespace { 382class NewArchiveIterator { 383 bool IsNewMember; 384 StringRef Name; 385 object::Archive::child_iterator OldI; 386 std::string NewFilename; 387 388public: 389 NewArchiveIterator(object::Archive::child_iterator I, StringRef Name); 390 NewArchiveIterator(std::string *I, StringRef Name); 391 NewArchiveIterator(); 392 bool isNewMember() const; 393 object::Archive::child_iterator getOld() const; 394 const char *getNew() const; 395 StringRef getName() const; 396}; 397} 398 399NewArchiveIterator::NewArchiveIterator() {} 400 401NewArchiveIterator::NewArchiveIterator(object::Archive::child_iterator I, 402 StringRef Name) 403 : IsNewMember(false), Name(Name), OldI(I) {} 404 405NewArchiveIterator::NewArchiveIterator(std::string *NewFilename, StringRef Name) 406 : IsNewMember(true), Name(Name), NewFilename(*NewFilename) {} 407 408StringRef NewArchiveIterator::getName() const { return Name; } 409 410bool NewArchiveIterator::isNewMember() const { return IsNewMember; } 411 412object::Archive::child_iterator NewArchiveIterator::getOld() const { 413 assert(!IsNewMember); 414 return OldI; 415} 416 417const char *NewArchiveIterator::getNew() const { 418 assert(IsNewMember); 419 return NewFilename.c_str(); 420} 421 422template <typename T> 423void addMember(std::vector<NewArchiveIterator> &Members, T I, StringRef Name, 424 int Pos = -1) { 425 NewArchiveIterator NI(I, Name); 426 if (Pos == -1) 427 Members.push_back(NI); 428 else 429 Members[Pos] = NI; 430} 431 432namespace { 433class HasName { 434 StringRef Name; 435 436public: 437 HasName(StringRef Name) : Name(Name) {} 438 bool operator()(StringRef Path) { return Name == sys::path::filename(Path); } 439}; 440} 441 442enum InsertAction { 443 IA_AddOldMember, 444 IA_AddNewMeber, 445 IA_Delete, 446 IA_MoveOldMember, 447 IA_MoveNewMember 448}; 449 450static InsertAction 451computeInsertAction(ArchiveOperation Operation, 452 object::Archive::child_iterator I, StringRef Name, 453 std::vector<std::string>::iterator &Pos) { 454 if (Operation == QuickAppend || Members.empty()) 455 return IA_AddOldMember; 456 457 std::vector<std::string>::iterator MI = 458 std::find_if(Members.begin(), Members.end(), HasName(Name)); 459 460 if (MI == Members.end()) 461 return IA_AddOldMember; 462 463 Pos = MI; 464 465 if (Operation == Delete) 466 return IA_Delete; 467 468 if (Operation == Move) 469 return IA_MoveOldMember; 470 471 if (Operation == ReplaceOrInsert) { 472 StringRef PosName = sys::path::filename(RelPos); 473 if (!OnlyUpdate) { 474 if (PosName.empty()) 475 return IA_AddNewMeber; 476 return IA_MoveNewMember; 477 } 478 479 // We could try to optimize this to a fstat, but it is not a common 480 // operation. 481 sys::fs::file_status Status; 482 failIfError(sys::fs::status(*MI, Status)); 483 if (Status.getLastModificationTime() < I->getLastModified()) { 484 if (PosName.empty()) 485 return IA_AddOldMember; 486 return IA_MoveOldMember; 487 } 488 489 if (PosName.empty()) 490 return IA_AddNewMeber; 491 return IA_MoveNewMember; 492 } 493 llvm_unreachable("No such operation"); 494} 495 496// We have to walk this twice and computing it is not trivial, so creating an 497// explicit std::vector is actually fairly efficient. 498static std::vector<NewArchiveIterator> 499computeNewArchiveMembers(ArchiveOperation Operation, 500 object::Archive *OldArchive) { 501 std::vector<NewArchiveIterator> Ret; 502 std::vector<NewArchiveIterator> Moved; 503 int InsertPos = -1; 504 StringRef PosName = sys::path::filename(RelPos); 505 if (OldArchive) { 506 for (object::Archive::child_iterator I = OldArchive->begin_children(), 507 E = OldArchive->end_children(); 508 I != E; ++I) { 509 int Pos = Ret.size(); 510 StringRef Name; 511 failIfError(I->getName(Name)); 512 if (Name == PosName) { 513 assert(AddAfter || AddBefore); 514 if (AddBefore) 515 InsertPos = Pos; 516 else 517 InsertPos = Pos + 1; 518 } 519 520 std::vector<std::string>::iterator MemberI = Members.end(); 521 InsertAction Action = computeInsertAction(Operation, I, Name, MemberI); 522 switch (Action) { 523 case IA_AddOldMember: 524 addMember(Ret, I, Name); 525 break; 526 case IA_AddNewMeber: 527 addMember(Ret, &*MemberI, Name); 528 break; 529 case IA_Delete: 530 break; 531 case IA_MoveOldMember: 532 addMember(Moved, I, Name); 533 break; 534 case IA_MoveNewMember: 535 addMember(Moved, &*MemberI, Name); 536 break; 537 } 538 if (MemberI != Members.end()) 539 Members.erase(MemberI); 540 } 541 } 542 543 if (Operation == Delete) 544 return Ret; 545 546 if (!RelPos.empty() && InsertPos == -1) 547 fail("Insertion point not found"); 548 549 if (RelPos.empty()) 550 InsertPos = Ret.size(); 551 552 assert(unsigned(InsertPos) <= Ret.size()); 553 Ret.insert(Ret.begin() + InsertPos, Moved.begin(), Moved.end()); 554 555 Ret.insert(Ret.begin() + InsertPos, Members.size(), NewArchiveIterator()); 556 int Pos = InsertPos; 557 for (std::vector<std::string>::iterator I = Members.begin(), 558 E = Members.end(); 559 I != E; ++I, ++Pos) { 560 StringRef Name = sys::path::filename(*I); 561 addMember(Ret, &*I, Name, Pos); 562 } 563 564 return Ret; 565} 566 567template <typename T> 568static void printWithSpacePadding(raw_ostream &OS, T Data, unsigned Size) { 569 uint64_t OldPos = OS.tell(); 570 OS << Data; 571 unsigned SizeSoFar = OS.tell() - OldPos; 572 assert(Size >= SizeSoFar && "Data doesn't fit in Size"); 573 unsigned Remaining = Size - SizeSoFar; 574 for (unsigned I = 0; I < Remaining; ++I) 575 OS << ' '; 576} 577 578static void print32BE(raw_fd_ostream &Out, unsigned Val) { 579 for (int I = 3; I >= 0; --I) { 580 char V = (Val >> (8 * I)) & 0xff; 581 Out << V; 582 } 583} 584 585static void printRestOfMemberHeader(raw_fd_ostream &Out, 586 const sys::TimeValue &ModTime, unsigned UID, 587 unsigned GID, unsigned Perms, 588 unsigned Size) { 589 printWithSpacePadding(Out, ModTime.toEpochTime(), 12); 590 printWithSpacePadding(Out, UID, 6); 591 printWithSpacePadding(Out, GID, 6); 592 printWithSpacePadding(Out, format("%o", Perms), 8); 593 printWithSpacePadding(Out, Size, 10); 594 Out << "`\n"; 595} 596 597static void printMemberHeader(raw_fd_ostream &Out, StringRef Name, 598 const sys::TimeValue &ModTime, unsigned UID, 599 unsigned GID, unsigned Perms, unsigned Size) { 600 printWithSpacePadding(Out, Twine(Name) + "/", 16); 601 printRestOfMemberHeader(Out, ModTime, UID, GID, Perms, Size); 602} 603 604static void printMemberHeader(raw_fd_ostream &Out, unsigned NameOffset, 605 const sys::TimeValue &ModTime, unsigned UID, 606 unsigned GID, unsigned Perms, unsigned Size) { 607 Out << '/'; 608 printWithSpacePadding(Out, NameOffset, 15); 609 printRestOfMemberHeader(Out, ModTime, UID, GID, Perms, Size); 610} 611 612static void writeStringTable(raw_fd_ostream &Out, 613 ArrayRef<NewArchiveIterator> Members, 614 std::vector<unsigned> &StringMapIndexes) { 615 unsigned StartOffset = 0; 616 for (ArrayRef<NewArchiveIterator>::iterator I = Members.begin(), 617 E = Members.end(); 618 I != E; ++I) { 619 StringRef Name = I->getName(); 620 if (Name.size() < 16) 621 continue; 622 if (StartOffset == 0) { 623 printWithSpacePadding(Out, "//", 58); 624 Out << "`\n"; 625 StartOffset = Out.tell(); 626 } 627 StringMapIndexes.push_back(Out.tell() - StartOffset); 628 Out << Name << "/\n"; 629 } 630 if (StartOffset == 0) 631 return; 632 if (Out.tell() % 2) 633 Out << '\n'; 634 int Pos = Out.tell(); 635 Out.seek(StartOffset - 12); 636 printWithSpacePadding(Out, Pos - StartOffset, 10); 637 Out.seek(Pos); 638} 639 640static void writeSymbolTable( 641 raw_fd_ostream &Out, ArrayRef<NewArchiveIterator> Members, 642 std::vector<std::pair<unsigned, unsigned> > &MemberOffsetRefs) { 643 unsigned StartOffset = 0; 644 unsigned MemberNum = 0; 645 std::vector<StringRef> SymNames; 646 std::vector<object::ObjectFile *> DeleteIt; 647 for (ArrayRef<NewArchiveIterator>::iterator I = Members.begin(), 648 E = Members.end(); 649 I != E; ++I, ++MemberNum) { 650 object::ObjectFile *Obj; 651 if (I->isNewMember()) { 652 const char *Filename = I->getNew(); 653 Obj = object::ObjectFile::createObjectFile(Filename); 654 } else { 655 object::Archive::child_iterator OldMember = I->getOld(); 656 OwningPtr<object::Binary> Binary; 657 error_code EC = OldMember->getAsBinary(Binary); 658 if (EC) { // FIXME: check only for "not an object file" errors. 659 Obj = NULL; 660 } else { 661 Obj = dyn_cast<object::ObjectFile>(Binary.get()); 662 if (Obj) 663 Binary.take(); 664 } 665 } 666 if (!Obj) 667 continue; 668 DeleteIt.push_back(Obj); 669 if (!StartOffset) { 670 printMemberHeader(Out, "", sys::TimeValue::now(), 0, 0, 0, 0); 671 StartOffset = Out.tell(); 672 print32BE(Out, 0); 673 } 674 675 error_code Err; 676 for (object::symbol_iterator I = Obj->begin_symbols(), 677 E = Obj->end_symbols(); 678 I != E; I.increment(Err), failIfError(Err)) { 679 uint32_t Symflags; 680 failIfError(I->getFlags(Symflags)); 681 if (Symflags & object::SymbolRef::SF_FormatSpecific) 682 continue; 683 if (!(Symflags & object::SymbolRef::SF_Global)) 684 continue; 685 if (Symflags & object::SymbolRef::SF_Undefined) 686 continue; 687 StringRef Name; 688 failIfError(I->getName(Name)); 689 SymNames.push_back(Name); 690 MemberOffsetRefs.push_back(std::make_pair(Out.tell(), MemberNum)); 691 print32BE(Out, 0); 692 } 693 } 694 for (std::vector<StringRef>::iterator I = SymNames.begin(), 695 E = SymNames.end(); 696 I != E; ++I) { 697 Out << *I; 698 Out << '\0'; 699 } 700 701 for (std::vector<object::ObjectFile *>::iterator I = DeleteIt.begin(), 702 E = DeleteIt.end(); 703 I != E; ++I) { 704 object::ObjectFile *O = *I; 705 delete O; 706 } 707 708 if (StartOffset == 0) 709 return; 710 711 if (Out.tell() % 2) 712 Out << '\0'; 713 714 unsigned Pos = Out.tell(); 715 Out.seek(StartOffset - 12); 716 printWithSpacePadding(Out, Pos - StartOffset, 10); 717 Out.seek(StartOffset); 718 print32BE(Out, SymNames.size()); 719 Out.seek(Pos); 720} 721 722static void performWriteOperation(ArchiveOperation Operation, 723 object::Archive *OldArchive) { 724 SmallString<128> TmpArchive; 725 failIfError(sys::fs::createUniqueFile(ArchiveName + ".temp-archive-%%%%%%%.a", 726 TmpArchiveFD, TmpArchive)); 727 728 TemporaryOutput = TmpArchive.c_str(); 729 tool_output_file Output(TemporaryOutput, TmpArchiveFD); 730 raw_fd_ostream &Out = Output.os(); 731 Out << "!<arch>\n"; 732 733 std::vector<NewArchiveIterator> NewMembers = 734 computeNewArchiveMembers(Operation, OldArchive); 735 736 std::vector<std::pair<unsigned, unsigned> > MemberOffsetRefs; 737 738 if (Symtab) { 739 writeSymbolTable(Out, NewMembers, MemberOffsetRefs); 740 } 741 742 std::vector<unsigned> StringMapIndexes; 743 writeStringTable(Out, NewMembers, StringMapIndexes); 744 745 std::vector<std::pair<unsigned, unsigned> >::iterator MemberRefsI = 746 MemberOffsetRefs.begin(); 747 748 unsigned MemberNum = 0; 749 unsigned LongNameMemberNum = 0; 750 for (std::vector<NewArchiveIterator>::iterator I = NewMembers.begin(), 751 E = NewMembers.end(); 752 I != E; ++I, ++MemberNum) { 753 754 unsigned Pos = Out.tell(); 755 while (MemberRefsI != MemberOffsetRefs.end() && 756 MemberRefsI->second == MemberNum) { 757 Out.seek(MemberRefsI->first); 758 print32BE(Out, Pos); 759 ++MemberRefsI; 760 } 761 Out.seek(Pos); 762 763 if (I->isNewMember()) { 764 const char *FileName = I->getNew(); 765 766 int FD; 767 failIfError(sys::fs::openFileForRead(FileName, FD), FileName); 768 769 sys::fs::file_status Status; 770 failIfError(sys::fs::status(FD, Status), FileName); 771 772 OwningPtr<MemoryBuffer> File; 773 failIfError( 774 MemoryBuffer::getOpenFile(FD, FileName, File, Status.getSize()), 775 FileName); 776 777 StringRef Name = sys::path::filename(FileName); 778 if (Name.size() < 16) 779 printMemberHeader(Out, Name, Status.getLastModificationTime(), 780 Status.getUser(), Status.getGroup(), 781 Status.permissions(), Status.getSize()); 782 else 783 printMemberHeader(Out, StringMapIndexes[LongNameMemberNum++], 784 Status.getLastModificationTime(), Status.getUser(), 785 Status.getGroup(), Status.permissions(), 786 Status.getSize()); 787 Out << File->getBuffer(); 788 } else { 789 object::Archive::child_iterator OldMember = I->getOld(); 790 StringRef Name = I->getName(); 791 792 if (Name.size() < 16) 793 printMemberHeader(Out, Name, OldMember->getLastModified(), 794 OldMember->getUID(), OldMember->getGID(), 795 OldMember->getAccessMode(), OldMember->getSize()); 796 else 797 printMemberHeader(Out, StringMapIndexes[LongNameMemberNum++], 798 OldMember->getLastModified(), OldMember->getUID(), 799 OldMember->getGID(), OldMember->getAccessMode(), 800 OldMember->getSize()); 801 Out << OldMember->getBuffer(); 802 } 803 804 if (Out.tell() % 2) 805 Out << '\n'; 806 } 807 Output.keep(); 808 Out.close(); 809 sys::fs::rename(TemporaryOutput, ArchiveName); 810 TemporaryOutput = NULL; 811} 812 813static void performOperation(ArchiveOperation Operation, 814 object::Archive *OldArchive) { 815 switch (Operation) { 816 case Print: 817 case DisplayTable: 818 case Extract: 819 performReadOperation(Operation, OldArchive); 820 return; 821 822 case Delete: 823 case Move: 824 case QuickAppend: 825 case ReplaceOrInsert: 826 performWriteOperation(Operation, OldArchive); 827 return; 828 } 829 llvm_unreachable("Unknown operation."); 830} 831 832// main - main program for llvm-ar .. see comments in the code 833int main(int argc, char **argv) { 834 ToolName = argv[0]; 835 // Print a stack trace if we signal out. 836 sys::PrintStackTraceOnErrorSignal(); 837 PrettyStackTraceProgram X(argc, argv); 838 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. 839 840 // Have the command line options parsed and handle things 841 // like --help and --version. 842 cl::ParseCommandLineOptions(argc, argv, 843 "LLVM Archiver (llvm-ar)\n\n" 844 " This program archives bitcode files into single libraries\n" 845 ); 846 847 // Do our own parsing of the command line because the CommandLine utility 848 // can't handle the grouped positional parameters without a dash. 849 ArchiveOperation Operation = parseCommandLine(); 850 851 // Create or open the archive object. 852 OwningPtr<MemoryBuffer> Buf; 853 error_code EC = MemoryBuffer::getFile(ArchiveName, Buf, -1, false); 854 if (EC && EC != llvm::errc::no_such_file_or_directory) { 855 errs() << argv[0] << ": error opening '" << ArchiveName 856 << "': " << EC.message() << "!\n"; 857 return 1; 858 } 859 860 if (!EC) { 861 object::Archive Archive(Buf.take(), EC); 862 863 if (EC) { 864 errs() << argv[0] << ": error loading '" << ArchiveName 865 << "': " << EC.message() << "!\n"; 866 return 1; 867 } 868 performOperation(Operation, &Archive); 869 return 0; 870 } 871 872 assert(EC == llvm::errc::no_such_file_or_directory); 873 874 if (!shouldCreateArchive(Operation)) { 875 failIfError(EC, Twine("error loading '") + ArchiveName + "'"); 876 } else { 877 if (!Create) { 878 // Produce a warning if we should and we're creating the archive 879 errs() << argv[0] << ": creating " << ArchiveName << "\n"; 880 } 881 } 882 883 performOperation(Operation, NULL); 884 return 0; 885} 886