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