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