This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rGd853bd7a4e86: [lldb/Lua] add support for multiline scripted 
breakpoints (authored by tammela).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D93481/new/

https://reviews.llvm.org/D93481

Files:
  lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp
  lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h
  lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp
  lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h
  lldb/test/Shell/ScriptInterpreter/Lua/breakpoint_callback.test
  lldb/test/Shell/ScriptInterpreter/Lua/partial_statements.test

Index: lldb/test/Shell/ScriptInterpreter/Lua/partial_statements.test
===================================================================
--- /dev/null
+++ lldb/test/Shell/ScriptInterpreter/Lua/partial_statements.test
@@ -0,0 +1,15 @@
+# REQUIRES: lua
+# RUN: %lldb -s %s --script-language lua 2>&1 | FileCheck %s
+script
+do
+local a = 123
+print(a)
+end
+# CHECK: 123
+str = 'hello there!'
+function callme()
+print(str)
+end
+callme()
+# CHECK: hello there!
+# CHECK-NOT: error
Index: lldb/test/Shell/ScriptInterpreter/Lua/breakpoint_callback.test
===================================================================
--- lldb/test/Shell/ScriptInterpreter/Lua/breakpoint_callback.test
+++ lldb/test/Shell/ScriptInterpreter/Lua/breakpoint_callback.test
@@ -1,5 +1,13 @@
 # REQUIRES: lua
-# RUN: %lldb -s %s --script-language lua 2>&1 | FileCheck %s
+# RUN: echo "int main() { return 0; }" | %clang_host -x c - -o %t
+# RUN: %lldb -s %s --script-language lua %t 2>&1 | FileCheck %s
 b main
 breakpoint command add -s lua
-# CHECK: error: This script interpreter does not support breakpoint callbacks
+local a = 123
+print(a)
+quit
+run
+# CHECK: 123
+breakpoint command add -s lua
+789_nil
+# CHECK: unexpected symbol near '789'
Index: lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h
===================================================================
--- lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h
+++ lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h
@@ -65,6 +65,10 @@
   llvm::Error EnterSession(lldb::user_id_t debugger_id);
   llvm::Error LeaveSession();
 
+  void CollectDataForBreakpointCommandCallback(
+      std::vector<BreakpointOptions *> &bp_options_vec,
+      CommandReturnObject &result) override;
+
   Status SetBreakpointCommandCallback(BreakpointOptions *bp_options,
                                       const char *command_body_text) override;
 
Index: lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp
===================================================================
--- lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp
+++ lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp
@@ -17,23 +17,33 @@
 #include "lldb/Utility/Stream.h"
 #include "lldb/Utility/StringList.h"
 #include "lldb/Utility/Timer.h"
+#include "llvm/ADT/StringRef.h"
 #include "llvm/Support/FormatAdapters.h"
 #include <memory>
+#include <vector>
 
 using namespace lldb;
 using namespace lldb_private;
 
 LLDB_PLUGIN_DEFINE(ScriptInterpreterLua)
 
+enum ActiveIOHandler {
+  eIOHandlerNone,
+  eIOHandlerBreakpoint,
+  eIOHandlerWatchpoint
+};
+
 class IOHandlerLuaInterpreter : public IOHandlerDelegate,
                                 public IOHandlerEditline {
 public:
   IOHandlerLuaInterpreter(Debugger &debugger,
-                          ScriptInterpreterLua &script_interpreter)
+                          ScriptInterpreterLua &script_interpreter,
+                          ActiveIOHandler active_io_handler = eIOHandlerNone)
       : IOHandlerEditline(debugger, IOHandler::Type::LuaInterpreter, "lua",
                           ">>> ", "..> ", true, debugger.GetUseColor(), 0,
                           *this, nullptr),
