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