581da4ebfa06f1893b16e48497b7cd0f0e759557
[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> Verbose("verbose", desc("Verbosity level"), init(false),
51                          cat(DsymCategory));
52
53 static opt<bool>
54     NoOutput("no-output",
55              desc("Do the link in memory, but do not emit the result file."),
56              init(false), cat(DsymCategory));
57
58 static list<std::string> ArchFlags(
59     "arch",
60     desc("Link DWARF debug information only for specified CPU architecture\n"
61          "types. This option can be specified multiple times, once for each\n"
62          "desired architecture.  All cpu architectures will be linked by\n"
63          "default."),
64     ZeroOrMore, cat(DsymCategory));
65
66 static opt<bool>
67     NoODR("no-odr",
68           desc("Do not use ODR (One Definition Rule) for type uniquing."),
69           init(false), cat(DsymCategory));
70
71 static opt<bool> DumpDebugMap(
72     "dump-debug-map",
73     desc("Parse and dump the debug map to standard output. Not DWARF link "
74          "will take place."),
75     init(false), cat(DsymCategory));
76
77 static opt<bool> InputIsYAMLDebugMap(
78     "y", desc("Treat the input file is a YAML debug map rather than a binary."),
79     init(false), cat(DsymCategory));
80 }
81
82 static std::string getOutputFileName(llvm::StringRef InputFile,
83                                      bool TempFile = false) {
84   if (TempFile) {
85     std::string OutputFile = (InputFile + ".tmp%%%%%%.dwarf").str();
86     int FD;
87     llvm::SmallString<128> UniqueFile;
88     if (auto EC = llvm::sys::fs::createUniqueFile(OutputFile, FD, UniqueFile)) {
89       llvm::errs() << "error: failed to create temporary outfile '"
90                    << OutputFile << "': " << EC.message() << '\n';
91       return "";
92     }
93     llvm::sys::RemoveFileOnSignal(UniqueFile);
94     // Close the file immediately. We know it is unique. It will be
95     // reopened and written to later.
96     llvm::raw_fd_ostream CloseImmediately(FD, true /* shouldClose */, true);
97     return UniqueFile.str();
98   }
99
100   if (OutputFileOpt.empty()) {
101     if (InputFile == "-")
102       return "a.out.dwarf";
103     return (InputFile + ".dwarf").str();
104   }
105   return OutputFileOpt;
106 }
107
108 void llvm::dsymutil::exitDsymutil(int ExitStatus) {
109   // Cleanup temporary files.
110   llvm::sys::RunInterruptHandlers();
111   exit(ExitStatus);
112 }
113
114 int main(int argc, char **argv) {
115   llvm::sys::PrintStackTraceOnErrorSignal();
116   llvm::PrettyStackTraceProgram StackPrinter(argc, argv);
117   llvm::llvm_shutdown_obj Shutdown;
118   LinkOptions Options;
119
120   HideUnrelatedOptions(DsymCategory);
121   llvm::cl::ParseCommandLineOptions(
122       argc, argv,
123       "manipulate archived DWARF debug symbol files.\n\n"
124       "dsymutil links the DWARF debug information found in the object files\n"
125       "for the executable <input file> by using debug symbols information\n"
126       "contained in its symbol table.\n");
127
128   if (Help)
129     PrintHelpMessage();
130
131   if (Version) {
132     llvm::cl::PrintVersionMessage();
133     return 0;
134   }
135
136   Options.Verbose = Verbose;
137   Options.NoOutput = NoOutput;
138   Options.NoODR = NoODR;
139
140   llvm::InitializeAllTargetInfos();
141   llvm::InitializeAllTargetMCs();
142   llvm::InitializeAllTargets();
143   llvm::InitializeAllAsmPrinters();
144
145   if (InputFiles.size() > 1 && !OutputFileOpt.empty()) {
146     llvm::errs() << "error: cannot use -o with multiple inputs\n";
147     return 1;
148   }
149
150   for (const auto &Arch : ArchFlags)
151     if (Arch != "*" && Arch != "all" &&
152         !llvm::object::MachOObjectFile::isValidArch(Arch)) {
153       llvm::errs() << "error: Unsupported cpu architecture: '" << Arch << "'\n";
154       exitDsymutil(1);
155     }
156
157   for (auto &InputFile : InputFiles) {
158     auto DebugMapPtrsOrErr = parseDebugMap(InputFile, ArchFlags, OsoPrependPath,
159                                            Verbose, InputIsYAMLDebugMap);
160
161     if (auto EC = DebugMapPtrsOrErr.getError()) {
162       llvm::errs() << "error: cannot parse the debug map for \"" << InputFile
163                    << "\": " << EC.message() << '\n';
164       exitDsymutil(1);
165     }
166
167     if (DebugMapPtrsOrErr->empty()) {
168       llvm::errs() << "error: no architecture to link\n";
169       exitDsymutil(1);
170     }
171
172     // If there is more than one link to execute, we need to generate
173     // temporary files.
174     bool NeedsTempFiles = !DumpDebugMap && (*DebugMapPtrsOrErr).size() != 1;
175     llvm::SmallVector<MachOUtils::ArchAndFilename, 4> TempFiles;
176     for (auto &Map : *DebugMapPtrsOrErr) {
177       if (Verbose || DumpDebugMap)
178         Map->print(llvm::outs());
179
180       if (DumpDebugMap)
181         continue;
182
183       std::string OutputFile = getOutputFileName(InputFile, NeedsTempFiles);
184       if (OutputFile.empty() || !linkDwarf(OutputFile, *Map, Options))
185         exitDsymutil(1);
186
187       if (NeedsTempFiles)
188         TempFiles.emplace_back(Map->getTriple().getArchName().str(),
189                                OutputFile);
190     }
191
192     if (NeedsTempFiles &&
193         !MachOUtils::generateUniversalBinary(
194             TempFiles, getOutputFileName(InputFile), Options))
195       exitDsymutil(1);
196   }
197
198   exitDsymutil(0);
199 }