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