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