xref: /freebsd-src/contrib/llvm-project/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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 
43*bdd1243dSDimitry Andric #define PREFIX(NAME, VALUE)                                                    \
44*bdd1243dSDimitry Andric   static constexpr StringLiteral NAME##_init[] = VALUE;                        \
45*bdd1243dSDimitry Andric   static constexpr ArrayRef<StringLiteral> NAME(NAME##_init,                   \
46*bdd1243dSDimitry Andric                                                 std::size(NAME##_init) - 1);
47fcaf7f86SDimitry Andric #include "Options.inc"
48fcaf7f86SDimitry Andric #undef PREFIX
49fcaf7f86SDimitry Andric 
50*bdd1243dSDimitry 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 
62*bdd1243dSDimitry Andric class DwarfutilOptTable : public opt::GenericOptTable {
63fcaf7f86SDimitry Andric public:
64*bdd1243dSDimitry 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*bdd1243dSDimitry Andric   if (opt::Arg *BuildAccelerator = Args.getLastArg(OPT_build_accelerator)) {
127*bdd1243dSDimitry Andric     StringRef S = BuildAccelerator->getValue();
128*bdd1243dSDimitry Andric 
129*bdd1243dSDimitry Andric     if (S == "none")
130*bdd1243dSDimitry Andric       Options.AccelTableKind = DwarfUtilAccelKind::None;
131*bdd1243dSDimitry Andric     else if (S == "DWARF")
132*bdd1243dSDimitry Andric       Options.AccelTableKind = DwarfUtilAccelKind::DWARF;
133*bdd1243dSDimitry Andric     else
134*bdd1243dSDimitry Andric       return createStringError(
135*bdd1243dSDimitry Andric           std::errc::invalid_argument,
136*bdd1243dSDimitry Andric           formatv("unknown build-accelerator value: '{0}'", S).str().c_str());
137*bdd1243dSDimitry Andric   }
138*bdd1243dSDimitry Andric 
139fcaf7f86SDimitry Andric   if (Options.Verbose) {
140fcaf7f86SDimitry Andric     if (Options.NumThreads != 1 && Args.hasArg(OPT_threads))
141fcaf7f86SDimitry Andric       warning("--num-threads set to 1 because verbose mode is specified");
142fcaf7f86SDimitry Andric 
143fcaf7f86SDimitry Andric     Options.NumThreads = 1;
144fcaf7f86SDimitry Andric   }
145fcaf7f86SDimitry Andric 
146fcaf7f86SDimitry Andric   if (Options.DoODRDeduplication && Args.hasArg(OPT_odr_deduplication) &&
147fcaf7f86SDimitry Andric       !Options.DoGarbageCollection)
148fcaf7f86SDimitry Andric     return createStringError(
149fcaf7f86SDimitry Andric         std::errc::invalid_argument,
150fcaf7f86SDimitry Andric         "cannot use --odr-deduplication without --garbage-collection");
151fcaf7f86SDimitry Andric 
152fcaf7f86SDimitry Andric   if (Options.BuildSeparateDebugFile && Options.OutputFileName == "-")
153fcaf7f86SDimitry Andric     return createStringError(
154fcaf7f86SDimitry Andric         std::errc::invalid_argument,
155fcaf7f86SDimitry Andric         "unable to write to stdout when --separate-debug-file specified");
156fcaf7f86SDimitry Andric 
157fcaf7f86SDimitry Andric   return Error::success();
158fcaf7f86SDimitry Andric }
159fcaf7f86SDimitry Andric 
160fcaf7f86SDimitry Andric static Error setConfigToAddNewDebugSections(objcopy::ConfigManager &Config,
161fcaf7f86SDimitry Andric                                             ObjectFile &ObjFile) {
162fcaf7f86SDimitry Andric   // Add new debug sections.
163fcaf7f86SDimitry Andric   for (SectionRef Sec : ObjFile.sections()) {
164fcaf7f86SDimitry Andric     Expected<StringRef> SecName = Sec.getName();
165fcaf7f86SDimitry Andric     if (!SecName)
166fcaf7f86SDimitry Andric       return SecName.takeError();
167fcaf7f86SDimitry Andric 
168fcaf7f86SDimitry Andric     if (isDebugSection(*SecName)) {
169fcaf7f86SDimitry Andric       Expected<StringRef> SecData = Sec.getContents();
170fcaf7f86SDimitry Andric       if (!SecData)
171fcaf7f86SDimitry Andric         return SecData.takeError();
172fcaf7f86SDimitry Andric 
173fcaf7f86SDimitry Andric       Config.Common.AddSection.emplace_back(objcopy::NewSectionInfo(
174fcaf7f86SDimitry Andric           *SecName, MemoryBuffer::getMemBuffer(*SecData, *SecName, false)));
175fcaf7f86SDimitry Andric     }
176fcaf7f86SDimitry Andric   }
177fcaf7f86SDimitry Andric 
178fcaf7f86SDimitry Andric   return Error::success();
179fcaf7f86SDimitry Andric }
180fcaf7f86SDimitry Andric 
181fcaf7f86SDimitry Andric static Error verifyOutput(const Options &Opts) {
182fcaf7f86SDimitry Andric   if (Opts.OutputFileName == "-") {
183fcaf7f86SDimitry Andric     warning("verification skipped because writing to stdout");
184fcaf7f86SDimitry Andric     return Error::success();
185fcaf7f86SDimitry Andric   }
186fcaf7f86SDimitry Andric 
187fcaf7f86SDimitry Andric   std::string FileName = Opts.BuildSeparateDebugFile
188fcaf7f86SDimitry Andric                              ? Opts.getSeparateDebugFileName()
189fcaf7f86SDimitry Andric                              : Opts.OutputFileName;
190fcaf7f86SDimitry Andric   Expected<OwningBinary<Binary>> BinOrErr = createBinary(FileName);
191fcaf7f86SDimitry Andric   if (!BinOrErr)
192fcaf7f86SDimitry Andric     return createFileError(FileName, BinOrErr.takeError());
193fcaf7f86SDimitry Andric 
194fcaf7f86SDimitry Andric   if (BinOrErr->getBinary()->isObject()) {
195fcaf7f86SDimitry Andric     if (ObjectFile *Obj = static_cast<ObjectFile *>(BinOrErr->getBinary())) {
196fcaf7f86SDimitry Andric       verbose("Verifying DWARF...", Opts.Verbose);
197fcaf7f86SDimitry Andric       std::unique_ptr<DWARFContext> DICtx = DWARFContext::create(*Obj);
198fcaf7f86SDimitry Andric       DIDumpOptions DumpOpts;
199fcaf7f86SDimitry Andric       if (!DICtx->verify(Opts.Verbose ? outs() : nulls(),
200fcaf7f86SDimitry Andric                          DumpOpts.noImplicitRecursion()))
201fcaf7f86SDimitry Andric         return createFileError(FileName,
202fcaf7f86SDimitry Andric                                createError("output verification failed"));
203fcaf7f86SDimitry Andric 
204fcaf7f86SDimitry Andric       return Error::success();
205fcaf7f86SDimitry Andric     }
206fcaf7f86SDimitry Andric   }
207fcaf7f86SDimitry Andric 
208fcaf7f86SDimitry Andric   // The file "FileName" was created by this utility in the previous steps
209fcaf7f86SDimitry Andric   // (i.e. it is already known that it should pass the isObject check).
210fcaf7f86SDimitry Andric   // If the createBinary() function does not return an error, the isObject
211fcaf7f86SDimitry Andric   // check should also be successful.
212fcaf7f86SDimitry Andric   llvm_unreachable(
213fcaf7f86SDimitry Andric       formatv("tool unexpectedly did not emit a supported object file: '{0}'",
214fcaf7f86SDimitry Andric               FileName)
215fcaf7f86SDimitry Andric           .str()
216fcaf7f86SDimitry Andric           .c_str());
217fcaf7f86SDimitry Andric }
218fcaf7f86SDimitry Andric 
219fcaf7f86SDimitry Andric class raw_crc_ostream : public raw_ostream {
220fcaf7f86SDimitry Andric public:
221fcaf7f86SDimitry Andric   explicit raw_crc_ostream(raw_ostream &O) : OS(O) { SetUnbuffered(); }
222fcaf7f86SDimitry Andric 
223fcaf7f86SDimitry Andric   void reserveExtraSpace(uint64_t ExtraSize) override {
224fcaf7f86SDimitry Andric     OS.reserveExtraSpace(ExtraSize);
225fcaf7f86SDimitry Andric   }
226fcaf7f86SDimitry Andric 
227fcaf7f86SDimitry Andric   uint32_t getCRC32() { return CRC32; }
228fcaf7f86SDimitry Andric 
229fcaf7f86SDimitry Andric protected:
230fcaf7f86SDimitry Andric   raw_ostream &OS;
231fcaf7f86SDimitry Andric   uint32_t CRC32 = 0;
232fcaf7f86SDimitry Andric 
233fcaf7f86SDimitry Andric   /// See raw_ostream::write_impl.
234fcaf7f86SDimitry Andric   void write_impl(const char *Ptr, size_t Size) override {
235fcaf7f86SDimitry Andric     CRC32 = crc32(
236fcaf7f86SDimitry Andric         CRC32, ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(Ptr), Size));
237fcaf7f86SDimitry Andric     OS.write(Ptr, Size);
238fcaf7f86SDimitry Andric   }
239fcaf7f86SDimitry Andric 
240fcaf7f86SDimitry Andric   /// Return the current position within the stream, not counting the bytes
241fcaf7f86SDimitry Andric   /// currently in the buffer.
242fcaf7f86SDimitry Andric   uint64_t current_pos() const override { return OS.tell(); }
243fcaf7f86SDimitry Andric };
244fcaf7f86SDimitry Andric 
245fcaf7f86SDimitry Andric static Expected<uint32_t> saveSeparateDebugInfo(const Options &Opts,
246fcaf7f86SDimitry Andric                                                 ObjectFile &InputFile) {
247fcaf7f86SDimitry Andric   objcopy::ConfigManager Config;
248fcaf7f86SDimitry Andric   std::string OutputFilename = Opts.getSeparateDebugFileName();
249fcaf7f86SDimitry Andric   Config.Common.InputFilename = Opts.InputFileName;
250fcaf7f86SDimitry Andric   Config.Common.OutputFilename = OutputFilename;
251fcaf7f86SDimitry Andric   Config.Common.OnlyKeepDebug = true;
252fcaf7f86SDimitry Andric   uint32_t WrittenFileCRC32 = 0;
253fcaf7f86SDimitry Andric 
254fcaf7f86SDimitry Andric   if (Error Err = writeToOutput(
255fcaf7f86SDimitry Andric           Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error {
256fcaf7f86SDimitry Andric             raw_crc_ostream CRCBuffer(OutFile);
257fcaf7f86SDimitry Andric             if (Error Err = objcopy::executeObjcopyOnBinary(Config, InputFile,
258fcaf7f86SDimitry Andric                                                             CRCBuffer))
259fcaf7f86SDimitry Andric               return Err;
260fcaf7f86SDimitry Andric 
261fcaf7f86SDimitry Andric             WrittenFileCRC32 = CRCBuffer.getCRC32();
262fcaf7f86SDimitry Andric             return Error::success();
263fcaf7f86SDimitry Andric           }))
264fcaf7f86SDimitry Andric     return std::move(Err);
265fcaf7f86SDimitry Andric 
266fcaf7f86SDimitry Andric   return WrittenFileCRC32;
267fcaf7f86SDimitry Andric }
268fcaf7f86SDimitry Andric 
269fcaf7f86SDimitry Andric static Error saveNonDebugInfo(const Options &Opts, ObjectFile &InputFile,
270fcaf7f86SDimitry Andric                               uint32_t GnuDebugLinkCRC32) {
271fcaf7f86SDimitry Andric   objcopy::ConfigManager Config;
272fcaf7f86SDimitry Andric   Config.Common.InputFilename = Opts.InputFileName;
273fcaf7f86SDimitry Andric   Config.Common.OutputFilename = Opts.OutputFileName;
274fcaf7f86SDimitry Andric   Config.Common.StripDebug = true;
275fcaf7f86SDimitry Andric   std::string SeparateDebugFileName = Opts.getSeparateDebugFileName();
276fcaf7f86SDimitry Andric   Config.Common.AddGnuDebugLink = sys::path::filename(SeparateDebugFileName);
277fcaf7f86SDimitry Andric   Config.Common.GnuDebugLinkCRC32 = GnuDebugLinkCRC32;
278fcaf7f86SDimitry Andric 
279fcaf7f86SDimitry Andric   if (Error Err = writeToOutput(
280fcaf7f86SDimitry Andric           Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error {
281fcaf7f86SDimitry Andric             if (Error Err =
282fcaf7f86SDimitry Andric                     objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile))
283fcaf7f86SDimitry Andric               return Err;
284fcaf7f86SDimitry Andric 
285fcaf7f86SDimitry Andric             return Error::success();
286fcaf7f86SDimitry Andric           }))
287fcaf7f86SDimitry Andric     return Err;
288fcaf7f86SDimitry Andric 
289fcaf7f86SDimitry Andric   return Error::success();
290fcaf7f86SDimitry Andric }
291fcaf7f86SDimitry Andric 
292fcaf7f86SDimitry Andric static Error splitDebugIntoSeparateFile(const Options &Opts,
293fcaf7f86SDimitry Andric                                         ObjectFile &InputFile) {
294fcaf7f86SDimitry Andric   Expected<uint32_t> SeparateDebugFileCRC32OrErr =
295fcaf7f86SDimitry Andric       saveSeparateDebugInfo(Opts, InputFile);
296fcaf7f86SDimitry Andric   if (!SeparateDebugFileCRC32OrErr)
297fcaf7f86SDimitry Andric     return SeparateDebugFileCRC32OrErr.takeError();
298fcaf7f86SDimitry Andric 
299fcaf7f86SDimitry Andric   if (Error Err =
300fcaf7f86SDimitry Andric           saveNonDebugInfo(Opts, InputFile, *SeparateDebugFileCRC32OrErr))
301fcaf7f86SDimitry Andric     return Err;
302fcaf7f86SDimitry Andric 
303fcaf7f86SDimitry Andric   return Error::success();
304fcaf7f86SDimitry Andric }
305fcaf7f86SDimitry Andric 
306fcaf7f86SDimitry Andric using DebugInfoBits = SmallString<10000>;
307fcaf7f86SDimitry Andric 
308fcaf7f86SDimitry Andric static Error addSectionsFromLinkedData(objcopy::ConfigManager &Config,
309fcaf7f86SDimitry Andric                                        ObjectFile &InputFile,
310fcaf7f86SDimitry Andric                                        DebugInfoBits &LinkedDebugInfoBits) {
311972a253aSDimitry Andric   if (isa<ELFObjectFile<ELF32LE>>(&InputFile)) {
312fcaf7f86SDimitry Andric     Expected<ELFObjectFile<ELF32LE>> MemFile = ELFObjectFile<ELF32LE>::create(
313fcaf7f86SDimitry Andric         MemoryBufferRef(LinkedDebugInfoBits, ""));
314fcaf7f86SDimitry Andric     if (!MemFile)
315fcaf7f86SDimitry Andric       return MemFile.takeError();
316fcaf7f86SDimitry Andric 
317fcaf7f86SDimitry Andric     if (Error Err = setConfigToAddNewDebugSections(Config, *MemFile))
318fcaf7f86SDimitry Andric       return Err;
319972a253aSDimitry Andric   } else if (isa<ELFObjectFile<ELF64LE>>(&InputFile)) {
320fcaf7f86SDimitry Andric     Expected<ELFObjectFile<ELF64LE>> MemFile = ELFObjectFile<ELF64LE>::create(
321fcaf7f86SDimitry Andric         MemoryBufferRef(LinkedDebugInfoBits, ""));
322fcaf7f86SDimitry Andric     if (!MemFile)
323fcaf7f86SDimitry Andric       return MemFile.takeError();
324fcaf7f86SDimitry Andric 
325fcaf7f86SDimitry Andric     if (Error Err = setConfigToAddNewDebugSections(Config, *MemFile))
326fcaf7f86SDimitry Andric       return Err;
327972a253aSDimitry Andric   } else if (isa<ELFObjectFile<ELF32BE>>(&InputFile)) {
328fcaf7f86SDimitry Andric     Expected<ELFObjectFile<ELF32BE>> MemFile = ELFObjectFile<ELF32BE>::create(
329fcaf7f86SDimitry Andric         MemoryBufferRef(LinkedDebugInfoBits, ""));
330fcaf7f86SDimitry Andric     if (!MemFile)
331fcaf7f86SDimitry Andric       return MemFile.takeError();
332fcaf7f86SDimitry Andric 
333fcaf7f86SDimitry Andric     if (Error Err = setConfigToAddNewDebugSections(Config, *MemFile))
334fcaf7f86SDimitry Andric       return Err;
335972a253aSDimitry Andric   } else if (isa<ELFObjectFile<ELF64BE>>(&InputFile)) {
336fcaf7f86SDimitry Andric     Expected<ELFObjectFile<ELF64BE>> MemFile = ELFObjectFile<ELF64BE>::create(
337fcaf7f86SDimitry Andric         MemoryBufferRef(LinkedDebugInfoBits, ""));
338fcaf7f86SDimitry Andric     if (!MemFile)
339fcaf7f86SDimitry Andric       return MemFile.takeError();
340fcaf7f86SDimitry Andric 
341fcaf7f86SDimitry Andric     if (Error Err = setConfigToAddNewDebugSections(Config, *MemFile))
342fcaf7f86SDimitry Andric       return Err;
343fcaf7f86SDimitry Andric   } else
344fcaf7f86SDimitry Andric     return createStringError(std::errc::invalid_argument,
345fcaf7f86SDimitry Andric                              "unsupported file format");
346fcaf7f86SDimitry Andric 
347fcaf7f86SDimitry Andric   return Error::success();
348fcaf7f86SDimitry Andric }
349fcaf7f86SDimitry Andric 
350fcaf7f86SDimitry Andric static Expected<uint32_t>
351fcaf7f86SDimitry Andric saveSeparateLinkedDebugInfo(const Options &Opts, ObjectFile &InputFile,
352fcaf7f86SDimitry Andric                             DebugInfoBits LinkedDebugInfoBits) {
353fcaf7f86SDimitry Andric   objcopy::ConfigManager Config;
354fcaf7f86SDimitry Andric   std::string OutputFilename = Opts.getSeparateDebugFileName();
355fcaf7f86SDimitry Andric   Config.Common.InputFilename = Opts.InputFileName;
356fcaf7f86SDimitry Andric   Config.Common.OutputFilename = OutputFilename;
357fcaf7f86SDimitry Andric   Config.Common.StripDebug = true;
358fcaf7f86SDimitry Andric   Config.Common.OnlyKeepDebug = true;
359fcaf7f86SDimitry Andric   uint32_t WrittenFileCRC32 = 0;
360fcaf7f86SDimitry Andric 
361fcaf7f86SDimitry Andric   if (Error Err =
362fcaf7f86SDimitry Andric           addSectionsFromLinkedData(Config, InputFile, LinkedDebugInfoBits))
363fcaf7f86SDimitry Andric     return std::move(Err);
364fcaf7f86SDimitry Andric 
365fcaf7f86SDimitry Andric   if (Error Err = writeToOutput(
366fcaf7f86SDimitry Andric           Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error {
367fcaf7f86SDimitry Andric             raw_crc_ostream CRCBuffer(OutFile);
368fcaf7f86SDimitry Andric 
369fcaf7f86SDimitry Andric             if (Error Err = objcopy::executeObjcopyOnBinary(Config, InputFile,
370fcaf7f86SDimitry Andric                                                             CRCBuffer))
371fcaf7f86SDimitry Andric               return Err;
372fcaf7f86SDimitry Andric 
373fcaf7f86SDimitry Andric             WrittenFileCRC32 = CRCBuffer.getCRC32();
374fcaf7f86SDimitry Andric             return Error::success();
375fcaf7f86SDimitry Andric           }))
376fcaf7f86SDimitry Andric     return std::move(Err);
377fcaf7f86SDimitry Andric 
378fcaf7f86SDimitry Andric   return WrittenFileCRC32;
379fcaf7f86SDimitry Andric }
380fcaf7f86SDimitry Andric 
381fcaf7f86SDimitry Andric static Error saveSingleLinkedDebugInfo(const Options &Opts,
382fcaf7f86SDimitry Andric                                        ObjectFile &InputFile,
383fcaf7f86SDimitry Andric                                        DebugInfoBits LinkedDebugInfoBits) {
384fcaf7f86SDimitry Andric   objcopy::ConfigManager Config;
385fcaf7f86SDimitry Andric 
386fcaf7f86SDimitry Andric   Config.Common.InputFilename = Opts.InputFileName;
387fcaf7f86SDimitry Andric   Config.Common.OutputFilename = Opts.OutputFileName;
388fcaf7f86SDimitry Andric   Config.Common.StripDebug = true;
389fcaf7f86SDimitry Andric   if (Error Err =
390fcaf7f86SDimitry Andric           addSectionsFromLinkedData(Config, InputFile, LinkedDebugInfoBits))
391fcaf7f86SDimitry Andric     return Err;
392fcaf7f86SDimitry Andric 
393fcaf7f86SDimitry Andric   if (Error Err = writeToOutput(
394fcaf7f86SDimitry Andric           Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error {
395fcaf7f86SDimitry Andric             return objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile);
396fcaf7f86SDimitry Andric           }))
397fcaf7f86SDimitry Andric     return Err;
398fcaf7f86SDimitry Andric 
399fcaf7f86SDimitry Andric   return Error::success();
400fcaf7f86SDimitry Andric }
401fcaf7f86SDimitry Andric 
402fcaf7f86SDimitry Andric static Error saveLinkedDebugInfo(const Options &Opts, ObjectFile &InputFile,
403fcaf7f86SDimitry Andric                                  DebugInfoBits LinkedDebugInfoBits) {
404fcaf7f86SDimitry Andric   if (Opts.BuildSeparateDebugFile) {
405fcaf7f86SDimitry Andric     Expected<uint32_t> SeparateDebugFileCRC32OrErr =
406fcaf7f86SDimitry Andric         saveSeparateLinkedDebugInfo(Opts, InputFile,
407fcaf7f86SDimitry Andric                                     std::move(LinkedDebugInfoBits));
408fcaf7f86SDimitry Andric     if (!SeparateDebugFileCRC32OrErr)
409fcaf7f86SDimitry Andric       return SeparateDebugFileCRC32OrErr.takeError();
410fcaf7f86SDimitry Andric 
411fcaf7f86SDimitry Andric     if (Error Err =
412fcaf7f86SDimitry Andric             saveNonDebugInfo(Opts, InputFile, *SeparateDebugFileCRC32OrErr))
413fcaf7f86SDimitry Andric       return Err;
414fcaf7f86SDimitry Andric   } else {
415fcaf7f86SDimitry Andric     if (Error Err = saveSingleLinkedDebugInfo(Opts, InputFile,
416fcaf7f86SDimitry Andric                                               std::move(LinkedDebugInfoBits)))
417fcaf7f86SDimitry Andric       return Err;
418fcaf7f86SDimitry Andric   }
419fcaf7f86SDimitry Andric 
420fcaf7f86SDimitry Andric   return Error::success();
421fcaf7f86SDimitry Andric }
422fcaf7f86SDimitry Andric 
423fcaf7f86SDimitry Andric static Error saveCopyOfFile(const Options &Opts, ObjectFile &InputFile) {
424fcaf7f86SDimitry Andric   objcopy::ConfigManager Config;
425fcaf7f86SDimitry Andric 
426fcaf7f86SDimitry Andric   Config.Common.InputFilename = Opts.InputFileName;
427fcaf7f86SDimitry Andric   Config.Common.OutputFilename = Opts.OutputFileName;
428fcaf7f86SDimitry Andric 
429fcaf7f86SDimitry Andric   if (Error Err = writeToOutput(
430fcaf7f86SDimitry Andric           Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error {
431fcaf7f86SDimitry Andric             return objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile);
432fcaf7f86SDimitry Andric           }))
433fcaf7f86SDimitry Andric     return Err;
434fcaf7f86SDimitry Andric 
435fcaf7f86SDimitry Andric   return Error::success();
436fcaf7f86SDimitry Andric }
437fcaf7f86SDimitry Andric 
438fcaf7f86SDimitry Andric static Error applyCLOptions(const struct Options &Opts, ObjectFile &InputFile) {
439*bdd1243dSDimitry Andric   if (Opts.DoGarbageCollection ||
440*bdd1243dSDimitry Andric       Opts.AccelTableKind != DwarfUtilAccelKind::None) {
441*bdd1243dSDimitry Andric     verbose("Do debug info linking...", Opts.Verbose);
442fcaf7f86SDimitry Andric 
443fcaf7f86SDimitry Andric     DebugInfoBits LinkedDebugInfo;
444fcaf7f86SDimitry Andric     raw_svector_ostream OutStream(LinkedDebugInfo);
445fcaf7f86SDimitry Andric 
446972a253aSDimitry Andric     if (Error Err = linkDebugInfo(InputFile, Opts, OutStream))
447972a253aSDimitry Andric       return Err;
448972a253aSDimitry Andric 
449fcaf7f86SDimitry Andric     if (Error Err =
450fcaf7f86SDimitry Andric             saveLinkedDebugInfo(Opts, InputFile, std::move(LinkedDebugInfo)))
451fcaf7f86SDimitry Andric       return Err;
452fcaf7f86SDimitry Andric 
453fcaf7f86SDimitry Andric     return Error::success();
454fcaf7f86SDimitry Andric   } else if (Opts.BuildSeparateDebugFile) {
455fcaf7f86SDimitry Andric     if (Error Err = splitDebugIntoSeparateFile(Opts, InputFile))
456fcaf7f86SDimitry Andric       return Err;
457fcaf7f86SDimitry Andric   } else {
458fcaf7f86SDimitry Andric     if (Error Err = saveCopyOfFile(Opts, InputFile))
459fcaf7f86SDimitry Andric       return Err;
460fcaf7f86SDimitry Andric   }
461fcaf7f86SDimitry Andric 
462fcaf7f86SDimitry Andric   return Error::success();
463fcaf7f86SDimitry Andric }
464fcaf7f86SDimitry Andric 
465fcaf7f86SDimitry Andric } // end of namespace dwarfutil
466fcaf7f86SDimitry Andric } // end of namespace llvm
467fcaf7f86SDimitry Andric 
468fcaf7f86SDimitry Andric int main(int Argc, char const *Argv[]) {
469fcaf7f86SDimitry Andric   using namespace dwarfutil;
470fcaf7f86SDimitry Andric 
471fcaf7f86SDimitry Andric   InitLLVM X(Argc, Argv);
472fcaf7f86SDimitry Andric   ToolName = Argv[0];
473fcaf7f86SDimitry Andric 
474fcaf7f86SDimitry Andric   // Parse arguments.
475fcaf7f86SDimitry Andric   DwarfutilOptTable T;
476fcaf7f86SDimitry Andric   unsigned MAI;
477fcaf7f86SDimitry Andric   unsigned MAC;
478*bdd1243dSDimitry Andric   ArrayRef<const char *> ArgsArr = ArrayRef(Argv + 1, Argc - 1);
479fcaf7f86SDimitry Andric   opt::InputArgList Args = T.ParseArgs(ArgsArr, MAI, MAC);
480fcaf7f86SDimitry Andric 
481fcaf7f86SDimitry Andric   if (Args.hasArg(OPT_help) || Args.size() == 0) {
482fcaf7f86SDimitry Andric     T.printHelp(
483fcaf7f86SDimitry Andric         outs(), (ToolName + " [options] <input file> <output file>").c_str(),
484fcaf7f86SDimitry Andric         "llvm-dwarfutil is a tool to copy and manipulate debug info", false);
485fcaf7f86SDimitry Andric     return EXIT_SUCCESS;
486fcaf7f86SDimitry Andric   }
487fcaf7f86SDimitry Andric 
488fcaf7f86SDimitry Andric   if (Args.hasArg(OPT_version)) {
489fcaf7f86SDimitry Andric     cl::PrintVersionMessage();
490fcaf7f86SDimitry Andric     return EXIT_SUCCESS;
491fcaf7f86SDimitry Andric   }
492fcaf7f86SDimitry Andric 
493fcaf7f86SDimitry Andric   Options Opts;
494fcaf7f86SDimitry Andric   if (Error Err = validateAndSetOptions(Args, Opts))
495fcaf7f86SDimitry Andric     error(std::move(Err), dwarfutil::ToolName);
496fcaf7f86SDimitry Andric 
497fcaf7f86SDimitry Andric   InitializeAllTargets();
498fcaf7f86SDimitry Andric   InitializeAllTargetMCs();
499fcaf7f86SDimitry Andric   InitializeAllTargetInfos();
500fcaf7f86SDimitry Andric   InitializeAllAsmPrinters();
501fcaf7f86SDimitry Andric 
502fcaf7f86SDimitry Andric   ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
503fcaf7f86SDimitry Andric       MemoryBuffer::getFileOrSTDIN(Opts.InputFileName);
504fcaf7f86SDimitry Andric   if (BuffOrErr.getError())
505fcaf7f86SDimitry Andric     error(createFileError(Opts.InputFileName, BuffOrErr.getError()));
506fcaf7f86SDimitry Andric 
507fcaf7f86SDimitry Andric   Expected<std::unique_ptr<Binary>> BinOrErr =
508fcaf7f86SDimitry Andric       object::createBinary(**BuffOrErr);
509fcaf7f86SDimitry Andric   if (!BinOrErr)
510fcaf7f86SDimitry Andric     error(createFileError(Opts.InputFileName, BinOrErr.takeError()));
511fcaf7f86SDimitry Andric 
512fcaf7f86SDimitry Andric   Expected<FilePermissionsApplier> PermsApplierOrErr =
513fcaf7f86SDimitry Andric       FilePermissionsApplier::create(Opts.InputFileName);
514fcaf7f86SDimitry Andric   if (!PermsApplierOrErr)
515fcaf7f86SDimitry Andric     error(createFileError(Opts.InputFileName, PermsApplierOrErr.takeError()));
516fcaf7f86SDimitry Andric 
517fcaf7f86SDimitry Andric   if (!(*BinOrErr)->isObject())
518fcaf7f86SDimitry Andric     error(createFileError(Opts.InputFileName,
519fcaf7f86SDimitry Andric                           createError("unsupported input file")));
520fcaf7f86SDimitry Andric 
521fcaf7f86SDimitry Andric   if (Error Err =
522fcaf7f86SDimitry Andric           applyCLOptions(Opts, *static_cast<ObjectFile *>((*BinOrErr).get())))
523fcaf7f86SDimitry Andric     error(createFileError(Opts.InputFileName, std::move(Err)));
524fcaf7f86SDimitry Andric 
525fcaf7f86SDimitry Andric   BinOrErr->reset();
526fcaf7f86SDimitry Andric   BuffOrErr->reset();
527fcaf7f86SDimitry Andric 
528fcaf7f86SDimitry Andric   if (Error Err = PermsApplierOrErr->apply(Opts.OutputFileName))
529fcaf7f86SDimitry Andric     error(std::move(Err));
530fcaf7f86SDimitry Andric 
531fcaf7f86SDimitry Andric   if (Opts.BuildSeparateDebugFile)
532fcaf7f86SDimitry Andric     if (Error Err = PermsApplierOrErr->apply(Opts.getSeparateDebugFileName()))
533fcaf7f86SDimitry Andric       error(std::move(Err));
534fcaf7f86SDimitry Andric 
535fcaf7f86SDimitry Andric   if (Opts.Verify) {
536fcaf7f86SDimitry Andric     if (Error Err = verifyOutput(Opts))
537fcaf7f86SDimitry Andric       error(std::move(Err));
538fcaf7f86SDimitry Andric   }
539fcaf7f86SDimitry Andric 
540fcaf7f86SDimitry Andric   return EXIT_SUCCESS;
541fcaf7f86SDimitry Andric }
542