1 //=== llvm-dwarfutil.cpp --------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "DebugInfoLinker.h" 10 #include "Error.h" 11 #include "Options.h" 12 #include "llvm/DebugInfo/DWARF/DWARFContext.h" 13 #include "llvm/DebugInfo/DWARF/DWARFVerifier.h" 14 #include "llvm/MC/MCTargetOptionsCommandFlags.h" 15 #include "llvm/ObjCopy/CommonConfig.h" 16 #include "llvm/ObjCopy/ConfigManager.h" 17 #include "llvm/ObjCopy/ObjCopy.h" 18 #include "llvm/Option/Arg.h" 19 #include "llvm/Option/ArgList.h" 20 #include "llvm/Option/Option.h" 21 #include "llvm/Support/CRC.h" 22 #include "llvm/Support/CommandLine.h" 23 #include "llvm/Support/FileUtilities.h" 24 #include "llvm/Support/InitLLVM.h" 25 #include "llvm/Support/PrettyStackTrace.h" 26 #include "llvm/Support/Process.h" 27 #include "llvm/Support/Signals.h" 28 #include "llvm/Support/TargetSelect.h" 29 30 using namespace llvm; 31 using namespace object; 32 33 namespace { 34 enum ID { 35 OPT_INVALID = 0, // This is not an option ID. 36 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ 37 HELPTEXT, METAVAR, VALUES) \ 38 OPT_##ID, 39 #include "Options.inc" 40 #undef OPTION 41 }; 42 43 #define PREFIX(NAME, VALUE) \ 44 static constexpr std::initializer_list<StringLiteral> NAME = VALUE; 45 #include "Options.inc" 46 #undef PREFIX 47 48 static constexpr std::initializer_list<opt::OptTable::Info> InfoTable = { 49 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ 50 HELPTEXT, METAVAR, VALUES) \ 51 { \ 52 PREFIX, NAME, HELPTEXT, \ 53 METAVAR, OPT_##ID, opt::Option::KIND##Class, \ 54 PARAM, FLAGS, OPT_##GROUP, \ 55 OPT_##ALIAS, ALIASARGS, VALUES}, 56 #include "Options.inc" 57 #undef OPTION 58 }; 59 60 class DwarfutilOptTable : public opt::OptTable { 61 public: 62 DwarfutilOptTable() : OptTable(InfoTable) {} 63 }; 64 } // namespace 65 66 namespace llvm { 67 namespace dwarfutil { 68 69 std::string ToolName; 70 71 static mc::RegisterMCTargetOptionsFlags MOF; 72 73 static Error validateAndSetOptions(opt::InputArgList &Args, Options &Options) { 74 auto UnknownArgs = Args.filtered(OPT_UNKNOWN); 75 if (!UnknownArgs.empty()) 76 return createStringError( 77 std::errc::invalid_argument, 78 formatv("unknown option: {0}", (*UnknownArgs.begin())->getSpelling()) 79 .str() 80 .c_str()); 81 82 std::vector<std::string> InputFiles = Args.getAllArgValues(OPT_INPUT); 83 if (InputFiles.size() != 2) 84 return createStringError( 85 std::errc::invalid_argument, 86 formatv("exactly two positional arguments expected, {0} provided", 87 InputFiles.size()) 88 .str() 89 .c_str()); 90 91 Options.InputFileName = InputFiles[0]; 92 Options.OutputFileName = InputFiles[1]; 93 94 Options.BuildSeparateDebugFile = 95 Args.hasFlag(OPT_separate_debug_file, OPT_no_separate_debug_file, false); 96 Options.DoODRDeduplication = 97 Args.hasFlag(OPT_odr_deduplication, OPT_no_odr_deduplication, true); 98 Options.DoGarbageCollection = 99 Args.hasFlag(OPT_garbage_collection, OPT_no_garbage_collection, true); 100 Options.Verbose = Args.hasArg(OPT_verbose); 101 Options.Verify = Args.hasArg(OPT_verify); 102 103 if (opt::Arg *NumThreads = Args.getLastArg(OPT_threads)) 104 Options.NumThreads = atoi(NumThreads->getValue()); 105 else 106 Options.NumThreads = 0; // Use all available hardware threads 107 108 if (opt::Arg *Tombstone = Args.getLastArg(OPT_tombstone)) { 109 StringRef S = Tombstone->getValue(); 110 if (S == "bfd") 111 Options.Tombstone = TombstoneKind::BFD; 112 else if (S == "maxpc") 113 Options.Tombstone = TombstoneKind::MaxPC; 114 else if (S == "universal") 115 Options.Tombstone = TombstoneKind::Universal; 116 else if (S == "exec") 117 Options.Tombstone = TombstoneKind::Exec; 118 else 119 return createStringError( 120 std::errc::invalid_argument, 121 formatv("unknown tombstone value: '{0}'", S).str().c_str()); 122 } 123 124 if (Options.Verbose) { 125 if (Options.NumThreads != 1 && Args.hasArg(OPT_threads)) 126 warning("--num-threads set to 1 because verbose mode is specified"); 127 128 Options.NumThreads = 1; 129 } 130 131 if (Options.DoODRDeduplication && Args.hasArg(OPT_odr_deduplication) && 132 !Options.DoGarbageCollection) 133 return createStringError( 134 std::errc::invalid_argument, 135 "cannot use --odr-deduplication without --garbage-collection"); 136 137 if (Options.BuildSeparateDebugFile && Options.OutputFileName == "-") 138 return createStringError( 139 std::errc::invalid_argument, 140 "unable to write to stdout when --separate-debug-file specified"); 141 142 return Error::success(); 143 } 144 145 static Error setConfigToAddNewDebugSections(objcopy::ConfigManager &Config, 146 ObjectFile &ObjFile) { 147 // Add new debug sections. 148 for (SectionRef Sec : ObjFile.sections()) { 149 Expected<StringRef> SecName = Sec.getName(); 150 if (!SecName) 151 return SecName.takeError(); 152 153 if (isDebugSection(*SecName)) { 154 Expected<StringRef> SecData = Sec.getContents(); 155 if (!SecData) 156 return SecData.takeError(); 157 158 Config.Common.AddSection.emplace_back(objcopy::NewSectionInfo( 159 *SecName, MemoryBuffer::getMemBuffer(*SecData, *SecName, false))); 160 } 161 } 162 163 return Error::success(); 164 } 165 166 static Error verifyOutput(const Options &Opts) { 167 if (Opts.OutputFileName == "-") { 168 warning("verification skipped because writing to stdout"); 169 return Error::success(); 170 } 171 172 std::string FileName = Opts.BuildSeparateDebugFile 173 ? Opts.getSeparateDebugFileName() 174 : Opts.OutputFileName; 175 Expected<OwningBinary<Binary>> BinOrErr = createBinary(FileName); 176 if (!BinOrErr) 177 return createFileError(FileName, BinOrErr.takeError()); 178 179 if (BinOrErr->getBinary()->isObject()) { 180 if (ObjectFile *Obj = static_cast<ObjectFile *>(BinOrErr->getBinary())) { 181 verbose("Verifying DWARF...", Opts.Verbose); 182 std::unique_ptr<DWARFContext> DICtx = DWARFContext::create(*Obj); 183 DIDumpOptions DumpOpts; 184 if (!DICtx->verify(Opts.Verbose ? outs() : nulls(), 185 DumpOpts.noImplicitRecursion())) 186 return createFileError(FileName, 187 createError("output verification failed")); 188 189 return Error::success(); 190 } 191 } 192 193 // The file "FileName" was created by this utility in the previous steps 194 // (i.e. it is already known that it should pass the isObject check). 195 // If the createBinary() function does not return an error, the isObject 196 // check should also be successful. 197 llvm_unreachable( 198 formatv("tool unexpectedly did not emit a supported object file: '{0}'", 199 FileName) 200 .str() 201 .c_str()); 202 } 203 204 class raw_crc_ostream : public raw_ostream { 205 public: 206 explicit raw_crc_ostream(raw_ostream &O) : OS(O) { SetUnbuffered(); } 207 208 void reserveExtraSpace(uint64_t ExtraSize) override { 209 OS.reserveExtraSpace(ExtraSize); 210 } 211 212 uint32_t getCRC32() { return CRC32; } 213 214 protected: 215 raw_ostream &OS; 216 uint32_t CRC32 = 0; 217 218 /// See raw_ostream::write_impl. 219 void write_impl(const char *Ptr, size_t Size) override { 220 CRC32 = crc32( 221 CRC32, ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(Ptr), Size)); 222 OS.write(Ptr, Size); 223 } 224 225 /// Return the current position within the stream, not counting the bytes 226 /// currently in the buffer. 227 uint64_t current_pos() const override { return OS.tell(); } 228 }; 229 230 static Expected<uint32_t> saveSeparateDebugInfo(const Options &Opts, 231 ObjectFile &InputFile) { 232 objcopy::ConfigManager Config; 233 std::string OutputFilename = Opts.getSeparateDebugFileName(); 234 Config.Common.InputFilename = Opts.InputFileName; 235 Config.Common.OutputFilename = OutputFilename; 236 Config.Common.OnlyKeepDebug = true; 237 uint32_t WrittenFileCRC32 = 0; 238 239 if (Error Err = writeToOutput( 240 Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error { 241 raw_crc_ostream CRCBuffer(OutFile); 242 if (Error Err = objcopy::executeObjcopyOnBinary(Config, InputFile, 243 CRCBuffer)) 244 return Err; 245 246 WrittenFileCRC32 = CRCBuffer.getCRC32(); 247 return Error::success(); 248 })) 249 return std::move(Err); 250 251 return WrittenFileCRC32; 252 } 253 254 static Error saveNonDebugInfo(const Options &Opts, ObjectFile &InputFile, 255 uint32_t GnuDebugLinkCRC32) { 256 objcopy::ConfigManager Config; 257 Config.Common.InputFilename = Opts.InputFileName; 258 Config.Common.OutputFilename = Opts.OutputFileName; 259 Config.Common.StripDebug = true; 260 std::string SeparateDebugFileName = Opts.getSeparateDebugFileName(); 261 Config.Common.AddGnuDebugLink = sys::path::filename(SeparateDebugFileName); 262 Config.Common.GnuDebugLinkCRC32 = GnuDebugLinkCRC32; 263 264 if (Error Err = writeToOutput( 265 Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error { 266 if (Error Err = 267 objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile)) 268 return Err; 269 270 return Error::success(); 271 })) 272 return Err; 273 274 return Error::success(); 275 } 276 277 static Error splitDebugIntoSeparateFile(const Options &Opts, 278 ObjectFile &InputFile) { 279 Expected<uint32_t> SeparateDebugFileCRC32OrErr = 280 saveSeparateDebugInfo(Opts, InputFile); 281 if (!SeparateDebugFileCRC32OrErr) 282 return SeparateDebugFileCRC32OrErr.takeError(); 283 284 if (Error Err = 285 saveNonDebugInfo(Opts, InputFile, *SeparateDebugFileCRC32OrErr)) 286 return Err; 287 288 return Error::success(); 289 } 290 291 using DebugInfoBits = SmallString<10000>; 292 293 static Error addSectionsFromLinkedData(objcopy::ConfigManager &Config, 294 ObjectFile &InputFile, 295 DebugInfoBits &LinkedDebugInfoBits) { 296 if (isa<ELFObjectFile<ELF32LE>>(&InputFile)) { 297 Expected<ELFObjectFile<ELF32LE>> MemFile = ELFObjectFile<ELF32LE>::create( 298 MemoryBufferRef(LinkedDebugInfoBits, "")); 299 if (!MemFile) 300 return MemFile.takeError(); 301 302 if (Error Err = setConfigToAddNewDebugSections(Config, *MemFile)) 303 return Err; 304 } else if (isa<ELFObjectFile<ELF64LE>>(&InputFile)) { 305 Expected<ELFObjectFile<ELF64LE>> MemFile = ELFObjectFile<ELF64LE>::create( 306 MemoryBufferRef(LinkedDebugInfoBits, "")); 307 if (!MemFile) 308 return MemFile.takeError(); 309 310 if (Error Err = setConfigToAddNewDebugSections(Config, *MemFile)) 311 return Err; 312 } else if (isa<ELFObjectFile<ELF32BE>>(&InputFile)) { 313 Expected<ELFObjectFile<ELF32BE>> MemFile = ELFObjectFile<ELF32BE>::create( 314 MemoryBufferRef(LinkedDebugInfoBits, "")); 315 if (!MemFile) 316 return MemFile.takeError(); 317 318 if (Error Err = setConfigToAddNewDebugSections(Config, *MemFile)) 319 return Err; 320 } else if (isa<ELFObjectFile<ELF64BE>>(&InputFile)) { 321 Expected<ELFObjectFile<ELF64BE>> MemFile = ELFObjectFile<ELF64BE>::create( 322 MemoryBufferRef(LinkedDebugInfoBits, "")); 323 if (!MemFile) 324 return MemFile.takeError(); 325 326 if (Error Err = setConfigToAddNewDebugSections(Config, *MemFile)) 327 return Err; 328 } else 329 return createStringError(std::errc::invalid_argument, 330 "unsupported file format"); 331 332 return Error::success(); 333 } 334 335 static Expected<uint32_t> 336 saveSeparateLinkedDebugInfo(const Options &Opts, ObjectFile &InputFile, 337 DebugInfoBits LinkedDebugInfoBits) { 338 objcopy::ConfigManager Config; 339 std::string OutputFilename = Opts.getSeparateDebugFileName(); 340 Config.Common.InputFilename = Opts.InputFileName; 341 Config.Common.OutputFilename = OutputFilename; 342 Config.Common.StripDebug = true; 343 Config.Common.OnlyKeepDebug = true; 344 uint32_t WrittenFileCRC32 = 0; 345 346 if (Error Err = 347 addSectionsFromLinkedData(Config, InputFile, LinkedDebugInfoBits)) 348 return std::move(Err); 349 350 if (Error Err = writeToOutput( 351 Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error { 352 raw_crc_ostream CRCBuffer(OutFile); 353 354 if (Error Err = objcopy::executeObjcopyOnBinary(Config, InputFile, 355 CRCBuffer)) 356 return Err; 357 358 WrittenFileCRC32 = CRCBuffer.getCRC32(); 359 return Error::success(); 360 })) 361 return std::move(Err); 362 363 return WrittenFileCRC32; 364 } 365 366 static Error saveSingleLinkedDebugInfo(const Options &Opts, 367 ObjectFile &InputFile, 368 DebugInfoBits LinkedDebugInfoBits) { 369 objcopy::ConfigManager Config; 370 371 Config.Common.InputFilename = Opts.InputFileName; 372 Config.Common.OutputFilename = Opts.OutputFileName; 373 Config.Common.StripDebug = true; 374 if (Error Err = 375 addSectionsFromLinkedData(Config, InputFile, LinkedDebugInfoBits)) 376 return Err; 377 378 if (Error Err = writeToOutput( 379 Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error { 380 return objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile); 381 })) 382 return Err; 383 384 return Error::success(); 385 } 386 387 static Error saveLinkedDebugInfo(const Options &Opts, ObjectFile &InputFile, 388 DebugInfoBits LinkedDebugInfoBits) { 389 if (Opts.BuildSeparateDebugFile) { 390 Expected<uint32_t> SeparateDebugFileCRC32OrErr = 391 saveSeparateLinkedDebugInfo(Opts, InputFile, 392 std::move(LinkedDebugInfoBits)); 393 if (!SeparateDebugFileCRC32OrErr) 394 return SeparateDebugFileCRC32OrErr.takeError(); 395 396 if (Error Err = 397 saveNonDebugInfo(Opts, InputFile, *SeparateDebugFileCRC32OrErr)) 398 return Err; 399 } else { 400 if (Error Err = saveSingleLinkedDebugInfo(Opts, InputFile, 401 std::move(LinkedDebugInfoBits))) 402 return Err; 403 } 404 405 return Error::success(); 406 } 407 408 static Error saveCopyOfFile(const Options &Opts, ObjectFile &InputFile) { 409 objcopy::ConfigManager Config; 410 411 Config.Common.InputFilename = Opts.InputFileName; 412 Config.Common.OutputFilename = Opts.OutputFileName; 413 414 if (Error Err = writeToOutput( 415 Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error { 416 return objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile); 417 })) 418 return Err; 419 420 return Error::success(); 421 } 422 423 static Error applyCLOptions(const struct Options &Opts, ObjectFile &InputFile) { 424 if (Opts.DoGarbageCollection) { 425 verbose("Do garbage collection for debug info ...", Opts.Verbose); 426 427 DebugInfoBits LinkedDebugInfo; 428 raw_svector_ostream OutStream(LinkedDebugInfo); 429 430 if (Error Err = linkDebugInfo(InputFile, Opts, OutStream)) 431 return Err; 432 433 if (Error Err = 434 saveLinkedDebugInfo(Opts, InputFile, std::move(LinkedDebugInfo))) 435 return Err; 436 437 return Error::success(); 438 } else if (Opts.BuildSeparateDebugFile) { 439 if (Error Err = splitDebugIntoSeparateFile(Opts, InputFile)) 440 return Err; 441 } else { 442 if (Error Err = saveCopyOfFile(Opts, InputFile)) 443 return Err; 444 } 445 446 return Error::success(); 447 } 448 449 } // end of namespace dwarfutil 450 } // end of namespace llvm 451 452 int main(int Argc, char const *Argv[]) { 453 using namespace dwarfutil; 454 455 InitLLVM X(Argc, Argv); 456 ToolName = Argv[0]; 457 458 // Parse arguments. 459 DwarfutilOptTable T; 460 unsigned MAI; 461 unsigned MAC; 462 ArrayRef<const char *> ArgsArr = makeArrayRef(Argv + 1, Argc - 1); 463 opt::InputArgList Args = T.ParseArgs(ArgsArr, MAI, MAC); 464 465 if (Args.hasArg(OPT_help) || Args.size() == 0) { 466 T.printHelp( 467 outs(), (ToolName + " [options] <input file> <output file>").c_str(), 468 "llvm-dwarfutil is a tool to copy and manipulate debug info", false); 469 return EXIT_SUCCESS; 470 } 471 472 if (Args.hasArg(OPT_version)) { 473 cl::PrintVersionMessage(); 474 return EXIT_SUCCESS; 475 } 476 477 Options Opts; 478 if (Error Err = validateAndSetOptions(Args, Opts)) 479 error(std::move(Err), dwarfutil::ToolName); 480 481 InitializeAllTargets(); 482 InitializeAllTargetMCs(); 483 InitializeAllTargetInfos(); 484 InitializeAllAsmPrinters(); 485 486 ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr = 487 MemoryBuffer::getFileOrSTDIN(Opts.InputFileName); 488 if (BuffOrErr.getError()) 489 error(createFileError(Opts.InputFileName, BuffOrErr.getError())); 490 491 Expected<std::unique_ptr<Binary>> BinOrErr = 492 object::createBinary(**BuffOrErr); 493 if (!BinOrErr) 494 error(createFileError(Opts.InputFileName, BinOrErr.takeError())); 495 496 Expected<FilePermissionsApplier> PermsApplierOrErr = 497 FilePermissionsApplier::create(Opts.InputFileName); 498 if (!PermsApplierOrErr) 499 error(createFileError(Opts.InputFileName, PermsApplierOrErr.takeError())); 500 501 if (!(*BinOrErr)->isObject()) 502 error(createFileError(Opts.InputFileName, 503 createError("unsupported input file"))); 504 505 if (Error Err = 506 applyCLOptions(Opts, *static_cast<ObjectFile *>((*BinOrErr).get()))) 507 error(createFileError(Opts.InputFileName, std::move(Err))); 508 509 BinOrErr->reset(); 510 BuffOrErr->reset(); 511 512 if (Error Err = PermsApplierOrErr->apply(Opts.OutputFileName)) 513 error(std::move(Err)); 514 515 if (Opts.BuildSeparateDebugFile) 516 if (Error Err = PermsApplierOrErr->apply(Opts.getSeparateDebugFileName())) 517 error(std::move(Err)); 518 519 if (Opts.Verify) { 520 if (Error Err = verifyOutput(Opts)) 521 error(std::move(Err)); 522 } 523 524 return EXIT_SUCCESS; 525 } 526