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