d-millar updated this revision to Diff 410920.
d-millar added a comment.

Rebased on v14


Repository:
  rLLDB LLDB

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

https://reviews.llvm.org/D111409

Files:
  lldb/CMakeLists.txt
  lldb/bindings/CMakeLists.txt
  lldb/bindings/java/CMakeLists.txt
  lldb/bindings/java/SWIG/LldbScriptInterpreter.java
  lldb/bindings/java/java-typemaps.swig
  lldb/bindings/java/java-wrapper.swig
  lldb/bindings/java/java.swig
  lldb/cmake/modules/FindJavaAndSwig.cmake
  lldb/cmake/modules/LLDBConfig.cmake
  lldb/docs/resources/build.rst
  lldb/include/lldb/Core/IOHandler.h
  lldb/include/lldb/Host/Config.h.cmake
  lldb/include/lldb/lldb-enumerations.h
  lldb/source/API/CMakeLists.txt
  lldb/source/API/SBDebugger.cpp
  lldb/source/API/liblldb-private.exports
  lldb/source/API/liblldb.exports
  lldb/source/Commands/CommandObjectBreakpointCommand.cpp
  lldb/source/Commands/CommandObjectScript.cpp
  lldb/source/Commands/CommandObjectWatchpointCommand.cpp
  lldb/source/Interpreter/OptionArgParser.cpp
  lldb/source/Interpreter/ScriptInterpreter.cpp
  lldb/source/Plugins/ScriptInterpreter/CMakeLists.txt
  lldb/source/Plugins/ScriptInterpreter/Java/CMakeLists.txt
  lldb/source/Plugins/ScriptInterpreter/Java/Java.cpp
  lldb/source/Plugins/ScriptInterpreter/Java/Java.h
  lldb/source/Plugins/ScriptInterpreter/Java/ScriptInterpreterJava.cpp
  lldb/source/Plugins/ScriptInterpreter/Java/ScriptInterpreterJava.h
  lldb/test/CMakeLists.txt
  lldb/test/Shell/ScriptInterpreter/Java/Inputs/independent_state.in
  lldb/test/Shell/ScriptInterpreter/Java/Inputs/nested_sessions.in
  lldb/test/Shell/ScriptInterpreter/Java/Inputs/nested_sessions_2.in
  lldb/test/Shell/ScriptInterpreter/Java/Inputs/testmodule.java
  lldb/test/Shell/ScriptInterpreter/Java/bindings.test
  lldb/test/Shell/ScriptInterpreter/Java/breakpoint_callback.test
  lldb/test/Shell/ScriptInterpreter/Java/breakpoint_function_callback.test
  lldb/test/Shell/ScriptInterpreter/Java/breakpoint_oneline_callback.test
  lldb/test/Shell/ScriptInterpreter/Java/command_script_import.test
  lldb/test/Shell/ScriptInterpreter/Java/convenience_variables.test
  lldb/test/Shell/ScriptInterpreter/Java/fail_breakpoint_oneline.test
  lldb/test/Shell/ScriptInterpreter/Java/independent_state.test
  lldb/test/Shell/ScriptInterpreter/Java/io.test
  lldb/test/Shell/ScriptInterpreter/Java/java-python.test
  lldb/test/Shell/ScriptInterpreter/Java/java.test
  lldb/test/Shell/ScriptInterpreter/Java/lit.local.cfg
  lldb/test/Shell/ScriptInterpreter/Java/nested_sessions.test
  lldb/test/Shell/ScriptInterpreter/Java/partial_statements.test
  lldb/test/Shell/ScriptInterpreter/Java/persistent_state.test
  lldb/test/Shell/ScriptInterpreter/Java/print.test
  lldb/test/Shell/ScriptInterpreter/Java/quit.test
  lldb/test/Shell/ScriptInterpreter/Java/watchpoint_callback.test
  lldb/test/Shell/lit.cfg.py
  lldb/test/Shell/lit.site.cfg.py.in
  lldb/test/Unit/lit.cfg.py
  lldb/unittests/ScriptInterpreter/CMakeLists.txt
  lldb/unittests/ScriptInterpreter/Java/CMakeLists.txt
  lldb/unittests/ScriptInterpreter/Java/JavaTests.cpp
  lldb/unittests/ScriptInterpreter/Java/ScriptInterpreterTests.cpp

Index: lldb/unittests/ScriptInterpreter/Java/ScriptInterpreterTests.cpp
===================================================================
--- /dev/null
+++ lldb/unittests/ScriptInterpreter/Java/ScriptInterpreterTests.cpp
@@ -0,0 +1,59 @@
+//===-- JavaTests.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 "Plugins/Platform/Linux/PlatformLinux.h"
+#include "Plugins/ScriptInterpreter/Java/ScriptInterpreterJava.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Utility/Reproducer.h"
+#include "gtest/gtest.h"
+
+using namespace lldb_private;
+using namespace lldb_private::repro;
+using namespace lldb;
+
+namespace {
+class ScriptInterpreterTest : public ::testing::Test {
+public:
+  void SetUp() override {
+    llvm::cantFail(Reproducer::Initialize(ReproducerMode::Off, llvm::None));
+    FileSystem::Initialize();
+    HostInfo::Initialize();
+
+    // Pretend Linux is the host platform.
+    platform_linux::PlatformLinux::Initialize();
+    ArchSpec arch("powerpc64-pc-linux");
+    Platform::SetHostPlatform(
+        platform_linux::PlatformLinux::CreateInstance(true, &arch));
+  }
+  void TearDown() override {
+    platform_linux::PlatformLinux::Terminate();
+    HostInfo::Terminate();
+    FileSystem::Terminate();
+    Reproducer::Terminate();
+  }
+};
+} // namespace
+
+TEST_F(ScriptInterpreterTest, ExecuteOneLine) {
+  DebuggerSP debugger_sp = Debugger::CreateInstance();
+  ASSERT_TRUE(debugger_sp);
+
+  ScriptInterpreterJava script_interpreter(*debugger_sp);
+  //if (llvm::Error e = script_interpreter.EnterSession(debugger_sp->GetID())) {
+  //  return;
+  //}
+  CommandReturnObject result(/*colors*/ false);
+  EXPECT_TRUE(script_interpreter.ExecuteOneLine("System.err.println(args);", &result));
+  EXPECT_FALSE(script_interpreter.ExecuteOneLine("nil = foo", &result));
+  EXPECT_TRUE(result.GetErrorData().startswith(
+      "error: java failed attempting to evaluate 'nil = foo'"));
+}
Index: lldb/unittests/ScriptInterpreter/Java/JavaTests.cpp
===================================================================
--- /dev/null
+++ lldb/unittests/ScriptInterpreter/Java/JavaTests.cpp
@@ -0,0 +1,64 @@
+//===-- JavaTests.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 "Plugins/ScriptInterpreter/Java/Java.h"
+#include "gtest/gtest.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+extern "C" int javaopen_lldb(JNIEnv *L) { return 0; }
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
+
+// Disable warning C4190: 'LLDBSwigPythonBreakpointCallbackFunction' has
+// C-linkage specified, but returns UDT 'llvm::Expected<bool>' which is
+// incompatible with C
+#if _MSC_VER
+#pragma warning (push)
+#pragma warning (disable : 4190)
+#endif
+
+extern "C" llvm::Expected<bool> LLDBSwigJavaBreakpointCallbackFunction(
+    JNIEnv *L, lldb::StackFrameSP stop_frame_sp,
+    lldb::BreakpointLocationSP bp_loc_sp, StructuredDataImpl *extra_args_impl) {
+  return false;
+}
+
+extern "C" llvm::Expected<bool> LLDBSwigJavaWatchpointCallbackFunction(
+    JNIEnv *L, lldb::StackFrameSP stop_frame_sp, lldb::WatchpointSP wp_sp) {
+  return false;
+}
+
+#if _MSC_VER
+#pragma warning (pop)
+#endif
+
+#pragma clang diagnostic pop
+
+TEST(JavaTest, RunValid) {
+  Java java;
+  llvm::Error error = java.Test("int foo = 1;");
+  EXPECT_FALSE(static_cast<bool>(error));
+}
+
+TEST(JavaTest, RunError) {
+  Java java;
+  llvm::Error error = java.RunError("ERROR");
+  EXPECT_TRUE(static_cast<bool>(error));
+  EXPECT_EQ(llvm::toString(std::move(error)),"ERROR\n");
+}
+
+TEST(JavaTest, RunInvalid) {
+  Java java;
+  llvm::Error error = java.Test("foo == 1");
+  EXPECT_TRUE(static_cast<bool>(error));
+  EXPECT_EQ(llvm::toString(std::move(error)), "Failed to execute '/run'");
+}
+
Index: lldb/unittests/ScriptInterpreter/Java/CMakeLists.txt
===================================================================
--- /dev/null
+++ lldb/unittests/ScriptInterpreter/Java/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_lldb_unittest(ScriptInterpreterJavaTests
+  JavaTests.cpp
+  ScriptInterpreterTests.cpp
+
+  LINK_LIBS
+    lldbHost
+    lldbPluginScriptInterpreterJava
+    lldbPluginPlatformLinux
+    LLVMTestingSupport
+  LINK_COMPONENTS
+    Support
+  )
Index: lldb/unittests/ScriptInterpreter/CMakeLists.txt
===================================================================
--- lldb/unittests/ScriptInterpreter/CMakeLists.txt
+++ lldb/unittests/ScriptInterpreter/CMakeLists.txt
@@ -4,3 +4,6 @@
 if (LLDB_ENABLE_LUA)
   add_subdirectory(Lua)
 endif()
+if (LLDB_ENABLE_JAVA)
+  add_subdirectory(Java)
+endif()
Index: lldb/test/Unit/lit.cfg.py
===================================================================
--- lldb/test/Unit/lit.cfg.py
+++ lldb/test/Unit/lit.cfg.py
@@ -29,6 +29,9 @@
     'TEMP',
     'TMP',
     'XDG_CACHE_HOME',
+    'JAVA_HOME',
+    'CLASSPATH',
+    'LLVM_SYMBOLIZER_PATH',
 ])
 llvm_config.with_environment('PATH',
                              os.path.dirname(sys.executable),
Index: lldb/test/Shell/lit.site.cfg.py.in
===================================================================
--- lldb/test/Shell/lit.site.cfg.py.in
+++ lldb/test/Shell/lit.site.cfg.py.in
@@ -21,6 +21,7 @@
 config.lldb_bitness = 64 if @LLDB_IS_64_BITS@ else 32
 config.lldb_enable_python = @LLDB_ENABLE_PYTHON@
 config.lldb_enable_lua = @LLDB_ENABLE_LUA@
+config.lldb_enable_java = @LLDB_ENABLE_JAVA@
 config.lldb_build_directory = "@LLDB_TEST_BUILD_DIRECTORY@"
 config.lldb_system_debugserver = @LLDB_USE_SYSTEM_DEBUGSERVER@
 # The shell tests use their own module caches.
Index: lldb/test/Shell/lit.cfg.py
===================================================================
--- lldb/test/Shell/lit.cfg.py
+++ lldb/test/Shell/lit.cfg.py
@@ -45,6 +45,9 @@
     'TEMP',
     'TMP',
     'XDG_CACHE_HOME',
+    'JAVA_HOME',
+    'CLASSPATH',
+    'LLVM_SYMBOLIZER_PATH',
 ])
 
 # Support running the test suite under the lldb-repro wrapper. This makes it
@@ -118,6 +121,9 @@
 if config.lldb_enable_lua:
     config.available_features.add('lua')
 
+if config.lldb_enable_java:
+    config.available_features.add('java')
+
 if config.lldb_enable_lzma:
     config.available_features.add('lzma')
 
