1 //=== llvm-dwarfutil.cpp --------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "DebugInfoLinker.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"
31 using namespace object
;
35 OPT_INVALID
= 0, // This is not an option ID.
36 #define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
37 #include "Options.inc"
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"
48 using namespace llvm::opt
;
49 static constexpr opt::OptTable::Info InfoTable
[] = {
50 #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
51 #include "Options.inc"
55 class DwarfutilOptTable
: public opt::GenericOptTable
{
57 DwarfutilOptTable() : opt::GenericOptTable(InfoTable
) {}
66 static mc::RegisterMCTargetOptionsFlags MOF
;
68 static Error
validateAndSetOptions(opt::InputArgList
&Args
, Options
&Options
) {
69 auto UnknownArgs
= Args
.filtered(OPT_UNKNOWN
);
70 if (!UnknownArgs
.empty())
71 return createStringError(
72 std::errc::invalid_argument
,
73 formatv("unknown option: {0}", (*UnknownArgs
.begin())->getSpelling())
77 std::vector
<std::string
> InputFiles
= Args
.getAllArgValues(OPT_INPUT
);
78 if (InputFiles
.size() != 2)
79 return createStringError(
80 std::errc::invalid_argument
,
81 formatv("exactly two positional arguments expected, {0} provided",
86 Options
.InputFileName
= InputFiles
[0];
87 Options
.OutputFileName
= InputFiles
[1];
89 Options
.BuildSeparateDebugFile
=
90 Args
.hasFlag(OPT_separate_debug_file
, OPT_no_separate_debug_file
, false);
91 Options
.DoODRDeduplication
=
92 Args
.hasFlag(OPT_odr_deduplication
, OPT_no_odr_deduplication
, true);
93 Options
.DoGarbageCollection
=
94 Args
.hasFlag(OPT_garbage_collection
, OPT_no_garbage_collection
, true);
95 Options
.Verbose
= Args
.hasArg(OPT_verbose
);
96 Options
.Verify
= Args
.hasArg(OPT_verify
);
98 if (opt::Arg
*NumThreads
= Args
.getLastArg(OPT_threads
))
99 Options
.NumThreads
= atoi(NumThreads
->getValue());
101 Options
.NumThreads
= 0; // Use all available hardware threads
103 if (opt::Arg
*Tombstone
= Args
.getLastArg(OPT_tombstone
)) {
104 StringRef S
= Tombstone
->getValue();
106 Options
.Tombstone
= TombstoneKind::BFD
;
107 else if (S
== "maxpc")
108 Options
.Tombstone
= TombstoneKind::MaxPC
;
109 else if (S
== "universal")
110 Options
.Tombstone
= TombstoneKind::Universal
;
111 else if (S
== "exec")
112 Options
.Tombstone
= TombstoneKind::Exec
;
114 return createStringError(
115 std::errc::invalid_argument
,
116 formatv("unknown tombstone value: '{0}'", S
).str().c_str());
119 if (opt::Arg
*LinkerKind
= Args
.getLastArg(OPT_linker
)) {
120 StringRef S
= LinkerKind
->getValue();
122 Options
.UseLLVMDWARFLinker
= false;
123 else if (S
== "llvm")
124 Options
.UseLLVMDWARFLinker
= true;
126 return createStringError(
127 std::errc::invalid_argument
,
128 formatv("unknown linker kind value: '{0}'", S
).str().c_str());
131 if (opt::Arg
*BuildAccelerator
= Args
.getLastArg(OPT_build_accelerator
)) {
132 StringRef S
= BuildAccelerator
->getValue();
135 Options
.AccelTableKind
= DwarfUtilAccelKind::None
;
136 else if (S
== "DWARF")
137 Options
.AccelTableKind
= DwarfUtilAccelKind::DWARF
;
139 return createStringError(
140 std::errc::invalid_argument
,
141 formatv("unknown build-accelerator value: '{0}'", S
).str().c_str());
144 if (Options
.Verbose
) {
145 if (Options
.NumThreads
!= 1 && Args
.hasArg(OPT_threads
))
146 warning("--num-threads set to 1 because verbose mode is specified");
148 Options
.NumThreads
= 1;
151 if (Options
.DoODRDeduplication
&& Args
.hasArg(OPT_odr_deduplication
) &&
152 !Options
.DoGarbageCollection
)
153 return createStringError(
154 std::errc::invalid_argument
,
155 "cannot use --odr-deduplication without --garbage-collection");
157 if (Options
.BuildSeparateDebugFile
&& Options
.OutputFileName
== "-")
158 return createStringError(
159 std::errc::invalid_argument
,
160 "unable to write to stdout when --separate-debug-file specified");
162 return Error::success();
165 static Error
setConfigToAddNewDebugSections(objcopy::ConfigManager
&Config
,
166 ObjectFile
&ObjFile
) {
167 // Add new debug sections.
168 for (SectionRef Sec
: ObjFile
.sections()) {
169 Expected
<StringRef
> SecName
= Sec
.getName();
171 return SecName
.takeError();
173 if (isDebugSection(*SecName
)) {
174 Expected
<StringRef
> SecData
= Sec
.getContents();
176 return SecData
.takeError();
178 Config
.Common
.AddSection
.emplace_back(objcopy::NewSectionInfo(
179 *SecName
, MemoryBuffer::getMemBuffer(*SecData
, *SecName
, false)));
183 return Error::success();
186 static Error
verifyOutput(const Options
&Opts
) {
187 if (Opts
.OutputFileName
== "-") {
188 warning("verification skipped because writing to stdout");
189 return Error::success();
192 std::string FileName
= Opts
.BuildSeparateDebugFile
193 ? Opts
.getSeparateDebugFileName()
194 : Opts
.OutputFileName
;
195 Expected
<OwningBinary
<Binary
>> BinOrErr
= createBinary(FileName
);
197 return createFileError(FileName
, BinOrErr
.takeError());
199 if (BinOrErr
->getBinary()->isObject()) {
200 if (ObjectFile
*Obj
= static_cast<ObjectFile
*>(BinOrErr
->getBinary())) {
201 verbose("Verifying DWARF...", Opts
.Verbose
);
202 std::unique_ptr
<DWARFContext
> DICtx
= DWARFContext::create(*Obj
);
203 DIDumpOptions DumpOpts
;
204 if (!DICtx
->verify(Opts
.Verbose
? outs() : nulls(),
205 DumpOpts
.noImplicitRecursion()))
206 return createFileError(FileName
,
207 createError("output verification failed"));
209 return Error::success();
213 // The file "FileName" was created by this utility in the previous steps
214 // (i.e. it is already known that it should pass the isObject check).
215 // If the createBinary() function does not return an error, the isObject
216 // check should also be successful.
218 formatv("tool unexpectedly did not emit a supported object file: '{0}'",
224 class raw_crc_ostream
: public raw_ostream
{
226 explicit raw_crc_ostream(raw_ostream
&O
) : OS(O
) { SetUnbuffered(); }
228 void reserveExtraSpace(uint64_t ExtraSize
) override
{
229 OS
.reserveExtraSpace(ExtraSize
);
232 uint32_t getCRC32() { return CRC32
; }
238 /// See raw_ostream::write_impl.
239 void write_impl(const char *Ptr
, size_t Size
) override
{
241 CRC32
, ArrayRef
<uint8_t>(reinterpret_cast<const uint8_t *>(Ptr
), Size
));
245 /// Return the current position within the stream, not counting the bytes
246 /// currently in the buffer.
247 uint64_t current_pos() const override
{ return OS
.tell(); }
250 static Expected
<uint32_t> saveSeparateDebugInfo(const Options
&Opts
,
251 ObjectFile
&InputFile
) {
252 objcopy::ConfigManager Config
;
253 std::string OutputFilename
= Opts
.getSeparateDebugFileName();
254 Config
.Common
.InputFilename
= Opts
.InputFileName
;
255 Config
.Common
.OutputFilename
= OutputFilename
;
256 Config
.Common
.OnlyKeepDebug
= true;
257 uint32_t WrittenFileCRC32
= 0;
259 if (Error Err
= writeToOutput(
260 Config
.Common
.OutputFilename
, [&](raw_ostream
&OutFile
) -> Error
{
261 raw_crc_ostream
CRCBuffer(OutFile
);
262 if (Error Err
= objcopy::executeObjcopyOnBinary(Config
, InputFile
,
266 WrittenFileCRC32
= CRCBuffer
.getCRC32();
267 return Error::success();
269 return std::move(Err
);
271 return WrittenFileCRC32
;
274 static Error
saveNonDebugInfo(const Options
&Opts
, ObjectFile
&InputFile
,
275 uint32_t GnuDebugLinkCRC32
) {
276 objcopy::ConfigManager Config
;
277 Config
.Common
.InputFilename
= Opts
.InputFileName
;
278 Config
.Common
.OutputFilename
= Opts
.OutputFileName
;
279 Config
.Common
.StripDebug
= true;
280 std::string SeparateDebugFileName
= Opts
.getSeparateDebugFileName();
281 Config
.Common
.AddGnuDebugLink
= sys::path::filename(SeparateDebugFileName
);
282 Config
.Common
.GnuDebugLinkCRC32
= GnuDebugLinkCRC32
;
284 if (Error Err
= writeToOutput(
285 Config
.Common
.OutputFilename
, [&](raw_ostream
&OutFile
) -> Error
{
287 objcopy::executeObjcopyOnBinary(Config
, InputFile
, OutFile
))
290 return Error::success();
294 return Error::success();
297 static Error
splitDebugIntoSeparateFile(const Options
&Opts
,
298 ObjectFile
&InputFile
) {
299 Expected
<uint32_t> SeparateDebugFileCRC32OrErr
=
300 saveSeparateDebugInfo(Opts
, InputFile
);
301 if (!SeparateDebugFileCRC32OrErr
)
302 return SeparateDebugFileCRC32OrErr
.takeError();
305 saveNonDebugInfo(Opts
, InputFile
, *SeparateDebugFileCRC32OrErr
))
308 return Error::success();
311 using DebugInfoBits
= SmallString
<10000>;
313 static Error
addSectionsFromLinkedData(objcopy::ConfigManager
&Config
,
314 ObjectFile
&InputFile
,
315 DebugInfoBits
&LinkedDebugInfoBits
) {
316 if (isa
<ELFObjectFile
<ELF32LE
>>(&InputFile
)) {
317 Expected
<ELFObjectFile
<ELF32LE
>> MemFile
= ELFObjectFile
<ELF32LE
>::create(
318 MemoryBufferRef(LinkedDebugInfoBits
, ""));
320 return MemFile
.takeError();
322 if (Error Err
= setConfigToAddNewDebugSections(Config
, *MemFile
))
324 } else if (isa
<ELFObjectFile
<ELF64LE
>>(&InputFile
)) {
325 Expected
<ELFObjectFile
<ELF64LE
>> MemFile
= ELFObjectFile
<ELF64LE
>::create(
326 MemoryBufferRef(LinkedDebugInfoBits
, ""));
328 return MemFile
.takeError();
330 if (Error Err
= setConfigToAddNewDebugSections(Config
, *MemFile
))
332 } else if (isa
<ELFObjectFile
<ELF32BE
>>(&InputFile
)) {
333 Expected
<ELFObjectFile
<ELF32BE
>> MemFile
= ELFObjectFile
<ELF32BE
>::create(
334 MemoryBufferRef(LinkedDebugInfoBits
, ""));
336 return MemFile
.takeError();
338 if (Error Err
= setConfigToAddNewDebugSections(Config
, *MemFile
))
340 } else if (isa
<ELFObjectFile
<ELF64BE
>>(&InputFile
)) {
341 Expected
<ELFObjectFile
<ELF64BE
>> MemFile
= ELFObjectFile
<ELF64BE
>::create(
342 MemoryBufferRef(LinkedDebugInfoBits
, ""));
344 return MemFile
.takeError();
346 if (Error Err
= setConfigToAddNewDebugSections(Config
, *MemFile
))
349 return createStringError(std::errc::invalid_argument
,
350 "unsupported file format");
352 return Error::success();
355 static Expected
<uint32_t>
356 saveSeparateLinkedDebugInfo(const Options
&Opts
, ObjectFile
&InputFile
,
357 DebugInfoBits LinkedDebugInfoBits
) {
358 objcopy::ConfigManager Config
;
359 std::string OutputFilename
= Opts
.getSeparateDebugFileName();
360 Config
.Common
.InputFilename
= Opts
.InputFileName
;
361 Config
.Common
.OutputFilename
= OutputFilename
;
362 Config
.Common
.StripDebug
= true;
363 Config
.Common
.OnlyKeepDebug
= true;
364 uint32_t WrittenFileCRC32
= 0;
367 addSectionsFromLinkedData(Config
, InputFile
, LinkedDebugInfoBits
))
368 return std::move(Err
);
370 if (Error Err
= writeToOutput(
371 Config
.Common
.OutputFilename
, [&](raw_ostream
&OutFile
) -> Error
{
372 raw_crc_ostream
CRCBuffer(OutFile
);
374 if (Error Err
= objcopy::executeObjcopyOnBinary(Config
, InputFile
,
378 WrittenFileCRC32
= CRCBuffer
.getCRC32();
379 return Error::success();
381 return std::move(Err
);
383 return WrittenFileCRC32
;
386 static Error
saveSingleLinkedDebugInfo(const Options
&Opts
,
387 ObjectFile
&InputFile
,
388 DebugInfoBits LinkedDebugInfoBits
) {
389 objcopy::ConfigManager Config
;
391 Config
.Common
.InputFilename
= Opts
.InputFileName
;
392 Config
.Common
.OutputFilename
= Opts
.OutputFileName
;
393 Config
.Common
.StripDebug
= true;
395 addSectionsFromLinkedData(Config
, InputFile
, LinkedDebugInfoBits
))
398 if (Error Err
= writeToOutput(
399 Config
.Common
.OutputFilename
, [&](raw_ostream
&OutFile
) -> Error
{
400 return objcopy::executeObjcopyOnBinary(Config
, InputFile
, OutFile
);
404 return Error::success();
407 static Error
saveLinkedDebugInfo(const Options
&Opts
, ObjectFile
&InputFile
,
408 DebugInfoBits LinkedDebugInfoBits
) {
409 if (Opts
.BuildSeparateDebugFile
) {
410 Expected
<uint32_t> SeparateDebugFileCRC32OrErr
=
411 saveSeparateLinkedDebugInfo(Opts
, InputFile
,
412 std::move(LinkedDebugInfoBits
));
413 if (!SeparateDebugFileCRC32OrErr
)
414 return SeparateDebugFileCRC32OrErr
.takeError();
417 saveNonDebugInfo(Opts
, InputFile
, *SeparateDebugFileCRC32OrErr
))
420 if (Error Err
= saveSingleLinkedDebugInfo(Opts
, InputFile
,
421 std::move(LinkedDebugInfoBits
)))
425 return Error::success();
428 static Error
saveCopyOfFile(const Options
&Opts
, ObjectFile
&InputFile
) {
429 objcopy::ConfigManager Config
;
431 Config
.Common
.InputFilename
= Opts
.InputFileName
;
432 Config
.Common
.OutputFilename
= Opts
.OutputFileName
;
434 if (Error Err
= writeToOutput(
435 Config
.Common
.OutputFilename
, [&](raw_ostream
&OutFile
) -> Error
{
436 return objcopy::executeObjcopyOnBinary(Config
, InputFile
, OutFile
);
440 return Error::success();
443 static Error
applyCLOptions(const struct Options
&Opts
, ObjectFile
&InputFile
) {
444 if (Opts
.DoGarbageCollection
||
445 Opts
.AccelTableKind
!= DwarfUtilAccelKind::None
) {
446 verbose("Do debug info linking...", Opts
.Verbose
);
448 DebugInfoBits LinkedDebugInfo
;
449 raw_svector_ostream
OutStream(LinkedDebugInfo
);
451 if (Error Err
= linkDebugInfo(InputFile
, Opts
, OutStream
))
455 saveLinkedDebugInfo(Opts
, InputFile
, std::move(LinkedDebugInfo
)))
458 return Error::success();
459 } else if (Opts
.BuildSeparateDebugFile
) {
460 if (Error Err
= splitDebugIntoSeparateFile(Opts
, InputFile
))
463 if (Error Err
= saveCopyOfFile(Opts
, InputFile
))
467 return Error::success();
470 } // end of namespace dwarfutil
471 } // end of namespace llvm
473 int main(int Argc
, char const *Argv
[]) {
474 using namespace dwarfutil
;
476 InitLLVM
X(Argc
, Argv
);
483 ArrayRef
<const char *> ArgsArr
= ArrayRef(Argv
+ 1, Argc
- 1);
484 opt::InputArgList Args
= T
.ParseArgs(ArgsArr
, MAI
, MAC
);
486 if (Args
.hasArg(OPT_help
) || Args
.size() == 0) {
488 outs(), (ToolName
+ " [options] <input file> <output file>").c_str(),
489 "llvm-dwarfutil is a tool to copy and manipulate debug info", false);
493 if (Args
.hasArg(OPT_version
)) {
494 cl::PrintVersionMessage();
499 if (Error Err
= validateAndSetOptions(Args
, Opts
))
500 error(std::move(Err
), dwarfutil::ToolName
);
502 InitializeAllTargets();
503 InitializeAllTargetMCs();
504 InitializeAllTargetInfos();
505 InitializeAllAsmPrinters();
507 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> BuffOrErr
=
508 MemoryBuffer::getFileOrSTDIN(Opts
.InputFileName
);
509 if (BuffOrErr
.getError())
510 error(createFileError(Opts
.InputFileName
, BuffOrErr
.getError()));
512 Expected
<std::unique_ptr
<Binary
>> BinOrErr
=
513 object::createBinary(**BuffOrErr
);
515 error(createFileError(Opts
.InputFileName
, BinOrErr
.takeError()));
517 Expected
<FilePermissionsApplier
> PermsApplierOrErr
=
518 FilePermissionsApplier::create(Opts
.InputFileName
);
519 if (!PermsApplierOrErr
)
520 error(createFileError(Opts
.InputFileName
, PermsApplierOrErr
.takeError()));
522 if (!(*BinOrErr
)->isObject())
523 error(createFileError(Opts
.InputFileName
,
524 createError("unsupported input file")));
527 applyCLOptions(Opts
, *static_cast<ObjectFile
*>((*BinOrErr
).get())))
528 error(createFileError(Opts
.InputFileName
, std::move(Err
)));
533 if (Error Err
= PermsApplierOrErr
->apply(Opts
.OutputFileName
))
534 error(std::move(Err
));
536 if (Opts
.BuildSeparateDebugFile
)
537 if (Error Err
= PermsApplierOrErr
->apply(Opts
.getSeparateDebugFileName()))
538 error(std::move(Err
));
541 if (Error Err
= verifyOutput(Opts
))
542 error(std::move(Err
));