1 //===- llvm-objcopy.cpp ---------------------------------------------------===// 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 #include "llvm-objcopy.h" 11 #include "Buffer.h" 12 #include "CopyConfig.h" 13 #include "ELF/ELFObjcopy.h" 14 15 #include "llvm/ADT/STLExtras.h" 16 #include "llvm/ADT/SmallVector.h" 17 #include "llvm/ADT/StringRef.h" 18 #include "llvm/ADT/Twine.h" 19 #include "llvm/Object/Archive.h" 20 #include "llvm/Object/ArchiveWriter.h" 21 #include "llvm/Object/Binary.h" 22 #include "llvm/Object/ELFObjectFile.h" 23 #include "llvm/Object/ELFTypes.h" 24 #include "llvm/Object/Error.h" 25 #include "llvm/Option/Arg.h" 26 #include "llvm/Option/ArgList.h" 27 #include "llvm/Option/Option.h" 28 #include "llvm/Support/Casting.h" 29 #include "llvm/Support/Error.h" 30 #include "llvm/Support/ErrorHandling.h" 31 #include "llvm/Support/ErrorOr.h" 32 #include "llvm/Support/InitLLVM.h" 33 #include "llvm/Support/Memory.h" 34 #include "llvm/Support/Path.h" 35 #include "llvm/Support/Process.h" 36 #include "llvm/Support/WithColor.h" 37 #include "llvm/Support/raw_ostream.h" 38 #include <algorithm> 39 #include <cassert> 40 #include <cstdlib> 41 #include <memory> 42 #include <string> 43 #include <system_error> 44 #include <utility> 45 46 namespace llvm { 47 namespace objcopy { 48 49 // The name this program was invoked as. 50 StringRef ToolName; 51 52 LLVM_ATTRIBUTE_NORETURN void error(Twine Message) { 53 WithColor::error(errs(), ToolName) << Message << ".\n"; 54 errs().flush(); 55 exit(1); 56 } 57 58 LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, std::error_code EC) { 59 assert(EC); 60 WithColor::error(errs(), ToolName) 61 << "'" << File << "': " << EC.message() << ".\n"; 62 exit(1); 63 } 64 65 LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, Error E) { 66 assert(E); 67 std::string Buf; 68 raw_string_ostream OS(Buf); 69 logAllUnhandledErrors(std::move(E), OS, ""); 70 OS.flush(); 71 WithColor::error(errs(), ToolName) << "'" << File << "': " << Buf; 72 exit(1); 73 } 74 75 } // end namespace objcopy 76 } // end namespace llvm 77 78 using namespace llvm; 79 using namespace llvm::object; 80 using namespace llvm::objcopy; 81 82 // For regular archives this function simply calls llvm::writeArchive, 83 // For thin archives it writes the archive file itself as well as its members. 84 static Error deepWriteArchive(StringRef ArcName, 85 ArrayRef<NewArchiveMember> NewMembers, 86 bool WriteSymtab, object::Archive::Kind Kind, 87 bool Deterministic, bool Thin) { 88 Error E = 89 writeArchive(ArcName, NewMembers, WriteSymtab, Kind, Deterministic, Thin); 90 if (!Thin || E) 91 return E; 92 for (const NewArchiveMember &Member : NewMembers) { 93 // Internally, FileBuffer will use the buffer created by 94 // FileOutputBuffer::create, for regular files (that is the case for 95 // deepWriteArchive) FileOutputBuffer::create will return OnDiskBuffer. 96 // OnDiskBuffer uses a temporary file and then renames it. So in reality 97 // there is no inefficiency / duplicated in-memory buffers in this case. For 98 // now in-memory buffers can not be completely avoided since 99 // NewArchiveMember still requires them even though writeArchive does not 100 // write them on disk. 101 FileBuffer FB(Member.MemberName); 102 FB.allocate(Member.Buf->getBufferSize()); 103 std::copy(Member.Buf->getBufferStart(), Member.Buf->getBufferEnd(), 104 FB.getBufferStart()); 105 if (auto E = FB.commit()) 106 return E; 107 } 108 return Error::success(); 109 } 110 111 /// The function executeObjcopyOnRawBinary does the dispatch based on the format 112 /// of the output specified by the command line options. 113 static void executeObjcopyOnRawBinary(const CopyConfig &Config, 114 MemoryBuffer &In, Buffer &Out) { 115 // TODO: llvm-objcopy should parse CopyConfig.OutputFormat to recognize 116 // formats other than ELF / "binary" and invoke 117 // elf::executeObjcopyOnRawBinary, macho::executeObjcopyOnRawBinary or 118 // coff::executeObjcopyOnRawBinary accordingly. 119 return elf::executeObjcopyOnRawBinary(Config, In, Out); 120 } 121 122 /// The function executeObjcopyOnBinary does the dispatch based on the format 123 /// of the input binary (ELF, MachO or COFF). 124 static void executeObjcopyOnBinary(const CopyConfig &Config, object::Binary &In, 125 Buffer &Out) { 126 if (auto *ELFBinary = dyn_cast<object::ELFObjectFileBase>(&In)) 127 return elf::executeObjcopyOnBinary(Config, *ELFBinary, Out); 128 else 129 error("Unsupported object file format"); 130 } 131 132 static void executeObjcopyOnArchive(const CopyConfig &Config, 133 const Archive &Ar) { 134 std::vector<NewArchiveMember> NewArchiveMembers; 135 Error Err = Error::success(); 136 for (const Archive::Child &Child : Ar.children(Err)) { 137 Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary(); 138 if (!ChildOrErr) 139 reportError(Ar.getFileName(), ChildOrErr.takeError()); 140 Binary *Bin = ChildOrErr->get(); 141 142 Expected<StringRef> ChildNameOrErr = Child.getName(); 143 if (!ChildNameOrErr) 144 reportError(Ar.getFileName(), ChildNameOrErr.takeError()); 145 146 MemBuffer MB(ChildNameOrErr.get()); 147 executeObjcopyOnBinary(Config, *Bin, MB); 148 149 Expected<NewArchiveMember> Member = 150 NewArchiveMember::getOldMember(Child, true); 151 if (!Member) 152 reportError(Ar.getFileName(), Member.takeError()); 153 Member->Buf = MB.releaseMemoryBuffer(); 154 Member->MemberName = Member->Buf->getBufferIdentifier(); 155 NewArchiveMembers.push_back(std::move(*Member)); 156 } 157 158 if (Err) 159 reportError(Config.InputFilename, std::move(Err)); 160 if (Error E = 161 deepWriteArchive(Config.OutputFilename, NewArchiveMembers, 162 Ar.hasSymbolTable(), Ar.kind(), true, Ar.isThin())) 163 reportError(Config.OutputFilename, std::move(E)); 164 } 165 166 static void restoreDateOnFile(StringRef Filename, 167 const sys::fs::file_status &Stat) { 168 int FD; 169 170 if (auto EC = 171 sys::fs::openFileForWrite(Filename, FD, sys::fs::CD_OpenExisting)) 172 reportError(Filename, EC); 173 174 if (auto EC = sys::fs::setLastAccessAndModificationTime( 175 FD, Stat.getLastAccessedTime(), Stat.getLastModificationTime())) 176 reportError(Filename, EC); 177 178 if (auto EC = sys::Process::SafelyCloseFileDescriptor(FD)) 179 reportError(Filename, EC); 180 } 181 182 /// The function executeObjcopy does the higher level dispatch based on the type 183 /// of input (raw binary, archive or single object file) and takes care of the 184 /// format-agnostic modifications, i.e. preserving dates. 185 static void executeObjcopy(const CopyConfig &Config) { 186 sys::fs::file_status Stat; 187 if (Config.PreserveDates) 188 if (auto EC = sys::fs::status(Config.InputFilename, Stat)) 189 reportError(Config.InputFilename, EC); 190 191 if (Config.InputFormat == "binary") { 192 auto BufOrErr = MemoryBuffer::getFile(Config.InputFilename); 193 if (!BufOrErr) 194 reportError(Config.InputFilename, BufOrErr.getError()); 195 FileBuffer FB(Config.OutputFilename); 196 executeObjcopyOnRawBinary(Config, *BufOrErr->get(), FB); 197 } else { 198 Expected<OwningBinary<llvm::object::Binary>> BinaryOrErr = 199 createBinary(Config.InputFilename); 200 if (!BinaryOrErr) 201 reportError(Config.InputFilename, BinaryOrErr.takeError()); 202 203 if (Archive *Ar = dyn_cast<Archive>(BinaryOrErr.get().getBinary())) { 204 executeObjcopyOnArchive(Config, *Ar); 205 } else { 206 FileBuffer FB(Config.OutputFilename); 207 executeObjcopyOnBinary(Config, *BinaryOrErr.get().getBinary(), FB); 208 } 209 } 210 211 if (Config.PreserveDates) { 212 restoreDateOnFile(Config.OutputFilename, Stat); 213 if (!Config.SplitDWO.empty()) 214 restoreDateOnFile(Config.SplitDWO, Stat); 215 } 216 } 217 218 int main(int argc, char **argv) { 219 InitLLVM X(argc, argv); 220 ToolName = argv[0]; 221 DriverConfig DriverConfig; 222 if (sys::path::stem(ToolName).endswith_lower("strip")) 223 DriverConfig = parseStripOptions(makeArrayRef(argv + 1, argc)); 224 else 225 DriverConfig = parseObjcopyOptions(makeArrayRef(argv + 1, argc)); 226 for (const CopyConfig &CopyConfig : DriverConfig.CopyConfigs) 227 executeObjcopy(CopyConfig); 228 } 229