Index: lldb/test/Shell/ScriptInterpreter/Java/watchpoint_callback.test
===================================================================
--- /dev/null
+++ lldb/test/Shell/ScriptInterpreter/Java/watchpoint_callback.test
@@ -0,0 +1,32 @@
+# XFAIL: system-netbsd
+# RUN: echo "int main() { int val = 1; val++; return 0; }" | %clang_host -x c - -g -o %t
+# RUN: %lldb -s %s --script-language java %t 2>&1 | FileCheck %s
+b main
+r
+watchpoint set variable val
+watchpoint command add -s java
+System.out.println("val=" + frame.FindVariable("val").GetValue());
+quit
+c
+# CHECK: val=1
+# CHECK: val=2
+# CHECK: Process {{[0-9]+}} exited
+r
+watchpoint set variable val
+watchpoint modify 1 -c "(val == 1)"
+watchpoint command add -s java
+System.out.println("conditional watchpoint");
+SBWatchpoint wpx = target.FindWatchpointByID(wp.GetID());
+wpx.SetEnabled(false);
+quit
+c
+# CHECK-COUNT-1: conditional watchpoint
+# CHECK: Process {{[0-9]+}} exited
+r
+watchpoint set expr 0x00
+watchpoint command add -s java
+System.out.println("never triggers");
+quit
+c
+# CHECK-NOT: never triggers
+# CHECK: Process {{[0-9]+}} exited
Index: lldb/test/Shell/ScriptInterpreter/Java/quit.test
===================================================================
--- /dev/null
+++ lldb/test/Shell/ScriptInterpreter/Java/quit.test
@@ -0,0 +1,9 @@
+# UNSUPPORTED: lldb-repro
+#
+# RUN: cat %s | %lldb --script-language java 2>&1 | FileCheck %s
+script
+System.out.println(95000 + 126);
+quit
+target list
+# CHECK: 95126
+# CHECK: No targets
Index: lldb/test/Shell/ScriptInterpreter/Java/print.test
===================================================================
--- /dev/null
+++ lldb/test/Shell/ScriptInterpreter/Java/print.test
@@ -0,0 +1,29 @@
+# UNSUPPORTED: lldb-repro
+#
+# RUN: rm -rf %t.stderr %t.stdout
+# RUN: cat %s | %lldb --script-language java 2> %t.stderr > %t.stdout
+# RUN: cat %t.stdout | FileCheck %s --check-prefix STDOUT
+# RUN: cat %t.stderr | FileCheck %s --check-prefix STDERR
+script
+/main
+/init
+SBFile file = new SBFile(2, "w", false);
+debugger.SetOutputFile(file);
+System.out.println(95000 + 126);
+/close
+/run
+quit
+script
+/main
+/init
+System.err.println("SBD@"+debugger.GetID());
+/close
+/run
+quit
+
+# STDOUT: 95126
+# STDERR: SBD@1
+
+# RUN: rm -rf %t.stderr %t.stdout
+# RUN: %lldb --script-language java -o 'script System.out.println(95000 + 126);' 2> %t.stderr > %t.stdout
+# RUN: cat %t.stdout | FileCheck %s --check-prefix STDOUT
Index: lldb/test/Shell/ScriptInterpreter/Java/persistent_state.test
===================================================================
--- /dev/null
+++ lldb/test/Shell/ScriptInterpreter/Java/persistent_state.test
@@ -0,0 +1,2 @@
+# RUN: %lldb --script-language java -o 'script /shell int foo = 1010;' -o 'script /shell int bar = 101;' -o 'script /shell foo+bar;' 2>&1 | FileCheck %s
+# CHECK: 1111
Index: lldb/test/Shell/ScriptInterpreter/Java/partial_statements.test
===================================================================
--- /dev/null
+++ lldb/test/Shell/ScriptInterpreter/Java/partial_statements.test
@@ -0,0 +1,19 @@
+# RUN: %lldb -s %s --script-language java 2>&1 | FileCheck %s
+script
+/main
+{
+int a = 123;
+System.out.println(a);
+}
+/close
+/run
+/main
+System.out.println(str);
+}
+static String str = "hello there!";
+}
+/run
+quit
+# CHECK: 123
+# CHECK: hello there!
+# CHECK-NOT: error
Index: lldb/test/Shell/ScriptInterpreter/Java/nested_sessions.test
===================================================================
--- /dev/null
+++ lldb/test/Shell/ScriptInterpreter/Java/nested_sessions.test
@@ -0,0 +1,10 @@
+# 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 java -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: foo foo
+# CHECK-NEXT: foo bar
+# CHECK-NEXT: foo bar
+# CHECK: script
+# CHECK-NEXT: bar bar
Index: lldb/test/Shell/ScriptInterpreter/Java/lit.local.cfg
===================================================================
--- /dev/null
+++ lldb/test/Shell/ScriptInterpreter/Java/lit.local.cfg
@@ -0,0 +1,3 @@
+if 'java' not in config.available_features:
+  config.unsupported = True
+
Index: lldb/test/Shell/ScriptInterpreter/Java/java.test
===================================================================
--- /dev/null
+++ lldb/test/Shell/ScriptInterpreter/Java/java.test
@@ -0,0 +1,6 @@
+# RUN: %lldb --script-language java -o 'script System.out.println(1000+100+10+1);' 2>&1 | FileCheck %s
+# RUN: %lldb --script-language java -o 'script -- System.out.println(1000+100+10+1);' 2>&1 | FileCheck %s
+# RUN: %lldb --script-language java -o 'script --language default -- System.out.println(1000+100+10+1);' 2>&1 | FileCheck %s
+# RUN: %lldb -o 'script -l java -- System.out.println(1000+100+10+1);' 2>&1 | FileCheck %s
+# RUN: %lldb -o 'script --language java -- System.out.println(1000+100+10+1);' 2>&1 | FileCheck %s
+# CHECK: 1111
Index: lldb/test/Shell/ScriptInterpreter/Java/java-python.test
===================================================================
--- /dev/null
+++ lldb/test/Shell/ScriptInterpreter/Java/java-python.test
@@ -0,0 +1,20 @@
+# REQUIRES: python
+# UNSUPPORTED: lldb-repro
+
+# RUN: mkdir -p %t
+# RUN: cd %t
+# RUN: echo "int main() { return 0; }" | %clang_host -x c - -o a.out
+# RUN: cat %s | %lldb 2>&1 | FileCheck %s
+script -l java --
+/main
+/init
+target = debugger.CreateTarget("a.out");
+System.out.println("target is valid: " + target.IsValid());
+debugger.SetSelectedTarget(target);
+/close
+/run
+quit
+# CHECK: target is valid: true
+script -l python --
+print("selected target: {}".format(lldb.debugger.GetSelectedTarget()))
+# CHECK: selected target: a.out
Index: lldb/test/Shell/ScriptInterpreter/Java/io.test
===================================================================
--- /dev/null
+++ lldb/test/Shell/ScriptInterpreter/Java/io.test
@@ -0,0 +1,27 @@
+# UNSUPPORTED: lldb-repro
+#
+# RUN: rm -rf %t.stderr %t.stdout
+# RUN: cat %s | %lldb --script-language java 2> %t.stderr > %t.stdout
+# RUN: cat %t.stdout | FileCheck %s --check-prefix STDOUT
+# RUN: cat %t.stderr | FileCheck %s --check-prefix STDERR
+script
+/main
+/init
+SBFile file = new SBFile(2, "w", false);
+debugger.SetOutputFile(file);
+System.out.println(95000 + 126);
+/close
+/run
+quit
+script
+/main
+System.err.println(95000 + 14);
+/close
+/run
+
+# STDOUT: 95126
+# STDERR: 95014
+
+# RUN: rm -rf %t.stderr %t.stdout
+# RUN: %lldb --script-language java -o 'script System.err.println(95000 + 126);' 2> %t.stderr > %t.stdout
+# RUN: cat %t.stderr | FileCheck %s --check-prefix STDOUT
Index: lldb/test/Shell/ScriptInterpreter/Java/independent_state.test
===================================================================
--- /dev/null
+++ lldb/test/Shell/ScriptInterpreter/Java/independent_state.test
@@ -0,0 +1,5 @@
+# RUN:  %lldb --script-language java -s %S/Inputs/independent_state.in 2>&1 | FileCheck %s
+# CHECK: 47
+# CHECK: 47
+# CHECK: 42
+# CHECK: 42
Index: lldb/test/Shell/ScriptInterpreter/Java/fail_breakpoint_oneline.test
===================================================================
--- /dev/null
+++ lldb/test/Shell/ScriptInterpreter/Java/fail_breakpoint_oneline.test
@@ -0,0 +1,4 @@
+# RUN: %lldb -s %s --script-language java 2>&1 | FileCheck %s
+b main
+breakpoint command add -s java -o '1234_foo'
+# CHECK: error: Failed to execute '/compile'
Index: lldb/test/Shell/ScriptInterpreter/Java/convenience_variables.test
===================================================================
--- /dev/null
+++ lldb/test/Shell/ScriptInterpreter/Java/convenience_variables.test
@@ -0,0 +1,21 @@
+# UNSUPPORTED: lldb-repro
+#
+# 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 java 2>&1 | FileCheck %s
+script
+/main
+/init
+System.out.println("debugger is valid: " + debugger.IsValid());
+System.out.println("target is valid: " + target.IsValid());
+System.out.println("process is valid: " + process.IsValid());
+System.out.println("thread is valid: " + thread.IsValid());
+System.out.println("frame is valid: " + frame.IsValid());
+/close
+/run
+# 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
Index: lldb/test/Shell/ScriptInterpreter/Java/command_script_import.test
===================================================================
--- /dev/null
+++ lldb/test/Shell/ScriptInterpreter/Java/command_script_import.test
@@ -0,0 +1,12 @@
+# RUN: %lldb --script-language java -o 'command script import %S/Inputs/testmodule.java' -o 'script testmodule.foo();' 2>&1 | FileCheck %s
+# CHECK: Hello World!
+
+# RUN: mkdir -p %t
+# RUN: cp %S/Inputs/testmodule.java %t/testmodule.notjava
+# RUN: %lldb --script-language java -o 'command script import %t/testmodule.notjava' -o 'script testmodule.foo();' 2>&1 | FileCheck %s --check-prefix EXTENSION
+# EXTENSION: error: module importing failed: java failed to import '{{.*}}testmodule.notjava': invalid extension
+# EXTENSION-NOT: Hello World!
+
+# RUN: %lldb --script-language java -o 'command script import %S/Inputs/bogus' -o 'script testmodule.foo();' 2>&1 | FileCheck %s --check-prefix NONEXISTING
+# NONEXISTING: error: module importing failed: java failed to import '{{.*}}bogus': invalid path
+# NONEXISTING-NOT: Hello World!
Index: lldb/test/Shell/ScriptInterpreter/Java/breakpoint_oneline_callback.test
===================================================================
--- /dev/null
+++ lldb/test/Shell/ScriptInterpreter/Java/breakpoint_oneline_callback.test
@@ -0,0 +1,18 @@
+# RUN: echo "int main() { return 0; }" | %clang_host -x c - -o %t
+# RUN: %lldb -s %s --script-language java %t 2>&1 | FileCheck %s
+b main
+breakpoint command add -s java -o 'return false;'
+run
+# CHECK: Process {{[0-9]+}} exited with status = 0
+breakpoint command add -s java -o 'System.out.println("bacon");'
+run
+# CHECK: bacon
+# CHECK: Process {{[0-9]+}} exited with status = 0
+breakpoint command add -s java -o "return true;"
+run
+# CHECK: Process {{[0-9]+}} stopped
+breakpoint command add -s java -o 'System.out.println("my error message");'
+run
+# CHECK: my error message
+# CHECK: Process {{[0-9]+}} exited with status = 0
+
Index: lldb/test/Shell/ScriptInterpreter/Java/breakpoint_function_callback.test
===================================================================
--- /dev/null
+++ lldb/test/Shell/ScriptInterpreter/Java/breakpoint_function_callback.test
@@ -0,0 +1,23 @@
+# RUN: echo "int main() { return 0; }" | %clang_host -x c - -o %t
+# RUN: %lldb -s %s --script-language java %t 2>&1 | FileCheck %s
+b main
+script
+/bpt abc
+System.out.println(args);
+if (args != null) {
+   SBStream stream = new SBStream();
+   SBStructuredData val = args.GetValueForKey("foo");
+   val.GetDescription(stream);
+   System.out.println(stream.GetData());
+}
+return true;
+/close
+/compile
+quit
+breakpoint command add -s java -F abc
+r
+# CHECK: null
+breakpoint command add -s java -F abc -k foo -v 123pizza!
+r
+# CHECK: "123pizza!"
+
Index: lldb/test/Shell/ScriptInterpreter/Java/breakpoint_callback.test
===================================================================
--- /dev/null
+++ lldb/test/Shell/ScriptInterpreter/Java/breakpoint_callback.test
@@ -0,0 +1,11 @@
+# RUN: echo "int main() { return 0; }" | %clang_host -x c - -o %t
+# RUN: %lldb -s %s --script-language java %t 2>&1 | FileCheck %s
+b main
+breakpoint command add -s java
+int a = 123;
+System.out.println(a);
+return true;
+quit
+run
+# CHECK: 123
+
Index: lldb/test/Shell/ScriptInterpreter/Java/bindings.test
===================================================================
--- /dev/null
+++ lldb/test/Shell/ScriptInterpreter/Java/bindings.test
@@ -0,0 +1,8 @@
+# RUN: cat %s | %lldb --script-language java 2>&1 | FileCheck %s
+script
+/main
+SBDebugger debugger = SBDebugger.Create();
+System.err.println("debugger is valid: " + debugger.IsValid());
+/close
+/run
+# CHECK: debugger is valid: true
Index: lldb/test/Shell/ScriptInterpreter/Java/Inputs/testmodule.java
===================================================================
--- /dev/null
+++ lldb/test/Shell/ScriptInterpreter/Java/Inputs/testmodule.java
@@ -0,0 +1,3 @@
+class testmodule {
+  public static void foo() { System.out.println("Hello World!"); }
+}
Index: lldb/test/Shell/ScriptInterpreter/Java/Inputs/nested_sessions_2.in
===================================================================
--- /dev/null
+++ lldb/test/Shell/ScriptInterpreter/Java/Inputs/nested_sessions_2.in
@@ -0,0 +1,8 @@
+script
+/main
+/init
+    System.out.println(n(target) + " " + n(debugger.GetSelectedTarget()));
+  }
+  private static String n(SBTarget t) {return t.GetExecutable().GetFilename();}
+}
+/run
Index: lldb/test/Shell/ScriptInterpreter/Java/Inputs/nested_sessions.in
===================================================================
--- /dev/null
+++ lldb/test/Shell/ScriptInterpreter/Java/Inputs/nested_sessions.in
@@ -0,0 +1,12 @@
+script
+/main
+/init
+    System.out.println(n(target) + " " + n(debugger.GetSelectedTarget()));
+    debugger.SetSelectedTarget(debugger.GetTargetAtIndex(0));
+    System.out.println(n(target) + " " +  n(debugger.GetSelectedTarget()));
+    //debugger.HandleCommand("script SBDebugger debugger = SBDebugger.FindDebuggerWithID(1); SBTarget target =     debugger.GetSelectedTarget(); System.out.println(target.GetExecutable().GetFilename() + \" \" + debugger.GetSelectedTarget().GetExecutable().GetFilename());");
+    System.out.println(n(target)  + " " +  n(debugger.GetSelectedTarget()));
+  }
+  private static String n(SBTarget t) {return t.GetExecutable().GetFilename();}
+}
+/run
Index: lldb/test/Shell/ScriptInterpreter/Java/Inputs/independent_state.in
===================================================================
--- /dev/null
+++ lldb/test/Shell/ScriptInterpreter/Java/Inputs/independent_state.in
@@ -0,0 +1,10 @@
+script
+/main
+int foobar = 40 + 7;
+System.out.println(foobar);
+SBDebugger d = SBDebugger.Create();
+d.HandleCommand("script foobar = 40 + 2;");
+System.out.println(foobar);
+d.HandleCommand("script print(foobar);");
+/close
+/run
Index: lldb/test/CMakeLists.txt
===================================================================
--- lldb/test/CMakeLists.txt
+++ lldb/test/CMakeLists.txt
@@ -168,6 +168,7 @@
   LLDB_BUILD_INTEL_PT
   LLDB_ENABLE_PYTHON
   LLDB_ENABLE_LUA
