Desc<"When specified, debug the JIT code by setting a breakpoint on the "
"first instruction and forcing breakpoints to not be ignored (-i0) and no "
"unwinding to happen on error (-u0).">;
- def expression_options_language : Option<"language", "l">, Groups<[1,2]>,
+ def expression_options_language : Option<"language", "l">, Groups<[1,2,3]>,
Arg<"Language">, Desc<"Specifies the Language to use when parsing the "
"expression. If not set the target.language setting is used.">;
def expression_options_apply_fixits : Option<"apply-fixits", "X">,
add_subdirectory(OperatingSystem)
add_subdirectory(Platform)
add_subdirectory(Process)
+add_subdirectory(REPL)
add_subdirectory(ScriptInterpreter)
add_subdirectory(StructuredData)
add_subdirectory(SymbolFile)
--- /dev/null
+add_subdirectory(Clang)
--- /dev/null
+add_lldb_library(lldbPluginClangREPL PLUGIN
+ ClangREPL.cpp
+
+ LINK_LIBS
+ lldbCore
+ lldbDataFormatters
+ lldbHost
+ lldbSymbol
+ lldbTarget
+ lldbUtility
+ lldbPluginClangCommon
+ lldbPluginCPPRuntime
+ lldbPluginTypeSystemClang
+
+ LINK_COMPONENTS
+ Support
+)
--- /dev/null
+//===-- ClangREPL.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 "ClangREPL.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Expression/ExpressionVariable.h"
+
+using namespace lldb_private;
+
+LLDB_PLUGIN_DEFINE(ClangREPL)
+
+ClangREPL::ClangREPL(lldb::LanguageType language, Target &target)
+ : REPL(eKindClang, target), m_language(language),
+ m_implicit_expr_result_regex("\\$[0-9]+") {}
+
+ClangREPL::~ClangREPL() {}
+
+void ClangREPL::Initialize() {
+ LanguageSet languages;
+ // FIXME: There isn't a way to ask CPlusPlusLanguage and ObjCLanguage for
+ // a list of languages they support.
+ languages.Insert(lldb::LanguageType::eLanguageTypeC);
+ languages.Insert(lldb::LanguageType::eLanguageTypeC89);
+ languages.Insert(lldb::LanguageType::eLanguageTypeC99);
+ languages.Insert(lldb::LanguageType::eLanguageTypeC11);
+ languages.Insert(lldb::LanguageType::eLanguageTypeC_plus_plus);
+ languages.Insert(lldb::LanguageType::eLanguageTypeC_plus_plus_03);
+ languages.Insert(lldb::LanguageType::eLanguageTypeC_plus_plus_11);
+ languages.Insert(lldb::LanguageType::eLanguageTypeC_plus_plus_14);
+ languages.Insert(lldb::LanguageType::eLanguageTypeObjC);
+ languages.Insert(lldb::LanguageType::eLanguageTypeObjC_plus_plus);
+ PluginManager::RegisterPlugin(GetPluginNameStatic(), "C language REPL",
+ &CreateInstance, languages);
+}
+
+void ClangREPL::Terminate() {
+ PluginManager::UnregisterPlugin(&CreateInstance);
+}
+
+lldb::REPLSP ClangREPL::CreateInstance(Status &error,
+ lldb::LanguageType language,
+ Debugger *debugger, Target *target,
+ const char *repl_options) {
+ // Creating a dummy target if only a debugger is given isn't implemented yet.
+ if (!target) {
+ error.SetErrorString("must have a target to create a REPL");
+ return nullptr;
+ }
+ lldb::REPLSP result = std::make_shared<ClangREPL>(language, *target);
+ target->SetREPL(language, result);
+ error = Status();
+ return result;
+}
+
+Status ClangREPL::DoInitialization() { return Status(); }
+
+ConstString ClangREPL::GetSourceFileBasename() {
+ return ConstString("repl.c");
+}
+
+const char *ClangREPL::GetAutoIndentCharacters() { return " "; }
+
+bool ClangREPL::SourceIsComplete(const std::string &source) {
+ // FIXME: There isn't a good way to know if the input source is complete or
+ // not, so just say that every single REPL line is ready to be parsed.
+ return !source.empty();
+}
+
+lldb::offset_t ClangREPL::GetDesiredIndentation(const StringList &lines,
+ int cursor_position,
+ int tab_size) {
+ // FIXME: Not implemented.
+ return LLDB_INVALID_OFFSET;
+}
+
+lldb::LanguageType ClangREPL::GetLanguage() { return m_language; }
+
+bool ClangREPL::PrintOneVariable(Debugger &debugger,
+ lldb::StreamFileSP &output_sp,
+ lldb::ValueObjectSP &valobj_sp,
+ ExpressionVariable *var) {
+ // If a ExpressionVariable was passed, check first if that variable is just
+ // an automatically created expression result. These variables are already
+ // printed by the REPL so this is done to prevent printing the variable twice.
+ if (var) {
+ if (m_implicit_expr_result_regex.Execute(var->GetName().GetStringRef()))
+ return true;
+ }
+ valobj_sp->Dump(*output_sp);
+ return true;
+}
+
+void ClangREPL::CompleteCode(const std::string ¤t_code,
+ CompletionRequest &request) {
+ // Not implemented.
+}
--- /dev/null
+//===-- ClangREPL.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 LLDB_SOURCE_PLUGINS_REPL_CLANG_CLANGREPL_H
+#define LLDB_SOURCE_PLUGINS_REPL_CLANG_CLANGREPL_H
+
+#include "lldb/Expression/REPL.h"
+
+namespace lldb_private {
+/// Implements a Clang-based REPL for C languages on top of LLDB's REPL
+/// framework.
+class ClangREPL : public REPL {
+public:
+ ClangREPL(lldb::LanguageType language, Target &target);
+
+ ~ClangREPL() override;
+
+ static void Initialize();
+
+ static void Terminate();
+
+ static lldb::REPLSP CreateInstance(Status &error, lldb::LanguageType language,
+ Debugger *debugger, Target *target,
+ const char *repl_options);
+
+ static lldb_private::ConstString GetPluginNameStatic() {
+ return ConstString("ClangREPL");
+ }
+
+protected:
+ Status DoInitialization() override;
+
+ ConstString GetSourceFileBasename() override;
+
+ const char *GetAutoIndentCharacters() override;
+
+ bool SourceIsComplete(const std::string &source) override;
+
+ lldb::offset_t GetDesiredIndentation(const StringList &lines,
+ int cursor_position,
+ int tab_size) override;
+
+ lldb::LanguageType GetLanguage() override;
+
+ bool PrintOneVariable(Debugger &debugger, lldb::StreamFileSP &output_sp,
+ lldb::ValueObjectSP &valobj_sp,
+ ExpressionVariable *var = nullptr) override;
+
+ void CompleteCode(const std::string ¤t_code,
+ CompletionRequest &request) override;
+
+private:
+ /// The specific C language of this REPL.
+ lldb::LanguageType m_language;
+ /// A regex matching the implicitly created LLDB result variables.
+ lldb_private::RegularExpression m_implicit_expr_result_regex;
+};
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_REPL_CLANG_CLANGREPL_H
--- /dev/null
+C_SOURCES := main.c
+include Makefile.rules
--- /dev/null
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.lldbpexpect import PExpectTest
+
+class TestCase(PExpectTest):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ def expect_repl(self, expr, substrs=[]):
+ """ Evaluates the expression in the REPL and verifies that the list
+ of substrs is in the REPL output."""
+ # Only single line expressions supported.
+ self.assertNotIn("\n", expr)
+ self.child.send(expr + "\n")
+ for substr in substrs:
+ self.child.expect_exact(substr)
+ # Look for the start of the next REPL input line.
+ self.current_repl_line_number += 1
+ self.child.expect_exact(str(self.current_repl_line_number) + ">")
+
+ # PExpect uses many timeouts internally and doesn't play well
+ # under ASAN on a loaded machine..
+ @skipIfAsan
+ @skipIfEditlineSupportMissing
+ def test_basic_completion(self):
+ """Test that we can complete a simple multiline expression"""
+ self.build()
+ self.current_repl_line_number = 1
+
+ self.launch(executable=self.getBuildArtifact("a.out"), dimensions=(100,500))
+ # Try launching the REPL before we have a running target.
+ self.expect("expression --repl -l c --", substrs=["REPL requires a running target process."])
+
+ self.expect("b main", substrs=["Breakpoint 1", "address ="])
+ self.expect("run", substrs=["stop reason = breakpoint 1"])
+
+ # Start the REPL.
+ self.child.send("expression --repl -l c --\n")
+ self.child.expect_exact("1>")
+
+ # Try evaluating a simple expression.
+ self.expect_repl("3 + 3", substrs=["(int) $0 = 6"])
+
+ # Try declaring a persistent variable.
+ self.expect_repl("long $persistent = 7; 5",
+ substrs=["(int) $1 = 5",
+ "(long) $persistent = 7"])
+
+ # Try using the persistent variable from before.
+ self.expect_repl("$persistent + 10",
+ substrs=["(long) $2 = 17"])
+
+ self.quit()
--- /dev/null
+int main(int argc, char **argv) {
+ return 0;
+}