[Lldb-commits] [lldb] 0d01300 - [lldb] Add a "diagnostics dump" command

Jonas Devlieghere via lldb-commits lldb-commits at lists.llvm.org
Mon Oct 31 14:40:49 PDT 2022


Author: Jonas Devlieghere
Date: 2022-10-31T14:40:41-07:00
New Revision: 0d01300aacf6029b6d63f7dcede3ca8e15229d34

URL: https://github.com/llvm/llvm-project/commit/0d01300aacf6029b6d63f7dcede3ca8e15229d34
DIFF: https://github.com/llvm/llvm-project/commit/0d01300aacf6029b6d63f7dcede3ca8e15229d34.diff

LOG: [lldb] Add a "diagnostics dump" command

Add a "diagnostics dump" command to, as the name implies, dump the
diagnostics to disk. The goal of this command is to let the user
generate the diagnostics in case of an issue that doesn't cause the
debugger to crash.

This command is also critical for testing, where we don't want to cause
a crash to emit the diagnostics.

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

Added: 
    lldb/source/Commands/CommandObjectDiagnostics.cpp
    lldb/source/Commands/CommandObjectDiagnostics.h
    lldb/test/Shell/Diagnostics/TestDump.test

Modified: 
    lldb/include/lldb/Utility/Diagnostics.h
    lldb/source/Commands/CMakeLists.txt
    lldb/source/Commands/Options.td
    lldb/source/Interpreter/CommandInterpreter.cpp
    lldb/source/Utility/Diagnostics.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/include/lldb/Utility/Diagnostics.h b/lldb/include/lldb/Utility/Diagnostics.h
