[Lldb-commits] [lldb] [lldb] add javascript scripting support (PR #165805)

Chad Smith via lldb-commits lldb-commits at lists.llvm.org
Sat Nov 1 20:09:58 PDT 2025


https://github.com/cs01 updated https://github.com/llvm/llvm-project/pull/165805

>From e0622049d1670b4381ff9f17d8b9c79b5694ec7d Mon Sep 17 00:00:00 2001
From: Chad Smith <cssmith at fb.com>
Date: Tue, 28 Oct 2025 15:33:33 -0700
Subject: [PATCH] add javascript support

---
 lldb/CMakeLists.txt                           |  12 +-
 lldb/bindings/CMakeLists.txt                  |   4 +
 lldb/bindings/javascript/CMakeLists.txt       |  69 +++
 .../javascript/javascript-swigsafecast.swig   |   8 +
 .../javascript/javascript-typemaps.swig       |  48 ++
 .../javascript/javascript-wrapper.swig        |  12 +
 lldb/bindings/javascript/javascript.swig      |  30 ++
 lldb/cmake/modules/FindV8.cmake               |  71 +++
 lldb/cmake/modules/LLDBConfig.cmake           |   1 +
 lldb/docs/index.rst                           |   5 +-
 lldb/docs/resources/build.rst                 |   2 +
 lldb/docs/use/javascript-reference.md         | 263 +++++++++++
 .../Interpreter/CommandOptionArgumentTable.h  |   5 +
 lldb/include/lldb/lldb-enumerations.h         |  13 +-
 .../CommandObjectBreakpointCommand.cpp        |   1 +
 .../CommandObjectWatchpointCommand.cpp        |   1 +
 lldb/source/Core/Debugger.cpp                 |   5 +
 lldb/source/Interpreter/ScriptInterpreter.cpp |   4 +
 .../Plugins/ScriptInterpreter/CMakeLists.txt  |   4 +
 .../JavaScript/CMakeLists.txt                 |  40 ++
 .../JavaScript/JavaScript.cpp                 | 435 ++++++++++++++++++
 .../ScriptInterpreter/JavaScript/JavaScript.h | 107 +++++
 .../JavaScript/SWIGJavaScriptBridge.h         |  51 ++
 .../ScriptInterpreterJavaScript.cpp           | 278 +++++++++++
 .../JavaScript/ScriptInterpreterJavaScript.h  | 121 +++++
 25 files changed, 1586 insertions(+), 4 deletions(-)
 create mode 100644 lldb/bindings/javascript/CMakeLists.txt
 create mode 100644 lldb/bindings/javascript/javascript-swigsafecast.swig
 create mode 100644 lldb/bindings/javascript/javascript-typemaps.swig
 create mode 100644 lldb/bindings/javascript/javascript-wrapper.swig
 create mode 100644 lldb/bindings/javascript/javascript.swig
 create mode 100644 lldb/cmake/modules/FindV8.cmake
 create mode 100644 lldb/docs/use/javascript-reference.md
 create mode 100644 lldb/source/Plugins/ScriptInterpreter/JavaScript/CMakeLists.txt
 create mode 100644 lldb/source/Plugins/ScriptInterpreter/JavaScript/JavaScript.cpp
 create mode 100644 lldb/source/Plugins/ScriptInterpreter/JavaScript/JavaScript.h
 create mode 100644 lldb/source/Plugins/ScriptInterpreter/JavaScript/SWIGJavaScriptBridge.h
 create mode 100644 lldb/source/Plugins/ScriptInterpreter/JavaScript/ScriptInterpreterJavaScript.cpp
 create mode 100644 lldb/source/Plugins/ScriptInterpreter/JavaScript/ScriptInterpreterJavaScript.h

diff --git a/lldb/CMakeLists.txt b/lldb/CMakeLists.txt
index e3b72e94d4beb..a852e581160b5 100644
--- a/lldb/CMakeLists.txt
+++ b/lldb/CMakeLists.txt
@@ -95,7 +95,7 @@ if (LLDB_ENABLE_LUA)
     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_JAVASCRIPT)
   add_subdirectory(bindings)
 endif ()
 
@@ -150,6 +150,16 @@ if (LLDB_ENABLE_LUA)
   finish_swig_lua("lldb-lua" "${lldb_lua_bindings_dir}" "${LLDB_LUA_CPATH}")
 endif()
 
+if (LLDB_ENABLE_JAVASCRIPT)
+  if(LLDB_BUILD_FRAMEWORK)
+    set(lldb_javascript_target_dir "${LLDB_FRAMEWORK_ABSOLUTE_BUILD_DIR}/LLDB.framework/Resources/JavaScript")
+  else()
+    set(lldb_javascript_target_dir "${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib/javascript")
+  endif()
+  get_target_property(lldb_javascript_bindings_dir swig_wrapper_javascript BINARY_DIR)
+  finish_swig_javascript("lldb-javascript" "${lldb_javascript_bindings_dir}" "${lldb_javascript_target_dir}")
+endif()
+
 set(LLDB_INCLUDE_UNITTESTS ON)
 if (NOT TARGET llvm_gtest)
   set(LLDB_INCLUDE_UNITTESTS OFF)
diff --git a/lldb/bindings/CMakeLists.txt b/lldb/bindings/CMakeLists.txt
index bec694e43bd7b..984614a1238aa 100644
--- a/lldb/bindings/CMakeLists.txt
+++ b/lldb/bindings/CMakeLists.txt
@@ -57,3 +57,7 @@ endif()
 if (LLDB_ENABLE_LUA)
   add_subdirectory(lua)
 endif()
