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