[dwarfdump] Add support for redirecting output to a file
authorJonas Devlieghere <jonas@devlieghere.com>
Fri, 22 Sep 2017 09:20:57 +0000 (09:20 +0000)
committerJonas Devlieghere <jonas@devlieghere.com>
Fri, 22 Sep 2017 09:20:57 +0000 (09:20 +0000)
This patch adds the -o and --out-file options for compatibility with
Darwin's dwarfdump.

Differential revision: https://reviews.llvm.org/D38125

llvm-svn: 313969

llvm/test/tools/llvm-dwarfdump/X86/brief.s
llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp

index 06a9d24..a4a3417 100644 (file)
@@ -1,6 +1,9 @@
 # RUN: llvm-mc %s -filetype obj -triple x86_64-apple-darwin -o - \
 # RUN: | llvm-dwarfdump --debug-info --debug-line - \
 # RUN: | FileCheck %s
+# RUN: llvm-mc %s -filetype obj -triple x86_64-apple-darwin -o - \
+# RUN: | llvm-dwarfdump --debug-info --debug-line - -o %t
+# RUN: cat %t | FileCheck %s
 
 # CHECK-NOT: .debug_abbrev contents:
 #
index 5c9fe24..e1021b2 100644 (file)
@@ -28,6 +28,7 @@
 #include "llvm/Support/PrettyStackTrace.h"
 #include "llvm/Support/Signals.h"
 #include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/ToolOutputFile.h"
 #include "llvm/Support/raw_ostream.h"
 #include <algorithm>
 #include <cstring>
@@ -136,7 +137,13 @@ static list<std::string>
 static opt<bool> DumpUUID("uuid", desc("Show the UUID for each architecture"),
                           cat(DwarfDumpCategory));
 static alias DumpUUIDAlias("u", desc("Alias for -uuid"), aliasopt(DumpUUID));
