a609d1933de98446912106523369ef9d394c9a21
[oota-llvm.git] / tools / dsymutil / dsymutil.cpp
1 //===-- dsymutil.cpp - Debug info dumping utility for llvm ----------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This program is a utility that aims to be a dropin replacement for
11 // Darwin's dsymutil.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #include "DebugMap.h"
16 #include "MachOUtils.h"
17 #include "dsymutil.h"
18 #include "llvm/Object/MachO.h"
19 #include "llvm/Support/FileUtilities.h"
20 #include "llvm/Support/ManagedStatic.h"
21 #include "llvm/Support/Options.h"
22 #include "llvm/Support/PrettyStackTrace.h"
23 #include "llvm/Support/Signals.h"
24 #include "llvm/Support/raw_ostream.h"
25 #include "llvm/Support/TargetSelect.h"
26 #include <string>
27
28 using namespace llvm::dsymutil;
29
30 namespace {
31 using namespace llvm::cl;
32
33 OptionCategory DsymCategory("Specific Options");
34 static opt<bool> Help("h", desc("Alias for -help"), Hidden);
35 static opt<bool> Version("v", desc("Alias for -version"), Hidden);
36
37 static list<std::string> InputFiles(Positional, OneOrMore,
38                                     desc("<input files>"), cat(DsymCategory));
39
40 static opt<std::string>
41     OutputFileOpt("o",
42                   desc("Specify the output file. default: <input file>.dwarf"),
43                   value_desc("filename"), cat(DsymCategory));
44
45 static opt<std::string> OsoPrependPath(
46     "oso-prepend-path",
47     desc("Specify a directory to prepend to the paths of object files."),
48     value_desc("path"), cat(DsymCategory));
49
50 static opt<bool> FlatOut("flat",
51                          desc("Produce a flat dSYM file (not a bundle)."),
52                          init(false), cat(DsymCategory));
53 static alias FlatOutA("f", desc("Alias for --flat"), aliasopt(FlatOut));
54
55 static opt<bool> Verbose("verbose", desc("Verbosity level"), init(false),
56                          cat(DsymCategory));
57
58 static opt<bool>
59     NoOutput("no-output",
60              desc("Do the link in memory, but do not emit the result file."),
61              init(false), cat(DsymCategory));
62
63 static list<std::string> ArchFlags(
64     "arch",
65     desc("Link DWARF debug information only for specified CPU architecture\n"
66          "types. This option can be specified multiple times, once for each\n"
67          "desired architecture.  All cpu architectures will be linked by\n"
68          "default."),
69     ZeroOrMore, cat(DsymCategory));
70
71 static opt<bool>
72     NoODR("no-odr",
73           desc("Do not use ODR (One Definition Rule) for type uniquing."),
74           init(false), cat(DsymCategory));
75
76 static opt<bool> DumpDebugMap(
77     "dump-debug-map",
78     desc("Parse and dump the debug map to standard output. Not DWARF link "
79          "will take place."),
80     init(false), cat(DsymCategory));
81
82 static opt<bool> InputIsYAMLDebugMap(
83     "y", desc("Treat the input file is a YAML debug map rather than a binary."),
84     init(false), cat(DsymCategory));
85 }
86
87 static std::error_code getUniqueFile(const llvm::Twine &Model, int &ResultFD,
88                                      llvm::SmallVectorImpl<char> &ResultPath) {
89   // If in NoOutput mode, use the createUniqueFile variant that
90   // doesn't open the file but still generates a somewhat unique
91   // name. In the real usage scenario, we'll want to ensure that the
92   // file is trully unique, and creating it is the only way to achieve
93   // that.
94   if (NoOutput)
95     return llvm::sys::fs::createUniqueFile(Model, ResultPath);
96   return llvm::sys::fs::createUniqueFile(Model, ResultFD, ResultPath);
97 }
98
99 static std::string getOutputFileName(llvm::StringRef InputFile,
100                                      bool TempFile = false) {
101   if (TempFile) {
102     llvm::Twine OutputFile = InputFile + ".tmp%%%%%%.dwarf";
103     int FD;
104     llvm::SmallString<128> UniqueFile;
105     if (auto EC = getUniqueFile(OutputFile, FD, UniqueFile)) {
106       llvm::errs() << "error: failed to create temporary outfile '"
107                    << OutputFile << "': " << EC.message() << '\n';
108       return "";
109     }
110     llvm::sys::RemoveFileOnSignal(UniqueFile);
111     if (!NoOutput) {
112       // Close the file immediately. We know it is unique. It will be
113       // reopened and written to later.
114       llvm::raw_fd_ostream CloseImmediately(FD, true /* shouldClose */, true);
115     }
116     return UniqueFile.str();
117   }
118
119   if (OutputFileOpt.empty()) {
120     if (InputFile == "-")
121       return "a.out.dwarf";
122     return (InputFile + ".dwarf").str();
123   }
124   return OutputFileOpt;
125 }
126
127 void llvm::dsymutil::exitDsymutil(int ExitStatus) {
128   // Cleanup temporary files.
129   llvm::sys::RunInterruptHandlers();
130   exit(ExitStatus);
131 }
132
133 int main(int argc, char **argv) {
134   llvm::sys::PrintStackTraceOnErrorSignal();
135   llvm::PrettyStackTraceProgram StackPrinter(argc, argv);
136   llvm::llvm_shutdown_obj Shutdown;
137   LinkOptions Options;
138
139   HideUnrelatedOptions(DsymCategory);
140   llvm::cl::ParseCommandLineOptions(
141       argc, argv,
142       "manipulate archived DWARF debug symbol files.\n\n"
143       "dsymutil links the DWARF debug information found in the object files\n"
144       "for the executable <input file> by using debug symbols information\n"
145       "contained in its symbol table.\n");
146
147   if (Help)
148     PrintHelpMessage();
149
150   if (Version) {
151     llvm::cl::PrintVersionMessage();
152     return 0;
153   }
154
155   Options.Verbose = Verbose;
156   Options.NoOutput = NoOutput;
157   Options.NoODR = NoODR;
158
159   llvm::InitializeAllTargetInfos();
160   llvm::InitializeAllTargetMCs();
161   llvm::InitializeAllTargets();
162   llvm::InitializeAllAsmPrinters();
163
164   if (!FlatOut && OutputFileOpt == "-") {
165     llvm::errs() << "error: cannot emit to standard output without --flat\n";
166     return 1;
167   }
168
169   if (InputFiles.size() > 1 && FlatOut && !OutputFileOpt.empty()) {
170     llvm::errs() << "error: cannot use -o with multiple inputs in flat mode\n";
171     return 1;
172   }
173
174   for (const auto &Arch : ArchFlags)
175     if (Arch != "*" && Arch != "all" &&
176         !llvm::object::MachOObjectFile::isValidArch(Arch)) {
177       llvm::errs() << "error: Unsupported cpu architecture: '" << Arch << "'\n";
178       exitDsymutil(1);
179     }
180
181   for (auto &InputFile : InputFiles) {
182     auto DebugMapPtrsOrErr = parseDebugMap(InputFile, ArchFlags, OsoPrependPath,
183                                            Verbose, InputIsYAMLDebugMap);
184
185     if (auto EC = DebugMapPtrsOrErr.getError()) {
186       llvm::errs() << "error: cannot parse the debug map for \"" << InputFile
187                    << "\": " << EC.message() << '\n';
188       exitDsymutil(1);
189     }
190
191     if (DebugMapPtrsOrErr->empty()) {
192       llvm::errs() << "error: no architecture to link\n";
193       exitDsymutil(1);
194     }
195
196     // If there is more than one link to execute, we need to generate
197     // temporary files.
198     bool NeedsTempFiles = !DumpDebugMap && (*DebugMapPtrsOrErr).size() != 1;
199     llvm::SmallVector<MachOUtils::ArchAndFilename, 4> TempFiles;
200     for (auto &Map : *DebugMapPtrsOrErr) {
201       if (Verbose || DumpDebugMap)
202         Map->print(llvm::outs());
203
204       if (DumpDebugMap)
205         continue;
206
207       std::string OutputFile = getOutputFileName(InputFile, NeedsTempFiles);
208       if (OutputFile.empty() || !linkDwarf(OutputFile, *Map, Options))
209         exitDsymutil(1);
210
211       if (NeedsTempFiles)
212         TempFiles.emplace_back(Map->getTriple().getArchName().str(),
213                                OutputFile);
214     }
215
216     if (NeedsTempFiles &&
217         !MachOUtils::generateUniversalBinary(
218             TempFiles, getOutputFileName(InputFile), Options))
219       exitDsymutil(1);
220   }
221
222   exitDsymutil(0);
223 }