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 cl::init("-")); 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 template <class ELFT> 134 bool OnlyKeepDWOPred(const Object<ELFT> &Obj, const SectionBase &Sec) { 135 // We can't remove the section header string table. 136 if (&Sec == Obj.getSectionHeaderStrTab()) 137 return false; 138 // Short of keeping the string table we want to keep everything that is a DWO 139 // section and remove everything else. 140 return !IsDWOSection(Sec); 141 } 142 143 template <class ELFT> 144 void WriteObjectFile(const Object<ELFT> &Obj, StringRef File) { 145 std::unique_ptr<FileOutputBuffer> Buffer; 146 Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr = 147 FileOutputBuffer::create(File, Obj.totalSize(), 148 FileOutputBuffer::F_executable); 149 handleAllErrors(BufferOrErr.takeError(), [](const ErrorInfoBase &) { 150 error("failed to open " + OutputFilename); 151 }); 152 Buffer = std::move(*BufferOrErr); 153 154 Obj.write(*Buffer); 155 if (auto E = Buffer->commit()) 156 reportError(File, errorToErrorCode(std::move(E))); 157 } 158 159 template <class ELFT> 160 void SplitDWOToFile(const ELFObjectFile<ELFT> &ObjFile, StringRef File) { 161 // Construct a second output file for the DWO sections. 162 ELFObject<ELFT> DWOFile(ObjFile); 163 164 DWOFile.removeSections([&](const SectionBase &Sec) { 165 return OnlyKeepDWOPred<ELFT>(DWOFile, Sec); 166 }); 167 DWOFile.finalize(); 168 WriteObjectFile(DWOFile, File); 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 template <class ELFT> void CopyBinary(const ELFObjectFile<ELFT> &ObjFile) { 179 std::unique_ptr<Object<ELFT>> Obj; 180 181 if (!OutputFormat.empty() && OutputFormat != "binary") 182 error("invalid output format '" + OutputFormat + "'"); 183 if (!OutputFormat.empty() && OutputFormat == "binary") 184 Obj = llvm::make_unique<BinaryObject<ELFT>>(ObjFile); 185 else 186 Obj = llvm::make_unique<ELFObject<ELFT>>(ObjFile); 187 188 if (!SplitDWO.empty()) 189 SplitDWOToFile<ELFT>(ObjFile, SplitDWO.getValue()); 190 191 // Localize: 192 193 if (LocalizeHidden) { 194 Obj->getSymTab()->localize([](const Symbol &Sym) { 195 return Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL; 196 }); 197 } 198 199 SectionPred RemovePred = [](const SectionBase &) { return false; }; 200 201 // Removes: 202 203 if (!ToRemove.empty()) { 204 RemovePred = [&](const SectionBase &Sec) { 205 return std::find(std::begin(ToRemove), std::end(ToRemove), Sec.Name) != 206 std::end(ToRemove); 207 }; 208 } 209 210 if (StripDWO || !SplitDWO.empty()) 211 RemovePred = [RemovePred](const SectionBase &Sec) { 212 return IsDWOSection(Sec) || RemovePred(Sec); 213 }; 214 215 if (ExtractDWO) 216 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 217 return OnlyKeepDWOPred(*Obj, Sec) || RemovePred(Sec); 218 }; 219 220 if (StripAllGNU) 221 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 222 if (RemovePred(Sec)) 223 return true; 224 if ((Sec.Flags & SHF_ALLOC) != 0) 225 return false; 226 if (&Sec == Obj->getSectionHeaderStrTab()) 227 return false; 228 switch (Sec.Type) { 229 case SHT_SYMTAB: 230 case SHT_REL: 231 case SHT_RELA: 232 case SHT_STRTAB: 233 return true; 234 } 235 return Sec.Name.startswith(".debug"); 236 }; 237 238 if (StripSections) { 239 RemovePred = [RemovePred](const SectionBase &Sec) { 240 return RemovePred(Sec) || (Sec.Flags & SHF_ALLOC) == 0; 241 }; 242 Obj->WriteSectionHeaders = false; 243 } 244 245 if (StripDebug) { 246 RemovePred = [RemovePred](const SectionBase &Sec) { 247 return RemovePred(Sec) || Sec.Name.startswith(".debug"); 248 }; 249 } 250 251 if (StripNonAlloc) 252 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 253 if (RemovePred(Sec)) 254 return true; 255 if (&Sec == Obj->getSectionHeaderStrTab()) 256 return false; 257 return (Sec.Flags & SHF_ALLOC) == 0; 258 }; 259 260 if (StripAll) 261 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 262 if (RemovePred(Sec)) 263 return true; 264 if (&Sec == Obj->getSectionHeaderStrTab()) 265 return false; 266 if (Sec.Name.startswith(".gnu.warning")) 267 return false; 268 return (Sec.Flags & SHF_ALLOC) == 0; 269 }; 270 271 // Explicit copies: 272 273 if (!OnlyKeep.empty()) { 274 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 275 // Explicitly keep these sections regardless of previous removes. 276 if (std::find(std::begin(OnlyKeep), std::end(OnlyKeep), Sec.Name) != 277 std::end(OnlyKeep)) 278 return false; 279 280 // Allow all implicit removes. 281 if (RemovePred(Sec)) { 282 return true; 283 } 284 285 // Keep special sections. 286 if (Obj->getSectionHeaderStrTab() == &Sec) { 287 return false; 288 } 289 if (Obj->getSymTab() == &Sec || Obj->getSymTab()->getStrTab() == &Sec) { 290 return false; 291 } 292 // Remove everything else. 293 return true; 294 }; 295 } 296 297 if (!Keep.empty()) { 298 RemovePred = [RemovePred](const SectionBase &Sec) { 299 // Explicitly keep these sections regardless of previous removes. 300 if (std::find(std::begin(Keep), std::end(Keep), Sec.Name) != 301 std::end(Keep)) 302 return false; 303 // Otherwise defer to RemovePred. 304 return RemovePred(Sec); 305 }; 306 } 307 308 Obj->removeSections(RemovePred); 309 310 if (!AddSection.empty()) { 311 for (const auto &Flag : AddSection) { 312 auto SecPair = StringRef(Flag).split("="); 313 auto SecName = SecPair.first; 314 auto File = SecPair.second; 315 auto BufOrErr = MemoryBuffer::getFile(File); 316 if (!BufOrErr) 317 reportError(File, BufOrErr.getError()); 318 auto Buf = std::move(*BufOrErr); 319 auto BufPtr = reinterpret_cast<const uint8_t *>(Buf->getBufferStart()); 320 auto BufSize = Buf->getBufferSize(); 321 Obj->addSection(SecName, ArrayRef<uint8_t>(BufPtr, BufSize)); 322 } 323 } 324 325 if (!AddGnuDebugLink.empty()) { 326 Obj->addGnuDebugLink(AddGnuDebugLink); 327 } 328 329 Obj->finalize(); 330 WriteObjectFile(*Obj, OutputFilename.getValue()); 331 } 332 333 int main(int argc, char **argv) { 334 // Print a stack trace if we signal out. 335 sys::PrintStackTraceOnErrorSignal(argv[0]); 336 PrettyStackTraceProgram X(argc, argv); 337 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. 338 cl::ParseCommandLineOptions(argc, argv, "llvm objcopy utility\n"); 339 ToolName = argv[0]; 340 if (InputFilename.empty()) { 341 cl::PrintHelpMessage(); 342 return 2; 343 } 344 Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(InputFilename); 345 if (!BinaryOrErr) 346 reportError(InputFilename, BinaryOrErr.takeError()); 347 Binary &Binary = *BinaryOrErr.get().getBinary(); 348 if (auto *o = dyn_cast<ELFObjectFile<ELF64LE>>(&Binary)) { 349 CopyBinary(*o); 350 return 0; 351 } 352 if (auto *o = dyn_cast<ELFObjectFile<ELF32LE>>(&Binary)) { 353 CopyBinary(*o); 354 return 0; 355 } 356 if (auto *o = dyn_cast<ELFObjectFile<ELF64BE>>(&Binary)) { 357 CopyBinary(*o); 358 return 0; 359 } 360 if (auto *o = dyn_cast<ELFObjectFile<ELF32BE>>(&Binary)) { 361 CopyBinary(*o); 362 return 0; 363 } 364 reportError(InputFilename, object_error::invalid_file_type); 365 } 366