-
+static opt<std::string>
+    OutputFilename("out-file", cl::init(""),
+                   cl::desc("Redirect output to the specified file"),
+                   cl::value_desc("filename"));
+static alias OutputFilenameAlias("o", desc("Alias for -out-file"),
+                                 aliasopt(OutputFilename),
+                                 cat(DwarfDumpCategory));
 static opt<bool>
     ShowChildren("show-children",
                  desc("Show a debug info entry's children when selectively "
@@ -175,11 +182,10 @@ static alias VerboseAlias("v", desc("Alias for -verbose"), aliasopt(Verbose),
 /// @}
 //===----------------------------------------------------------------------===//
 
-
-static void error(StringRef Filename, std::error_code EC) {
+static void error(StringRef Prefix, std::error_code EC) {
   if (!EC)
     return;
-  errs() << Filename << ": " << EC.message() << "\n";
+  errs() << Prefix << ": " << EC.message() << "\n";
   exit(1);
 }
 
@@ -223,26 +229,27 @@ static bool filterArch(ObjectFile &Obj) {
   return false;
 }
 
-using HandlerFn = std::function<bool(ObjectFile &, DWARFContext &DICtx, Twine)>;
+using HandlerFn = std::function<bool(ObjectFile &, DWARFContext &DICtx, Twine,
+                                     raw_ostream &)>;
 
-static bool dumpObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
-                           Twine Filename) {
+static bool dumpObjectFile(ObjectFile &Obj, DWARFContext &DICtx, Twine Filename,
+                           raw_ostream &OS) {
   logAllUnhandledErrors(DICtx.loadRegisterInfo(Obj), errs(),
                         Filename.str() + ": ");
   // The UUID dump already contains all the same information.
   if (!(DumpType & DIDT_UUID) || DumpType == DIDT_All)
-    outs() << Filename << ":\tfile format " << Obj.getFileFormatName() << '\n';
+    OS << Filename << ":\tfile format " << Obj.getFileFormatName() << '\n';
 
   // Dump the complete DWARF structure.
-  DICtx.dump(outs(), getDumpOpts(), DumpOffsets);
+  DICtx.dump(OS, getDumpOpts(), DumpOffsets);
   return true;
 }
 
 static bool verifyObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
-                             Twine Filename) {
+                             Twine Filename, raw_ostream &OS) {
   // Verify the DWARF and exit with non-zero exit status if verification
   // fails.
-  raw_ostream &stream = Quiet ? nulls() : outs();
+  raw_ostream &stream = Quiet ? nulls() : OS;
   stream << "Verifying " << Filename.str() << ":\tfile format "
   << Obj.getFileFormatName() << "\n";
   bool Result = DICtx.verify(stream, getDumpOpts());
@@ -254,10 +261,10 @@ static bool verifyObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
 }
 
 static bool handleBuffer(StringRef Filename, MemoryBufferRef Buffer,
-                         HandlerFn HandleObj);
+                         HandlerFn HandleObj, raw_ostream &OS);
 
 static bool handleArchive(StringRef Filename, Archive &Arch,
-                          HandlerFn HandleObj) {
+                          HandlerFn HandleObj, raw_ostream &OS) {
   bool Result = true;
   Error Err = Error::success();
   for (auto Child : Arch.children(Err)) {
@@ -266,7 +273,7 @@ static bool handleArchive(StringRef Filename, Archive &Arch,
     auto NameOrErr = Child.getName();
     error(Filename, errorToErrorCode(NameOrErr.takeError()));
     std::string Name = (Filename + "(" + NameOrErr.get() + ")").str();
-    Result &= handleBuffer(Name, BuffOrErr.get(), HandleObj);
+    Result &= handleBuffer(Name, BuffOrErr.get(), HandleObj, OS);
   }
   error(Filename, errorToErrorCode(std::move(Err)));
 
@@ -274,7 +281,7 @@ static bool handleArchive(StringRef Filename, Archive &Arch,
 }
 
 static bool handleBuffer(StringRef Filename, MemoryBufferRef Buffer,
-                         HandlerFn HandleObj) {
+                         HandlerFn HandleObj, raw_ostream &OS) {
   Expected<std::unique_ptr<Binary>> BinOrErr = object::createBinary(Buffer);
   error(Filename, errorToErrorCode(BinOrErr.takeError()));
 
@@ -282,7 +289,7 @@ static bool handleBuffer(StringRef Filename, MemoryBufferRef Buffer,
   if (auto *Obj = dyn_cast<ObjectFile>(BinOrErr->get())) {
     if (filterArch(*Obj)) {
       std::unique_ptr<DWARFContext> DICtx = DWARFContext::create(*Obj);
-      Result = HandleObj(*Obj, *DICtx, Filename);
+      Result = HandleObj(*Obj, *DICtx, Filename, OS);
     }
   }
   else if (auto *Fat = dyn_cast<MachOUniversalBinary>(BinOrErr->get()))
@@ -293,29 +300,30 @@ static bool handleBuffer(StringRef Filename, MemoryBufferRef Buffer,
         auto &Obj = **MachOOrErr;
         if (filterArch(Obj)) {
           std::unique_ptr<DWARFContext> DICtx = DWARFContext::create(Obj);
-          Result &= HandleObj(Obj, *DICtx, ObjName);
+          Result &= HandleObj(Obj, *DICtx, ObjName, OS);
         }
         continue;
       } else
         consumeError(MachOOrErr.takeError());
       if (auto ArchiveOrErr = ObjForArch.getAsArchive()) {
         error(ObjName, errorToErrorCode(ArchiveOrErr.takeError()));
-        Result &= handleArchive(ObjName, *ArchiveOrErr.get(), HandleObj);
+        Result &= handleArchive(ObjName, *ArchiveOrErr.get(), HandleObj, OS);
         continue;
       } else
         consumeError(ArchiveOrErr.takeError());
     }
   else if (auto *Arch = dyn_cast<Archive>(BinOrErr->get()))
-    Result = handleArchive(Filename, *Arch, HandleObj);
+    Result = handleArchive(Filename, *Arch, HandleObj, OS);
   return Result;
 }
 
-static bool handleFile(StringRef Filename, HandlerFn HandleObj) {
+static bool handleFile(StringRef Filename, HandlerFn HandleObj,
+                       raw_ostream &OS) {
   ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
   MemoryBuffer::getFileOrSTDIN(Filename);
   error(Filename, BuffOrErr.getError());
   std::unique_ptr<MemoryBuffer> Buffer = std::move(BuffOrErr.get());
-  return handleBuffer(Filename, *Buffer, HandleObj);
+  return handleBuffer(Filename, *Buffer, HandleObj, OS);
 }
 
 /// If the input path is a .dSYM bundle (as created by the dsymutil tool),
@@ -371,6 +379,18 @@ int main(int argc, char **argv) {
     return 0;
   }
 
+  std::unique_ptr<tool_output_file> OutputFile;
+  if (!OutputFilename.empty()) {
+    std::error_code EC;
+    OutputFile =
+        make_unique<tool_output_file>(OutputFilename, EC, sys::fs::F_None);
+    error("Unable to open output file" + OutputFilename, EC);
+    // Don't remove output file if we exit with an error.
+    OutputFile->keep();
+  }
+
+  raw_ostream &OS = OutputFile ? OutputFile->os() : outs();
+
   // Defaults to dumping all sections, unless brief mode is specified in which
   // case only the .debug_info section in dumped.
 #define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME)                \
@@ -405,13 +425,13 @@ int main(int argc, char **argv) {
 
   if (Verify) {
     // If we encountered errors during verify, exit with a non-zero exit status.
-    if (!std::all_of(Objects.begin(), Objects.end(), [](std::string Object) {
-          return handleFile(Object, verifyObjectFile);
+    if (!std::all_of(Objects.begin(), Objects.end(), [&](std::string Object) {
+          return handleFile(Object, verifyObjectFile, OS);
         }))
       exit(1);
   } else
     for (auto Object : Objects)
-      handleFile(Object, dumpObjectFile);
+      handleFile(Object, dumpObjectFile, OS);
 
   return EXIT_SUCCESS;
 }