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