[Lldb-commits] [lldb] a37672e - Mark the execution of stop-hooks as non-interactive.

Jim Ingham via lldb-commits lldb-commits at lists.llvm.org
Thu Oct 29 14:42:20 PDT 2020


Author: Jim Ingham
Date: 2020-10-29T14:41:53-07:00
New Revision: a37672e2db7377681d996834a0c3073c9838a549

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

LOG: Mark the execution of stop-hooks as non-interactive.

The intention is not to allow stop-hook commands to query the
user, so this is correct.  It also works around a deadlock in
switching to the Python Session to execute python based commands
in the stop hook when the Debugger stdin is backed by a FILE *.

Differential Revision: https://reviews.llvm.org/D90332

Added: 
    lldb/test/API/api/multithreaded/some_cmd.py
    lldb/test/API/api/multithreaded/test_stop-hook.cpp.template

Modified: 
    lldb/packages/Python/lldbsuite/test/lldbtest.py
    lldb/source/Interpreter/CommandInterpreter.cpp
    lldb/source/Target/Target.cpp
    lldb/test/API/api/multithreaded/TestMultithreaded.py

Removed: 
    


################################################################################
diff  --git a/lldb/packages/Python/lldbsuite/test/lldbtest.py b/lldb/packages/Python/lldbsuite/test/lldbtest.py
index 69da3914f1f2..81110f9f80c4 100644
--- a/lldb/packages/Python/lldbsuite/test/lldbtest.py
+++ b/lldb/packages/Python/lldbsuite/test/lldbtest.py
@@ -1927,6 +1927,7 @@ def generateSource(self, source):
             header.startswith("SB") and header.endswith(".h"))]
         includes = '\n'.join(list)
         new_content = content.replace('%include_SB_APIs%', includes)
+        new_content = new_content.replace('%SOURCE_DIR%', self.getSourceDir())
         src = os.path.join(self.getBuildDir(), source)
         with open(src, 'w') as f:
             f.write(new_content)

diff  --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp
index c6031f571311..d6b4b89da1c9 100644
--- a/lldb/source/Interpreter/CommandInterpreter.cpp
+++ b/lldb/source/Interpreter/CommandInterpreter.cpp
@@ -2307,6 +2307,8 @@ void CommandInterpreter::HandleCommands(const StringList &commands,
     }
 
     CommandReturnObject tmp_result(m_debugger.GetUseColor());
+    tmp_result.SetInteractive(result.GetInteractive());
+
     // If override_context is not NULL, pass no_context_switching = true for
     // HandleCommand() since we updated our context already.
 

