//===----------------------------------------------------------------------===//
#include "DebugMap.h"
+#include "MachOUtils.h"
#include "dsymutil.h"
+#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Options.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/TargetSelect.h"
#include <string>
using namespace llvm::dsymutil;
namespace {
using namespace llvm::cl;
-static opt<std::string> InputFile(Positional, desc("<input file>"),
- init("a.out"));
+OptionCategory DsymCategory("Specific Options");
+static opt<bool> Help("h", desc("Alias for -help"), Hidden);
+static opt<bool> Version("v", desc("Alias for -version"), Hidden);
-static opt<std::string> OutputFileOpt("o", desc("Specify the output file."
- " default: <input file>.dwarf"),
- value_desc("filename"));
+static list<std::string> InputFiles(Positional, OneOrMore,
+ desc("<input files>"), cat(DsymCategory));
-static opt<std::string> OsoPrependPath("oso-prepend-path",
- desc("Specify a directory to prepend "
- "to the paths of object files."),
- value_desc("path"));
+static opt<std::string>
+ OutputFileOpt("o",
+ desc("Specify the output file. default: <input file>.dwarf"),
+ value_desc("filename"), cat(DsymCategory));
-static opt<bool> Verbose("v", desc("Verbosity level"), init(false));
+static opt<std::string> OsoPrependPath(
+ "oso-prepend-path",
+ desc("Specify a directory to prepend to the paths of object files."),
+ value_desc("path"), cat(DsymCategory));
+
+static opt<bool> Verbose("verbose", desc("Verbosity level"), init(false),
+ cat(DsymCategory));
+
+static opt<bool>
+ NoOutput("no-output",
+ desc("Do the link in memory, but do not emit the result file."),
+ init(false), cat(DsymCategory));
static opt<bool>
- ParseOnly("parse-only",
- desc("Only parse the debug map, do not actaully link "
- "the DWARF."),
- init(false));
+ NoODR("no-odr",
+ desc("Do not use ODR (One Definition Rule) for type uniquing."),
+ init(false), cat(DsymCategory));
+
+static opt<bool> DumpDebugMap(
+ "dump-debug-map",
+ desc("Parse and dump the debug map to standard output. Not DWARF link "
+ "will take place."),
+ init(false), cat(DsymCategory));
+
+static opt<bool> InputIsYAMLDebugMap(
+ "y", desc("Treat the input file is a YAML debug map rather than a binary."),
+ init(false), cat(DsymCategory));
+}
+
+static std::string getOutputFileName(llvm::StringRef InputFile,
+ bool TempFile = false) {
+ if (TempFile) {
+ std::string OutputFile = (InputFile + ".tmp%%%%%%.dwarf").str();
+ int FD;
+ llvm::SmallString<128> UniqueFile;
+ if (auto EC = llvm::sys::fs::createUniqueFile(OutputFile, FD, UniqueFile)) {
+ llvm::errs() << "error: failed to create temporary outfile '"
+ << OutputFile << "': " << EC.message() << '\n';
+ return "";
+ }
+ llvm::sys::RemoveFileOnSignal(UniqueFile);
+ // Close the file immediately. We know it is unique. It will be
+ // reopened and written to later.
+ llvm::raw_fd_ostream CloseImmediately(FD, true /* shouldClose */, true);
+ return UniqueFile.str();
+ }
+
+ if (OutputFileOpt.empty()) {
+ if (InputFile == "-")
+ return "a.out.dwarf";
+ return (InputFile + ".dwarf").str();
+ }
+ return OutputFileOpt;
+}
+
+void llvm::dsymutil::exitDsymutil(int ExitStatus) {
+ // Cleanup temporary files.
+ llvm::sys::RunInterruptHandlers();
+ exit(ExitStatus);
}
int main(int argc, char **argv) {
llvm::llvm_shutdown_obj Shutdown;
LinkOptions Options;
- llvm::cl::ParseCommandLineOptions(argc, argv, "llvm dsymutil\n");
- auto DebugMapPtrOrErr = parseDebugMap(InputFile, OsoPrependPath, Verbose);
+ HideUnrelatedOptions(DsymCategory);
+ llvm::cl::ParseCommandLineOptions(
+ argc, argv,
+ "manipulate archived DWARF debug symbol files.\n\n"
+ "dsymutil links the DWARF debug information found in the object files\n"
+ "for the executable <input file> by using debug symbols information\n"
+ "contained in its symbol table.\n");
- Options.Verbose = Verbose;
+ if (Help)
+ PrintHelpMessage();
- if (auto EC = DebugMapPtrOrErr.getError()) {
- llvm::errs() << "error: cannot parse the debug map for \"" << InputFile
- << "\": " << EC.message() << '\n';
- return 1;
+ if (Version) {
+ llvm::cl::PrintVersionMessage();
+ return 0;
}
- if (Verbose)
- (*DebugMapPtrOrErr)->print(llvm::outs());
+ Options.Verbose = Verbose;
+ Options.NoOutput = NoOutput;
+ Options.NoODR = NoODR;
- if (ParseOnly)
- return 0;
+ llvm::InitializeAllTargetInfos();
+ llvm::InitializeAllTargetMCs();
+ llvm::InitializeAllTargets();
+ llvm::InitializeAllAsmPrinters();
- std::string OutputFile;
- if (OutputFileOpt.empty()) {
- if (InputFile == "-")
- OutputFile = "a.out.dwarf";
- else
- OutputFile = InputFile + ".dwarf";
- } else {
- OutputFile = OutputFileOpt;
+ if (InputFiles.size() > 1 && !OutputFileOpt.empty()) {
+ llvm::errs() << "error: cannot use -o with multiple inputs\n";
+ return 1;
+ }
+
+ for (auto &InputFile : InputFiles) {
+ auto DebugMapPtrsOrErr =
+ parseDebugMap(InputFile, OsoPrependPath, Verbose, InputIsYAMLDebugMap);
+
+ if (auto EC = DebugMapPtrsOrErr.getError()) {
+ llvm::errs() << "error: cannot parse the debug map for \"" << InputFile
+ << "\": " << EC.message() << '\n';
+ exitDsymutil(1);
+ }
+
+ // If there is more than one link to execute, we need to generate
+ // temporary files.
+ bool NeedsTempFiles = !DumpDebugMap && (*DebugMapPtrsOrErr).size() != 1;
+ llvm::SmallVector<MachOUtils::ArchAndFilename, 4> TempFiles;
+ for (auto &Map : *DebugMapPtrsOrErr) {
+ if (Verbose || DumpDebugMap)
+ Map->print(llvm::outs());
+
+ if (DumpDebugMap)
+ continue;
+
+ std::string OutputFile = getOutputFileName(InputFile, NeedsTempFiles);
+ if (OutputFile.empty() || !linkDwarf(OutputFile, *Map, Options))
+ exitDsymutil(1);
+
+ if (NeedsTempFiles)
+ TempFiles.emplace_back(Map->getTriple().getArchName().str(),
+ OutputFile);
+ }
+
+ if (NeedsTempFiles &&
+ !MachOUtils::generateUniversalBinary(
+ TempFiles, getOutputFileName(InputFile), Options))
+ exitDsymutil(1);
}
- return !linkDwarf(OutputFile, **DebugMapPtrOrErr, Options);
+ exitDsymutil(0);
}