[lldb/Lua] Make lldb.debugger et al available to Lua
authorJonas Devlieghere <jonas@devlieghere.com>
Thu, 9 Jan 2020 16:15:01 +0000 (08:15 -0800)
committerJonas Devlieghere <jonas@devlieghere.com>
Thu, 9 Jan 2020 16:15:41 +0000 (08:15 -0800)
The Python script interpreter makes the current debugger, target,
process, thread and frame available to interactive scripting sessions
through convenience variables. This patch does the same for Lua.

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

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/Inputs/independent_state.in [new file with mode: 0644]
lldb/test/Shell/ScriptInterpreter/Lua/Inputs/nested_sessions.in [new file with mode: 0644]
lldb/test/Shell/ScriptInterpreter/Lua/Inputs/nested_sessions_2.in [new file with mode: 0644]
lldb/test/Shell/ScriptInterpreter/Lua/convenience_variables.test [new file with mode: 0644]
lldb/test/Shell/ScriptInterpreter/Lua/independent_state.test [new file with mode: 0644]
lldb/test/Shell/ScriptInterpreter/Lua/nested_sessions.test [new file with mode: 0644]

index dc64139..1dd0a9e 100644 (file)
@@ -10,9 +10,9 @@
 #include "llvm/Support/FormatVariadic.h"
 
 using namespace lldb_private;
+using namespace lldb;
 
 llvm::Error Lua::Run(llvm::StringRef buffer) {
-  std::lock_guard<std::mutex> lock(m_mutex);
   int error =
       luaL_loadbuffer(m_lua_state, buffer.data(), buffer.size(), "buffer") ||
       lua_pcall(m_lua_state, 0, 0, 0);
index ed1d159..adc6c61 100644 (file)
@@ -9,6 +9,7 @@
 #ifndef liblldb_Lua_h_
 #define liblldb_Lua_h_
 
+#include "lldb/lldb-types.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Error.h"
 
@@ -38,7 +39,6 @@ public:
   llvm::Error Run(llvm::StringRef buffer);
 
 private:
-  std::mutex m_mutex;
   lua_State *m_lua_state;
 };
 
index d5423b7..e46851c 100644 (file)
@@ -27,7 +27,13 @@ public:
       : IOHandlerEditline(debugger, IOHandler::Type::LuaInterpreter, "lua",
                           ">>> ", "..> ", true, debugger.GetUseColor(), 0,
                           *this, nullptr),