diff  --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp
index 6b8a053b972e..7c78b4a84c41 100644
--- a/lldb/source/Target/Target.cpp
+++ b/lldb/source/Target/Target.cpp
@@ -3286,6 +3286,7 @@ Target::StopHookCommandLine::HandleStop(ExecutionContext &exc_ctx,
 
   CommandReturnObject result(false);
   result.SetImmediateOutputStream(output_sp);
+  result.SetInteractive(false);
   Debugger &debugger = exc_ctx.GetTargetPtr()->GetDebugger();
   CommandInterpreterRunOptions options;
   options.SetStopOnContinue(true);

diff  --git a/lldb/test/API/api/multithreaded/TestMultithreaded.py b/lldb/test/API/api/multithreaded/TestMultithreaded.py
index 436f645e6521..60c2c3b372cb 100644
--- a/lldb/test/API/api/multithreaded/TestMultithreaded.py
+++ b/lldb/test/API/api/multithreaded/TestMultithreaded.py
@@ -23,9 +23,19 @@ def setUp(self):
         self.generateSource('test_listener_event_description.cpp')
         self.generateSource('test_listener_event_process_state.cpp')
         self.generateSource('test_listener_resume.cpp')
+        self.generateSource('test_stop-hook.cpp')
 
     mydir = TestBase.compute_mydir(__file__)
 
+    @skipIfRemote
+    @skipIfNoSBHeaders
+    # clang-cl does not support throw or catch (llvm.org/pr24538)
+    @skipIfWindows
+    def test_python_stop_hook(self):
+        """Test that you can run a python command in a stop-hook when stdin is File based. """
+        self.build_and_test('driver.cpp test_stop-hook.cpp',
+                            'test_python_stop_hook')
+
     @skipIfRemote
     @skipIfNoSBHeaders
     # clang-cl does not support throw or catch (llvm.org/pr24538)

diff  --git a/lldb/test/API/api/multithreaded/some_cmd.py b/lldb/test/API/api/multithreaded/some_cmd.py
new file mode 100644
index 000000000000..8db4b5f7b432
--- /dev/null
+++ b/lldb/test/API/api/multithreaded/some_cmd.py
@@ -0,0 +1,33 @@
+""" Test command for checking the Python commands can run in a stop-hook """
+import lldb
+
+did_run = False
+
+class SomeCommand:
+    def __init__(self, debugger, unused):
+        self.dbg = debugger
+    def __call__(self, debugger, command, exe_ctx, result):
+        global did_run
+        did_run = True
+        result.PutCString("some output\n")
+
+    def get_short_help(self):
+        return "Test command - sets a variable."
+
+class OtherCommand:
+    def __init__(self, debugger, unused):
+        self.dbg = debugger
+    def __call__(self, debugger, command, exe_ctx, result):
+        global did_run
+        if did_run:
+            result.SetStatus(lldb.eReturnStatusSuccessFinishNoResult)
+        else:
+            result.SetStatus(lldb.eReturnStatusFailed)
+
+    def get_short_help(self):
+        return "Test command - sets a variable."
+
+def __lldb_init_module(debugger, unused):
+    print("Adding command some-cmd and report-cmd")
+    debugger.HandleCommand("command script add -c some_cmd.SomeCommand some-cmd")
+    debugger.HandleCommand("command script add -c some_cmd.OtherCommand report-cmd")

diff  --git a/lldb/test/API/api/multithreaded/test_stop-hook.cpp.template b/lldb/test/API/api/multithreaded/test_stop-hook.cpp.template
new file mode 100644
index 000000000000..8b60421ec301
--- /dev/null
+++ b/lldb/test/API/api/multithreaded/test_stop-hook.cpp.template
@@ -0,0 +1,130 @@
+// LLDB C++ API Test: Verify that when the Debugger stdin
+// is set to a FILE *, lldb can still successfully run a
+// python command in a stop hook.
+
+#include <errno.h>
+#include <mutex>
+#include <stdio.h>
+#include <string>
+#include <vector>
+
+%include_SB_APIs%
+
+#include "common.h"
+
+using namespace lldb;
+
+void test(SBDebugger &dbg, std::vector<std::string> args) {
+  // The problem we had was that when the thread that was
+  // waiting on input went into the call to 'read' it had
+  // the file handle lock.  Then when the python interpreter
+  // Initialized itself to run the python command, it tried
+  // to flush the file channel, and that deadlocked.
+  // This only happens when Async is true, since otherwise
+  // the process event is handled on the I/O read thread,
+  // which sidestepped the problem.
+  dbg.SetAsync(true);
+
+  SBTarget target = dbg.CreateTarget(args.at(0).c_str());
+  if (!target.IsValid())
+    throw Exception("invalid target");
+
+  SBBreakpoint breakpoint = target.BreakpointCreateByName("next");
+  if (!breakpoint.IsValid())
+    throw Exception("invalid breakpoint");
+
+  SBCommandInterpreter interp = dbg.GetCommandInterpreter();
+  SBCommandReturnObject result;
+
+  // Bring in the python command. We actually add two commands,
+  // one that runs in the stop hook and sets a variable when it
+  // runs, and one that reports out the variable so we can ensure
+  // that we did indeed run the stop hook.
+  const char *source_dir = "%SOURCE_DIR%";
+  SBFileSpec script_spec(source_dir);
+  script_spec.AppendPathComponent("some_cmd.py");
+  char path[PATH_MAX];
+  script_spec.GetPath(path, PATH_MAX);
+
+  std::string import_command("command script import ");
+  import_command.append(path);
+  interp.HandleCommand(import_command.c_str(), result);
+  if (!result.Succeeded())
+    throw Exception("Couldn't import %SOURCE_DIR%/some_cmd.py");
+
+  SBProcess process = target.LaunchSimple(nullptr, nullptr, nullptr);
+  if (!process.IsValid())
+    throw Exception("Couldn't launch process.");
+  if (process.GetState() != lldb::eStateStopped)
+    throw Exception("Process was not stopped");
+
+  process.SetSelectedThreadByIndexID(0);
+
+  // Now add the stop hook:
+  interp.HandleCommand("target stop-hook add -o some-cmd", result);
+  if (!result.Succeeded())
+    throw Exception("Couldn't add a stop hook.");
+
+  // Now switch the I/O over to a pipe, which will be handled by the
+  // NativeFile class:
+  int to_lldb_des[2];
+  int pipe_result = pipe(to_lldb_des);
+  FILE *fh_lldb_in = fdopen(to_lldb_des[0], "r");
+  FILE *fh_to_lldb = fdopen(to_lldb_des[1], "w");
+
+  // We need to reset the handle before destroying the debugger
+  // or the same deadlock will stall exiting:
+  class Cleanup {
+  public:
+    Cleanup(SBDebugger dbg, int filedes[2]) : m_dbg(dbg) {
+      m_file = m_dbg.GetInputFileHandle();
+      m_filedes[0] = filedes[0];
+      m_filedes[1] = filedes[1];
+    }
+    ~Cleanup() {
+      m_dbg.SetInputFileHandle(m_file, false);
+      close(m_filedes[0]);
+      close(m_filedes[1]);
+    }
+
+  private:
+    FILE *m_file;
+    SBDebugger m_dbg;
+    int m_filedes[2];
+  };
+  Cleanup cleanup(dbg, to_lldb_des);
+
+  dbg.SetInputFileHandle(fh_lldb_in, false);
+
+  // Now run the command interpreter.  You have to pass true to
+  // start thread so we will run the I/O in a separate thread.
+  dbg.RunCommandInterpreter(false, true);
+
+  // Now issue a stepi, and fetch the running and stopped events:
+  fprintf(fh_to_lldb, "thread step-inst\n");
+
+  SBEvent proc_event;
+  StateType state;
+  bool got_event;
+
+  got_event = dbg.GetListener().WaitForEventForBroadcaster(
+      100, process.GetBroadcaster(), proc_event);
+  if (!got_event)
+    throw Exception("Didn't get running event");
+  state = SBProcess::GetStateFromEvent(proc_event);
+  if (state != eStateRunning)
+    throw Exception("Event wasn't a running event.");
+
+  got_event = dbg.GetListener().WaitForEventForBroadcaster(
+      100, process.GetBroadcaster(), proc_event);
+  if (!got_event)
+    throw Exception("Didn't get a stopped event");
+  state = SBProcess::GetStateFromEvent(proc_event);
+  if (state != eStateStopped)
+    throw Exception("Event wasn't a stop event.");
+
+  // At this point the stop hook should have run.  Check that:
+  interp.HandleCommand("report-cmd", result);
+  if (!result.Succeeded())
+    throw Exception("Didn't actually call stop hook.");
+}


        


More information about the lldb-commits mailing list