+  LLDB_ENABLE_JAVA
   LLDB_ENABLE_LZMA
   LLVM_ENABLE_ZLIB
   LLVM_ENABLE_SHARED_LIBS
Index: lldb/source/Plugins/ScriptInterpreter/Java/ScriptInterpreterJava.h
===================================================================
--- /dev/null
+++ lldb/source/Plugins/ScriptInterpreter/Java/ScriptInterpreterJava.h
@@ -0,0 +1,126 @@
+//===-- ScriptInterpreterJava.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 liblldb_ScriptInterpreterJava_h_
+#define liblldb_ScriptInterpreterJava_h_
+
+#include <vector>
+
+#include "lldb/Breakpoint/WatchpointOptions.h"
+#include "lldb/Core/StructuredDataImpl.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/lldb-enumerations.h"
+
+namespace lldb_private {
+class Java;
+class ScriptInterpreterJava : public ScriptInterpreter {
+public:
+  class CommandDataJava : public BreakpointOptions::CommandData {
+  public:
+    CommandDataJava() : BreakpointOptions::CommandData() {
+      interpreter = lldb::eScriptLanguageJava;
+    }
+    CommandDataJava(StructuredData::ObjectSP extra_args_sp)
+        : BreakpointOptions::CommandData(), m_extra_args_sp(extra_args_sp) {
+      interpreter = lldb::eScriptLanguageJava;
+    }
+    StructuredData::ObjectSP m_extra_args_sp;
+  };
+
+  ScriptInterpreterJava(Debugger &debugger);
+
+  ~ScriptInterpreterJava() override;
+
+  bool ExecuteOneLine(
+      llvm::StringRef command, CommandReturnObject *result,
+      const ExecuteScriptOptions &options = ExecuteScriptOptions()) override;
+
+  void ExecuteInterpreterLoop() override;
+
+  bool LoadScriptingModule(const char *filename,
+                           const LoadScriptOptions &options,
+                           lldb_private::Status &error,
+                           StructuredData::ObjectSP *module_sp = nullptr,
+                           FileSpec extra_search_dir = {}) override;
+
+  // Static Functions
+  static void Initialize();
+
+  static void Terminate();
+
+  static lldb::ScriptInterpreterSP CreateInstance(Debugger &debugger);
+
+  static llvm::StringRef GetPluginNameStatic() { return "script-java"; }
+
+  static llvm::StringRef GetPluginDescriptionStatic();
+
+/*
+  static lldb_private::ConstString GetPluginNameStatic();
+
+  static const char *GetPluginDescriptionStatic();
+*/
+
+  static bool BreakpointCallbackFunction(void *baton,
+                                         StoppointCallbackContext *context,
+                                         lldb::user_id_t break_id,
+                                         lldb::user_id_t break_loc_id);
+
+  static bool WatchpointCallbackFunction(void *baton,
+                                         StoppointCallbackContext *context,
+                                         lldb::user_id_t watch_id);
+
+  // PluginInterface protocol
+  llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+  Java &GetJava();
+
+  llvm::Error EnterSession(lldb::user_id_t debugger_id);
+  llvm::Error LeaveSession();
+
+  void CollectDataForBreakpointCommandCallback(
+      std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
+      CommandReturnObject &result) override;
+
+  void
+  CollectDataForWatchpointCommandCallback(WatchpointOptions *wp_options,
+                                          CommandReturnObject &result) override;
+
+  Status SetBreakpointCommandCallback(BreakpointOptions &bp_options,
+                                      const char *command_body_text) override;
+
+  void SetWatchpointCommandCallback(WatchpointOptions *wp_options,
+                                    const char *command_body_text) override;
+
+  Status SetBreakpointCommandCallbackFunction(
+      BreakpointOptions &bp_options, const char *function_name,
+      StructuredData::ObjectSP extra_args_sp) override;
+
+  Status
+  SetWatchpointCommandCallbackFunction(WatchpointOptions *wp_options,
+                                       const char *function_name,
+                                       StructuredData::ObjectSP extra_args_sp);
+
+private:
+  std::unique_ptr<Java> m_java;
+  bool m_session_is_active = false;
+
+  Status RegisterBreakpointCallback(BreakpointOptions &bp_options,
+                                    const char *command_body_text,
+                                    StructuredData::ObjectSP extra_args_sp,
+                                    bool existing);
+
+  Status RegisterWatchpointCallback(WatchpointOptions *wp_options,
+                                    const char *command_body_text,
+                                    StructuredData::ObjectSP extra_args_sp,
+                                    bool existing);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ScriptInterpreterJava_h_
Index: lldb/source/Plugins/ScriptInterpreter/Java/ScriptInterpreterJava.cpp
===================================================================
--- /dev/null
+++ lldb/source/Plugins/ScriptInterpreter/Java/ScriptInterpreterJava.cpp
@@ -0,0 +1,406 @@
+//===-- ScriptInterpreterJava.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 "ScriptInterpreterJava.h"
+#include "Java.h"
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/ExecutionContext.h"
+#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(ScriptInterpreterJava)
+
+enum ActiveIOHandler {
+  eIOHandlerNone,
+  eIOHandlerBreakpoint,
+  eIOHandlerWatchpoint
+};
+
+class IOHandlerJavaInterpreter : public IOHandlerDelegate,
+                                 public IOHandlerEditline {
+public:
+  IOHandlerJavaInterpreter(Debugger &debugger,
+                           ScriptInterpreterJava &script_interpreter,
+                           ActiveIOHandler active_io_handler = eIOHandlerNone)
+      : IOHandlerEditline(debugger, IOHandler::Type::JavaInterpreter, "java",
+                          ">>> ", "..> ", true, debugger.GetUseColor(), 0,
+                          *this, nullptr),
+        m_script_interpreter(script_interpreter),
+        m_active_io_handler(active_io_handler) {
+    llvm::cantFail(m_script_interpreter.EnterSession(debugger.GetID()));
+    llvm::cantFail(m_script_interpreter.GetJava().ChangeIO(
+        debugger.GetOutputFile().GetStream(),
+        debugger.GetErrorFile().GetStream()));
+  }
+
+  ~IOHandlerJavaInterpreter() override {
+    llvm::cantFail(m_script_interpreter.LeaveSession());
+  }
+
+  void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
+    const char *instructions = nullptr;
+    switch (m_active_io_handler) {
+    case eIOHandlerNone:
+      instructions =
+          "Enter your Java command(s). Type 'quit' to end.\n"
+          "Special commands include: \n"
+          "   /main      - sets up the standard prologue\n"
+          "   /bpt, /wpt - prologue for break & watchpoint handlers (not "
+          "required for 'br' & 'wa')\n"
+          "   /init      - defines debugger, target, process, thread, frame\n"
+          "   /close     - completes prologue\n"
+          "   /reset     - start over\n"
+          "   /compile   - compile a function (no args == current)\n"
+          "   /exec      - execute a function\n"
+          "   /run       - compile & execute\n"
+          "Sample sequence:   /main, /init, "
+          "System.out.println(frame.GetPC());, /close, /run\n";
+      break;
+    case eIOHandlerWatchpoint:
+      instructions = "Enter your Java command(s). Type 'quit' to end.\n"
+                     "The commands are compiled as the body of the following "
+                     "Java function:\n"
+                     "  boolean callback(_frame, wp) {}\n";
+      SetPrompt(llvm::StringRef("..> "));
+      break;
+    case eIOHandlerBreakpoint:
+      instructions = "Enter your Java command(s). Type 'quit' to end.\n"
+                     "The commands are compiled as the body of the following "
+                     "Java function:\n"
+                     "  boolean callback(_frame, loc, args) {}\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 ||
+          m_active_io_handler == eIOHandlerWatchpoint)
+        lines.DeleteStringAtIndex(last);
+      return true;
+    }
+    StreamString str;
+    lines.Join("\n", str);
+    if (llvm::Error E =
+            m_script_interpreter.GetJava().CheckSyntax(str.GetString())) {
+      std::string error_str = toString(std::move(E));
+      // Java always errors out to incomplete code with '<eof>'
+      return error_str.find("<eof>") == std::string::npos;
+    }
+    // The breakpoint and watchpoint handler only exits with a explicit 'quit'
+    return m_active_io_handler != eIOHandlerBreakpoint &&
+           m_active_io_handler != eIOHandlerWatchpoint;
+  }
+
+  void IOHandlerInputComplete(IOHandler &io_handler,
+                              std::string &data) override {
+    switch (m_active_io_handler) {
+    case eIOHandlerBreakpoint: {
+      auto *bp_options_vec =
+          static_cast<std::vector<std::reference_wrapper<BreakpointOptions>> *>(
+              io_handler.GetUserData());
+      for (BreakpointOptions &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: {
+      auto *wp_options =
+          static_cast<WatchpointOptions *>(io_handler.GetUserData());
+      m_script_interpreter.SetWatchpointCommandCallback(wp_options,
+                                                        data.c_str());
+      io_handler.SetIsDone(true);
+    } break;
+    case eIOHandlerNone:
+      if (IsQuitCommand(data)) {
+        io_handler.SetIsDone(true);
+        return;
+      }
+      if (llvm::Error error = m_script_interpreter.GetJava().Run(data))
+        *io_handler.GetErrorStreamFileSP() << toString(std::move(error));
+      break;
+    }
+  }
+
+private:
+  ScriptInterpreterJava &m_script_interpreter;
+  ActiveIOHandler m_active_io_handler;
+
+  bool IsQuitCommand(llvm::StringRef cmd) { return cmd.rtrim() == "quit"; }
+};
+
+ScriptInterpreterJava::ScriptInterpreterJava(Debugger &debugger)
+    : ScriptInterpreter(debugger, eScriptLanguageJava),
+      m_java(std::make_unique<Java>()) {}
+
+ScriptInterpreterJava::~ScriptInterpreterJava() = default;
+
+bool ScriptInterpreterJava::ExecuteOneLine(
+    llvm::StringRef command, CommandReturnObject *result,
+    const ExecuteScriptOptions &options) {
+  if (command.empty()) {
+    if (result)
+      result->AppendError("empty command passed to java\n");
+    return false;
+  }
+
+  llvm::Expected<std::unique_ptr<ScriptInterpreterIORedirect>>
+      io_redirect_or_error = ScriptInterpreterIORedirect::Create(
+          options.GetEnableIO(), m_debugger, result);
+  if (!io_redirect_or_error) {
+    if (result)
+      result->AppendErrorWithFormatv(
+          "failed to redirect I/O: {0}\n",
+          llvm::fmt_consume(io_redirect_or_error.takeError()));
+    else
+      llvm::consumeError(io_redirect_or_error.takeError());
+    return false;
+  }
+
+  ScriptInterpreterIORedirect &io_redirect = **io_redirect_or_error;
+
+  if (llvm::Error e =
+          m_java->ChangeIO(io_redirect.GetOutputFile()->GetStream(),
+                           io_redirect.GetErrorFile()->GetStream())) {
+    result->AppendErrorWithFormatv("java failed to redirect I/O: {0}\n",
+                                   llvm::toString(std::move(e)));
+    return false;
+  }
+
+  if (llvm::Error e = m_java->Test(command)) {
+    result->AppendErrorWithFormatv(
+        "java failed attempting to evaluate '{0}': {1}\n", command,
+        llvm::toString(std::move(e)));
+    return false;
+  }
+
+  io_redirect.Flush();
+  return true;
+}
+
+void ScriptInterpreterJava::ExecuteInterpreterLoop() {
+  LLDB_SCOPED_TIMER();
+
+  // At the moment, the only time the debugger does not have an input file
+  // handle is when this is called directly from java, in which case it is
+  // both dangerous and unnecessary (not to mention confusing) to try to embed
+  // a running interpreter loop inside the already running java interpreter
+  // loop, so we won't do it.
+  if (!m_debugger.GetInputFile().IsValid())
+    return;
+
+  IOHandlerSP io_handler_sp(new IOHandlerJavaInterpreter(m_debugger, *this));
+  m_debugger.RunIOHandlerAsync(io_handler_sp);
+}
+
+bool ScriptInterpreterJava::LoadScriptingModule(
+    const char *filename, const LoadScriptOptions &options,
+    lldb_private::Status &error, StructuredData::ObjectSP *module_sp,
+    FileSpec extra_search_dir) {
+
+  FileSystem::Instance().Collect(filename);
+  if (llvm::Error e = m_java->LoadModule(filename)) {
+    error.SetErrorStringWithFormatv("java failed to import '{0}': {1}\n",
+                                    filename, llvm::toString(std::move(e)));
+    return false;
+  }
+  return true;
+}
+
+void ScriptInterpreterJava::Initialize() {
+  static llvm::once_flag g_once_flag;
+
+  llvm::call_once(g_once_flag, []() {
+    PluginManager::RegisterPlugin(GetPluginNameStatic(),
+                                  GetPluginDescriptionStatic(),
+                                  lldb::eScriptLanguageJava, CreateInstance);
+  });
+}
+
+void ScriptInterpreterJava::Terminate() {}
+
+llvm::Error ScriptInterpreterJava::EnterSession(user_id_t debugger_id) {
+  // printf("EnterSession %x\n", m_session_is_active);
+  if (m_session_is_active)
+    return llvm::Error::success();
+
+  m_session_is_active = true;
+  return m_java->Init(debugger_id);
+}
+
+llvm::Error ScriptInterpreterJava::LeaveSession() {
+  if (!m_session_is_active)
+    return llvm::Error::success();
+
+  m_session_is_active = false;
+  return llvm::Error::success();
+}
+
+bool ScriptInterpreterJava::BreakpointCallbackFunction(
+    void *baton, StoppointCallbackContext *context, user_id_t break_id,
+    user_id_t break_loc_id) {
+  assert(context);
+
+  ExecutionContext exe_ctx(context->exe_ctx_ref);
+  Target *target = exe_ctx.GetTargetPtr();
+  if (target == nullptr)
+    return true;
+
+  StackFrameSP stop_frame_sp(exe_ctx.GetFrameSP());
+  BreakpointSP breakpoint_sp = target->GetBreakpointByID(break_id);
+  BreakpointLocationSP bp_loc_sp(breakpoint_sp->FindLocationByID(break_loc_id));
+
+  Debugger &debugger = target->GetDebugger();
+  ScriptInterpreterJava *java_interpreter =
+      static_cast<ScriptInterpreterJava *>(
+          debugger.GetScriptInterpreter(true, eScriptLanguageJava));
+  Java &java = java_interpreter->GetJava();
+
+  CommandDataJava *bp_option_data = static_cast<CommandDataJava *>(baton);
+  llvm::Expected<bool> BoolOrErr = java.CallBreakpointCallback(
+      baton, stop_frame_sp, bp_loc_sp, bp_option_data->m_extra_args_sp);
+  if (llvm::Error E = BoolOrErr.takeError()) {
+    debugger.GetErrorStream() << toString(std::move(E));
+    return true;
+  }
+
+  return *BoolOrErr;
+}
+
+bool ScriptInterpreterJava::WatchpointCallbackFunction(
+    void *baton, StoppointCallbackContext *context, user_id_t watch_id) {
+  assert(context);
+
+  ExecutionContext exe_ctx(context->exe_ctx_ref);
+  Target *target = exe_ctx.GetTargetPtr();
+  if (target == nullptr)
+    return true;
+
+  StackFrameSP stop_frame_sp(exe_ctx.GetFrameSP());
+  WatchpointSP wp_sp = target->GetWatchpointList().FindByID(watch_id);
+
+  Debugger &debugger = target->GetDebugger();
+  ScriptInterpreterJava *java_interpreter =
+      static_cast<ScriptInterpreterJava *>(
+          debugger.GetScriptInterpreter(true, eScriptLanguageJava));
+  Java &java = java_interpreter->GetJava();
+
+  llvm::Expected<bool> BoolOrErr =
+      java.CallWatchpointCallback(baton, stop_frame_sp, wp_sp);
+  if (llvm::Error E = BoolOrErr.takeError()) {
+    debugger.GetErrorStream() << toString(std::move(E));
+    return true;
+  }
+
+  return *BoolOrErr;
+}
+
+void ScriptInterpreterJava::CollectDataForBreakpointCommandCallback(
+    std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
+    CommandReturnObject &result) {
+  IOHandlerSP io_handler_sp(
+      new IOHandlerJavaInterpreter(m_debugger, *this, eIOHandlerBreakpoint));
+  io_handler_sp->SetUserData(&bp_options_vec);
+  m_debugger.RunIOHandlerAsync(io_handler_sp);
+}
+
+void ScriptInterpreterJava::CollectDataForWatchpointCommandCallback(
+    WatchpointOptions *wp_options, CommandReturnObject &result) {
+  IOHandlerSP io_handler_sp(
+      new IOHandlerJavaInterpreter(m_debugger, *this, eIOHandlerWatchpoint));
+  io_handler_sp->SetUserData(wp_options);
+  m_debugger.RunIOHandlerAsync(io_handler_sp);
+}
+
+Status ScriptInterpreterJava::SetBreakpointCommandCallbackFunction(
+    BreakpointOptions &bp_options, const char *function_name,
+    StructuredData::ObjectSP extra_args_sp) {
+  return RegisterBreakpointCallback(bp_options, function_name, extra_args_sp,
+                                    true);
+}
+
+Status ScriptInterpreterJava::SetBreakpointCommandCallback(
+    BreakpointOptions &bp_options, const char *command_body_text) {
+  return RegisterBreakpointCallback(bp_options, command_body_text, {}, false);
+}
+
+Status ScriptInterpreterJava::RegisterBreakpointCallback(
+    BreakpointOptions &bp_options, const char *command_body_text,
+    StructuredData::ObjectSP extra_args_sp, bool existing) {
+  Status error;
+  auto data_up = std::make_unique<CommandDataJava>(extra_args_sp);
+  error = m_java->RegisterBreakpointCallback(data_up.get(), command_body_text,
+                                             existing);
+  if (error.Fail())
+    return error;
+  auto baton_sp =
+      std::make_shared<BreakpointOptions::CommandBaton>(std::move(data_up));
+  bp_options.SetCallback(ScriptInterpreterJava::BreakpointCallbackFunction,
+                         baton_sp);
+  return error;
+}
+
+Status ScriptInterpreterJava::SetWatchpointCommandCallbackFunction(
+    WatchpointOptions *wp_options, const char *function_name,
+    StructuredData::ObjectSP extra_args_sp) {
+  return RegisterWatchpointCallback(wp_options, function_name, extra_args_sp,
+                                    true);
+}
+
+void ScriptInterpreterJava::SetWatchpointCommandCallback(
+    WatchpointOptions *wp_options, const char *command_body_text) {
+  RegisterWatchpointCallback(wp_options, command_body_text, {}, false);
+}
+
+Status ScriptInterpreterJava::RegisterWatchpointCallback(
+    WatchpointOptions *wp_options, const char *command_body_text,
+    StructuredData::ObjectSP extra_args_sp, bool existing) {
+  Status error;
+  auto data_up = std::make_unique<WatchpointOptions::CommandData>();
+  error = m_java->RegisterWatchpointCallback(data_up.get(), command_body_text,
+                                             existing);
+  if (error.Fail())
+    return error;
+  auto baton_sp =
+      std::make_shared<WatchpointOptions::CommandBaton>(std::move(data_up));
+  wp_options->SetCallback(ScriptInterpreterJava::WatchpointCallbackFunction,
+                          baton_sp);
+  return error;
+}
+
+lldb::ScriptInterpreterSP
+ScriptInterpreterJava::CreateInstance(Debugger &debugger) {
+  return std::make_shared<ScriptInterpreterJava>(debugger);
+}
+
+llvm::StringRef ScriptInterpreterJava::GetPluginDescriptionStatic() {
+  return "Java script interpreter";
+}
+Java &ScriptInterpreterJava::GetJava() { return *m_java; }
Index: lldb/source/Plugins/ScriptInterpreter/Java/Java.h
===================================================================
--- /dev/null
+++ lldb/source/Plugins/ScriptInterpreter/Java/Java.h
@@ -0,0 +1,66 @@
+//===-- ScriptInterpreterJava.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 liblldb_Java_h_
+#define liblldb_Java_h_
+
+#include "jni.h"
+#include "lldb/API/SBBreakpointLocation.h"
+#include "lldb/API/SBFrame.h"
+#include "lldb/Core/StructuredDataImpl.h"
+#include "lldb/lldb-types.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+
+//#include "Java.hpp"
+
+#include <mutex>
+
+namespace lldb_private {
+
+extern "C" {
+int Javaopen_lldb(JNIEnv *env);
+}
+
+class Java {
+public:
+  Java();
+  ~Java();
+
+  llvm::Error Init(lldb::user_id_t debugger_id);
+  llvm::Error Test(llvm::StringRef buffer);
+  llvm::Error Run(llvm::StringRef buffer);
+  llvm::Error RunError(llvm::StringRef buffer);
+  llvm::Error Run(const char *data);
+  llvm::Error RegisterBreakpointCallback(void *baton, const char *body,
+                                         bool existing);
+  llvm::Expected<bool>
+  CallBreakpointCallback(void *baton, lldb::StackFrameSP stop_frame_sp,
+                         lldb::BreakpointLocationSP bp_loc_sp,
+                         StructuredData::ObjectSP extra_args_sp);
+  llvm::Error RegisterWatchpointCallback(void *baton, const char *body,
+                                         bool existing);
+  llvm::Expected<bool> CallWatchpointCallback(void *baton,
+                                              lldb::StackFrameSP stop_frame_sp,
+                                              lldb::WatchpointSP wp_sp);
+  llvm::Error LoadModule(llvm::StringRef filename);
+  llvm::Error CheckSyntax(llvm::StringRef buffer);
+  llvm::Error ChangeIO(FILE *out, FILE *err);
+
+private:
+  JavaVM *m_vm = NULL;
+  JNIEnv *m_env = NULL;
+  jclass interpreter_cls = NULL;
+  jobject interpreter = NULL;
+  const char *swigJarPath = NULL;
+  lldb::user_id_t dbg_id = -1;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Java_h_
Index: lldb/source/Plugins/ScriptInterpreter/Java/Java.cpp
===================================================================
--- /dev/null
+++ lldb/source/Plugins/ScriptInterpreter/Java/Java.cpp
@@ -0,0 +1,395 @@
+//===-- Java.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 "Java.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Utility/FileSpec.h"
+#include "llvm/Support/DynamicLibrary.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FormatVariadic.h"
+#include <stdio.h>
+
+using namespace lldb_private;
+using namespace lldb;
+using namespace llvm;
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
+
+// Disable warning C4190: 'LLDBSwigPythonBreakpointCallbackFunction' has
+// C-linkage specified, but returns UDT 'llvm::Expected<bool>' which is
+// incompatible with C
+#if _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4190)
+#endif
+
+extern "C" llvm::Expected<bool> LLDBSwigJavaBreakpointCallbackFunction(
+    JNIEnv *L, void *baton, lldb::user_id_t debugger_id,
+    const char *swigJarPath, lldb::StackFrameSP stop_frame_sp,
+    lldb::BreakpointLocationSP bp_loc_sp, StructuredDataImpl *extra_args_impl);
+
+extern "C" llvm::Expected<bool> LLDBSwigJavaWatchpointCallbackFunction(
+    JNIEnv *L, void *baton, lldb::user_id_t debugger_id,
+    const char *swigJarPath, lldb::StackFrameSP stop_frame_sp,
+    lldb::WatchpointSP wp_sp);
+
+#if _MSC_VER
+#pragma warning(pop)
+#endif
+
+#pragma clang diagnostic pop
+
+bool loadLibJVM();
+bool loadSwigJar();
+
+Java::Java() {
+
+  if (!loadLibJVM()) {
+    return;
+  }
+
+  swigJarPath = ::getenv("CLASSPATH");
+  if (swigJarPath == NULL) {
+    printf("Failed to find SWIG.jar in CLASSPATH=%s\n", swigJarPath);
+    return;
+  }
+
+  JavaVMInitArgs vm_args;
+  JavaVMOption *options = new JavaVMOption[1];
+  std::string javaClassPath =
+      llvm::formatv("-Djava.class.path={0}", swigJarPath).str();
+  options[0].optionString = strdup(javaClassPath.c_str());
+  options[0].extraInfo = NULL;
+
+  vm_args.version = JNI_VERSION_1_2;
+  vm_args.nOptions = 1;
+  vm_args.options = options;
+  vm_args.ignoreUnrecognized = false;
+
+  jint (*JNI_CreateJavaVM)(JavaVM * *p_vm, void **p_env, void *vm_args);
+  jint (*JNI_GetCreatedJavaVMs)(JavaVM * *vmBuf, jsize bufLen, jsize * nVMs);
+
+  void *fn_ptr =
+      sys::DynamicLibrary::SearchForAddressOfSymbol("JNI_GetCreatedJavaVMs");
+  JNI_GetCreatedJavaVMs = (jint(*)(JavaVM **, jsize, jsize *))fn_ptr;
+  fn_ptr = sys::DynamicLibrary::SearchForAddressOfSymbol("JNI_CreateJavaVM");
+  JNI_CreateJavaVM = (jint(*)(JavaVM **, void **, void *))fn_ptr;
+
+  // Construct a VM
+  jsize nVMs = -1;
+  jint res = (*JNI_GetCreatedJavaVMs)(NULL, 0, &nVMs);
+  if (res != JNI_OK) {
+    printf("Failed to get Java VM count\n");
+    delete options;
+    return;
+  }
+
+  if (nVMs > 0) {
+    JavaVM **buffer = new JavaVM *[nVMs];
+    res = (*JNI_GetCreatedJavaVMs)(buffer, nVMs, &nVMs);
+    if (res != JNI_OK) {
+      printf("Failed to locate existing Java VM %x\n", res);
+      delete options;
+      return;
+    }
+    m_vm = buffer[0];
+    m_vm->GetEnv((void **)&m_env, JNI_VERSION_1_8);
+  } else {
+    m_vm = NULL;
+    m_env = NULL;
+    // FYI: This throws SIGSEGV but seems to not be normal for JVM startup
+    res = (*JNI_CreateJavaVM)(&m_vm, (void **)&m_env, &vm_args);
+    if (res != JNI_OK) {
+      printf("Failed to create Java VM %x\n", res);
+      delete options;
+      return;
+    }
+    res = (*JNI_GetCreatedJavaVMs)(NULL, 0, &nVMs);
+  }
+  delete options;
+
+  assert(m_env);
+}
+
+Java::~Java() {
+
+  assert(m_env);
+  // Shutdown the VM.
+  /// m_vm->DestroyJavaVM();
+}
+
+llvm::Error Java::Init(lldb::user_id_t debugger_id) {
+
+  m_vm->AttachCurrentThread((void **)&m_env, NULL);
+  dbg_id = debugger_id;
+
+  interpreter_cls = m_env->FindClass("SWIG/LldbScriptInterpreter");
+  if (interpreter_cls == nullptr) {
+    return createStringError(llvm::inconvertibleErrorCode(),
+                             "Failed to find 'LldbScriptInterpreter' class");
+  }
+
+  jint jid = (jint)debugger_id;
+  jstring jstr = m_env->NewStringUTF(swigJarPath);
+  jmethodID mid =
+      m_env->GetMethodID(interpreter_cls, "<init>", "(ILjava/lang/String;)V");
+  if (mid == nullptr) {
+    return createStringError(llvm::inconvertibleErrorCode(),
+                             "Failed to find <init> function");
+  }
+
+  interpreter = m_env->NewObject(interpreter_cls, mid, jid, jstr);
+  return llvm::Error::success();
+}
+
+llvm::Error Java::Test(llvm::StringRef buffer) {
+
+  m_vm->AttachCurrentThread((void **)&m_env, NULL);
+
+  if (llvm::Error e = Java::Init(dbg_id)) {
+    return e;
+  }
+  if (llvm::Error e = Run("/main")) {
+    return e;
+  }
+  if (llvm::Error e = Run(buffer.data())) {
+    return e;
+  }
+  if (llvm::Error e = Run("/close")) {
+    return e;
+  }
+  if (llvm::Error e = Run("/run")) {
+    return e;
+  }
+
+  return llvm::Error::success();
+}
+
+llvm::Error Java::Run(llvm::StringRef buffer) {
+
+  if (llvm::Error e = Run(buffer.data())) {
+    return e;
+  }
+  return llvm::Error::success();
+}
+
+llvm::Error Java::Run(const char *data) {
+
+  m_vm->AttachCurrentThread((void **)&m_env, NULL);
+
+  jmethodID midRunCmd =
+      m_env->GetMethodID(interpreter_cls, "runCmd", "(Ljava/lang/String;)Z");
+  if (midRunCmd == NULL) {
+    return createStringError(llvm::inconvertibleErrorCode(),
+                             "Failed to find 'runCmd' function");
+  }
+
+  jstring jstr = m_env->NewStringUTF(data);
+  jboolean res = m_env->CallBooleanMethod(interpreter, midRunCmd, jstr);
+  if (!(bool)res) {
+    return createStringError(llvm::inconvertibleErrorCode(),
+                             llvm::formatv("Failed to execute '{0}'", data));
+  }
+  return llvm::Error::success();
+}
+
+llvm::Error Java::RegisterBreakpointCallback(void *baton, const char *body,
+                                             bool existing) {
+
+  m_vm->AttachCurrentThread((void **)&m_env, NULL);
+
+  if (interpreter_cls == NULL) {
+    if (llvm::Error e = Java::Init(dbg_id)) {
+      return e;
+    }
+  }
+
+  if (!existing) {
+    std::string baton_str = llvm::formatv("/bpt {0}", baton);
+    if (llvm::Error e = Run(baton_str.c_str()))
+      return e;
+    if (llvm::Error e = Run("/init"))
+      return e;
+    if (llvm::Error e = Run(body))
+      return e;
+    if (strstr(body, "return ") == NULL) {
+      if (llvm::Error e = Run("return false;"))
+        return e;
+    }
+    if (llvm::Error e = Run("/close"))
+      return e;
+    if (llvm::Error e = Run("/compile"))
+      return e;
+  } else {
+    std::string baton_str = llvm::formatv("/register {0} {1}", baton, body);
+    if (llvm::Error e = Run(baton_str.c_str()))
+      return e;
+  }
+
+  return llvm::Error::success();
+}
+
+llvm::Expected<bool>
+Java::CallBreakpointCallback(void *baton, lldb::StackFrameSP stop_frame_sp,
+                             lldb::BreakpointLocationSP bp_loc_sp,
+                             StructuredData::ObjectSP extra_args_sp) {
+
+  m_vm->AttachCurrentThread((void **)&m_env, NULL);
+
+  auto *extra_args_impl = [&]() -> StructuredDataImpl * {
+    if (extra_args_sp == nullptr)
+      return nullptr;
+    auto *extra_args_impl = new StructuredDataImpl();
+    extra_args_impl->SetObjectSP(extra_args_sp);
+    return extra_args_impl;
+  }();
+
+  return LLDBSwigJavaBreakpointCallbackFunction(m_env, baton, dbg_id,
+                                                swigJarPath, stop_frame_sp,
+                                                bp_loc_sp, extra_args_impl);
+}
+
+llvm::Error Java::RegisterWatchpointCallback(void *baton, const char *body,
+                                             bool existing) {
+
+  if (interpreter_cls == NULL) {
+    if (llvm::Error e = Java::Init(dbg_id)) {
+      return e;
+    }
+  }
+
+  m_vm->AttachCurrentThread((void **)&m_env, NULL);
+
+  if (!existing) {
+    std::string baton_str = llvm::formatv("/wpt {0}", baton);
+    if (llvm::Error e = Run(baton_str.c_str()))
+      return e;
+    if (llvm::Error e = Run("/init"))
+      return e;
+    if (llvm::Error e = Run(body))
+      return e;
+    if (strcmp(body, "return ") < 0) {
+      if (llvm::Error e = Run("return false;"))
+        return e;
+    }
+    if (llvm::Error e = Run("/close"))
+      return e;
+    if (llvm::Error e = Run("/compile"))
+      return e;
+  } else {
+    std::string baton_str = llvm::formatv("/register {0} {1}", baton, body);
+    if (llvm::Error e = Run(baton_str.c_str()))
+      return e;
+  }
+
+  return llvm::Error::success();
+}
+
+llvm::Expected<bool>
+Java::CallWatchpointCallback(void *baton, lldb::StackFrameSP stop_frame_sp,
+                             lldb::WatchpointSP wp_sp) {
+
+  m_vm->AttachCurrentThread((void **)&m_env, NULL);
+
+  return LLDBSwigJavaWatchpointCallbackFunction(
+      m_env, baton, dbg_id, swigJarPath, stop_frame_sp, wp_sp);
+}
+
+llvm::Error Java::CheckSyntax(llvm::StringRef buffer) {
+  return llvm::Error::success();
+}
+
+llvm::Error Java::LoadModule(llvm::StringRef filename) {
+
+  if (interpreter_cls == NULL) {
+    if (llvm::Error e = Java::Init(dbg_id)) {
+      return e;
+    }
+  }
+
+  FileSpec file(filename);
+  if (!FileSystem::Instance().Exists(file)) {
+    return llvm::make_error<llvm::StringError>("invalid path",
+                                               llvm::inconvertibleErrorCode());
+  }
+
+  ConstString module_extension = file.GetFileNameExtension();
+  if (module_extension != ".java") {
+    return llvm::make_error<llvm::StringError>("invalid extension",
+                                               llvm::inconvertibleErrorCode());
+  }
+
+  std::string import_str = llvm::formatv("/import {0}", filename);
+  if (llvm::Error e = Run(import_str.c_str())) {
+    return e;
+  }
+
+  return llvm::Error::success();
+}
+
+llvm::Error Java::ChangeIO(FILE *out, FILE *err) {
+  assert(out != nullptr);
+  assert(err != nullptr);
+
+  if (interpreter_cls == NULL) {
+    return llvm::Error::success();
+  }
+
+  jmethodID midChangeIOCmd =
+      m_env->GetMethodID(interpreter_cls, "runChangeIO", "(JJ)Z");
+  if (midChangeIOCmd == NULL) {
+    return createStringError(llvm::inconvertibleErrorCode(),
+                             "Failed to find 'runChangeIO' function");
+  }
+
+  FileSP fout = std::make_shared<NativeFile>(out, false);
+  FileSP ferr = std::make_shared<NativeFile>(err, false);
+  jlong outPtr = jlong(&fout);
+  jlong errPtr = jlong(&ferr);
+  m_env->CallBooleanMethod(interpreter, midChangeIOCmd, outPtr, errPtr);
+  return llvm::Error::success();
+}
+
+llvm::Error makeError(const char *text) {
+  printf("makeError %s\n", text);
+  llvm::Error e = llvm::make_error<llvm::StringError>(
+      llvm::formatv("{0}\n", text), llvm::inconvertibleErrorCode());
+  return e;
+}
+
+llvm::Error Java::RunError(llvm::StringRef buffer) {
+
+  llvm::Error e = llvm::make_error<llvm::StringError>(
+      llvm::formatv("{0}\n", buffer.data()), llvm::inconvertibleErrorCode());
+  return std::move(e);
+}
+
+bool loadLibJVM() {
+
+#if defined(_WIN32)
+  const char *Suffix = ".dll";
+#elif defined(__APPLE__)
+  const char *Suffix = ".dylib";
+#else
+  const char *Suffix = ".so";
+#endif
+
+  const char *ldLibraryPath = ::getenv("JAVA_HOME");
+  std::string err = llvm::formatv("");
+
+  std::string jvmPath =
+      llvm::formatv("{0}/lib/server/libjvm{1}", ldLibraryPath, Suffix);
+  sys::DynamicLibrary::LoadLibraryPermanently(jvmPath.c_str(), &err);
+  if (strlen(err.c_str()) == 0) {
+    return true;
+  }
+
+  printf("Failed to find 'libjvm in %s/lib/server\n", ldLibraryPath);
+  return false;
+}
Index: lldb/source/Plugins/ScriptInterpreter/Java/CMakeLists.txt
===================================================================
--- /dev/null
+++ lldb/source/Plugins/ScriptInterpreter/Java/CMakeLists.txt
@@ -0,0 +1,17 @@
+find_package(Java REQUIRED)
+
+add_lldb_library(lldbPluginScriptInterpreterJava PLUGIN
+  Java.cpp
+  ScriptInterpreterJava.cpp
+
+  LINK_LIBS
+    lldbCore
+    lldbInterpreter
+  )
+
+string(TOLOWER ${CMAKE_SYSTEM_NAME} LC_CMAKE_SYSTEM_NAME)
+target_include_directories(lldbPluginScriptInterpreterJava PUBLIC ${JAVA_INCLUDE_DIR})
+target_include_directories(lldbPluginScriptInterpreterJava PUBLIC ${JAVA_INCLUDE_DIR}/${LC_CMAKE_SYSTEM_NAME})
+target_link_directories(lldbPluginScriptInterpreterJava PUBLIC ${JAVA_LIBRARIES})
+target_link_directories(lldbPluginScriptInterpreterJava PUBLIC ${JAVA_SERVER_LIB})
+
Index: lldb/source/Plugins/ScriptInterpreter/CMakeLists.txt
===================================================================
--- lldb/source/Plugins/ScriptInterpreter/CMakeLists.txt
+++ lldb/source/Plugins/ScriptInterpreter/CMakeLists.txt
@@ -6,3 +6,9 @@
 if (LLDB_ENABLE_LUA)
   add_subdirectory(Lua)
 endif()
+
+if (LLDB_ENABLE_JAVA)
+  add_subdirectory(Java)
+endif()
+
+
Index: lldb/source/Interpreter/ScriptInterpreter.cpp
===================================================================
--- lldb/source/Interpreter/ScriptInterpreter.cpp
+++ lldb/source/Interpreter/ScriptInterpreter.cpp
@@ -68,6 +68,8 @@
     return "Python";
   case eScriptLanguageLua:
     return "Lua";
+  case eScriptLanguageJava:
+    return "Java";
   case eScriptLanguageUnknown:
     return "Unknown";
   }
@@ -103,6 +105,8 @@
     return eScriptLanguagePython;
   if (language.equals_insensitive(LanguageToString(eScriptLanguageLua)))
     return eScriptLanguageLua;
+  if (language.equals_insensitive(LanguageToString(eScriptLanguageJava)))
+    return eScriptLanguageJava;
   return eScriptLanguageUnknown;
 }
 
Index: lldb/source/Interpreter/OptionArgParser.cpp
===================================================================
--- lldb/source/Interpreter/OptionArgParser.cpp
+++ lldb/source/Interpreter/OptionArgParser.cpp
@@ -129,6 +129,8 @@
     return eScriptLanguagePython;
   if (s.equals_insensitive("lua"))
     return eScriptLanguageLua;
+  if (s.equals_insensitive("java"))
+    return eScriptLanguageJava;
   if (s.equals_insensitive("default"))
     return eScriptLanguageDefault;
   if (s.equals_insensitive("none"))
Index: lldb/source/Commands/CommandObjectWatchpointCommand.cpp
===================================================================
--- lldb/source/Commands/CommandObjectWatchpointCommand.cpp
+++ lldb/source/Commands/CommandObjectWatchpointCommand.cpp
@@ -41,6 +41,11 @@
         "lua",
         "Commands are in the Lua language.",
     },
+    {
+        eScriptLanguageJava,
+        "java",
+        "Commands are in the Java language.",
+    },
     {
         eSortOrderByName,
         "default-script",
@@ -336,6 +341,7 @@
         switch (m_script_language) {
         case eScriptLanguagePython:
         case eScriptLanguageLua:
+        case eScriptLanguageJava:
           m_use_script_language = true;
           break;
         case eScriptLanguageNone:
Index: lldb/source/Commands/CommandObjectScript.cpp
===================================================================
--- lldb/source/Commands/CommandObjectScript.cpp
+++ lldb/source/Commands/CommandObjectScript.cpp
@@ -31,6 +31,11 @@
         "lua",
         "Lua",
     },
+    {
+        eScriptLanguageJava,
+        "java",
+        "Java",
+    },
     {
         eScriptLanguageNone,
         "default",
Index: lldb/source/Commands/CommandObjectBreakpointCommand.cpp
===================================================================
--- lldb/source/Commands/CommandObjectBreakpointCommand.cpp
+++ lldb/source/Commands/CommandObjectBreakpointCommand.cpp
@@ -41,6 +41,11 @@
         "lua",
         "Commands are in the Lua language.",
     },
+    {
+        eScriptLanguageJava,
+        "java",
+        "Commands are in the Java language.",
+    },
     {
         eScriptLanguageDefault,
         "default-script",
@@ -305,6 +310,7 @@
         switch (m_script_language) {
         case eScriptLanguagePython:
         case eScriptLanguageLua:
+        case eScriptLanguageJava:
           m_use_script_language = true;
           break;
         case eScriptLanguageNone:
Index: lldb/source/API/liblldb.exports
===================================================================
--- lldb/source/API/liblldb.exports
+++ lldb/source/API/liblldb.exports
@@ -1,5 +1,8 @@
 _ZN4lldb*
 _ZNK4lldb*
+_ZN12lldb*
+_ZNK12lldb*
 init_lld*
 PyInit__lldb*
 luaopen_lldb*
+Java*
Index: lldb/source/API/liblldb-private.exports
===================================================================
--- lldb/source/API/liblldb-private.exports
+++ lldb/source/API/liblldb-private.exports
@@ -5,3 +5,5 @@
 init_lld*
 PyInit__lldb*
 luaopen_lldb*
+Java*
+
Index: lldb/source/API/SBDebugger.cpp
===================================================================
--- lldb/source/API/SBDebugger.cpp
+++ lldb/source/API/SBDebugger.cpp
@@ -709,6 +709,9 @@
   AddBoolConfigEntry(
       *config_up, "lua", LLDB_ENABLE_LUA,
       "A boolean value that indicates if lua support is enabled in LLDB");
+  AddBoolConfigEntry(
+      *config_up, "java", LLDB_ENABLE_JAVA,
+      "A boolean value that indicates if java support is enabled in LLDB");
   AddBoolConfigEntry(*config_up, "fbsdvmcore", LLDB_ENABLE_FBSDVMCORE,
                      "A boolean value that indicates if fbsdvmcore support is "
                      "enabled in LLDB");
Index: lldb/source/API/CMakeLists.txt
===================================================================
--- lldb/source/API/CMakeLists.txt
+++ lldb/source/API/CMakeLists.txt
@@ -15,6 +15,11 @@
   set(lldb_lua_wrapper ${lua_bindings_dir}/LLDBWrapLua.cpp)
 endif()
 
+if(LLDB_ENABLE_JAVA)
+  get_target_property(java_bindings_dir swig_wrapper_java BINARY_DIR)
+  set(lldb_java_wrapper ${java_bindings_dir}/SWIG/LLDBWrapJava.cpp)
+endif()
+
 add_lldb_library(liblldb SHARED ${option_framework}
   SBAddress.cpp
   SBAttachInfo.cpp
@@ -88,6 +93,7 @@
   SystemInitializerFull.cpp
   ${lldb_python_wrapper}
   ${lldb_lua_wrapper}
+  ${lldb_java_wrapper}
 
   LINK_LIBS
     lldbBreakpoint
@@ -156,6 +162,21 @@
   set_source_files_properties(${lldb_lua_wrapper} PROPERTIES GENERATED ON)
 endif()
 
+if(LLDB_ENABLE_JAVA)
+  add_dependencies(liblldb swig_wrapper_java)
+  target_include_directories(liblldb PRIVATE ${JAVA_INCLUDE_DIR})
+  target_include_directories(liblldb PRIVATE ${JAVA_INCLUDE_DIR}/darwin)
+
+  if (MSVC)
+    set_property(SOURCE ${lldb_java_wrapper} APPEND_STRING PROPERTY COMPILE_FLAGS " /W0")
+  else()
+    set_property(SOURCE ${lldb_java_wrapper} APPEND_STRING PROPERTY COMPILE_FLAGS " ")
+  endif()
+
+  set_source_files_properties(${lldb_java_wrapper} PROPERTIES GENERATED ON)
+endif()
+
+
 set_target_properties(liblldb
   PROPERTIES
   VERSION ${LLDB_VERSION}
Index: lldb/include/lldb/lldb-enumerations.h
===================================================================
--- lldb/include/lldb/lldb-enumerations.h
+++ lldb/include/lldb/lldb-enumerations.h
@@ -217,6 +217,7 @@
   eScriptLanguageNone = 0,
   eScriptLanguagePython,
   eScriptLanguageLua,
+  eScriptLanguageJava,
   eScriptLanguageUnknown,
   eScriptLanguageDefault = eScriptLanguagePython
 };
Index: lldb/include/lldb/Host/Config.h.cmake
===================================================================
--- lldb/include/lldb/Host/Config.h.cmake
+++ lldb/include/lldb/Host/Config.h.cmake
@@ -41,6 +41,8 @@
 
 #cmakedefine01 LLDB_ENABLE_LIBXML2
 
+#cmakedefine01 LLDB_ENABLE_JAVA
+
 #cmakedefine01 LLDB_ENABLE_LUA
 
 #cmakedefine01 LLDB_ENABLE_PYTHON
Index: lldb/include/lldb/Core/IOHandler.h
===================================================================
--- lldb/include/lldb/Core/IOHandler.h
+++ lldb/include/lldb/Core/IOHandler.h
@@ -55,6 +55,7 @@
     ProcessIO,
     PythonInterpreter,
     LuaInterpreter,
+    JavaInterpreter,
     PythonCode,
     Other
   };
Index: lldb/docs/resources/build.rst
===================================================================
--- lldb/docs/resources/build.rst
+++ lldb/docs/resources/build.rst
@@ -64,6 +64,8 @@
 +-------------------+------------------------------------------------------+--------------------------+
 | Lua               | Lua scripting                                        | ``LLDB_ENABLE_LUA``      |
 +-------------------+------------------------------------------------------+--------------------------+
+| Java              | Java scripting                                       | ``LLDB_ENABLE_JAVA``     |
++-------------------+------------------------------------------------------+--------------------------+
 
 Depending on your platform and package manager, one might run any of the
 commands below.
Index: lldb/cmake/modules/LLDBConfig.cmake
===================================================================
--- lldb/cmake/modules/LLDBConfig.cmake
+++ lldb/cmake/modules/LLDBConfig.cmake
@@ -60,6 +60,7 @@
 add_optional_dependency(LLDB_ENABLE_CURSES "Enable curses support in LLDB" CursesAndPanel CURSESANDPANEL_FOUND)
 add_optional_dependency(LLDB_ENABLE_LZMA "Enable LZMA compression support in LLDB" LibLZMA LIBLZMA_FOUND)
 add_optional_dependency(LLDB_ENABLE_LUA "Enable Lua scripting support in LLDB" LuaAndSwig LUAANDSWIG_FOUND)
+add_optional_dependency(LLDB_ENABLE_JAVA "Enable Java scripting support in LLDB" JavaAndSwig JAVAANDSWIG_FOUND)
 add_optional_dependency(LLDB_ENABLE_PYTHON "Enable Python scripting support in LLDB" PythonAndSwig PYTHONANDSWIG_FOUND)
 add_optional_dependency(LLDB_ENABLE_LIBXML2 "Enable Libxml 2 support in LLDB" LibXml2 LIBXML2_FOUND VERSION 2.8)
 add_optional_dependency(LLDB_ENABLE_FBSDVMCORE "Enable libfbsdvmcore support in LLDB" FBSDVMCore FBSDVMCore_FOUND QUIET)
@@ -185,6 +186,9 @@
 check_cxx_compiler_flag("-Wno-vla-extension" CXX_SUPPORTS_NO_VLA_EXTENSION)
 append_if(CXX_SUPPORTS_NO_VLA_EXTENSION "-Wno-vla-extension" CMAKE_CXX_FLAGS)
 
+check_cxx_compiler_flag("-fexceptions" CXX_SUPPORTS_EXCEPTIONS)
+append_if(CXX_SUPPORTS_EXCEPTIONS "-fexceptions" CMAKE_CXX_FLAGS)
+
 # Disable MSVC warnings
 if( MSVC )
   add_definitions(
Index: lldb/cmake/modules/FindJavaAndSwig.cmake
===================================================================
--- /dev/null
+++ lldb/cmake/modules/FindJavaAndSwig.cmake
@@ -0,0 +1,44 @@
+#.rst:
+# FindJavaAndSwig
+# --------------
+#
+# Find Java and SWIG as a whole.
+
+if(JAVA_LIBRARIES AND JAVA_INCLUDE_DIR AND SWIG_EXECUTABLE)
+  set(JAVAANDSWIG_FOUND TRUE)
+else()
+  find_package(SWIG 3.0)
+  if (SWIG_FOUND)
+    find_package(Java 11.0)
+    if(JAVA_FOUND AND SWIG_FOUND)
+      mark_as_advanced(
+        JAVA_LIBRARIES
+        JAVA_INCLUDE_DIR
+        SWIG_EXECUTABLE)
+    endif()
+  else()
+    message(STATUS "SWIG 3 or later is required for Java support in LLDB but could not be found")
+  endif()
+
+  if (DEFINED ENV{JAVA_HOME})
+    set(JAVA_LIBRARIES  $ENV{JAVA_HOME}/lib)
+    set(JAVA_SERVER_LIB  $ENV{JAVA_HOME}/lib/server)
+    set(JAVA_INCLUDE_DIR  $ENV{JAVA_HOME}/include)
+    set(JAVAC_EXECUTABLE  $ENV{JAVA_HOME}/bin/javac)
+    set(JAR_EXECUTABLE  $ENV{JAVA_HOME}/bin/jar)
+    include_directories(${JAVA_INCLUDE_DIR})
+    link_directories(${JAVA_SERVER_LIB})
+    set(JAVAANDSWIG_FOUND TRUE)
+  else()
+    message(STATUS "Please ensure the Environment variable JAVA_HOME has been set correctly")
+  endif()
+  
+  include(FindPackageHandleStandardArgs)
+  find_package_handle_standard_args(JavaAndSwig
+                                    FOUND_VAR
+                                      JAVAANDSWIG_FOUND
+                                    REQUIRED_VARS
+                                      JAVA_LIBRARIES
+                                      JAVA_INCLUDE_DIR
+                                      SWIG_EXECUTABLE)
+endif()
Index: lldb/bindings/java/java.swig
===================================================================
--- /dev/null
+++ lldb/bindings/java/java.swig
@@ -0,0 +1,24 @@
+/*
+   lldb.swig
+
+   This is the input file for SWIG, to create the appropriate C++ wrappers and
+   functions for various scripting languages, to enable them to call the
+   liblldb Script Bridge functions.
+*/
+
+%module lldb
+
+%include <std_string.i>
+%include "java-typemaps.swig"
+%include "macros.swig"
+%include "headers.swig"
+
+%{
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FormatVariadic.h"
+using namespace lldb_private;
+using namespace lldb;
+%}
+
+%include "interfaces.swig"
+%include "java-wrapper.swig"
Index: lldb/bindings/java/java-wrapper.swig
===================================================================
--- /dev/null
+++ lldb/bindings/java/java-wrapper.swig
@@ -0,0 +1,121 @@
+%header %{
+
+%}
+
+%wrapper %{
+
+// This function is called from Java::CallBreakpointCallback
+SWIGEXPORT llvm::Expected<bool>
+LLDBSwigJavaBreakpointCallbackFunction
+(
+   JNIEnv *env,
+   void *baton,
+   lldb::user_id_t debugger_id,
+   const char * swigJarPath,
+   lldb::StackFrameSP stop_frame_sp,
+   lldb::BreakpointLocationSP bp_loc_sp,
+   StructuredDataImpl *extra_args_impl
+)
+{
+  //printf("entering LLDBSwigJavaBreakpointCallbackFunction %x %x\n", stop_frame_sp, bp_loc_sp);
+                                               
+  lldb::SBFrame sb_frame(stop_frame_sp);
+  lldb::SBBreakpointLocation sb_bp_loc(bp_loc_sp);
+
+  jclass interpreter_cls = env->FindClass("SWIG/LldbScriptInterpreter");
+  if (interpreter_cls == NULL) {
+    printf("Failed to find 'LldbScriptInterpreter' class");
+    return false;
+  }
+   
+  jint jid = (jint) debugger_id;
+  jstring jpath = env->NewStringUTF(swigJarPath);
+  jmethodID mid = env->GetMethodID(interpreter_cls, "<init>", "(ILjava/lang/String;)V");
+  if (mid == nullptr) {
+    printf("Failed to find '<init>' function");
+    return false;
+  }
+
+  jobject interpreter = env->NewObject(interpreter_cls, mid, jid, jpath);
+  if (interpreter == NULL) {
+    printf("Failed to find 'interpreter' for %ld %s", debugger_id, swigJarPath);
+    return false;
+  }
+
+  jmethodID midCallbackCmd = env->GetMethodID(interpreter_cls, "runBreakpointCallback", "(Ljava/lang/String;JJJ)Z");
+  if (midCallbackCmd == NULL) {
+    printf("Failed to find 'runBreakpointCallback' function");
+    return false;
+  }
+
+  lldb::SBStructuredData *extra_args = NULL;
+  if (extra_args_impl)
+     extra_args = new lldb::SBStructuredData(extra_args_impl);
+ 
+  std::string baton_str = llvm::formatv("{0}", baton);
+  jstring jstr = env->NewStringUTF(baton_str.c_str());
+  jlong framePtr = jlong(&sb_frame);
+  jlong bptPtr = jlong(&sb_bp_loc);
+  jlong argsPtr = jlong(extra_args);
+  jboolean ret = (jboolean) env->CallBooleanMethod(interpreter, midCallbackCmd, jstr, framePtr, bptPtr, argsPtr);
+  
+  if (extra_args_impl)
+    delete extra_args;   
+  return (bool) ret;
+}
+
+// This function is called from Java::CallWatchpointCallback
+SWIGEXPORT llvm::Expected<bool>
+LLDBSwigJavaWatchpointCallbackFunction
+(
+   JNIEnv *env,
+   void *baton,
+   lldb::user_id_t debugger_id,
+   const char * swigJarPath,
+   lldb::StackFrameSP stop_frame_sp,
+   lldb::WatchpointSP wp_sp
+)
+{
+  //printf("entering LLDBSwigJavaWatchpointCallbackFunction\n");
+  
+  lldb::SBFrame sb_frame(stop_frame_sp);
+  lldb::SBWatchpoint sb_wp(wp_sp);
+ 
+  jclass interpreter_cls = env->FindClass("SWIG/LldbScriptInterpreter");
+  if (interpreter_cls == NULL) {
+    printf("Failed to find 'LldbScriptInterpreter' class");
+    return false;
+  }
+   
+  jint jid = (jint) debugger_id;
+  jstring jpath = env->NewStringUTF(swigJarPath);
+  jmethodID mid = env->GetMethodID(interpreter_cls, "<init>", "(ILjava/lang/String;)V");
+  if (mid == nullptr) {
+    printf("Failed to find '<init>' function");
+    return false;
+  }
+
+  jobject interpreter = env->NewObject(interpreter_cls, mid, jid, jpath);
+  if (interpreter == NULL) {
+    printf("Failed to find 'interpreter' for %ld %s", debugger_id, swigJarPath);
+    return false;
+  }
+
+  jmethodID midCallbackCmd = env->GetMethodID(interpreter_cls, "runWatchpointCallback", 
+  	"(Ljava/lang/String;JJ)Z");
+  if (midCallbackCmd == NULL) {
+    printf("Failed to find 'runWatchpointCallback' function");
+    return false;
+  }
+
+  std::string baton_str = llvm::formatv("{0}", baton);
+  jstring jstr = env->NewStringUTF(baton_str.c_str());
+  jlong framePtr = jlong(&sb_frame);
+  jlong wptPtr = jlong(&sb_wp);
+  jboolean ret = (jboolean) env->CallBooleanMethod(interpreter, midCallbackCmd, jstr, framePtr, wptPtr);
+  
+  return (bool) ret;
+}
+
+
+%}
Index: lldb/bindings/java/java-typemaps.swig
===================================================================
--- /dev/null
+++ lldb/bindings/java/java-typemaps.swig
@@ -0,0 +1,18 @@
+%include <typemaps.i>
+%include <carrays.i>
+%include <various.i>
+
+%typemap(javabase) ByteArray "SWIGTYPE_p_void"
+%typemap(javabody) ByteArray %{
+  private long swigCPtr; // Minor bodge to work around private variable in parent
+  private boolean swigCMemOwn;
+  public $javaclassname(long cPtr, boolean cMemoryOwn) {
+    super(cPtr, cMemoryOwn);
+    this.swigCPtr = SWIGTYPE_p_void.getCPtr(this);
+    swigCMemOwn = cMemoryOwn;
+  }
+%}
+
+%array_class(jbyte, ByteArray);
+
+%apply char **STRING_ARRAY { char ** }
Index: lldb/bindings/java/SWIG/LldbScriptInterpreter.java
===================================================================
--- /dev/null
+++ lldb/bindings/java/SWIG/LldbScriptInterpreter.java
@@ -0,0 +1,411 @@
+package SWIG;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.tools.Diagnostic;
+import javax.tools.DiagnosticCollector;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.ToolProvider;
+import jdk.jshell.JShell;
+import jdk.jshell.JShellException;
+import jdk.jshell.Snippet.Status;
+import jdk.jshell.SnippetEvent;
+
+public class LldbScriptInterpreter {
+
+  private int debuggerID;
+  private String tmpDirPath;
+  private JavaCompiler compiler;
+  StandardJavaFileManager fm;
+  PrintWriter writer;
+  DiagnosticCollector<JavaFileObject> diagnostics;
+  List<String> options = new ArrayList<>();
+
+  StringWriter sw;
+  PrintWriter pw;
+  private boolean initialized = false;
+  private String className, methodName, methodSig;
+  private static Map<String, String> map = new HashMap<>();
+  private static boolean shellEnabled = false;
+  private static JShell shell;
+
+  public LldbScriptInterpreter(int debuggerID, String swigPath) {
+    this.debuggerID = debuggerID;
+    tmpDirPath = System.getProperty("java.io.tmpdir");
+    compiler = ToolProvider.getSystemJavaCompiler();
+    fm = compiler.getStandardFileManager(null, null, null);
+    writer = new PrintWriter(new StringWriter());
+    diagnostics = new DiagnosticCollector<JavaFileObject>();
+
+    options.add("-g");
+    options.add("-d");
+    options.add(tmpDirPath);
+    options.add("-classpath");
+    options.add(System.getProperty("java.class.path") + File.pathSeparator +
+                tmpDirPath + File.pathSeparator + swigPath);
+    options.add("-proc:none");
+    System.loadLibrary("lldb");
+  }
+
+  public boolean runCmd(String cmd) {
+
+    if (!initialized) {
+      initializeWriter();
+    }
+    if (!cmd.startsWith("/")) {
+      return evalAsCode(cmd);
+    }
+
+    // Might be a special command
+    boolean compile = cmd.startsWith("/ru") || cmd.startsWith("/co");
+    boolean execute =
+        cmd.startsWith("/ru") || cmd.startsWith("/x") || cmd.startsWith("/ex");
+    if (compile || execute) {
+      if (compile) {
+        if (!runCompile()) {
+          System.err.println("compile failed");
+          return false;
+        }
+      }
+      initialized = false;
+      if (execute && map.containsValue(className)) {
+        return runMain(cmd);
+      }
+      return true;
+    } else if (cmd.equals("/reset")) {
+      initialized = false;
+      return true;
+    } else if (cmd.startsWith("/register")) {
+      return runRegister(cmd);
+    } else if (cmd.startsWith("/main") || cmd.startsWith("/bpt") ||
+               cmd.startsWith("/wpt")) {
+      return buildPrologue(cmd);
+    } else if (cmd.equals("/init")) {
+      return buildContext();
+    } else if (cmd.equals("/close")) {
+      return buildEpilogue();
+    } else if (cmd.startsWith("/import")) {
+      return runImport(cmd);
+    } else if (cmd.startsWith("/shell")) {
+      return runShell(cmd);
+    }
+    return evalAsCode(cmd);
+  }
+
+  private void initializeWriter() {
+    sw = new StringWriter();
+    pw = new PrintWriter(sw);
+    initialized = true;
+  }
+
+  private boolean evalAsCode(String cmd) {
+    if (shellEnabled || cmd.startsWith("/shell")) {
+      execShell(cmd);
+    } else {
+      pw.println(cmd);
+    }
+    return true;
+  }
+
+  private boolean buildPrologue(String cmd) {
+    int randomInt = (int)(Math.random() * 1000);
+    className = "LLDB_" + randomInt;
+    methodName = cmd.startsWith("/main") ? "main" : "callback";
+    methodSig = cmd.startsWith("/main") ? "void" : "boolean";
+    String[] split = cmd.split(" ");
+    if (split.length > 1) {
+      map.put(split[1], className);
+    }
+    pw.println("import SWIG.*;");
+    pw.println("public class " + className + " {");
+    pw.print("  public static " + methodSig + " " + methodName);
+    if (cmd.startsWith("/main")) {
+      pw.println("(String args[]) {");
+      return true;
+    } else if (cmd.startsWith("/bpt")) {
+      pw.println(
+          "(SBFrame _frame, SBBreakpointLocation loc, SBStructuredData args) {");
+      return true;
+    } else if (cmd.startsWith("/wpt")) {
+      pw.println("(SBFrame _frame, SBWatchpoint wp) {");
+      return true;
+    }
+    return false;
+  }
+
+  private boolean buildContext() {
+    pw.println("SBDebugger debugger = SBDebugger.FindDebuggerWithID(" +
+               debuggerID + ");");
+    pw.println("SBTarget target = debugger.GetSelectedTarget();");
+    pw.println("SBProcess process = target.GetProcess();");
+    pw.println("SBThread thread = process.GetSelectedThread();");
+    pw.println("SBFrame frame = thread.GetSelectedFrame();");
+    return true;
+  }
+
+  private boolean buildEpilogue() {
+    pw.println("  }");
+    pw.println("}");
+    pw.close();
+    return true;
+  }
+
+  public boolean runCompile() {
+    if (!execCompile(className, sw.toString())) {
+      return false;
+    }
+    map.put(className, className);
+    return true;
+  }
+
+  private boolean runMain(String cmd) {
+    String[] split = cmd.split(" ");
+    if (split.length > 1) {
+      if (map.containsKey(split[1])) {
+        className = map.get(split[1]);
+      } else {
+        System.err.println("Class for " + split[1] + " not found!");
+        return false;
+      }
+    }
+    execMain(className);
+    return true;
+  }
+
+  private boolean runRegister(String cmd) {
+    String[] split = cmd.split(" ");
+    if (split.length > 2) {
+      String x = map.get(split[2]);
+      if (x == null) {
+        System.err.println("Map does not contain " + split[2]);
+        System.err.println(map.keySet());
+        return false;
+      }
+      map.put("LLDB_" + split[1], x);
+    }
+    return true;
+  }
+
+  private boolean runImport(String cmd) {
+    String[] split = cmd.split(" ");
+    File f = new File(split[1]);
+    className = f.getName();
+    try {
+      BufferedReader in = new BufferedReader(new InputStreamReader(
+          new FileInputStream(f), StandardCharsets.UTF_8));
+      String line;
+      while ((line = in.readLine()) != null) {
+        pw.println(line);
+      }
+    } catch (IOException e) {
+      e.printStackTrace();
+      return false;
+    }
+    pw.close();
+    if (!execCompile(className, sw.toString())) {
+      return false;
+    }
+    map.put(className, className);
+    return true;
+  }
+
+  private boolean runShell(String cmd) {
+    String[] split = cmd.split(" ");
+    if (split.length > 1) {
+      if (split[1].equals("off")) {
+        shellEnabled = false;
+        return true;
+      }
+      cmd = cmd.substring(6);
+    }
+    if (!shellEnabled) {
+      shell = JShell.builder().build();
+    }
+    shellEnabled = true;
+    execShell(cmd);
+    return true;
+  }
+
+  public boolean runBreakpointCallback(String baton, long framePtr,
+                                       long bpLocPtr, long extraArgsPtr) {
+    SBFrame frame = framePtr == 0 ? null : new SBFrame(framePtr, false);
+    SBBreakpointLocation loc =
+        bpLocPtr == 0 ? null : new SBBreakpointLocation(framePtr, false);
+    SBStructuredData extraArgs =
+        extraArgsPtr == 0 ? null : new SBStructuredData(extraArgsPtr, false);
+    return execBreakpointCallback(baton, frame, loc, extraArgs);
+  }
+
+  public boolean runWatchpointCallback(String baton, long framePtr,
+                                       long wpLocPtr) {
+    SBFrame frame = framePtr == 0 ? null : new SBFrame(framePtr, false);
+    SBWatchpoint wp = wpLocPtr == 0 ? null : new SBWatchpoint(framePtr, false);
+    return execWatchpointCallback(baton, frame, wp);
+  }
+
+  public boolean runChangeIO(long outPtr, long errPtr) {
+    SWIGTYPE_p_std__shared_ptrT_lldb_private__File_t out =
+        new SWIGTYPE_p_std__shared_ptrT_lldb_private__File_t(outPtr, true);
+    SWIGTYPE_p_std__shared_ptrT_lldb_private__File_t err =
+        new SWIGTYPE_p_std__shared_ptrT_lldb_private__File_t(errPtr, true);
+    SBDebugger debugger = SBDebugger.FindDebuggerWithID(debuggerID);
+    debugger.SetOutputFile(out);
+    debugger.SetErrorFile(err);
+    return true;
+  }
+
+  public boolean execCompile(String fname, String code) {
+    JavaFileObject file = new JavaSourceFromString(fname, code);
+
+    List<? extends JavaFileObject> files = Arrays.asList(file);
+    JavaCompiler.CompilationTask task =
+        compiler.getTask(writer, fm, diagnostics, options, null, files);
+    if (!task.call()) {
+      System.err.println("Unexpected compilation failure:");
+      System.err.println(code);
+      StringBuffer sb = new StringBuffer();
+      for (Diagnostic<?> diagnostic : diagnostics.getDiagnostics()) {
+        sb.append("Error on line " + diagnostic.getLineNumber() + " in " +
+                  diagnostic);
+      }
+      System.err.println(sb.toString());
+      return false;
+    }
+    return true;
+  }
+
+  public void execMain(String fileName) {
+    try {
+      File x = new File(tmpDirPath);
+      URLClassLoader classLoader = URLClassLoader.newInstance(
+          new URL[] {x.toURI().toURL()}); // root is path to class file
+      Class<?> cls = Class.forName(fileName, true, classLoader);
+      cls.getDeclaredMethod("main", new Class[] {String[].class})
+          .invoke(null, new Object[] {null});
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+
+  public boolean execBreakpointCallback(String batonName, SBFrame frame,
+                                        SBBreakpointLocation loc,
+                                        SBStructuredData args) {
+    Boolean retval = false;
+    String className = map.containsKey(batonName)
+                           ? map.get(batonName)
+                           : map.get("LLDB_" + batonName);
+    if (className == null) {
+      System.err.println("Class for " + batonName + " not found!");
+      return false;
+    }
+    try {
+      File x = new File(tmpDirPath);
+      URLClassLoader classLoader = URLClassLoader.newInstance(
+          new URL[] {x.toURI().toURL()}); // root is path to class file
+      Class<?> cls = Class.forName(className, true, classLoader);
+      Object ret = cls.getDeclaredMethod(
+                          "callback", new Class[] {SBFrame.class,
+                                                   SBBreakpointLocation.class,
+                                                   SBStructuredData.class})
+                       .invoke(null, new Object[] {frame, loc, args});
+      retval = (Boolean)ret;
+      return retval;
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+    return retval;
+  }
+
+  public boolean execWatchpointCallback(String batonName, SBFrame frame,
+                                        SBWatchpoint wp) {
+    Boolean retval = false;
+    String className = map.containsKey(batonName)
+                           ? map.get(batonName)
+                           : map.get("LLDB_" + batonName);
+    if (className == null) {
+      System.err.println("Class for " + batonName + " not found!");
+      return false;
+    }
+    try {
+      File x = new File(tmpDirPath);
+      URLClassLoader classLoader = URLClassLoader.newInstance(
+          new URL[] {x.toURI().toURL()}); // root is path to class file
+      Class<?> cls = Class.forName(className, true, classLoader);
+      Object ret =
+          cls.getDeclaredMethod("callback",
+                                new Class[] {SBFrame.class, SBWatchpoint.class})
+              .invoke(null, new Object[] {frame, wp});
+      retval = (Boolean)ret;
+      return retval;
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+    return retval;
+  }
+
+  public String execShell(String shellCmd) {
+    List<SnippetEvent> events = shell.eval(shellCmd);
+    String retval = "";
+    for (SnippetEvent event : events) {
+      Status status = event.status();
+      switch (status) {
+      case OVERWRITTEN:
+        retval += "OVERWRITING: ";
+      case VALID:
+        retval += event.value() + "\n";
+        break;
+      case RECOVERABLE_DEFINED:
+      case RECOVERABLE_NOT_DEFINED:
+      case DROPPED:
+      case REJECTED:
+      case NONEXISTENT:
+        retval += event.toString() + "\n";
+        break;
+      }
+      JShellException exception = event.exception();
+      if (exception != null) {
+        retval += "EXC: " + exception + "\n";
+        StackTraceElement[] stackTrace = exception.getStackTrace();
+        for (int i = 0; i < stackTrace.length; i++) {
+          System.err.println(stackTrace[i].getMethodName() + ":" +
+                             stackTrace[i].getLineNumber());
+        }
+      }
+    }
+    System.out.print(retval);
+    return retval;
+  }
+
+  class JavaSourceFromString extends SimpleJavaFileObject {
+    final String code;
+
+    JavaSourceFromString(String name, String code) {
+      super(URI.create("string:///" + name.replace('.', '/') +
+                       Kind.SOURCE.extension),
+            Kind.SOURCE);
+      this.code = code;
+    }
+
+    @Override
+    public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+      return code;
+    }
+  }
+}
Index: lldb/bindings/java/CMakeLists.txt
===================================================================
--- /dev/null
+++ lldb/bindings/java/CMakeLists.txt
@@ -0,0 +1,27 @@
+FILE(MAKE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/SWIG")
+add_custom_command(
+  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/SWIG/LLDBWrapJava.cpp
+  DEPENDS ${SWIG_SOURCES}
+  DEPENDS ${SWIG_INTERFACES}
+  DEPENDS ${SWIG_HEADERS}
+  COMMAND ${SWIG_EXECUTABLE}
+      ${SWIG_COMMON_FLAGS}
+      -I${CMAKE_CURRENT_SOURCE_DIR}
+      -java
+      -package SWIG
+      -c++
+      -outdir ${CMAKE_CURRENT_BINARY_DIR}/SWIG
+      -o ${CMAKE_CURRENT_BINARY_DIR}/SWIG/LLDBWrapJava.cpp
+      ${CMAKE_CURRENT_SOURCE_DIR}/java.swig
+  VERBATIM
+  COMMENT "Building LLDB Java wrapper")
+
+add_custom_target(swig_wrapper_java ALL DEPENDS
+  ${CMAKE_CURRENT_BINARY_DIR}/SWIG/LLDBWrapJava.cpp
+)
+
+FILE(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/classes")
+add_custom_command(TARGET swig_wrapper_java POST_BUILD
+  COMMAND "${JAVAC_EXECUTABLE}" -d ${CMAKE_CURRENT_BINARY_DIR}/classes ${CMAKE_CURRENT_SOURCE_DIR}/SWIG/*.java
+  COMMAND ${JAR_EXECUTABLE} -cfM SWIG.jar -C ${CMAKE_CURRENT_BINARY_DIR}/classes .
+)
Index: lldb/bindings/CMakeLists.txt
===================================================================
--- lldb/bindings/CMakeLists.txt
+++ lldb/bindings/CMakeLists.txt
@@ -52,3 +52,8 @@
 if (LLDB_ENABLE_LUA)
   add_subdirectory(lua)
 endif()
+
+if (LLDB_ENABLE_JAVA)
+  add_subdirectory(java)
+endif()
+
Index: lldb/CMakeLists.txt
===================================================================
--- lldb/CMakeLists.txt
+++ lldb/CMakeLists.txt
@@ -71,7 +71,7 @@
     CACHE STRING "Path where Lua modules are installed, relative to install prefix")
 endif ()
 
-if (LLDB_ENABLE_PYTHON OR LLDB_ENABLE_LUA)
+if (LLDB_ENABLE_PYTHON OR LLDB_ENABLE_LUA OR LLDB_ENABLE_JAVA)
   add_subdirectory(bindings)
 endif ()
 
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to