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