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