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> Verbose("verbose", desc("Verbosity level"), init(false),
55 desc("Do the link in memory, but do not emit the result file."),
56 init(false), cat(DsymCategory));
58 static list<std::string> ArchFlags(
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"
64 ZeroOrMore, cat(DsymCategory));
68 desc("Do not use ODR (One Definition Rule) for type uniquing."),
69 init(false), cat(DsymCategory));
71 static opt<bool> DumpDebugMap(
73 desc("Parse and dump the debug map to standard output. Not DWARF link "
75 init(false), cat(DsymCategory));
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));
82 static std::error_code getUniqueFile(const llvm::Twine &Model, int &ResultFD,
83 llvm::SmallVectorImpl<char> &ResultPath) {
84 // If in NoOutput mode, use the createUniqueFile variant that
85 // doesn't open the file but still generates a somewhat unique
86 // name. In the real usage scenario, we'll want to ensure that the
87 // file is trully unique, and creating it is the only way to achieve
90 return llvm::sys::fs::createUniqueFile(Model, ResultPath);
91 return llvm::sys::fs::createUniqueFile(Model, ResultFD, ResultPath);
94 static std::string getOutputFileName(llvm::StringRef InputFile,
95 bool TempFile = false) {
97 llvm::Twine OutputFile = InputFile + ".tmp%%%%%%.dwarf";
99 llvm::SmallString<128> UniqueFile;
100 if (auto EC = getUniqueFile(OutputFile, FD, UniqueFile)) {
101 llvm::errs() << "error: failed to create temporary outfile '"
102 << OutputFile << "': " << EC.message() << '\n';
105 llvm::sys::RemoveFileOnSignal(UniqueFile);
107 // Close the file immediately. We know it is unique. It will be
108 // reopened and written to later.
109 llvm::raw_fd_ostream CloseImmediately(FD, true /* shouldClose */, true);
111 return UniqueFile.str();
114 if (OutputFileOpt.empty()) {
115 if (InputFile == "-")
116 return "a.out.dwarf";
117 return (InputFile + ".dwarf").str();
119 return OutputFileOpt;
122 void llvm::dsymutil::exitDsymutil(int ExitStatus) {
123 // Cleanup temporary files.
124 llvm::sys::RunInterruptHandlers();
128 int main(int argc, char **argv) {
129 llvm::sys::PrintStackTraceOnErrorSignal();
130 llvm::PrettyStackTraceProgram StackPrinter(argc, argv);
131 llvm::llvm_shutdown_obj Shutdown;
134 HideUnrelatedOptions(DsymCategory);
135 llvm::cl::ParseCommandLineOptions(
137 "manipulate archived DWARF debug symbol files.\n\n"
138 "dsymutil links the DWARF debug information found in the object files\n"
139 "for the executable <input file> by using debug symbols information\n"
140 "contained in its symbol table.\n");
146 llvm::cl::PrintVersionMessage();
150 Options.Verbose = Verbose;
151 Options.NoOutput = NoOutput;
152 Options.NoODR = NoODR;
154 llvm::InitializeAllTargetInfos();
155 llvm::InitializeAllTargetMCs();
156 llvm::InitializeAllTargets();
157 llvm::InitializeAllAsmPrinters();
159 if (InputFiles.size() > 1 && !OutputFileOpt.empty()) {
160 llvm::errs() << "error: cannot use -o with multiple inputs\n";
164 for (const auto &Arch : ArchFlags)
165 if (Arch != "*" && Arch != "all" &&
166 !llvm::object::MachOObjectFile::isValidArch(Arch)) {
167 llvm::errs() << "error: Unsupported cpu architecture: '" << Arch << "'\n";
171 for (auto &InputFile : InputFiles) {
172 auto DebugMapPtrsOrErr = parseDebugMap(InputFile, ArchFlags, OsoPrependPath,
173 Verbose, InputIsYAMLDebugMap);
175 if (auto EC = DebugMapPtrsOrErr.getError()) {
176 llvm::errs() << "error: cannot parse the debug map for \"" << InputFile
177 << "\": " << EC.message() << '\n';
181 if (DebugMapPtrsOrErr->empty()) {
182 llvm::errs() << "error: no architecture to link\n";
186 // If there is more than one link to execute, we need to generate
188 bool NeedsTempFiles = !DumpDebugMap && (*DebugMapPtrsOrErr).size() != 1;
189 llvm::SmallVector<MachOUtils::ArchAndFilename, 4> TempFiles;
190 for (auto &Map : *DebugMapPtrsOrErr) {
191 if (Verbose || DumpDebugMap)
192 Map->print(llvm::outs());
197 std::string OutputFile = getOutputFileName(InputFile, NeedsTempFiles);
198 if (OutputFile.empty() || !linkDwarf(OutputFile, *Map, Options))
202 TempFiles.emplace_back(Map->getTriple().getArchName().str(),
206 if (NeedsTempFiles &&
207 !MachOUtils::generateUniversalBinary(
208 TempFiles, getOutputFileName(InputFile), Options))