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