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 "Object.h" 12 #include "llvm/ADT/STLExtras.h" 13 #include "llvm/ADT/StringRef.h" 14 #include "llvm/ADT/Twine.h" 15 #include "llvm/BinaryFormat/ELF.h" 16 #include "llvm/Object/Binary.h" 17 #include "llvm/Object/ELFObjectFile.h" 18 #include "llvm/Object/ELFTypes.h" 19 #include "llvm/Object/Error.h" 20 #include "llvm/Support/Casting.h" 21 #include "llvm/Support/CommandLine.h" 22 #include "llvm/Support/Compiler.h" 23 #include "llvm/Support/Error.h" 24 #include "llvm/Support/ErrorHandling.h" 25 #include "llvm/Support/ErrorOr.h" 26 #include "llvm/Support/FileOutputBuffer.h" 27 #include "llvm/Support/ManagedStatic.h" 28 #include "llvm/Support/PrettyStackTrace.h" 29 #include "llvm/Support/Signals.h" 30 #include "llvm/Support/raw_ostream.h" 31 #include <algorithm> 32 #include <cassert> 33 #include <cstdlib> 34 #include <functional> 35 #include <iterator> 36 #include <memory> 37 #include <string> 38 #include <system_error> 39 #include <utility> 40 41 using namespace llvm; 42 using namespace object; 43 using namespace ELF; 44 45 // The name this program was invoked as. 46 static StringRef ToolName; 47 48 namespace llvm { 49 50 LLVM_ATTRIBUTE_NORETURN void error(Twine Message) { 51 errs() << ToolName << ": " << Message << ".\n"; 52 errs().flush(); 53 exit(1); 54 } 55 56 LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, std::error_code EC) { 57 assert(EC); 58 errs() << ToolName << ": '" << File << "': " << EC.message() << ".\n"; 59 exit(1); 60 } 61 62 LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, Error E) { 63 assert(E); 64 std::string Buf; 65 raw_string_ostream OS(Buf); 66 logAllUnhandledErrors(std::move(E), OS, ""); 67 OS.flush(); 68 errs() << ToolName << ": '" << File << "': " << Buf; 69 exit(1); 70 } 71 72 } // end namespace llvm 73 74 static cl::opt<std::string> InputFilename(cl::Positional, cl::desc("<input>")); 75 static cl::opt<std::string> OutputFilename(cl::Positional, cl::desc("[ <output> ]")); 76 77 static cl::opt<std::string> 78 OutputFormat("O", cl::desc("Set output format to one of the following:" 79 "\n\tbinary")); 80 static cl::list<std::string> ToRemove("remove-section", 81 cl::desc("Remove <section>"), 82 cl::value_desc("section")); 83 static cl::alias ToRemoveA("R", cl::desc("Alias for remove-section"), 84 cl::aliasopt(ToRemove)); 85 static cl::opt<bool> StripAll( 86 "strip-all", 87 cl::desc( 88 "Removes non-allocated sections other than .gnu.warning* sections")); 89 static cl::opt<bool> 90 StripAllGNU("strip-all-gnu", 91 cl::desc("Removes symbol, relocation, and debug information")); 92 static cl::list<std::string> Keep("keep", cl::desc("Keep <section>"), 93 cl::value_desc("section")); 94 static cl::list<std::string> OnlyKeep("only-keep", 95 cl::desc("Remove all but <section>"), 96 cl::value_desc("section")); 97 static cl::alias OnlyKeepA("j", cl::desc("Alias for only-keep"), 98 cl::aliasopt(OnlyKeep)); 99 static cl::opt<bool> StripDebug("strip-debug", 100 cl::desc("Removes all debug information")); 101 static cl::opt<bool> StripSections("strip-sections", 102 cl::desc("Remove all section headers")); 103 static cl::opt<bool> 104 StripNonAlloc("strip-non-alloc", 105 cl::desc("Remove all non-allocated sections")); 106 static cl::opt<bool> 107 StripDWO("strip-dwo", cl::desc("Remove all DWARF .dwo sections from file")); 108 static cl::opt<bool> ExtractDWO( 109 "extract-dwo", 110 cl::desc("Remove all sections that are not DWARF .dwo sections from file")); 111 static cl::opt<std::string> 112 SplitDWO("split-dwo", 113 cl::desc("Equivalent to extract-dwo on the input file to " 114 "<dwo-file>, then strip-dwo on the input file"), 115 cl::value_desc("dwo-file")); 116 static cl::list<std::string> AddSection( 117 "add-section", 118 cl::desc("Make a section named <section> with the contents of <file>."), 119 cl::value_desc("section=file")); 120 static cl::opt<bool> LocalizeHidden( 121 "localize-hidden", 122 cl::desc( 123 "Mark all symbols that have hidden or internal visibility as local")); 124 static cl::opt<std::string> 125 AddGnuDebugLink("add-gnu-debuglink", 126 cl::desc("adds a .gnu_debuglink for <debug-file>"), 127 cl::value_desc("debug-file")); 128 129 using SectionPred = std::function<bool(const SectionBase &Sec)>; 130 131 bool IsDWOSection(const SectionBase &Sec) { return Sec.Name.endswith(".dwo"); } 132 133 bool OnlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) { 134 // We can't remove the section header string table. 135 if (&Sec == Obj.SectionNames) 136 return false; 137 // Short of keeping the string table we want to keep everything that is a DWO 138 // section and remove everything else. 139 return !IsDWOSection(Sec); 140 } 141 142 static ElfType OutputElfType; 143 144 std::unique_ptr<Writer> CreateWriter(Object &Obj, StringRef File) { 145 if (OutputFormat == "binary") { 146 return llvm::make_unique<BinaryWriter>(OutputFilename, Obj); 147 } 148 // Depending on the initial ELFT and OutputFormat we need a different Writer. 149 switch (OutputElfType) { 150 case ELFT_ELF32LE: 151 return llvm::make_unique<ELFWriter<ELF32LE>>(File, Obj, !StripSections); 152 case ELFT_ELF64LE: 153 return llvm::make_unique<ELFWriter<ELF64LE>>(File, Obj, !StripSections); 154 case ELFT_ELF32BE: 155 return llvm::make_unique<ELFWriter<ELF32BE>>(File, Obj, !StripSections); 156 case ELFT_ELF64BE: 157 return llvm::make_unique<ELFWriter<ELF64BE>>(File, Obj, !StripSections); 158 } 159 llvm_unreachable("Invalid output format"); 160 } 161 162 void SplitDWOToFile(const Reader &Reader, StringRef File) { 163 auto DWOFile = Reader.create(); 164 DWOFile->removeSections( 165 [&](const SectionBase &Sec) { return OnlyKeepDWOPred(*DWOFile, Sec); }); 166 auto Writer = CreateWriter(*DWOFile, File); 167 Writer->finalize(); 168 Writer->write(); 169 } 170 171 // This function handles the high level operations of GNU objcopy including 172 // handling command line options. It's important to outline certain properties 173 // we expect to hold of the command line operations. Any operation that "keeps" 174 // should keep regardless of a remove. Additionally any removal should respect 175 // any previous removals. Lastly whether or not something is removed shouldn't 176 // depend a) on the order the options occur in or b) on some opaque priority 177 // system. The only priority is that keeps/copies overrule removes. 178 void HandleArgs(Object &Obj, const Reader &Reader) { 179 180 if (!SplitDWO.empty()) { 181 SplitDWOToFile(Reader, SplitDWO); 182 } 183 184 // Localize: 185 186 if (LocalizeHidden) { 187 Obj.SymbolTable->localize([](const Symbol &Sym) { 188 return Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL; 189 }); 190 } 191 192 SectionPred RemovePred = [](const SectionBase &) { return false; }; 193 194 // Removes: 195 196 if (!ToRemove.empty()) { 197 RemovePred = [&](const SectionBase &Sec) { 198 return std::find(std::begin(ToRemove), std::end(ToRemove), Sec.Name) != 199 std::end(ToRemove); 200 }; 201 } 202 203 if (StripDWO || !SplitDWO.empty()) 204 RemovePred = [RemovePred](const SectionBase &Sec) { 205 return IsDWOSection(Sec) || RemovePred(Sec); 206 }; 207 208 if (ExtractDWO) 209 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 210 return OnlyKeepDWOPred(Obj, Sec) || RemovePred(Sec); 211 }; 212 213 if (StripAllGNU) 214 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 215 if (RemovePred(Sec)) 216 return true; 217 if ((Sec.Flags & SHF_ALLOC) != 0) 218 return false; 219 if (&Sec == Obj.SectionNames) 220 return false; 221 switch (Sec.Type) { 222 case SHT_SYMTAB: 223 case SHT_REL: 224 case SHT_RELA: 225 case SHT_STRTAB: 226 return true; 227 } 228 return Sec.Name.startswith(".debug"); 229 }; 230 231 if (StripSections) { 232 RemovePred = [RemovePred](const SectionBase &Sec) { 233 return RemovePred(Sec) || (Sec.Flags & SHF_ALLOC) == 0; 234 }; 235 } 236 237 if (StripDebug) { 238 RemovePred = [RemovePred](const SectionBase &Sec) { 239 return RemovePred(Sec) || Sec.Name.startswith(".debug"); 240 }; 241 } 242 243 if (StripNonAlloc) 244 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 245 if (RemovePred(Sec)) 246 return true; 247 if (&Sec == Obj.SectionNames) 248 return false; 249 return (Sec.Flags & SHF_ALLOC) == 0; 250 }; 251 252 if (StripAll) 253 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 254 if (RemovePred(Sec)) 255 return true; 256 if (&Sec == Obj.SectionNames) 257 return false; 258 if (Sec.Name.startswith(".gnu.warning")) 259 return false; 260 return (Sec.Flags & SHF_ALLOC) == 0; 261 }; 262 263 // Explicit copies: 264 265 if (!OnlyKeep.empty()) { 266 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 267 // Explicitly keep these sections regardless of previous removes. 268 if (std::find(std::begin(OnlyKeep), std::end(OnlyKeep), Sec.Name) != 269 std::end(OnlyKeep)) 270 return false; 271 272 // Allow all implicit removes. 273 if (RemovePred(Sec)) 274 return true; 275 276 // Keep special sections. 277 if (Obj.SectionNames == &Sec) 278 return false; 279 if (Obj.SymbolTable == &Sec || Obj.SymbolTable->getStrTab() == &Sec) 280 return false; 281 282 // Remove everything else. 283 return true; 284 }; 285 } 286 287 if (!Keep.empty()) { 288 RemovePred = [RemovePred](const SectionBase &Sec) { 289 // Explicitly keep these sections regardless of previous removes. 290 if (std::find(std::begin(Keep), std::end(Keep), Sec.Name) != 291 std::end(Keep)) 292 return false; 293 // Otherwise defer to RemovePred. 294 return RemovePred(Sec); 295 }; 296 } 297 298 Obj.removeSections(RemovePred); 299 300 if (!AddSection.empty()) { 301 for (const auto &Flag : AddSection) { 302 auto SecPair = StringRef(Flag).split("="); 303 auto SecName = SecPair.first; 304 auto File = SecPair.second; 305 auto BufOrErr = MemoryBuffer::getFile(File); 306 if (!BufOrErr) 307 reportError(File, BufOrErr.getError()); 308 auto Buf = std::move(*BufOrErr); 309 auto BufPtr = reinterpret_cast<const uint8_t *>(Buf->getBufferStart()); 310 auto BufSize = Buf->getBufferSize(); 311 Obj.addSection<OwnedDataSection>(SecName, 312 ArrayRef<uint8_t>(BufPtr, BufSize)); 313 } 314 } 315 316 if (!AddGnuDebugLink.empty()) { 317 Obj.addSection<GnuDebugLinkSection>(StringRef(AddGnuDebugLink)); 318 } 319 } 320 321 std::unique_ptr<Reader> CreateReader() { 322 // Right now we can only read ELF files so there's only one reader; 323 auto Out = llvm::make_unique<ELFReader>(StringRef(InputFilename)); 324 // We need to set the default ElfType for output. 325 OutputElfType = Out->getElfType(); 326 return std::move(Out); 327 } 328 329 int main(int argc, char **argv) { 330 // Print a stack trace if we signal out. 331 sys::PrintStackTraceOnErrorSignal(argv[0]); 332 PrettyStackTraceProgram X(argc, argv); 333 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. 334 cl::ParseCommandLineOptions(argc, argv, "llvm objcopy utility\n"); 335 ToolName = argv[0]; 336 if (InputFilename.empty()) { 337 cl::PrintHelpMessage(); 338 return 2; 339 } 340 341 auto Reader = CreateReader(); 342 auto Obj = Reader->create(); 343 StringRef Output = 344 OutputFilename.getNumOccurrences() ? OutputFilename : InputFilename; 345 auto Writer = CreateWriter(*Obj, Output); 346 HandleArgs(*Obj, *Reader); 347 Writer->finalize(); 348 Writer->write(); 349 } 350