[Lldb-commits] [lldb] [lldb/Interpreter] Propagate `script` output back to command return object (PR #109440)
Med Ismail Bennani via lldb-commits
lldb-commits at lists.llvm.org
Fri Sep 20 09:11:52 PDT 2024
https://github.com/medismailben created https://github.com/llvm/llvm-project/pull/109440
When running a oneliner script expression, if the script interpreter returned a value, that value would be printed to the debugger standard output straight from the interpreter instead of being propagated back to the command return object, which would then forward it to its output stream.
This implies that when evaluating a oneliner script expression (with `SBCommandInterpreter::HandleCommand`), the return value would get printed to stdout, but we would not be able to fetch it from the command return object.
This patch solves this issue by extending the default Python `InteractiveConsole` class to keep track of the return value, before include it to the command return object.
rdar://132420488
>From 77d1924a105ef60bf2328f7f67302b9d8f026c7a Mon Sep 17 00:00:00 2001
From: Med Ismail Bennani <ismail at bennani.ma>
Date: Mon, 19 Aug 2024 21:11:18 -0700
Subject: [PATCH] [lldb/Interpreter] Propagate `script` output back to command
return object
When running a oneliner script expression, if the script interpreter
returned a value, that value would be printed to the debugger standard
output straight from the interpreter instead of being propagated back to
the command return object, which would then forward it to its output stream.
This implies that when evaluating a oneliner script expression (with
`SBCommandInterpreter::HandleCommand`), the return value would get
printed to stdout, but we would not be able to fetch it from the command
return object.
This patch solves this issue by extending the default Python
`InteractiveConsole` class to keep track of the return value, before
include it to the command return object.
rdar://132420488
Signed-off-by: Med Ismail Bennani <ismail at bennani.ma>
---
.../Interpreter/embedded_interpreter.py | 39 +++++++++++++++++--
.../Python/ScriptInterpreterPython.cpp | 7 +++-
2 files changed, 41 insertions(+), 5 deletions(-)
diff --git a/lldb/source/Interpreter/embedded_interpreter.py b/lldb/source/Interpreter/embedded_interpreter.py
index a487592ef1aee5..fd5c44d0121fbd 100644
--- a/lldb/source/Interpreter/embedded_interpreter.py
+++ b/lldb/source/Interpreter/embedded_interpreter.py
@@ -8,6 +8,8 @@
import lldb
import traceback
+from io import StringIO
+
try:
import readline
import rlcompleter
@@ -116,19 +118,50 @@ def run_python_interpreter(local_dict):
print("Script exited with code %s" % e.code)
+class LLDBInteractiveConsole(code.InteractiveConsole):
+ def __init__(self, locals=None):
+ super().__init__(locals)
+ self.result_output = None
+
+ ### Implementation detail:
+ ### https://docs.python.org/3/library/code.html#code.InteractiveInterpreter.runsource
+ def runsource(self, source, filename="<input>", symbol="single"):
+ # Redirect stdout to capture print statements
+ old_stdout = sys.stdout
+ sys.stdout = result_output = StringIO()
+
+ try:
+ compiled_code = self.compile(source, filename, symbol)
+ if compiled_code is None:
+ return False
+
+ exec(compiled_code, self.locals)
+ return True
+ except Exception as e:
+ self.showsyntaxerror(filename)
+ return False
+ finally:
+ self.result_output = result_output
+ sys.stdout = old_stdout
+
+ def get_last_result(self):
+ return self.result_output.getvalue()
+
def run_one_line(local_dict, input_string):
global g_run_one_line_str
try:
input_string = strip_and_check_exit(input_string)
- repl = code.InteractiveConsole(local_dict)
+ repl = LLDBInteractiveConsole(local_dict)
if input_string:
# A newline is appended to support one-line statements containing
# control flow. For example "if True: print(1)" silently does
# nothing, but works with a newline: "if True: print(1)\n".
input_string += "\n"
- repl.runsource(input_string)
+ if repl.runsource(input_string):
+ return repl.get_last_result()
elif g_run_one_line_str:
- repl.runsource(g_run_one_line_str)
+ if repl.runsource(g_run_one_line_str):
+ return repl.get_last_result()
except LLDBExit:
pass
except SystemExit as e:
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
index 63691d24f0dadb..30b67ce48a4be9 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
@@ -884,9 +884,12 @@ bool ScriptInterpreterPythonImpl::ExecuteOneLine(
PyRefType::Owned,
PyObject_CallObject(m_run_one_line_function.get(),
pargs.get()));
- if (return_value.IsValid())
+ if (return_value.IsValid()) {
success = true;
- else if (options.GetMaskoutErrors() && PyErr_Occurred()) {
+ PythonString repr = return_value.Repr();
+ if (repr && repr.GetSize())
+ result->AppendMessage(repr.GetString());
+ } else if (options.GetMaskoutErrors() && PyErr_Occurred()) {
PyErr_Print();
PyErr_Clear();
}
More information about the lldb-commits
mailing list