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::string getOutputFileName(llvm::StringRef InputFile,
83 bool TempFile = false) {
85 std::string OutputFile = (InputFile + ".tmp%%%%%%.dwarf").str();
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';
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();
100 if (OutputFileOpt.empty()) {
101 if (InputFile == "-")
102 return "a.out.dwarf";
103 return (InputFile + ".dwarf").str();
105 return OutputFileOpt;
108 void llvm::dsymutil::exitDsymutil(int ExitStatus) {
109 // Cleanup temporary files.
110 llvm::sys::RunInterruptHandlers();
114 int main(int argc, char **argv) {
115 llvm::sys::PrintStackTraceOnErrorSignal();
116 llvm::PrettyStackTraceProgram StackPrinter(argc, argv);
117 llvm::llvm_shutdown_obj Shutdown;
120 HideUnrelatedOptions(DsymCategory);
121 llvm::cl::ParseCommandLineOptions(
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");
132 llvm::cl::PrintVersionMessage();
136 Options.Verbose = Verbose;
137 Options.NoOutput = NoOutput;
138 Options.NoODR = NoODR;
140 llvm::InitializeAllTargetInfos();
141 llvm::InitializeAllTargetMCs();
142 llvm::InitializeAllTargets();
143 llvm::InitializeAllAsmPrinters();
145 if (InputFiles.size() > 1 && !OutputFileOpt.empty()) {
146 llvm::errs() << "error: cannot use -o with multiple inputs\n";
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";
157 for (auto &InputFile : InputFiles) {
158 auto DebugMapPtrsOrErr = parseDebugMap(InputFile, ArchFlags, OsoPrependPath,
159 Verbose, InputIsYAMLDebugMap);
161 if (auto EC = DebugMapPtrsOrErr.getError()) {
162 llvm::errs() << "error: cannot parse the debug map for \"" << InputFile
163 << "\": " << EC.message() << '\n';
167 if (DebugMapPtrsOrErr->empty()) {
168 llvm::errs() << "error: no architecture to link\n";
172 // If there is more than one link to execute, we need to generate
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());
183 std::string OutputFile = getOutputFileName(InputFile, NeedsTempFiles);
184 if (OutputFile.empty() || !linkDwarf(OutputFile, *Map, Options))
188 TempFiles.emplace_back(Map->getTriple().getArchName().str(),
192 if (NeedsTempFiles &&
193 !MachOUtils::generateUniversalBinary(
194 TempFiles, getOutputFileName(InputFile), Options))