-        m_script_interpreter(script_interpreter) {
+        m_script_interpreter(script_interpreter),
+        m_active_io_handler(active_io_handler) {
     llvm::cantFail(m_script_interpreter.GetLua().ChangeIO(
         debugger.GetOutputFile().GetStream(),
         debugger.GetErrorFile().GetStream()));
@@ -44,20 +54,79 @@
     llvm::cantFail(m_script_interpreter.LeaveSession());
   }
 
-  void IOHandlerInputComplete(IOHandler &io_handler,
-                              std::string &data) override {
-    if (llvm::StringRef(data).rtrim() == "quit") {
-      io_handler.SetIsDone(true);
+  void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
+    const char *instructions = nullptr;
+    switch (m_active_io_handler) {
+    case eIOHandlerNone:
+    case eIOHandlerWatchpoint:
+      break;
+    case eIOHandlerBreakpoint:
+      instructions = "Enter your Lua command(s). Type 'quit' to end.\n"
+                     "The commands are compiled as the body of the following "
+                     "Lua function\n"
+                     "function (frame, bp_loc, ...) end\n";
+      SetPrompt(llvm::StringRef("..> "));
+      break;
+    }
+    if (instructions == nullptr)
       return;
+    if (interactive)
+      *io_handler.GetOutputStreamFileSP() << instructions;
+  }
+
+  bool IOHandlerIsInputComplete(IOHandler &io_handler,
+                                StringList &lines) override {
+    size_t last = lines.GetSize() - 1;
+    if (IsQuitCommand(lines.GetStringAtIndex(last))) {
+      if (m_active_io_handler == eIOHandlerBreakpoint)
+        lines.DeleteStringAtIndex(last);
+      return true;
+    }
+    StreamString str;
+    lines.Join("\n", str);
+    if (llvm::Error E =
+            m_script_interpreter.GetLua().CheckSyntax(str.GetString())) {
+      std::string error_str = toString(std::move(E));
+      // Lua always errors out to incomplete code with '<eof>'
+      return error_str.find("<eof>") == std::string::npos;
     }
+    // The breakpoint handler only exits with a explicit 'quit'
+    return m_active_io_handler != eIOHandlerBreakpoint;
+  }
 
-    if (llvm::Error error = m_script_interpreter.GetLua().Run(data)) {
-      *GetOutputStreamFileSP() << llvm::toString(std::move(error));
+  void IOHandlerInputComplete(IOHandler &io_handler,
+                              std::string &data) override {
+    switch (m_active_io_handler) {
+    case eIOHandlerBreakpoint: {
+      auto *bp_options_vec = static_cast<std::vector<BreakpointOptions *> *>(
+          io_handler.GetUserData());
+      for (auto *bp_options : *bp_options_vec) {
+        Status error = m_script_interpreter.SetBreakpointCommandCallback(
+            bp_options, data.c_str());
+        if (error.Fail())
+          *io_handler.GetErrorStreamFileSP() << error.AsCString() << '\n';
+      }
+      io_handler.SetIsDone(true);
+    } break;
+    case eIOHandlerWatchpoint:
+      io_handler.SetIsDone(true);
+      break;
+    case eIOHandlerNone:
+      if (IsQuitCommand(data)) {
+        io_handler.SetIsDone(true);
+        return;
+      }
+      if (llvm::Error error = m_script_interpreter.GetLua().Run(data))
+        *io_handler.GetErrorStreamFileSP() << toString(std::move(error));
+      break;
     }
   }
 
 private:
   ScriptInterpreterLua &m_script_interpreter;
+  ActiveIOHandler m_active_io_handler;
+
+  bool IsQuitCommand(llvm::StringRef cmd) { return cmd.rtrim() == "quit"; }
 };
 
 ScriptInterpreterLua::ScriptInterpreterLua(Debugger &debugger)
@@ -205,6 +274,15 @@
   return *BoolOrErr;
 }
 
+void ScriptInterpreterLua::CollectDataForBreakpointCommandCallback(
+    std::vector<BreakpointOptions *> &bp_options_vec,
+    CommandReturnObject &result) {
+  IOHandlerSP io_handler_sp(
+      new IOHandlerLuaInterpreter(m_debugger, *this, eIOHandlerBreakpoint));
+  io_handler_sp->SetUserData(&bp_options_vec);
+  m_debugger.RunIOHandlerAsync(io_handler_sp);
+}
+
 Status ScriptInterpreterLua::SetBreakpointCommandCallback(
     BreakpointOptions *bp_options, const char *command_body_text) {
   Status error;
Index: lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h
===================================================================
--- lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h
+++ lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h
@@ -36,6 +36,7 @@
   CallBreakpointCallback(void *baton, lldb::StackFrameSP stop_frame_sp,
                          lldb::BreakpointLocationSP bp_loc_sp);
   llvm::Error LoadModule(llvm::StringRef filename);
+  llvm::Error CheckSyntax(llvm::StringRef buffer);
   llvm::Error ChangeIO(FILE *out, FILE *err);
 
 private:
Index: lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp
===================================================================
--- lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp
+++ lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp
@@ -105,6 +105,23 @@
                                                bp_loc_sp);
 }
 
+llvm::Error Lua::CheckSyntax(llvm::StringRef buffer) {
+  int error =
+      luaL_loadbuffer(m_lua_state, buffer.data(), buffer.size(), "buffer");
+  if (error == LUA_OK) {
+    // Pop buffer
+    lua_pop(m_lua_state, 1);
+    return llvm::Error::success();
+  }
+
+  llvm::Error e = llvm::make_error<llvm::StringError>(
+      llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)),
+      llvm::inconvertibleErrorCode());
+  // Pop error message from the stack.
+  lua_pop(m_lua_state, 1);
+  return e;
+}
+
 llvm::Error Lua::LoadModule(llvm::StringRef filename) {
   FileSpec file(filename);
   if (!FileSystem::Instance().Exists(file)) {
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to