+
+if (LLDB_ENABLE_JAVASCRIPT)
+  add_subdirectory(javascript)
+endif()
diff --git a/lldb/bindings/javascript/CMakeLists.txt b/lldb/bindings/javascript/CMakeLists.txt
new file mode 100644
index 0000000000000..7356625f71a90
--- /dev/null
+++ b/lldb/bindings/javascript/CMakeLists.txt
@@ -0,0 +1,69 @@
+add_custom_command(
+  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/LLDBWrapJavaScript.cpp
+  DEPENDS ${SWIG_SOURCES}
+  DEPENDS ${SWIG_INTERFACES}
+  DEPENDS ${SWIG_HEADERS}
+  DEPENDS lldb-sbapi-dwarf-enums
+  COMMAND ${SWIG_EXECUTABLE}
+      ${SWIG_COMMON_FLAGS}
+      -I${CMAKE_CURRENT_SOURCE_DIR}
+      -javascript
+      -v8
+      -w503
+      -outdir ${CMAKE_CURRENT_BINARY_DIR}
+      -o ${CMAKE_CURRENT_BINARY_DIR}/LLDBWrapJavaScript.cpp
+      ${CMAKE_CURRENT_SOURCE_DIR}/javascript.swig
+  VERBATIM
+  COMMENT "Building LLDB JavaScript wrapper")
+
+add_custom_target(swig_wrapper_javascript ALL DEPENDS
+  ${CMAKE_CURRENT_BINARY_DIR}/LLDBWrapJavaScript.cpp
+)
+
+function(create_javascript_package swig_target working_dir pkg_dir)
+  cmake_parse_arguments(ARG "NOINIT" "" "FILES" ${ARGN})
+  add_custom_command(TARGET ${swig_target} POST_BUILD VERBATIM
+    COMMAND ${CMAKE_COMMAND} -E make_directory ${pkg_dir}
+    WORKING_DIRECTORY ${working_dir})
+endfunction()
+
+function(finish_swig_javascript swig_target lldb_javascript_bindings_dir lldb_javascript_target_dir)
+  add_custom_target(${swig_target} ALL VERBATIM
+    COMMAND ${CMAKE_COMMAND} -E make_directory ${lldb_javascript_target_dir}
+    DEPENDS swig_wrapper_javascript liblldb
+    COMMENT "LLDB JavaScript API")
+  if(LLDB_BUILD_FRAMEWORK)
+    set(LIBLLDB_SYMLINK_DEST "${LLDB_FRAMEWORK_ABSOLUTE_BUILD_DIR}/LLDB.framework/LLDB")
+  else()
+    set(LIBLLDB_SYMLINK_DEST "${LLVM_SHLIB_OUTPUT_INTDIR}/liblldb${CMAKE_SHARED_LIBRARY_SUFFIX}")
+  endif()
+  if(WIN32)
+    set(LIBLLDB_SYMLINK_OUTPUT_FILE "lldb.dll")
+  else()
+    set(LIBLLDB_SYMLINK_OUTPUT_FILE "lldb.so")
+  endif()
+  create_relative_symlink(${swig_target} ${LIBLLDB_SYMLINK_DEST}
+                          ${lldb_javascript_target_dir} ${LIBLLDB_SYMLINK_OUTPUT_FILE})
+  set(lldb_javascript_library_target "${swig_target}-library")
+  add_custom_target(${lldb_javascript_library_target})
+  add_dependencies(${lldb_javascript_library_target} ${swig_target})
+
+  # Ensure we do the JavaScript post-build step when building lldb.
+  add_dependencies(lldb ${swig_target})
+
+  if(LLDB_BUILD_FRAMEWORK)
+    set(LLDB_JAVASCRIPT_INSTALL_PATH ${LLDB_FRAMEWORK_INSTALL_DIR}/LLDB.framework/Resources/JavaScript)
+  else()
+    set(LLDB_JAVASCRIPT_INSTALL_PATH lib/javascript)
+  endif()
+  install(DIRECTORY ${lldb_javascript_target_dir}/
+          DESTINATION ${LLDB_JAVASCRIPT_INSTALL_PATH}
+          COMPONENT ${lldb_javascript_library_target})
+
+  set(lldb_javascript_library_install_target "install-${lldb_javascript_library_target}")
+  if (NOT LLVM_ENABLE_IDE)
+    add_llvm_install_targets(${lldb_javascript_library_install_target}
+                            COMPONENT ${lldb_javascript_library_target}
+                            DEPENDS ${lldb_javascript_library_target})
+  endif()
+endfunction()
diff --git a/lldb/bindings/javascript/javascript-swigsafecast.swig b/lldb/bindings/javascript/javascript-swigsafecast.swig
new file mode 100644
index 0000000000000..5d2b50f1fd249
--- /dev/null
+++ b/lldb/bindings/javascript/javascript-swigsafecast.swig
@@ -0,0 +1,8 @@
+/*
+   Safe casting for JavaScript SWIG bindings
+*/
+
+// This file provides safe type casting between LLDB types
+// Similar to lua-swigsafecast.swig and python-swigsafecast.swig
+
+// TODO: Implement safe casting functions as needed
diff --git a/lldb/bindings/javascript/javascript-typemaps.swig b/lldb/bindings/javascript/javascript-typemaps.swig
new file mode 100644
index 0000000000000..cc11067e712bd
--- /dev/null
+++ b/lldb/bindings/javascript/javascript-typemaps.swig
@@ -0,0 +1,48 @@
+/*
+   JavaScript-specific typemaps for LLDB
+*/
+
+%header %{
+#include <v8.h>
+%}
+
+// Typemap for char ** (string arrays) - used in LaunchSimple, Launch, etc.
+// Converts JavaScript arrays to C string arrays
+%typemap(in) char ** {
+  if ($input->IsArray()) {
+    v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast($input);
+    uint32_t length = array->Length();
+    $1 = (char **)malloc((length + 1) * sizeof(char *));
+
+    for (uint32_t i = 0; i < length; i++) {
+      v8::Local<v8::Value> element;
+      if (array->Get(SWIGV8_CURRENT_CONTEXT(), i).ToLocal(&element)) {
+        if (element->IsString()) {
+          v8::String::Utf8Value str(SWIGV8_CURRENT_CONTEXT()->GetIsolate(), element);
+          $1[i] = strdup(*str);
+        } else {
+          free($1);
+          SWIG_exception_fail(SWIG_TypeError, "Array elements must be strings");
+        }
+      }
+    }
+    $1[length] = NULL;
+  } else if ($input->IsNull() || $input->IsUndefined()) {
+    $1 = NULL;
+  } else {
+    SWIG_exception_fail(SWIG_TypeError, "Expected array of strings or null");
+  }
+}
+
+%typemap(freearg) char ** {
+  if ($1) {
+    for (int i = 0; $1[i] != NULL; i++) {
+      free($1[i]);
+    }
+    free($1);
+  }
+}
+
+%typemap(typecheck, precedence=SWIG_TYPECHECK_STRING_ARRAY) char ** {
+  $1 = $input->IsArray() || $input->IsNull() || $input->IsUndefined();
+}
diff --git a/lldb/bindings/javascript/javascript-wrapper.swig b/lldb/bindings/javascript/javascript-wrapper.swig
new file mode 100644
index 0000000000000..af952201ddd05
--- /dev/null
+++ b/lldb/bindings/javascript/javascript-wrapper.swig
@@ -0,0 +1,12 @@
+/*
+   JavaScript-specific wrapper functions for LLDB
+*/
+
+// This file will contain JavaScript-specific wrapper code
+// to bridge between LLDB's C++ API and JavaScript/V8
+
+// TODO: Add wrapper functions for:
+// - Breakpoint callbacks
+// - Watchpoint callbacks
+// - Custom commands
+// - Data formatters
diff --git a/lldb/bindings/javascript/javascript.swig b/lldb/bindings/javascript/javascript.swig
new file mode 100644
index 0000000000000..098c04ad8d365
--- /dev/null
+++ b/lldb/bindings/javascript/javascript.swig
@@ -0,0 +1,30 @@
+/*
+   lldb.swig
+
+   This is the input file for SWIG, to create the appropriate C++ wrappers and
+   functions for JavaScript (V8/Node.js), to enable them to call the
+   liblldb Script Bridge functions.
+*/
+
+%module lldb
+
+%include <std_string.i>
+%include "javascript-typemaps.swig"
+%include "macros.swig"
+%include "headers.swig"
+
+%{
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "../bindings/javascript/javascript-swigsafecast.swig"
+#include "../source/Plugins/ScriptInterpreter/JavaScript/SWIGJavaScriptBridge.h"
+
+// required headers for typemaps
+#include "lldb/Host/File.h"
+
+using namespace lldb_private;
+using namespace lldb;
+%}
+
+%include "interfaces.swig"
+%include "javascript-wrapper.swig"
diff --git a/lldb/cmake/modules/FindV8.cmake b/lldb/cmake/modules/FindV8.cmake
new file mode 100644
index 0000000000000..d6ce23feddef1
--- /dev/null
+++ b/lldb/cmake/modules/FindV8.cmake
@@ -0,0 +1,71 @@
+#.rst:
+# FindV8
+# ------
+#
+# Find V8 JavaScript engine
+#
+# This module will search for V8 in standard system locations, or use
+# user-specified paths. Users can override the search by setting:
+#   -DV8_INCLUDE_DIR=/path/to/v8/include
+#   -DV8_LIBRARIES=/path/to/libv8.so (or libv8_monolith.a)
+#
+# The module defines:
+#   V8_FOUND - System has V8
+#   V8_INCLUDE_DIR - V8 include directory
+#   V8_LIBRARIES - V8 libraries to link against
+
+if(V8_LIBRARIES AND V8_INCLUDE_DIR)
+  set(V8_FOUND TRUE)
+  if(NOT V8_FIND_QUIETLY)
+    message(STATUS "Found V8: ${V8_INCLUDE_DIR}")
+    message(STATUS "Found V8 library: ${V8_LIBRARIES}")
+    set(V8_FIND_QUIETLY TRUE CACHE BOOL "Suppress repeated V8 find messages" FORCE)
+  endif()
+else()
+  # Try to find system V8
+  find_path(V8_INCLUDE_DIR
+    NAMES v8.h
+    PATHS
+      # Standard system locations
+      /usr/include
+      /usr/local/include
+      /opt/v8/include
+      # Homebrew on macOS
+      /opt/homebrew/include
+      /usr/local/opt/v8/include
+    PATH_SUFFIXES
+      v8
+    DOC "V8 include directory"
+  )
+
+  find_library(V8_LIBRARIES
+    NAMES v8_monolith v8 v8_libbase v8_libplatform
+    PATHS
+      # Standard system locations
+      /usr/lib
+      /usr/local/lib
+      /opt/v8/lib
+      # Homebrew on macOS
+      /opt/homebrew/lib
+      /usr/local/opt/v8/lib
+    DOC "V8 library"
+  )
+
+  include(FindPackageHandleStandardArgs)
+  find_package_handle_standard_args(V8
+                                    FOUND_VAR
+                                      V8_FOUND
+                                    REQUIRED_VARS
+                                      V8_INCLUDE_DIR
+                                      V8_LIBRARIES)
+
+  if(V8_FOUND)
+    mark_as_advanced(V8_LIBRARIES V8_INCLUDE_DIR)
+    message(STATUS "Found V8: ${V8_INCLUDE_DIR}")
+    if(V8_LIBRARIES)
+      message(STATUS "Found V8 library: ${V8_LIBRARIES}")
+    else()
+      message(STATUS "V8 headers found (library may need to be built or specified manually)")
+    endif()
+  endif()
+endif()
diff --git a/lldb/cmake/modules/LLDBConfig.cmake b/lldb/cmake/modules/LLDBConfig.cmake
index 4b568d27c4709..e42522e8b8765 100644
--- a/lldb/cmake/modules/LLDBConfig.cmake
+++ b/lldb/cmake/modules/LLDBConfig.cmake
@@ -62,6 +62,7 @@ add_optional_dependency(LLDB_ENABLE_CURSES "Enable curses support in LLDB" Curse
 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_PYTHON "Enable Python scripting support in LLDB" PythonAndSwig PYTHONANDSWIG_FOUND)
