1 //===-- dsymutil.cpp - Debug info dumping utility for llvm ----------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This program is a utility that aims to be a dropin replacement for
13 //===----------------------------------------------------------------------===//
16 #include "MachOUtils.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"
28 using namespace llvm::dsymutil;
31 using namespace llvm::cl;
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);
37 static list<std::string> InputFiles(Positional, OneOrMore,
38 desc("<input files>"), cat(DsymCategory));
40 static opt<std::string>
42 desc("Specify the output file. default: <input file>.dwarf"),
43 value_desc("filename"), cat(DsymCategory));
45 static opt<std::string> OsoPrependPath(
47 desc("Specify a directory to prepend to the paths of object files."),
48 value_desc("path"), cat(DsymCategory));
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));
55 static opt<bool> Verbose("verbose", desc("Verbosity level"), init(false),
60 desc("Do the link in memory, but do not emit the result file."),
61 init(false), cat(DsymCategory));
63 static list<std::string> ArchFlags(
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"
69 ZeroOrMore, cat(DsymCategory));
73 desc("Do not use ODR (One Definition Rule) for type uniquing."),
74 init(false), cat(DsymCategory));
76 static opt<bool> DumpDebugMap(
78 desc("Parse and dump the debug map to standard output. Not DWARF link "
80 init(false), cat(DsymCategory));
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));
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
95 return llvm::sys::fs::createUniqueFile(Model, ResultPath);
96 return llvm::sys::fs::createUniqueFile(Model, ResultFD, ResultPath);
99 static std::string getOutputFileName(llvm::StringRef InputFile,
100 bool TempFile = false) {
102 llvm::Twine OutputFile = InputFile + ".tmp%%%%%%.dwarf";
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';
110 llvm::sys::RemoveFileOnSignal(UniqueFile);
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);
116 return UniqueFile.str();
119 if (OutputFileOpt.empty()) {
120 if (InputFile == "-")
121 return "a.out.dwarf";
122 return (InputFile + ".dwarf").str();
124 return OutputFileOpt;
127 void llvm::dsymutil::exitDsymutil(int ExitStatus) {
128 // Cleanup temporary files.
129 llvm::sys::RunInterruptHandlers();
133 int main(int argc, char **argv) {
134 llvm::sys::PrintStackTraceOnErrorSignal();
135 llvm::PrettyStackTraceProgram StackPrinter(argc, argv);
136 llvm::llvm_shutdown_obj Shutdown;
139 HideUnrelatedOptions(DsymCategory);
140 llvm::cl::ParseCommandLineOptions(
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");
151 llvm::cl::PrintVersionMessage();
155 Options.Verbose = Verbose;
156 Options.NoOutput = NoOutput;
157 Options.NoODR = NoODR;
159 llvm::InitializeAllTargetInfos();
160 llvm::InitializeAllTargetMCs();
161 llvm::InitializeAllTargets();
162 llvm::InitializeAllAsmPrinters();
164 if (!FlatOut && OutputFileOpt == "-") {
165 llvm::errs() << "error: cannot emit to standard output without --flat\n";
169 if (InputFiles.size() > 1 && FlatOut && !OutputFileOpt.empty()) {
170 llvm::errs() << "error: cannot use -o with multiple inputs in flat mode\n";
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";
181 for (auto &InputFile : InputFiles) {
182 auto DebugMapPtrsOrErr = parseDebugMap(InputFile, ArchFlags, OsoPrependPath,
183 Verbose, InputIsYAMLDebugMap);
185 if (auto EC = DebugMapPtrsOrErr.getError()) {
186 llvm::errs() << "error: cannot parse the debug map for \"" << InputFile
187 << "\": " << EC.message() << '\n';
191 if (DebugMapPtrsOrErr->empty()) {
192 llvm::errs() << "error: no architecture to link\n";
196 // If there is more than one link to execute, we need to generate
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());
207 std::string OutputFile = getOutputFileName(InputFile, NeedsTempFiles);
208 if (OutputFile.empty() || !linkDwarf(OutputFile, *Map, Options))
212 TempFiles.emplace_back(Map->getTriple().getArchName().str(),
216 if (NeedsTempFiles &&
217 !MachOUtils::generateUniversalBinary(
218 TempFiles, getOutputFileName(InputFile), Options))