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