+add_optional_dependency(LLDB_ENABLE_JAVASCRIPT "Enable JavaScript scripting support in LLDB" V8 V8_FOUND)
 add_optional_dependency(LLDB_ENABLE_LIBXML2 "Enable Libxml 2 support in LLDB" LibXml2 LIBXML2_FOUND VERSION ${LLDB_LIBXML2_VERSION})
 add_optional_dependency(LLDB_ENABLE_FBSDVMCORE "Enable libfbsdvmcore support in LLDB" FBSDVMCore FBSDVMCore_FOUND QUIET)
 
diff --git a/lldb/docs/index.rst b/lldb/docs/index.rst
index a981c0ab8d6e9..bfe39dc9d5297 100644
--- a/lldb/docs/index.rst
+++ b/lldb/docs/index.rst
@@ -27,7 +27,9 @@ with GDB there is a cheat sheet listing common tasks and their LLDB equivalent
 in the `GDB to LLDB command map <https://lldb.llvm.org/use/map.html>`_.
 
 There are also multiple resources on how to script LLDB using Python: the
-:doc:`use/python-reference` is a great starting point for that.
+:doc:`use/python-reference` is a great starting point for that. LLDB also
+supports scripting with JavaScript through the V8 engine (see
+`JavaScript Reference <use/javascript-reference.html>`_).
 
 Compiler Integration Benefits
 -----------------------------
@@ -148,6 +150,7 @@ interesting areas to contribute to lldb.
 
    use/python
    use/python-reference
+   use/javascript-reference
    Python API <python_api>
    Python Extensions <python_extensions>
 
diff --git a/lldb/docs/resources/build.rst b/lldb/docs/resources/build.rst
index 0db8c92ad49d6..5d6ee39ea6164 100644
--- a/lldb/docs/resources/build.rst
+++ b/lldb/docs/resources/build.rst
@@ -66,6 +66,8 @@ CMake configuration error.
 +-------------------+--------------------------------------------------------------+--------------------------+
 | Lua               | Lua scripting. Lua 5.3 and 5.4 are supported.                | ``LLDB_ENABLE_LUA``      |
 +-------------------+--------------------------------------------------------------+--------------------------+
+| JavaScript        | JavaScript scripting via V8 engine. Experimental.            | ``LLDB_ENABLE_JAVASCRIPT``|
++-------------------+--------------------------------------------------------------+--------------------------+
 
 Depending on your platform and package manager, one might run any of the
 commands below.
