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