-        m_script_interpreter(script_interpreter) {}
+        m_script_interpreter(script_interpreter) {
+    llvm::cantFail(m_script_interpreter.EnterSession(debugger.GetID()));
+  }
+
+  ~IOHandlerLuaInterpreter() {
+    llvm::cantFail(m_script_interpreter.LeaveSession());
+  }
 
   void IOHandlerInputComplete(IOHandler &io_handler,
                               std::string &data) override {
@@ -89,6 +95,33 @@ void ScriptInterpreterLua::Initialize() {
 
 void ScriptInterpreterLua::Terminate() {}
 
+llvm::Error ScriptInterpreterLua::EnterSession(user_id_t debugger_id) {
+  if (m_session_is_active)
+    return llvm::Error::success();
+
+  const char *fmt_str =
+      "lldb.debugger = lldb.SBDebugger.FindDebuggerWithID({0}); "
+      "lldb.target = lldb.debugger:GetSelectedTarget(); "
+      "lldb.process = lldb.target:GetProcess(); "
+      "lldb.thread = lldb.process:GetSelectedThread(); "
+      "lldb.frame = lldb.thread:GetSelectedFrame()";
+  return m_lua->Run(llvm::formatv(fmt_str, debugger_id).str());
+}
+
+llvm::Error ScriptInterpreterLua::LeaveSession() {
+  if (!m_session_is_active)
+    return llvm::Error::success();
+
+  m_session_is_active = false;
+
+  llvm::StringRef str = "lldb.debugger = nil; "
+                        "lldb.target = nil; "
+                        "lldb.process = nil; "
+                        "lldb.thread = nil; "
+                        "lldb.frame = nil";
+  return m_lua->Run(str);
+}
+
 lldb::ScriptInterpreterSP
 ScriptInterpreterLua::CreateInstance(Debugger &debugger) {
   return std::make_shared<ScriptInterpreterLua>(debugger);
index b34c7d0..550e103 100644 (file)
@@ -43,8 +43,12 @@ public:
 
   Lua &GetLua();
 
+  llvm::Error EnterSession(lldb::user_id_t debugger_id);
+  llvm::Error LeaveSession();
+
 private:
   std::unique_ptr<Lua> m_lua;
+  bool m_session_is_active = false;
 };
 
 } // namespace lldb_private
diff --git a/lldb/test/Shell/ScriptInterpreter/Lua/Inputs/independent_state.in b/lldb/test/Shell/ScriptInterpreter/Lua/Inputs/independent_state.in
new file mode 100644 (file)
index 0000000..6e15a8f
--- /dev/null
@@ -0,0 +1,6 @@
+script foobar = 40 + 7
+script print(foobar)
+script d = lldb.SBDebugger.Create()
+script d:HandleCommand("script foobar = 40 + 2")
+script print(foobar)
+script d:HandleCommand("script print(foobar)")
diff --git a/lldb/test/Shell/ScriptInterpreter/Lua/Inputs/nested_sessions.in b/lldb/test/Shell/ScriptInterpreter/Lua/Inputs/nested_sessions.in
new file mode 100644 (file)
index 0000000..75c57e3
--- /dev/null
@@ -0,0 +1,6 @@
+script
+print(lldb.target, lldb.debugger:GetSelectedTarget())
+lldb.debugger:SetSelectedTarget(lldb.debugger:GetTargetAtIndex(0))
+print(lldb.target, lldb.debugger:GetSelectedTarget())
+lldb.debugger:HandleCommand("script print(lldb.target, lldb.debugger:GetSelectedTarget())")
+print(lldb.target, lldb.debugger:GetSelectedTarget())
diff --git a/lldb/test/Shell/ScriptInterpreter/Lua/Inputs/nested_sessions_2.in b/lldb/test/Shell/ScriptInterpreter/Lua/Inputs/nested_sessions_2.in
new file mode 100644 (file)
index 0000000..a8cc2a5
--- /dev/null
@@ -0,0 +1,2 @@
+script
+print(lldb.target, lldb.debugger:GetSelectedTarget())
diff --git a/lldb/test/Shell/ScriptInterpreter/Lua/convenience_variables.test b/lldb/test/Shell/ScriptInterpreter/Lua/convenience_variables.test
new file mode 100644 (file)
index 0000000..022f2e3
--- /dev/null
@@ -0,0 +1,17 @@
+# REQUIRES: lua
+#
+# This tests that the convenience variables are not nil. Given that there is no
+# target we only expect the debugger to be valid.
+#
+# RUN: cat %s | %lldb --script-language lua 2>&1 | FileCheck %s
+script
+print(string.format("lldb.debugger is valid: %s", lldb.debugger:IsValid()))
+print(string.format("lldb.target is valid: %s", lldb.target:IsValid()))
+print(string.format("lldb.process is valid: %s", lldb.process:IsValid()))
+print(string.format("lldb.thread is valid: %s", lldb.thread:IsValid()))
+print(string.format("lldb.frame is valid: %s", lldb.frame:IsValid()))
+# CHECK: debugger is valid: true
+# CHECK: target is valid: false
+# CHECK: process is valid: false
+# CHECK: thread is valid: false
+# CHECK: frame is valid: false
diff --git a/lldb/test/Shell/ScriptInterpreter/Lua/independent_state.test b/lldb/test/Shell/ScriptInterpreter/Lua/independent_state.test
new file mode 100644 (file)
index 0000000..2ade1b9
--- /dev/null
@@ -0,0 +1,6 @@
+# REQUIRES: lua
+#
+# RUN:  %lldb --script-language lua -s %S/Inputs/independent_state.in 2>&1 | FileCheck %s
+# CHECK: 47
+# CHECK: 47
+# CHECK: 42
diff --git a/lldb/test/Shell/ScriptInterpreter/Lua/nested_sessions.test b/lldb/test/Shell/ScriptInterpreter/Lua/nested_sessions.test
new file mode 100644 (file)
index 0000000..a81418b
--- /dev/null
@@ -0,0 +1,12 @@
+# REQUIRES: lua
+# RUN: mkdir -p %t
+# RUN: echo "int main() { return 0; }" | %clang_host -x c - -o %t/foo
+# RUN: echo "int main() { return 0; }" | %clang_host -x c - -o %t/bar
+# RUN:  %lldb --script-language lua -o "file %t/bar" -o "file %t/foo" -s %S/Inputs/nested_sessions.in  -s %S/Inputs/nested_sessions_2.in 2>&1 | FileCheck %s
+# CHECK: script
+# CHECK-NEXT: foo foo
+# CHECK-NEXT: foo bar
+# CHECK-NEXT: foo bar
+# CHECK-NEXT: foo bar
+# CHECK: script
+# CHECK-NEXT: bar bar