diff --git a/lldb/docs/use/javascript-reference.md b/lldb/docs/use/javascript-reference.md
new file mode 100644
index 0000000000000..a73befa02f224
--- /dev/null
+++ b/lldb/docs/use/javascript-reference.md
@@ -0,0 +1,263 @@
+# JavaScript Reference
+
+LLDB has extensive support for interacting with JavaScript through the V8
+JavaScript engine. This document describes how to use JavaScript scripting
+within LLDB and provides reference documentation for the JavaScript API.
+
+## Using JavaScript in LLDB
+
+LLDB's JavaScript support is built on top of the V8 JavaScript engine, the same
+engine that powers Node.js and Chrome. This provides full ES2020+ language
+support with modern JavaScript features.
+
+### Interactive JavaScript
+
+JavaScript can be run interactively in LLDB. First, set JavaScript as the script language, then use the `script` command:
+
+```
+(lldb) settings set script-lang javascript
+(lldb) script
+>>> let message = "Hello from JavaScript!";
+>>> console.log(message);
+Hello from JavaScript!
+>>> lldb.debugger.GetVersionString()
+lldb version 18.0.0
+```
+
+### Running JavaScript from Files
+
+You can execute JavaScript files using the `command script import` command:
+
+```
+(lldb) command script import /path/to/myscript.js
+```
+
+The JavaScript file will be executed in the current LLDB context with access
+to all LLDB APIs.
+
+### Example JavaScript Script
+
+Here's a simple example that demonstrates using the LLDB JavaScript API:
+
+```javascript
+// Get the current debugger instance
+let debugger = lldb.debugger;
+
+// Get the current target
+let target = debugger.GetSelectedTarget();
+
+// Get the current process
+let process = target.GetProcess();
+
+// Get the selected thread
+let thread = process.GetSelectedThread();
+
+// Get the selected frame
+let frame = thread.GetSelectedFrame();
+
+// Evaluate an expression
+let result = frame.EvaluateExpression("myVariable");
+console.log("Value:", result.GetValue());
+
+// Print all local variables
+let variables = frame.GetVariables(true, true, false, false);
+for (let i = 0; i < variables.GetSize(); i++) {
+  let variable = variables.GetValueAtIndex(i);
+  console.log(variable.GetName() + " = " + variable.GetValue());
+}
+```
+
+## The JavaScript API
+
+The JavaScript API provides access to all of LLDB's Script Bridge (SB) API
+classes. These classes are automatically available in the `lldb` module when
+running JavaScript within LLDB.
+
+### Global Objects
+
+* `lldb`: The main LLDB module containing all SB API classes
+* `lldb.debugger`: The current debugger instance (shortcut to avoid passing
+  debugger around)
+* `console`: Standard JavaScript console object for logging
+
+### Available Classes
+
+The JavaScript API includes all of LLDB's SB API classes, like `SBDebugger`,
+`SBTarget`, etc.
+
+For complete documentation of all classes and their methods, refer to the
+[C++ API documentation](https://lldb.llvm.org/cpp_reference/namespacelldb.html),
+as the JavaScript API mirrors the C++ API closely.
+
+### Console Output
+
+JavaScript scripts can use the standard `console` object for output:
+
+```javascript
+console.log("Informational message");
+console.error("Error message");
+console.warn("Warning message");
+```
+
+Output from `console.log()` and other console methods will be displayed in
+the LLDB command output.
+
+## Building LLDB with JavaScript Support
+
+### Prerequisites
+
+To build LLDB with JavaScript support, you need:
+
+* [V8 JavaScript Engine](https://v8.dev) (version 8.0 or later recommended)
+* [SWIG](http://swig.org/) 4 or later (for generating language bindings)
+* All standard LLDB build dependencies (see [build documentation](../resources/build.rst))
+
+### Installing V8
+
+The V8 JavaScript engine must be installed on your system. Installation methods
+vary by platform:
+
+**Ubuntu/Debian:**
+
+```bash
+$ sudo apt-get install libv8-dev
+```
+
+After installation, V8 will typically be installed in:
+- Headers: `/usr/include/v8/` or `/usr/include/`
+- Libraries: `/usr/lib/x86_64-linux-gnu/libv8.so` (or similar for your architecture)
+
+You can verify the installation with:
+```bash
+$ dpkg -L libv8-dev | grep -E '(include|lib)'
+```
+
+**macOS (using Homebrew):**
+
+```bash
+$ brew install v8
+```
+
+After installation, you can find the paths with:
+```bash
+$ brew info v8
+```
+
+Homebrew typically installs to `/opt/homebrew/` (Apple Silicon) or `/usr/local/` (Intel).
+
+**Building V8 from source:**
+
+If V8 is not available as a package for your platform, you can build it from
+source. Follow the instructions at https://v8.dev/docs/build
+
+### CMake Configuration
+
+To enable JavaScript support when building LLDB, add the following CMake
+options:
+
+```bash
+$ cmake -G Ninja \
+    -DLLDB_ENABLE_JAVASCRIPT=ON \
+    [other cmake options] \
+    /path/to/llvm-project/llvm
+```
+
+The `LLDB_ENABLE_JAVASCRIPT` flag enables JavaScript scripting support. If
+V8 is installed via a package manager in standard system locations, CMake
+should auto-detect it. If CMake cannot find V8, you can specify the paths
+manually:
+
+```bash
+$ cmake -G Ninja \
+    -DLLDB_ENABLE_JAVASCRIPT=ON \
+    -DV8_INCLUDE_DIR=/path/to/v8/include \
+    -DV8_LIBRARIES=/path/to/v8/lib/libv8.so \
+    [other cmake options] \
+    /path/to/llvm-project/llvm
+```
+
+where:
+* `V8_INCLUDE_DIR`: Path to V8 header files
+* `V8_LIBRARIES`: Path to V8 library files
+
+### Verifying JavaScript Support
+
+After building LLDB with JavaScript support, you can verify it's working:
+
+```
+$ lldb
+(lldb) settings set script-lang javascript
+(lldb) script
+>>> console.log("JavaScript is working!")
+JavaScript is working!
+>>> lldb.debugger.GetVersionString()
+lldb version 18.0.0
+```
+
+If JavaScript support is not enabled, you'll see an error message when trying
+to set the script language to JavaScript.
+
+### Build Example
+
+Here's a complete example of building LLDB with JavaScript support from scratch:
+
+```bash
+# Clone the LLVM project
+$ git clone https://github.com/llvm/llvm-project.git
+
+# Create build directory
+$ mkdir llvm-build && cd llvm-build
+
+# Configure with JavaScript support
+$ cmake -G Ninja \
+    -DCMAKE_BUILD_TYPE=Release \
+    -DLLVM_ENABLE_PROJECTS="clang;lldb" \
+    -DLLDB_ENABLE_JAVASCRIPT=ON \
+    -DV8_INCLUDE_DIR=/usr/include/v8 \
+    -DV8_LIBRARIES=/usr/lib/x86_64-linux-gnu/libv8.so \
+    ../llvm-project/llvm
+
+# Build LLDB
+$ ninja lldb
+
+# Test JavaScript support
+$ ./bin/lldb -o "settings set script-lang javascript" -o "script -e \"console.log('Hello!')\"" -o "quit"
+```
+
+## Differences from Python API and JavaScript Environment
+
+Important differences to understand:
+
+**Not a Node.js Environment:**
+
+LLDB's JavaScript environment uses the V8 engine but is **not** Node.js. This means:
+
+* **No module system**: `import`, `require()`, and `module.exports` are not available
+* **No event loop**: Asynchronous operations like `setTimeout`, `setInterval`, `Promise.then()` callbacks are not supported
+* **Limited global APIs**: Only specific functions are implemented:
+  * `console.log()`, `console.error()`, `console.warn()` for output
+  * `lldb` global object for LLDB API access
+  * Standard JavaScript language features (ES2020+)
+
+**Module Access:**
+
+In Python, you typically import with `import lldb`. In JavaScript, `lldb`
+is automatically available as a global object without any import statement.
+
+Scripts should be written as self-contained synchronous code that directly uses the
+`lldb` global object.
+
+## Known Limitations
+
+The JavaScript support in LLDB is not as extensive as Python. The
+following features are not yet implemented:
+
+* Custom breakpoint callbacks in JavaScript
+* Custom watchpoint callbacks in JavaScript
+* Some advanced type mapping and conversions
+
+## Additional Resources
+
+* [LLDB C++ API Reference](https://lldb.llvm.org/cpp_reference/namespacelldb.html)
+* [V8 JavaScript Engine Documentation](https://v8.dev/docs)
+* [LLDB Python Reference](python-reference.html) (similar concepts apply to JavaScript)
diff --git a/lldb/include/lldb/Interpreter/CommandOptionArgumentTable.h b/lldb/include/lldb/Interpreter/CommandOptionArgumentTable.h
index 4face717531b1..9e4ab5d1425e6 100644
--- a/lldb/include/lldb/Interpreter/CommandOptionArgumentTable.h
+++ b/lldb/include/lldb/Interpreter/CommandOptionArgumentTable.h
@@ -96,6 +96,11 @@ static constexpr OptionEnumValueElement g_script_option_enumeration[] = {
         "lua",
         "Commands are in the Lua language.",
     },
+    {
+        lldb::eScriptLanguageJavaScript,
+        "javascript",
+        "Commands are in the JavaScript language.",
+    },
     {
         lldb::eScriptLanguageNone,
         "default",
diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h
index 1a7db8faecd94..879c25e3ae0d5 100644
--- a/lldb/include/lldb/lldb-enumerations.h
+++ b/lldb/include/lldb/lldb-enumerations.h
@@ -227,8 +227,17 @@ enum ScriptLanguage {
   eScriptLanguageNone = 0,
   eScriptLanguagePython,
   eScriptLanguageLua,
+  eScriptLanguageJavaScript,
   eScriptLanguageUnknown,
+#if LLDB_ENABLE_PYTHON
   eScriptLanguageDefault = eScriptLanguagePython
+#elif LLDB_ENABLE_LUA
+  eScriptLanguageDefault = eScriptLanguageLua
+#elif LLDB_ENABLE_JAVASCRIPT
+  eScriptLanguageDefault = eScriptLanguageJavaScript
+#else
+  eScriptLanguageDefault = eScriptLanguageNone
+#endif
 };
 
 /// Register numbering types.
@@ -314,7 +323,7 @@ enum ConnectionStatus {
   eConnectionStatusNoConnection,   ///< No connection
   eConnectionStatusLostConnection, ///< Lost connection while connected to a
                                    ///< valid connection
-  eConnectionStatusInterrupted ///< Interrupted read
+  eConnectionStatusInterrupted     ///< Interrupted read
 };
 
 enum ErrorType {
@@ -1109,7 +1118,7 @@ enum PathType {
   ePathTypeGlobalLLDBTempSystemDir, ///< The LLDB temp directory for this
                                     ///< system, NOT cleaned up on a process
                                     ///< exit.
-  ePathTypeClangDir ///< Find path to Clang builtin headers
+  ePathTypeClangDir                 ///< Find path to Clang builtin headers
 };
 
 /// Kind of member function.
diff --git a/lldb/source/Commands/CommandObjectBreakpointCommand.cpp b/lldb/source/Commands/CommandObjectBreakpointCommand.cpp
index a913ed5fa12b3..8e60ebce987bd 100644
--- a/lldb/source/Commands/CommandObjectBreakpointCommand.cpp
+++ b/lldb/source/Commands/CommandObjectBreakpointCommand.cpp
@@ -266,6 +266,7 @@ are no syntax errors may indicate that a function was declared but never called.
         switch (m_script_language) {
         case eScriptLanguagePython:
         case eScriptLanguageLua:
+        case eScriptLanguageJavaScript:
           m_use_script_language = true;
           break;
         case eScriptLanguageNone:
diff --git a/lldb/source/Commands/CommandObjectWatchpointCommand.cpp b/lldb/source/Commands/CommandObjectWatchpointCommand.cpp
index 062bf75eb8ae8..1e5543096e5a2 100644
--- a/lldb/source/Commands/CommandObjectWatchpointCommand.cpp
+++ b/lldb/source/Commands/CommandObjectWatchpointCommand.cpp
@@ -297,6 +297,7 @@ are no syntax errors may indicate that a function was declared but never called.
         switch (m_script_language) {
         case eScriptLanguagePython:
         case eScriptLanguageLua:
+        case eScriptLanguageJavaScript:
           m_use_script_language = true;
           break;
         case eScriptLanguageNone:
diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp
index b37d9d3ed85e3..d8a6fd44c7f3f 100644
--- a/lldb/source/Core/Debugger.cpp
+++ b/lldb/source/Core/Debugger.cpp
@@ -147,6 +147,11 @@ static constexpr OptionEnumValueElement g_language_enumerators[] = {
         "python",
         "Select python as the default scripting language.",
     },
+    {
+        eScriptLanguageJavaScript,
+        "javascript",
+        "Select javascript as the default scripting language.",
+    },
     {
         eScriptLanguageDefault,
         "default",
diff --git a/lldb/source/Interpreter/ScriptInterpreter.cpp b/lldb/source/Interpreter/ScriptInterpreter.cpp
index ca768db1199c1..b215710a545f0 100644
--- a/lldb/source/Interpreter/ScriptInterpreter.cpp
+++ b/lldb/source/Interpreter/ScriptInterpreter.cpp
@@ -65,6 +65,8 @@ std::string ScriptInterpreter::LanguageToString(lldb::ScriptLanguage language) {
     return "Python";
   case eScriptLanguageLua:
     return "Lua";
+  case eScriptLanguageJavaScript:
+    return "JavaScript";
   case eScriptLanguageUnknown:
     return "Unknown";
   }
@@ -158,6 +160,8 @@ ScriptInterpreter::StringToLanguage(const llvm::StringRef &language) {
     return eScriptLanguagePython;
   if (language.equals_insensitive(LanguageToString(eScriptLanguageLua)))
     return eScriptLanguageLua;
+  if (language.equals_insensitive(LanguageToString(eScriptLanguageJavaScript)))
+    return eScriptLanguageJavaScript;
   return eScriptLanguageUnknown;
 }
 
diff --git a/lldb/source/Plugins/ScriptInterpreter/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/CMakeLists.txt
index 4429b006173a7..ae74db4db31c0 100644
--- a/lldb/source/Plugins/ScriptInterpreter/CMakeLists.txt
+++ b/lldb/source/Plugins/ScriptInterpreter/CMakeLists.txt
@@ -8,3 +8,7 @@ endif()
 if (LLDB_ENABLE_LUA)
   add_subdirectory(Lua)
 endif()
+
+if (LLDB_ENABLE_JAVASCRIPT)
+  add_subdirectory(JavaScript)
+endif()
diff --git a/lldb/source/Plugins/ScriptInterpreter/JavaScript/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/JavaScript/CMakeLists.txt
new file mode 100644
index 0000000000000..e7c5baffcaed5
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/JavaScript/CMakeLists.txt
@@ -0,0 +1,40 @@
+if(NOT LLDB_ENABLE_JAVASCRIPT)
+  return()
+endif()
+
+find_package(V8)
+
+if(NOT V8_FOUND)
+  message(FATAL_ERROR "V8 JavaScript engine not found. JavaScript scripting will not be available.")
+  return()
+endif()
+
+add_lldb_library(lldbPluginScriptInterpreterJavaScript PLUGIN
+  JavaScript.cpp
+  ScriptInterpreterJavaScript.cpp
+  ${CMAKE_BINARY_DIR}/tools/lldb/bindings/javascript/LLDBWrapJavaScript.cpp
+
+  LINK_LIBS
+    lldbBreakpoint
+    lldbCore
+    lldbDataFormatters
+    lldbHost
+    lldbInterpreter
+    lldbTarget
+    lldbUtility
+
+  LINK_COMPONENTS
+    Support
+
+  CLANG_LIBS
+    clangBasic
+)
+
+target_include_directories(lldbPluginScriptInterpreterJavaScript PUBLIC
+  ${V8_INCLUDE_DIR}
+)
+
+# Link against V8
+if(V8_LIBRARIES)
+  target_link_libraries(lldbPluginScriptInterpreterJavaScript PRIVATE ${V8_LIBRARIES})
+endif()
diff --git a/lldb/source/Plugins/ScriptInterpreter/JavaScript/JavaScript.cpp b/lldb/source/Plugins/ScriptInterpreter/JavaScript/JavaScript.cpp
new file mode 100644
index 0000000000000..a5c4074dabc3b
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/JavaScript/JavaScript.cpp
@@ -0,0 +1,435 @@
+//===-- JavaScript.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 "JavaScript.h"
+#include "lldb/API/SBDebugger.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Utility/FileSpec.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FormatVariadic.h"
+
+#include <libplatform/libplatform.h>
+#include <v8.h>
+
+using namespace lldb_private;
+using namespace lldb;
+
+// SWIG-generated init function (SWIGV8_INIT is a macro that expands to
+// lldb_initialize)
+extern "C" void lldb_initialize(v8::Local<v8::Object> exports,
+                                v8::Local<v8::Object> module);
+
+// Static V8 platform (initialized once)
+std::unique_ptr<v8::Platform> JavaScript::s_platform;
+bool JavaScript::s_platform_initialized = false;
+
+// Helper to format and write output
+static void
+WriteFormattedOutput(const v8::FunctionCallbackInfo<v8::Value> &args,
+                     bool add_newline = true) {
+  v8::Isolate *isolate = args.GetIsolate();
+  v8::HandleScope handle_scope(isolate);
+
+  v8::Local<v8::Context> context = isolate->GetCurrentContext();
+  JavaScript *js_instance =
+      static_cast<JavaScript *>(context->GetAlignedPointerFromEmbedderData(1));
+
+  std::string output;
+  for (int i = 0; i < args.Length(); i++) {
+    if (i > 0)
+      output += " ";
+    v8::String::Utf8Value str(isolate, args[i]);
+    output += *str;
+  }
+  if (add_newline)
+    output += "\n";
+
+  if (js_instance) {
+    js_instance->WriteOutput(output);
+  } else {
+    printf("%s", output.c_str());
+    fflush(stdout);
+  }
+}
+
+// Console.log implementation
+static void ConsoleLog(const v8::FunctionCallbackInfo<v8::Value> &args) {
+  WriteFormattedOutput(args, true);
+}
+
+// Console.warn implementation
+static void ConsoleWarn(const v8::FunctionCallbackInfo<v8::Value> &args) {
+  WriteFormattedOutput(args, true);
+}
+
+// Console.error implementation
+static void ConsoleError(const v8::FunctionCallbackInfo<v8::Value> &args) {
+  WriteFormattedOutput(args, true);
+}
+
+void JavaScript::InitializePlatform() {
+  if (s_platform_initialized)
+    return;
+
+  v8::V8::InitializeICUDefaultLocation("");
+  v8::V8::InitializeExternalStartupData("");
+  s_platform = v8::platform::NewDefaultPlatform();
+  v8::V8::InitializePlatform(s_platform.get());
+  v8::V8::Initialize();
+
+  s_platform_initialized = true;
+}
+
+JavaScript::JavaScript(lldb::FileSP output_file)
+    : m_stdout(stdout), m_stderr(stderr), m_output_file(output_file) {
+  InitializePlatform();
+
+  // Create isolate
+  v8::Isolate::CreateParams create_params;
+  create_params.array_buffer_allocator =
+      v8::ArrayBuffer::Allocator::NewDefaultAllocator();
+  m_isolate = v8::Isolate::New(create_params);
+
+  // Create context
+  v8::Isolate::Scope isolate_scope(m_isolate);
+  v8::HandleScope handle_scope(m_isolate);
+
+  v8::Local<v8::Context> context = v8::Context::New(m_isolate);
+  m_context = new v8::Global<v8::Context>(m_isolate, context);
+
+  // Initialize SWIG bindings
+  v8::Context::Scope context_scope(context);
+  v8::Local<v8::Object> lldb_module = v8::Object::New(m_isolate);
+  v8::Local<v8::Object> empty_module = v8::Object::New(m_isolate);
+
+  lldb_initialize(lldb_module, empty_module);
+
+  context->Global()
+      ->Set(context,
+            v8::String::NewFromUtf8(m_isolate, "lldb").ToLocalChecked(),
+            lldb_module)
+      .Check();
+
+  v8::Local<v8::Object> console_obj = v8::Object::New(m_isolate);
+  console_obj
+      ->Set(context, v8::String::NewFromUtf8(m_isolate, "log").ToLocalChecked(),
+            v8::Function::New(context, ConsoleLog).ToLocalChecked())
+      .Check();
+  console_obj
+      ->Set(context,
+            v8::String::NewFromUtf8(m_isolate, "warn").ToLocalChecked(),
+            v8::Function::New(context, ConsoleWarn).ToLocalChecked())
+      .Check();
+  console_obj
+      ->Set(context,
+            v8::String::NewFromUtf8(m_isolate, "error").ToLocalChecked(),
+            v8::Function::New(context, ConsoleError).ToLocalChecked())
+      .Check();
+  context->Global()
+      ->Set(context,
+            v8::String::NewFromUtf8(m_isolate, "console").ToLocalChecked(),
+            console_obj)
+      .Check();
+
+  context->SetAlignedPointerInEmbedderData(1, this);
+}
+
+JavaScript::~JavaScript() {
+  // Clear all callbacks
+  for (auto &pair : m_breakpoint_callbacks) {
+    pair.second.Reset();
+  }
+  m_breakpoint_callbacks.clear();
+
+  for (auto &pair : m_watchpoint_callbacks) {
+    pair.second.Reset();
+  }
+  m_watchpoint_callbacks.clear();
+
+  if (m_context) {
+    m_context->Reset();
+    delete m_context;
+  }
+  if (m_isolate) {
+    m_isolate->Dispose();
+  }
+}
+
+llvm::Error JavaScript::Run(llvm::StringRef code) {
+  v8::Isolate::Scope isolate_scope(m_isolate);
+  v8::HandleScope handle_scope(m_isolate);
+  v8::Local<v8::Context> context = m_context->Get(m_isolate);
+  v8::Context::Scope context_scope(context);
+
+  v8::TryCatch try_catch(m_isolate);
+
+  // Compile
+  v8::Local<v8::String> source =
+      v8::String::NewFromUtf8(m_isolate, code.data(),
+                              v8::NewStringType::kNormal, code.size())
+          .ToLocalChecked();
+
+  v8::Local<v8::Script> script;
+  if (!v8::Script::Compile(context, source).ToLocal(&script)) {
+    v8::String::Utf8Value error(m_isolate, try_catch.Exception());
+    return llvm::make_error<llvm::StringError>(
+        llvm::formatv("Compilation error: {0}\n", *error),
+        llvm::inconvertibleErrorCode());
+  }
+
+  // Run
+  v8::Local<v8::Value> result;
+  if (!script->Run(context).ToLocal(&result)) {
+    v8::String::Utf8Value error(m_isolate, try_catch.Exception());
+    return llvm::make_error<llvm::StringError>(
+        llvm::formatv("Runtime error: {0}\n", *error),
+        llvm::inconvertibleErrorCode());
+  }
+
+  // Print the result if it's not undefined (REPL behavior)
+  if (!result->IsUndefined()) {
+    v8::String::Utf8Value result_str(m_isolate, result);
+    WriteOutput(std::string(*result_str) + "\n");
+  }
+
+  return llvm::Error::success();
+}
+
+llvm::Error JavaScript::LoadModule(llvm::StringRef filename) {
+  const FileSpec file(filename);
+  if (!FileSystem::Instance().Exists(file)) {
+    return llvm::make_error<llvm::StringError>("File not found",
+                                               llvm::inconvertibleErrorCode());
+  }
+
+  if (file.GetFileNameExtension() != ".js") {
+    return llvm::make_error<llvm::StringError>(
+        "Invalid extension (expected .js)", llvm::inconvertibleErrorCode());
+  }
+
+  // Read file using llvm MemoryBuffer
+  auto buffer_or_error = llvm::MemoryBuffer::getFile(file.GetPath());
+  if (!buffer_or_error) {
+    return llvm::make_error<llvm::StringError>(
+        llvm::formatv("Failed to read file: {0}",
+                      buffer_or_error.getError().message()),
+        llvm::inconvertibleErrorCode());
+  }
+
+  std::unique_ptr<llvm::MemoryBuffer> buffer = std::move(*buffer_or_error);
+  llvm::StringRef contents = buffer->getBuffer();
+
+  if (contents.empty()) {
+    return llvm::make_error<llvm::StringError>("Empty file",
+                                               llvm::inconvertibleErrorCode());
+  }
+
+  return Run(contents);
+}
+
+llvm::Error JavaScript::CheckSyntax(llvm::StringRef code) {
+  v8::Isolate::Scope isolate_scope(m_isolate);
+  v8::HandleScope handle_scope(m_isolate);
+  v8::Local<v8::Context> context = m_context->Get(m_isolate);
+  v8::Context::Scope context_scope(context);
+
+  v8::TryCatch try_catch(m_isolate);
+
+  v8::Local<v8::String> source =
+      v8::String::NewFromUtf8(m_isolate, code.data(),
+                              v8::NewStringType::kNormal, code.size())
+          .ToLocalChecked();
+
+  v8::Local<v8::Script> script;
+  if (!v8::Script::Compile(context, source).ToLocal(&script)) {
+    v8::String::Utf8Value error(m_isolate, try_catch.Exception());
+    return llvm::make_error<llvm::StringError>(
+        llvm::formatv("Syntax error: {0}\n", *error),
+        llvm::inconvertibleErrorCode());
+  }
+
+  return llvm::Error::success();
+}
+
+llvm::Error JavaScript::ChangeIO(FILE *out, FILE *err) {
+  m_stdout = out;
+  m_stderr = err;
+  return llvm::Error::success();
+}
+
+llvm::Error
+JavaScript::RegisterBreakpointCallback(void *baton,
+                                       const char *command_body_text) {
+  v8::Isolate::Scope isolate_scope(m_isolate);
+  v8::HandleScope handle_scope(m_isolate);
+  v8::Local<v8::Context> context = m_context->Get(m_isolate);
+  v8::Context::Scope context_scope(context);
+
+  v8::TryCatch try_catch(m_isolate);
+
+  v8::Local<v8::String> source =
+      v8::String::NewFromUtf8(m_isolate, command_body_text,
+                              v8::NewStringType::kNormal,
+                              strlen(command_body_text))
+          .ToLocalChecked();
+
+  v8::Local<v8::Script> script;
+  if (!v8::Script::Compile(context, source).ToLocal(&script)) {
+    v8::String::Utf8Value error(m_isolate, try_catch.Exception());
+    return llvm::make_error<llvm::StringError>(
+        llvm::formatv("Failed to compile callback: {0}", *error),
+        llvm::inconvertibleErrorCode());
+  }
+
+  v8::Local<v8::Value> result;
+  if (!script->Run(context).ToLocal(&result)) {
+    v8::String::Utf8Value error(m_isolate, try_catch.Exception());
+    return llvm::make_error<llvm::StringError>(
+        llvm::formatv("Failed to evaluate callback: {0}", *error),
+        llvm::inconvertibleErrorCode());
+  }
+
+  if (!result->IsFunction()) {
+    return llvm::make_error<llvm::StringError>(
+        "Breakpoint callback must be a JavaScript function",
+        llvm::inconvertibleErrorCode());
+  }
+
+  // Store the function in our map
+  v8::Local<v8::Function> callback = result.As<v8::Function>();
+  m_breakpoint_callbacks[baton] = v8::Global<v8::Function>(m_isolate, callback);
+
+  return llvm::Error::success();
+}
+
+llvm::Expected<bool>
+JavaScript::CallBreakpointCallback(void *baton,
+                                   lldb::StackFrameSP stop_frame_sp,
+                                   lldb::BreakpointLocationSP bp_loc_sp,
+                                   StructuredData::ObjectSP extra_args_sp) {
+  auto it = m_breakpoint_callbacks.find(baton);
+  if (it == m_breakpoint_callbacks.end()) {
+    return llvm::make_error<llvm::StringError>(
+        "No callback registered for this baton",
+        llvm::inconvertibleErrorCode());
+  }
+
+  v8::Isolate::Scope isolate_scope(m_isolate);
+  v8::HandleScope handle_scope(m_isolate);
+  v8::Local<v8::Context> context = m_context->Get(m_isolate);
+  v8::Context::Scope context_scope(context);
+
+  v8::TryCatch try_catch(m_isolate);
+
+  v8::Local<v8::Function> callback = it->second.Get(m_isolate);
+
+  v8::Local<v8::Value> args[2] = {v8::Null(m_isolate), v8::Null(m_isolate)};
+
+  v8::Local<v8::Value> result;
+  if (!callback->Call(context, context->Global(), 2, args).ToLocal(&result)) {
+    v8::String::Utf8Value error(m_isolate, try_catch.Exception());
+    WriteOutput(
+        llvm::formatv("Breakpoint callback error: {0}\n", *error).str());
+    return false;
+  }
+
+  bool should_stop = false;
+  if (result->IsBoolean()) {
+    should_stop = result->BooleanValue(m_isolate);
+  }
+
+  return should_stop;
+}
+
+llvm::Error
+JavaScript::RegisterWatchpointCallback(void *baton,
+                                       const char *command_body_text) {
+  return llvm::make_error<llvm::StringError>(
+      "Watchpoint callbacks not yet implemented",
+      llvm::inconvertibleErrorCode());
+}
+
+llvm::Expected<bool> JavaScript::CallWatchpointCallback(
+    void *baton, lldb::StackFrameSP stop_frame_sp, lldb::WatchpointSP wp_sp) {
+  return false;
+}
+
+void JavaScript::SetOutputCallback(OutputCallback callback) {
+  m_output_callback = callback;
+}
+
+void JavaScript::WriteOutput(const std::string &text) {
+  if (m_output_callback) {
+    m_output_callback(text);
+  } else if (m_output_file && m_output_file->IsValid()) {
+    m_output_file->Printf("%s", text.c_str());
+    m_output_file->Flush();
+  } else {
+    printf("%s", text.c_str());
+    fflush(stdout);
+  }
+}
+
+void JavaScript::SetDebugger(lldb::DebuggerSP debugger_sp) {
+  m_debugger = debugger_sp;
+
+  if (!debugger_sp)
+    return;
+
+  v8::Isolate::Scope isolate_scope(m_isolate);
+  v8::HandleScope handle_scope(m_isolate);
+  v8::Local<v8::Context> context = m_context->Get(m_isolate);
+  v8::Context::Scope context_scope(context);
+
+  v8::Local<v8::Value> lldb_val;
+  if (!context->Global()
+           ->Get(context,
+                 v8::String::NewFromUtf8(m_isolate, "lldb").ToLocalChecked())
+           .ToLocal(&lldb_val) ||
+      !lldb_val->IsObject())
+    return;
+
+  v8::Local<v8::Object> lldb_obj = lldb_val.As<v8::Object>();
+
+  std::string js_code = llvm::formatv("lldb.SBDebugger.FindDebuggerWithID({0})",
+                                      debugger_sp->GetID())
+                            .str();
+
+  v8::TryCatch try_catch(m_isolate);
+  v8::Local<v8::String> source =
+      v8::String::NewFromUtf8(m_isolate, js_code.c_str(),
+                              v8::NewStringType::kNormal, js_code.length())
+          .ToLocalChecked();
+
+  v8::Local<v8::Script> script;
+  if (!v8::Script::Compile(context, source).ToLocal(&script)) {
+    lldb_obj
+        ->Set(context,
+              v8::String::NewFromUtf8(m_isolate, "debugger").ToLocalChecked(),
+              v8::Null(m_isolate))
+        .Check();
+    return;
+  }
+
+  v8::Local<v8::Value> debugger_obj;
+  if (!script->Run(context).ToLocal(&debugger_obj)) {
+    lldb_obj
+        ->Set(context,
+              v8::String::NewFromUtf8(m_isolate, "debugger").ToLocalChecked(),
+              v8::Null(m_isolate))
+        .Check();
+    return;
+  }
+
+  lldb_obj
+      ->Set(context,
+            v8::String::NewFromUtf8(m_isolate, "debugger").ToLocalChecked(),
+            debugger_obj)
+      .Check();
+}
diff --git a/lldb/source/Plugins/ScriptInterpreter/JavaScript/JavaScript.h b/lldb/source/Plugins/ScriptInterpreter/JavaScript/JavaScript.h
new file mode 100644
index 0000000000000..ed13034e33969
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/JavaScript/JavaScript.h
@@ -0,0 +1,107 @@
+//===-- JavaScript.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 LLVM_LLDB_SOURCE_PLUGINS_SCRIPTINTERPRETER_JAVASCRIPT_JAVASCRIPT_H
+#define LLVM_LLDB_SOURCE_PLUGINS_SCRIPTINTERPRETER_JAVASCRIPT_JAVASCRIPT_H
+
+#include "lldb/Utility/StructuredData.h"
+#include "lldb/lldb-forward.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+#include <functional>
+#include <memory>
+
+// Forward declare V8 types to avoid including V8 headers here
+namespace v8 {
+class Isolate;
+template <class T> class Global;
+class Context;
+class Platform;
+class Function;
+} // namespace v8
+
+namespace lldb_private {
+
+class JavaScript {
+public:
+  JavaScript(lldb::FileSP output_file = nullptr);
+  ~JavaScript();
+
+  // Execute JavaScript code
+  llvm::Error Run(llvm::StringRef code);
+
+  // Set callback for output (used by console.log)
+  using OutputCallback = std::function<void(const std::string &)>;
+  void SetOutputCallback(OutputCallback callback);
+
+  // Load and execute a JavaScript module
+  llvm::Error LoadModule(llvm::StringRef filename);
+
+  // Check syntax without executing
+  llvm::Error CheckSyntax(llvm::StringRef code);
+
+  // Change IO streams
+  llvm::Error ChangeIO(FILE *out, FILE *err);
+
+  // Breakpoint callback support
+  llvm::Error RegisterBreakpointCallback(void *baton,
+                                         const char *command_body_text);
+
+  llvm::Expected<bool>
+  CallBreakpointCallback(void *baton, lldb::StackFrameSP stop_frame_sp,
+                         lldb::BreakpointLocationSP bp_loc_sp,
+                         StructuredData::ObjectSP extra_args_sp);
+
+  // Watchpoint callback support
+  llvm::Error RegisterWatchpointCallback(void *baton,
+                                         const char *command_body_text);
+
+  llvm::Expected<bool> CallWatchpointCallback(void *baton,
+                                              lldb::StackFrameSP stop_frame_sp,
+                                              lldb::WatchpointSP wp_sp);
+
+  // Get the V8 isolate (for advanced usage)
+  v8::Isolate *GetIsolate() { return m_isolate; }
+
+  // Get the output file (for console.log implementation)
+  lldb::FileSP GetOutputFile() { return m_output_file; }
+
+  // Set the output file (for routing console.log to the correct stream)
+  void SetOutputFile(lldb::FileSP output_file) { m_output_file = output_file; }
+
+  // Write output (used by console.log)
+  void WriteOutput(const std::string &text);
+
+  // Set the debugger instance (exposes lldb.debugger to scripts)
+  void SetDebugger(lldb::DebuggerSP debugger_sp);
+
+private:
+  static std::unique_ptr<v8::Platform> s_platform;
+  static bool s_platform_initialized;
+
+  v8::Isolate *m_isolate;
+  v8::Global<v8::Context> *m_context;
+
+  FILE *m_stdout;
+  FILE *m_stderr;
+  lldb::FileSP m_output_file;
+  OutputCallback m_output_callback;
+
+  // Map from baton pointer to JavaScript callback function
+  std::map<void *, v8::Global<v8::Function>> m_breakpoint_callbacks;
+  std::map<void *, v8::Global<v8::Function>> m_watchpoint_callbacks;
+
+  lldb::DebuggerSP m_debugger;
+
+  // Initialize V8 platform (called once)
+  static void InitializePlatform();
+};
+
+} // namespace lldb_private
+
+#endif // LLVM_LLDB_SOURCE_PLUGINS_SCRIPTINTERPRETER_JAVASCRIPT_JAVASCRIPT_H
diff --git a/lldb/source/Plugins/ScriptInterpreter/JavaScript/SWIGJavaScriptBridge.h b/lldb/source/Plugins/ScriptInterpreter/JavaScript/SWIGJavaScriptBridge.h
new file mode 100644
index 0000000000000..8e2a8579a70b5
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/JavaScript/SWIGJavaScriptBridge.h
@@ -0,0 +1,51 @@
+//===-- SWIGJavaScriptBridge.h --------------------------------------------===//
+//
+// 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 LLVM_LLDB_SOURCE_PLUGINS_SCRIPTINTERPRETER_JAVASCRIPT_SWIGJAVASCRIPTBRIDGE_H
+#define LLVM_LLDB_SOURCE_PLUGINS_SCRIPTINTERPRETER_JAVASCRIPT_SWIGJAVASCRIPTBRIDGE_H
+
+#include "lldb/lldb-forward.h"
+#include "llvm/Support/Error.h"
+
+namespace lldb_private {
+class StructuredDataImpl;
+} // namespace lldb_private
+
+namespace v8 {
+class Isolate;
+} // namespace v8
+
+// This will be implemented by SWIG-generated code
+extern "C" {
+void init_lldb(v8::Isolate *isolate);
+}
+
+namespace javascript {
+
+// Bridge functions for calling LLDB from JavaScript
+// These will be generated/implemented by SWIG
+namespace SWIGBridge {
+
+// TODO: Implement bridge functions
+// These are similar to LuaBridge functions but for JavaScript/V8
+
+llvm::Expected<bool> LLDBSwigJavaScriptBreakpointCallbackFunction(
+    v8::Isolate *isolate, lldb::StackFrameSP stop_frame_sp,
+    lldb::BreakpointLocationSP bp_loc_sp,
+    const lldb_private::StructuredDataImpl &extra_args_impl);
+
+llvm::Expected<bool>
+LLDBSwigJavaScriptWatchpointCallbackFunction(v8::Isolate *isolate,
+                                             lldb::StackFrameSP stop_frame_sp,
+                                             lldb::WatchpointSP wp_sp);
+
+} // namespace SWIGBridge
+
+} // namespace javascript
+
+#endif // LLVM_LLDB_SOURCE_PLUGINS_SCRIPTINTERPRETER_JAVASCRIPT_SWIGJAVASCRIPTBRIDGE_H
diff --git a/lldb/source/Plugins/ScriptInterpreter/JavaScript/ScriptInterpreterJavaScript.cpp b/lldb/source/Plugins/ScriptInterpreter/JavaScript/ScriptInterpreterJavaScript.cpp
new file mode 100644
index 0000000000000..78f9d9faa502f
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/JavaScript/ScriptInterpreterJavaScript.cpp
@@ -0,0 +1,278 @@
+//===-- ScriptInterpreterJavaScript.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 "ScriptInterpreterJavaScript.h"
+#include "JavaScript.h"
+
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/IOHandler.h"
+#include "lldb/Core/PluginManager.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/Support/FormatVariadic.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+LLDB_PLUGIN_DEFINE(ScriptInterpreterJavaScript)
+
+// IOHandler for JavaScript REPL
+class IOHandlerJavaScriptInterpreter : public IOHandlerDelegate,
+                                       public IOHandlerEditline {
+public:
+  IOHandlerJavaScriptInterpreter(
+      Debugger &debugger, ScriptInterpreterJavaScript &script_interpreter)
+      : IOHandlerEditline(debugger, IOHandler::Type::Other, "javascript",
+                          "> ",              // Prompt
+                          llvm::StringRef(), // No continuation prompt
+                          false,             // Single-line for now
+                          debugger.GetUseColor(), 0, *this),
+        m_script_interpreter(script_interpreter) {
+    llvm::cantFail(m_script_interpreter.EnterSession(debugger.GetID()));
+  }
+
+  ~IOHandlerJavaScriptInterpreter() override {
+    llvm::cantFail(m_script_interpreter.LeaveSession());
+  }
+
+  void IOHandlerInputComplete(IOHandler &io_handler,
+                              std::string &data) override {
+    if (data == "quit" || data == "exit") {
+      io_handler.SetIsDone(true);
+      return;
+    }
+
+    // Execute the JavaScript code
+    llvm::Error error = m_script_interpreter.GetJavaScript().Run(data);
+
+    if (error) {
+      // Print error
+      if (LockableStreamFileSP error_sp = io_handler.GetErrorStreamFileSP()) {
+        LockedStreamFile locked_stream = error_sp->Lock();
+        locked_stream << "error: " << llvm::toString(std::move(error)) << "\n";
+      }
+    }
+  }
+
+private:
+  ScriptInterpreterJavaScript &m_script_interpreter;
+};
+
+ScriptInterpreterJavaScript::ScriptInterpreterJavaScript(Debugger &debugger)
+    : ScriptInterpreter(debugger, eScriptLanguageJavaScript),
+      m_javascript(std::make_unique<JavaScript>(debugger.GetOutputFileSP())) {}
+
+ScriptInterpreterJavaScript::~ScriptInterpreterJavaScript() = default;
+
+bool ScriptInterpreterJavaScript::ExecuteOneLine(
+    llvm::StringRef command, CommandReturnObject *result,
+    const ExecuteScriptOptions &options) {
+  if (command.empty()) {
+    if (result)
+      result->AppendError("Empty command string\n");
+    return false;
+  }
+
+  // Set output callback to write console.log output to the result stream
+  if (result) {
+    m_javascript->SetOutputCallback([result](const std::string &text) {
+      result->GetOutputStream().Printf("%s", text.c_str());
+    });
+  }
+
+  llvm::Error error = m_javascript->Run(command);
+
+  // Clear the callback after execution
+  m_javascript->SetOutputCallback(nullptr);
+
+  if (error) {
+    if (result)
+      result->AppendError(llvm::toString(std::move(error)));
+    return false;
+  }
+
+  if (result)
+    result->SetStatus(eReturnStatusSuccessFinishResult);
+  return true;
+}
+
+void ScriptInterpreterJavaScript::ExecuteInterpreterLoop() {
+  LLDB_SCOPED_TIMER();
+
+  if (!m_debugger.GetInputFile().IsValid())
+    return;
+
+  IOHandlerSP io_handler_sp(
+      new IOHandlerJavaScriptInterpreter(m_debugger, *this));
+  m_debugger.RunIOHandlerAsync(io_handler_sp);
+}
+
+bool ScriptInterpreterJavaScript::LoadScriptingModule(
+    const char *filename, const LoadScriptOptions &options,
+    lldb_private::Status &error, StructuredData::ObjectSP *module_sp,
+    FileSpec extra_search_dir, lldb::TargetSP loaded_into_target_sp) {
+
+  if (!filename || filename[0] == '\0') {
+    error = Status::FromErrorString("Empty filename");
+    return false;
+  }
+
+  llvm::Error session_error = EnterSession(m_debugger.GetID());
+  if (session_error) {
+    error = Status::FromErrorString(
+        llvm::toString(std::move(session_error)).c_str());
+    return false;
+  }
+
+  llvm::Error load_error = m_javascript->LoadModule(filename);
+  if (load_error) {
+    error =
+        Status::FromErrorString(llvm::toString(std::move(load_error)).c_str());
+    return false;
+  }
+
+  return true;
+}
+
+StructuredData::DictionarySP ScriptInterpreterJavaScript::GetInterpreterInfo() {
+  auto info_dict = std::make_shared<StructuredData::Dictionary>();
+  info_dict->AddStringItem("language", "javascript");
+  info_dict->AddStringItem("version", "ES2020+ (V8)");
+  return info_dict;
+}
+
+void ScriptInterpreterJavaScript::Initialize() {
+  static llvm::once_flag g_once_flag;
+  llvm::call_once(g_once_flag, []() {
+    PluginManager::RegisterPlugin(
+        GetPluginNameStatic(), GetPluginDescriptionStatic(),
+        lldb::eScriptLanguageJavaScript, CreateInstance);
+  });
+}
+
+void ScriptInterpreterJavaScript::Terminate() {
+  PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+lldb::ScriptInterpreterSP
+ScriptInterpreterJavaScript::CreateInstance(Debugger &debugger) {
+  return std::make_shared<ScriptInterpreterJavaScript>(debugger);
+}
+
+llvm::StringRef ScriptInterpreterJavaScript::GetPluginDescriptionStatic() {
+  return "JavaScript script interpreter";
+}
+
+JavaScript &ScriptInterpreterJavaScript::GetJavaScript() {
+  return *m_javascript;
+}
+
+llvm::Error
+ScriptInterpreterJavaScript::EnterSession(lldb::user_id_t debugger_id) {
+  if (m_session_is_active)
+    return llvm::Error::success();
+
+  m_javascript->SetDebugger(m_debugger.shared_from_this());
+  m_session_is_active = true;
+  return llvm::Error::success();
+}
+
+llvm::Error ScriptInterpreterJavaScript::LeaveSession() {
+  if (!m_session_is_active)
+    return llvm::Error::success();
+
+  m_session_is_active = false;
+  return llvm::Error::success();
+}
+
+void ScriptInterpreterJavaScript::CollectDataForBreakpointCommandCallback(
+    std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
+    CommandReturnObject &result) {
+  result.AppendError("Breakpoint callbacks not yet implemented for JavaScript");
+}
+
+void ScriptInterpreterJavaScript::CollectDataForWatchpointCommandCallback(
+    WatchpointOptions *wp_options, CommandReturnObject &result) {
+  result.AppendError("Watchpoint callbacks not yet implemented for JavaScript");
+}
+
+Status ScriptInterpreterJavaScript::SetBreakpointCommandCallback(
+    BreakpointOptions &bp_options, const char *command_body_text,
+    bool is_callback) {
+  return Status::FromErrorString(
+      "Breakpoint callbacks not yet implemented for JavaScript");
+}
+
+void ScriptInterpreterJavaScript::SetWatchpointCommandCallback(
+    WatchpointOptions *wp_options, const char *command_body_text,
+    bool is_callback) {
+  // TODO: Implement
+}
+
+Status ScriptInterpreterJavaScript::SetBreakpointCommandCallbackFunction(
+    BreakpointOptions &bp_options, const char *function_name,
+    StructuredData::ObjectSP extra_args_sp) {
+  const char *fmt_str = "({0})";
+  std::string oneliner = llvm::formatv(fmt_str, function_name).str();
+
+  auto data_up = std::make_unique<CommandDataJavaScript>(extra_args_sp);
+
+  llvm::Error err =
+      m_javascript->RegisterBreakpointCallback(data_up.get(), oneliner.c_str());
+  if (err)
+    return Status::FromError(std::move(err));
+
+  auto baton_sp =
+      std::make_shared<BreakpointOptions::CommandBaton>(std::move(data_up));
+  bp_options.SetCallback(
+      ScriptInterpreterJavaScript::BreakpointCallbackFunction, baton_sp);
+
+  return Status();
+}
+
+bool ScriptInterpreterJavaScript::BreakpointCallbackFunction(
+    void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id,
+    lldb::user_id_t break_loc_id) {
+
+  ExecutionContext exe_ctx(context->exe_ctx_ref);
+  Target *target = exe_ctx.GetTargetPtr();
+  if (!target)
+    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();
+  ScriptInterpreterJavaScript *js_interpreter =
+      static_cast<ScriptInterpreterJavaScript *>(
+          debugger.GetScriptInterpreter(true, eScriptLanguageJavaScript));
+  JavaScript &js = js_interpreter->GetJavaScript();
+
+  CommandDataJavaScript *bp_option_data =
+      static_cast<CommandDataJavaScript *>(baton);
+  llvm::Expected<bool> BoolOrErr =
+      js.CallBreakpointCallback(baton, stop_frame_sp, bp_loc_sp,
+                                bp_option_data->m_extra_args.GetObjectSP());
+  if (llvm::Error E = BoolOrErr.takeError()) {
+    llvm::consumeError(std::move(E));
+    return true;
+  }
+
+  return *BoolOrErr;
+}
+
+bool ScriptInterpreterJavaScript::WatchpointCallbackFunction(
+    void * /*baton*/, StoppointCallbackContext * /*context*/,
+    lldb::user_id_t /*watch_id*/) {
+  return false;
+}
diff --git a/lldb/source/Plugins/ScriptInterpreter/JavaScript/ScriptInterpreterJavaScript.h b/lldb/source/Plugins/ScriptInterpreter/JavaScript/ScriptInterpreterJavaScript.h
new file mode 100644
index 0000000000000..40555d6c0fdca
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/JavaScript/ScriptInterpreterJavaScript.h
@@ -0,0 +1,121 @@
+//===-- ScriptInterpreterJavaScript.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 LLVM_LLDB_SOURCE_PLUGINS_SCRIPTINTERPRETER_JAVASCRIPT_SCRIPTINTERPRETERJAVASCRIPT_H
+#define LLVM_LLDB_SOURCE_PLUGINS_SCRIPTINTERPRETER_JAVASCRIPT_SCRIPTINTERPRETERJAVASCRIPT_H
+
+#include <memory>
+#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 v8 {
+class Isolate;
+template <class T> class Global;
+class Context;
+class Platform;
+} // namespace v8
+
+namespace lldb_private {
+
+class JavaScript;
+
+class ScriptInterpreterJavaScript : public ScriptInterpreter {
+public:
+  class CommandDataJavaScript : public BreakpointOptions::CommandData {
+  public:
+    CommandDataJavaScript() : BreakpointOptions::CommandData() {
+      interpreter = lldb::eScriptLanguageJavaScript;
+    }
+    CommandDataJavaScript(StructuredData::ObjectSP extra_args_sp)
+        : BreakpointOptions::CommandData(),
+          m_extra_args(std::move(extra_args_sp)) {
+      interpreter = lldb::eScriptLanguageJavaScript;
+    }
+    StructuredDataImpl m_extra_args;
+  };
+
+  ScriptInterpreterJavaScript(Debugger &debugger);
+
+  ~ScriptInterpreterJavaScript() 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 = {},
+                           lldb::TargetSP loaded_into_target_sp = {}) override;
+
+  StructuredData::DictionarySP GetInterpreterInfo() override;
+
+  // Static Functions
+  static void Initialize();
+
+  static void Terminate();
+
+  static lldb::ScriptInterpreterSP CreateInstance(Debugger &debugger);
+
+  static llvm::StringRef GetPluginNameStatic() { return "script-javascript"; }
+
+  static llvm::StringRef 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(); }
+
+  JavaScript &GetJavaScript();
+
+  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,
+                                      bool is_callback) override;
+
+  void SetWatchpointCommandCallback(WatchpointOptions *wp_options,
+                                    const char *command_body_text,
+                                    bool is_callback) override;
+
+  Status SetBreakpointCommandCallbackFunction(
+      BreakpointOptions &bp_options, const char *function_name,
+      StructuredData::ObjectSP extra_args_sp) override;
+
+private:
+  std::unique_ptr<JavaScript> m_javascript;
+  bool m_session_is_active = false;
+};
+
+} // namespace lldb_private
+
+#endif // LLVM_LLDB_SOURCE_PLUGINS_SCRIPTINTERPRETER_JAVASCRIPT_SCRIPTINTERPRETERJAVASCRIPT_H



More information about the lldb-commits mailing list