index 4a748bd73fd50..86c97c7ff074d 100644
--- a/lldb/include/lldb/Utility/Diagnostics.h
+++ b/lldb/include/lldb/Utility/Diagnostics.h
@@ -34,7 +34,10 @@ class Diagnostics {
   llvm::Error Create(const FileSpec &dir);
 
   /// Gather diagnostics and print a message to the given output stream.
+  /// @{
   bool Dump(llvm::raw_ostream &stream);
+  bool Dump(llvm::raw_ostream &stream, const FileSpec &dir);
+  /// @}
 
   using Callback = std::function<llvm::Error(const FileSpec &)>;
 
@@ -44,6 +47,9 @@ class Diagnostics {
   static void Initialize();
   static void Terminate();
 
+  /// Create a unique diagnostic directory.
+  static llvm::Expected<FileSpec> CreateUniqueDirectory();
+
 private:
   static llvm::Optional<Diagnostics> &InstanceImpl();
 

diff  --git a/lldb/source/Commands/CMakeLists.txt b/lldb/source/Commands/CMakeLists.txt
index a7d64a3de374a..0b705ade5ea87 100644
--- a/lldb/source/Commands/CMakeLists.txt
+++ b/lldb/source/Commands/CMakeLists.txt
@@ -8,6 +8,7 @@ add_lldb_library(lldbCommands
   CommandObjectBreakpoint.cpp
   CommandObjectBreakpointCommand.cpp
   CommandObjectCommands.cpp
+  CommandObjectDiagnostics.cpp
   CommandObjectDisassemble.cpp
   CommandObjectExpression.cpp
   CommandObjectFrame.cpp

diff  --git a/lldb/source/Commands/CommandObjectDiagnostics.cpp b/lldb/source/Commands/CommandObjectDiagnostics.cpp
new file mode 100644
index 0000000000000..12d491529ebaf
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectDiagnostics.cpp
@@ -0,0 +1,114 @@
+//===-- CommandObjectDiagnostics.cpp --------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "CommandObjectDiagnostics.h"
+#include "lldb/Host/OptionParser.h"
+#include "lldb/Interpreter/CommandOptionArgumentTable.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/OptionArgParser.h"
+#include "lldb/Interpreter/OptionValueEnumeration.h"
+#include "lldb/Interpreter/OptionValueUInt64.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Utility/Diagnostics.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+#define LLDB_OPTIONS_diagnostics_dump
+#include "CommandOptions.inc"
+
+class CommandObjectDiagnosticsDump : public CommandObjectParsed {
+public:
+  // Constructors and Destructors
+  CommandObjectDiagnosticsDump(CommandInterpreter &interpreter)
+      : CommandObjectParsed(interpreter, "diagnostics dump",
+                            "Dump diagnostics to disk", nullptr) {}
+
+  ~CommandObjectDiagnosticsDump() override = default;
+
+  class CommandOptions : public Options {
+  public:
+    CommandOptions() = default;
+
+    ~CommandOptions() override = default;
+
+    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+                          ExecutionContext *execution_context) override {
+      Status error;
+      const int short_option = m_getopt_table[option_idx].val;
+
+      switch (short_option) {
+      case 'd':
+        directory.SetDirectory(option_arg);
+        break;
+      default:
+        llvm_unreachable("Unimplemented option");
+      }
+      return error;
+    }
+
+    void OptionParsingStarting(ExecutionContext *execution_context) override {
+      directory.Clear();
+    }
+
+    llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
+      return llvm::makeArrayRef(g_diagnostics_dump_options);
+    }
+
+    FileSpec directory;
+  };
+
+  Options *GetOptions() override { return &m_options; }
+
+protected:
+  llvm::Expected<FileSpec> GetDirectory() {
+    if (m_options.directory) {
+      auto ec =
+          llvm::sys::fs::create_directories(m_options.directory.GetPath());
+      if (ec)
+        return llvm::errorCodeToError(ec);
+      return m_options.directory;
+    }
+    return Diagnostics::CreateUniqueDirectory();
+  }
+
+  bool DoExecute(Args &args, CommandReturnObject &result) override {
+    llvm::Expected<FileSpec> directory = GetDirectory();
+
+    if (!directory) {
+      result.AppendError(llvm::toString(directory.takeError()));
+      return result.Succeeded();
+    }
+
+    llvm::Error error = Diagnostics::Instance().Create(*directory);
+    if (error) {
+      result.AppendErrorWithFormat("failed to write diagnostics to %s",
+                                   directory->GetPath().c_str());
+      result.AppendError(llvm::toString(std::move(error)));
+      return result.Succeeded();
+    }
+
+    result.GetOutputStream() << "diagnostics written to " << *directory << '\n';
+
+    result.SetStatus(eReturnStatusSuccessFinishResult);
+    return result.Succeeded();
+  }
+
+  CommandOptions m_options;
+};
+
+CommandObjectDiagnostics::CommandObjectDiagnostics(
+    CommandInterpreter &interpreter)
+    : CommandObjectMultiword(interpreter, "diagnostics",
+                             "Commands controlling LLDB diagnostics.",
+                             "diagnostics <subcommand> [<command-options>]") {
+  LoadSubCommand(
+      "dump", CommandObjectSP(new CommandObjectDiagnosticsDump(interpreter)));
+}
+
+CommandObjectDiagnostics::~CommandObjectDiagnostics() = default;

diff  --git a/lldb/source/Commands/CommandObjectDiagnostics.h b/lldb/source/Commands/CommandObjectDiagnostics.h
new file mode 100644
index 0000000000000..d28282b850236
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectDiagnostics.h
@@ -0,0 +1,29 @@
+//===-- CommandObjectDiagnostics.h ------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_COMMANDS_COMMANDOBJECTDIAGNOSTICS_H
+#define LLDB_SOURCE_COMMANDS_COMMANDOBJECTDIAGNOSTICS_H
+
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+
+namespace lldb_private {
+
+class CommandObjectDiagnostics : public CommandObjectMultiword {
+public:
+  CommandObjectDiagnostics(CommandInterpreter &interpreter);
+  ~CommandObjectDiagnostics() override;
+
+private:
+  CommandObjectDiagnostics(const CommandObjectDiagnostics &) = delete;
+  const CommandObjectDiagnostics &
+  operator=(const CommandObjectDiagnostics &) = delete;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_COMMANDS_COMMANDOBJECTDIAGNOSTICS_H

diff  --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td
index 6d2da2532b474..b4517877f91c9 100644
--- a/lldb/source/Commands/Options.td
+++ b/lldb/source/Commands/Options.td
@@ -343,6 +343,11 @@ let Command = "disassemble" in {
     Desc<"Force disassembly of large functions.">;
 }
 
+let Command = "diagnostics dump" in {
+  def diagnostics_dump_directory : Option<"directory", "d">, Group<1>,
+    Arg<"Path">, Desc<"Dump the diagnostics to the given directory.">;
+}
+
 let Command = "expression" in {
   def expression_options_all_threads : Option<"all-threads", "a">,
     Groups<[1,2]>, Arg<"Boolean">, Desc<"Should we run all threads if the "

diff  --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp
index 5c11b87dcbe03..eaad0195c1b74 100644
--- a/lldb/source/Interpreter/CommandInterpreter.cpp
+++ b/lldb/source/Interpreter/CommandInterpreter.cpp
@@ -15,6 +15,7 @@
 #include "Commands/CommandObjectApropos.h"
 #include "Commands/CommandObjectBreakpoint.h"
 #include "Commands/CommandObjectCommands.h"
+#include "Commands/CommandObjectDiagnostics.h"
 #include "Commands/CommandObjectDisassemble.h"
 #include "Commands/CommandObjectExpression.h"
 #include "Commands/CommandObjectFrame.h"
@@ -518,6 +519,7 @@ void CommandInterpreter::LoadCommandDictionary() {
   REGISTER_COMMAND_OBJECT("apropos", CommandObjectApropos);
   REGISTER_COMMAND_OBJECT("breakpoint", CommandObjectMultiwordBreakpoint);
   REGISTER_COMMAND_OBJECT("command", CommandObjectMultiwordCommands);
+  REGISTER_COMMAND_OBJECT("diagnostics", CommandObjectDiagnostics);
   REGISTER_COMMAND_OBJECT("disassemble", CommandObjectDisassemble);
   REGISTER_COMMAND_OBJECT("expression", CommandObjectExpression);
   REGISTER_COMMAND_OBJECT("frame", CommandObjectMultiwordFrame);

diff  --git a/lldb/source/Utility/Diagnostics.cpp b/lldb/source/Utility/Diagnostics.cpp
index 14e75c1f2dccb..6bd8fcf28b58b 100644
--- a/lldb/source/Utility/Diagnostics.cpp
+++ b/lldb/source/Utility/Diagnostics.cpp
@@ -44,19 +44,21 @@ void Diagnostics::AddCallback(Callback callback) {
 }
 
 bool Diagnostics::Dump(raw_ostream &stream) {
-  SmallString<128> diagnostics_dir;
-  std::error_code ec =
-      sys::fs::createUniqueDirectory("diagnostics", diagnostics_dir);
-  if (ec) {
+  Expected<FileSpec> diagnostics_dir = CreateUniqueDirectory();
+  if (!diagnostics_dir) {
     stream << "unable to create diagnostic dir: "
-           << toString(errorCodeToError(ec)) << '\n';
+           << toString(diagnostics_dir.takeError()) << '\n';
     return false;
   }
 
-  stream << "LLDB diagnostics written to " << diagnostics_dir << "\n";
+  return Dump(stream, *diagnostics_dir);
+}
+
+bool Diagnostics::Dump(raw_ostream &stream, const FileSpec &dir) {
+  stream << "LLDB diagnostics will be written to " << dir.GetPath() << "\n";
   stream << "Please include the directory content when filing a bug report\n";
 
-  Error error = Create(FileSpec(diagnostics_dir.str()));
+  Error error = Create(dir);
   if (error) {
     stream << toString(std::move(error)) << '\n';
     return false;
@@ -65,6 +67,15 @@ bool Diagnostics::Dump(raw_ostream &stream) {
   return true;
 }
 
+llvm::Expected<FileSpec> Diagnostics::CreateUniqueDirectory() {
+  SmallString<128> diagnostics_dir;
+  std::error_code ec =
+      sys::fs::createUniqueDirectory("diagnostics", diagnostics_dir);
+  if (ec)
+    return errorCodeToError(ec);
+  return FileSpec(diagnostics_dir.str());
+}
+
 Error Diagnostics::Create(const FileSpec &dir) {
   for (Callback c : m_callbacks) {
     if (Error err = c(dir))

diff  --git a/lldb/test/Shell/Diagnostics/TestDump.test b/lldb/test/Shell/Diagnostics/TestDump.test
new file mode 100644
index 0000000000000..9bb34aafc8c3a
--- /dev/null
+++ b/lldb/test/Shell/Diagnostics/TestDump.test
@@ -0,0 +1,15 @@
+# Check that the diagnostics dump command uses the correct directory and
+# creates one if needed.
+
+# Dump to an existing directory.
+# RUN: rm -rf %t.existing
+# RUN: mkdir -p %t.existing
+# RUN: %lldb -o 'diagnostics dump -d %t.existing'
+# RUN: file %t.existing | FileCheck %s
+
+# Dump to a non-existing directory.
+# RUN: rm -rf %t.nonexisting
+# RUN: %lldb -o 'diagnostics dump -d %t.nonexisting'
+# RUN: file %t.nonexisting | FileCheck %s
+
+# CHECK: : directory


        


More information about the lldb-commits mailing list