[Lldb-commits] [lldb] bbef51e - [lldb] make it easier to find LLDB's python
Lawrence D'Anna via lldb-commits
lldb-commits at lists.llvm.org
Wed Nov 10 10:34:02 PST 2021
Author: Lawrence D'Anna
Date: 2021-11-10T10:33:34-08:00
New Revision: bbef51eb43c2e8f8e36fbbc0d0b4cca75b6f0863
URL: https://github.com/llvm/llvm-project/commit/bbef51eb43c2e8f8e36fbbc0d0b4cca75b6f0863
DIFF: https://github.com/llvm/llvm-project/commit/bbef51eb43c2e8f8e36fbbc0d0b4cca75b6f0863.diff
LOG: [lldb] make it easier to find LLDB's python
It is surprisingly difficult to write a simple python script that
can reliably `import lldb` without failing, or crashing. I'm
currently resorting to convolutions like this:
def find_lldb(may_reexec=False):
if prefix := os.environ.get('LLDB_PYTHON_PREFIX'):
if os.path.realpath(prefix) != os.path.realpath(sys.prefix):
raise Exception("cannot import lldb.\n"
f" sys.prefix should be: {prefix}\n"
f" but it is: {sys.prefix}")
else:
line1, line2 = subprocess.run(
['lldb', '-x', '-b', '-o', 'script print(sys.prefix)'],
encoding='utf8', stdout=subprocess.PIPE,
check=True).stdout.strip().splitlines()
assert line1.strip() == '(lldb) script print(sys.prefix)'
prefix = line2.strip()
os.environ['LLDB_PYTHON_PREFIX'] = prefix
if sys.prefix != prefix:
if not may_reexec:
raise Exception(
"cannot import lldb.\n" +
f" This python, at {sys.prefix}\n"
f" does not math LLDB's python at {prefix}")
os.environ['LLDB_PYTHON_PREFIX'] = prefix
python_exe = os.path.join(prefix, 'bin', 'python3')
os.execl(python_exe, python_exe, *sys.argv)
lldb_path = subprocess.run(['lldb', '-P'],
check=True, stdout=subprocess.PIPE,
encoding='utf8').stdout.strip()
sys.path = [lldb_path] + sys.path
This patch aims to replace all that with:
#!/usr/bin/env lldb-python
import lldb
...
... by adding the following features:
* new command line option: --print-script-interpreter-info. This
prints language-specific information about the script interpreter
in JSON format.
* new tool (unix only): lldb-python which finds python and exec's it.
Reviewed By: JDevlieghere
Differential Revision: https://reviews.llvm.org/D112973
Added:
lldb/bindings/python/lldb-python
Modified:
lldb/bindings/interface/SBDebugger.i
lldb/bindings/python/CMakeLists.txt
lldb/docs/man/lldb.rst
lldb/include/lldb/API/SBDebugger.h
lldb/include/lldb/Interpreter/ScriptInterpreter.h
lldb/source/API/SBDebugger.cpp
lldb/source/Interpreter/ScriptInterpreter.cpp
lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp
lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h
lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h
lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
lldb/test/API/functionalities/paths/TestPaths.py
lldb/test/Shell/Driver/TestHelp.test
lldb/tools/driver/Driver.cpp
lldb/tools/driver/Driver.h
lldb/tools/driver/Options.td
Removed:
################################################################################
diff --git a/lldb/bindings/interface/SBDebugger.i b/lldb/bindings/interface/SBDebugger.i
index cf4411980cc30..aae72dd513940 100644
--- a/lldb/bindings/interface/SBDebugger.i
+++ b/lldb/bindings/interface/SBDebugger.i
@@ -479,6 +479,8 @@ public:
lldb::SBTypeSynthetic
GetSyntheticForType (lldb::SBTypeNameSpecifier);
+ SBStructuredData GetScriptInterpreterInfo(ScriptLanguage);
+
STRING_EXTENSION(SBDebugger)
%feature("docstring",
diff --git a/lldb/bindings/python/CMakeLists.txt b/lldb/bindings/python/CMakeLists.txt
index 9422ee00cb5fc..5aabaf574636c 100644
--- a/lldb/bindings/python/CMakeLists.txt
+++ b/lldb/bindings/python/CMakeLists.txt
@@ -23,6 +23,18 @@ add_custom_target(swig_wrapper_python ALL DEPENDS
${CMAKE_CURRENT_BINARY_DIR}/lldb.py
)
+if (NOT WIN32)
+add_custom_command(
+ OUTPUT ${LLVM_RUNTIME_OUTPUT_INTDIR}/lldb-python
+ VERBATIM
+ COMMAND ${CMAKE_COMMAND} -E copy lldb-python ${LLVM_RUNTIME_OUTPUT_INTDIR}/lldb-python
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+)
+add_custom_target(lldb-python-wrapper ALL DEPENDS
+ ${LLVM_RUNTIME_OUTPUT_INTDIR}/lldb-python
+)
+endif()
+
function(create_python_package swig_target working_dir pkg_dir)
cmake_parse_arguments(ARG "NOINIT" "" "FILES" ${ARGN})
if(ARG_FILES)
@@ -149,6 +161,11 @@ function(finish_swig_python swig_target lldb_python_bindings_dir lldb_python_tar
create_relative_symlink(${swig_target} ${LIBLLDB_SYMLINK_DEST}
${lldb_python_target_dir} ${LIBLLDB_SYMLINK_OUTPUT_FILE})
+
+ if (NOT WIN32)
+ add_dependencies(${swig_target} lldb-python-wrapper)
+ endif()
+
if(NOT LLDB_BUILD_FRAMEWORK)
set(LLDB_ARGDUMPER_FILENAME "lldb-argdumper${CMAKE_EXECUTABLE_SUFFIX}")
create_relative_symlink(${swig_target} "${LLVM_RUNTIME_OUTPUT_INTDIR}/${LLDB_ARGDUMPER_FILENAME}"
diff --git a/lldb/bindings/python/lldb-python b/lldb/bindings/python/lldb-python
new file mode 100755
index 0000000000000..3bb3b332d8523
--- /dev/null
+++ b/lldb/bindings/python/lldb-python
@@ -0,0 +1,17 @@
+#!/usr/bin/env python3
+
+import subprocess
+import os
+import sys
+import json
+
+lldb = os.path.join(os.path.dirname(__file__), 'lldb')
+
+info_json = subprocess.run([lldb, "-l", "python", "-print-script-interpreter-info"],
+ check=True, stdout=subprocess.PIPE, encoding='utf8').stdout
+info = json.loads(info_json)
+
+os.environ["PYTHONPATH"] = (
+ info["lldb-pythonpath"] + os.path.pathsep + os.environ.get("PYTHONPATH", ""))
+
+os.execl(info["executable"], info["executable"], *sys.argv[1:])
diff --git a/lldb/docs/man/lldb.rst b/lldb/docs/man/lldb.rst
index 35db1dc68c129..10b143cd0de8f 100644
--- a/lldb/docs/man/lldb.rst
+++ b/lldb/docs/man/lldb.rst
@@ -234,6 +234,10 @@ SCRIPTING
Alias for --script-language
+.. option:: --print-script-interpreter-info
+
+ Prints out a json dictionary with information about the scripting language interpreter.
+
.. option:: --python-path
Prints out the path to the lldb.py file for this version of lldb.
diff --git a/lldb/include/lldb/API/SBDebugger.h b/lldb/include/lldb/API/SBDebugger.h
index ef62141f579d6..64081f79205d6 100644
--- a/lldb/include/lldb/API/SBDebugger.h
+++ b/lldb/include/lldb/API/SBDebugger.h
@@ -247,6 +247,8 @@ class LLDB_API SBDebugger {
lldb::ScriptLanguage GetScriptingLanguage(const char *script_language_name);
+ SBStructuredData GetScriptInterpreterInfo(ScriptLanguage);
+
static const char *GetVersionString();
static const char *StateAsCString(lldb::StateType state);
diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreter.h b/lldb/include/lldb/Interpreter/ScriptInterpreter.h
index 56cfb5cb8dd54..2b96021fffc99 100644
--- a/lldb/include/lldb/Interpreter/ScriptInterpreter.h
+++ b/lldb/include/lldb/Interpreter/ScriptInterpreter.h
@@ -148,6 +148,8 @@ class ScriptInterpreter : public PluginInterface {
lldb::ScriptedProcessInterfaceUP scripted_process_interface_up =
std::make_unique<ScriptedProcessInterface>());
+ virtual StructuredData::DictionarySP GetInterpreterInfo();
+
~ScriptInterpreter() override = default;
virtual bool Interrupt() { return false; }
diff --git a/lldb/source/API/SBDebugger.cpp b/lldb/source/API/SBDebugger.cpp
index c22662d764a7f..4bb23c3e705c6 100644
--- a/lldb/source/API/SBDebugger.cpp
+++ b/lldb/source/API/SBDebugger.cpp
@@ -680,6 +680,21 @@ SBDebugger::GetScriptingLanguage(const char *script_language_name) {
llvm::StringRef(script_language_name), eScriptLanguageDefault, nullptr);
}
+SBStructuredData
+SBDebugger::GetScriptInterpreterInfo(lldb::ScriptLanguage language) {
+ LLDB_RECORD_METHOD(SBStructuredData, SBDebugger, GetScriptInterpreterInfo,
+ (lldb::ScriptLanguage), language);
+ SBStructuredData data;
+ if (m_opaque_sp) {
+ lldb_private::ScriptInterpreter *interp =
+ m_opaque_sp->GetScriptInterpreter(language);
+ if (interp) {
+ data.m_impl_up->SetObjectSP(interp->GetInterpreterInfo());
+ }
+ }
+ return LLDB_RECORD_RESULT(data);
+}
+
const char *SBDebugger::GetVersionString() {
LLDB_RECORD_STATIC_METHOD_NO_ARGS(const char *, SBDebugger, GetVersionString);
@@ -1783,6 +1798,8 @@ template <> void RegisterMethods<SBDebugger>(Registry &R) {
(const char *));
LLDB_REGISTER_METHOD(lldb::ScriptLanguage, SBDebugger, GetScriptingLanguage,
(const char *));
+ LLDB_REGISTER_METHOD(SBStructuredData, SBDebugger, GetScriptInterpreterInfo,
+ (lldb::ScriptLanguage));
LLDB_REGISTER_STATIC_METHOD(const char *, SBDebugger, GetVersionString, ());
LLDB_REGISTER_STATIC_METHOD(const char *, SBDebugger, StateAsCString,
(lldb::StateType));
diff --git a/lldb/source/Interpreter/ScriptInterpreter.cpp b/lldb/source/Interpreter/ScriptInterpreter.cpp
index 53e57ad59893d..fbdcbb8da8685 100644
--- a/lldb/source/Interpreter/ScriptInterpreter.cpp
+++ b/lldb/source/Interpreter/ScriptInterpreter.cpp
@@ -46,6 +46,10 @@ void ScriptInterpreter::CollectDataForWatchpointCommandCallback(
"This script interpreter does not support watchpoint callbacks.");
}
+StructuredData::DictionarySP ScriptInterpreter::GetInterpreterInfo() {
+ return nullptr;
+}
+
bool ScriptInterpreter::LoadScriptingModule(const char *filename,
const LoadScriptOptions &options,
lldb_private::Status &error,
diff --git a/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp
index 7c821e5933823..c677abfaa5f20 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp
@@ -148,6 +148,12 @@ ScriptInterpreterLua::ScriptInterpreterLua(Debugger &debugger)
ScriptInterpreterLua::~ScriptInterpreterLua() = default;
+StructuredData::DictionarySP ScriptInterpreterLua::GetInterpreterInfo() {
+ auto info = std::make_shared<StructuredData::Dictionary>();
+ info->AddStringItem("language", "lua");
+ return info;
+}
+
bool ScriptInterpreterLua::ExecuteOneLine(llvm::StringRef command,
CommandReturnObject *result,
const ExecuteScriptOptions &options) {
diff --git a/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h
index f3ca1e6b257d9..b601779ff301c 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h
@@ -49,6 +49,8 @@ class ScriptInterpreterLua : public ScriptInterpreter {
StructuredData::ObjectSP *module_sp = nullptr,
FileSpec extra_search_dir = {}) override;
+ StructuredData::DictionarySP GetInterpreterInfo() override;
+
// Static Functions
static void Initialize();
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
index 9b7508239f1b4..7c71c9329e579 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
@@ -998,20 +998,6 @@ bool PythonFile::Check(PyObject *py_obj) {
#endif
}
-namespace {
-class GIL {
-public:
- GIL() {
- m_state = PyGILState_Ensure();
- assert(!PyErr_Occurred());
- }
- ~GIL() { PyGILState_Release(m_state); }
-
-protected:
- PyGILState_STATE m_state;
-};
-} // namespace
-
const char *PythonException::toCString() const {
if (!m_repr_bytes)
return "unknown exception";
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h
index 4577253227cd4..56bc55d239d12 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h
@@ -71,6 +71,18 @@ class PythonDictionary;
class PythonInteger;
class PythonException;
+class GIL {
+public:
+ GIL() {
+ m_state = PyGILState_Ensure();
+ assert(!PyErr_Occurred());
+ }
+ ~GIL() { PyGILState_Release(m_state); }
+
+protected:
+ PyGILState_STATE m_state;
+};
+
class StructuredPythonObject : public StructuredData::Generic {
public:
StructuredPythonObject() : StructuredData::Generic() {}
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
index 74fb42ae03308..418e2239a771e 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
@@ -410,6 +410,35 @@ FileSpec ScriptInterpreterPython::GetPythonDir() {
return g_spec;
}
+StructuredData::DictionarySP ScriptInterpreterPython::GetInterpreterInfo() {
+ GIL gil;
+ FileSpec python_dir_spec = GetPythonDir();
+ if (!python_dir_spec)
+ return nullptr;
+ PythonString python_dir(python_dir_spec.GetPath());
+ PythonDictionary info(PyInitialValue::Empty);
+ llvm::Error error = info.SetItem("lldb-pythonpath", python_dir);
+ if (error)
+ return nullptr;
+ static const char script[] = R"(
+def main(info):
+ import sys
+ import os
+ name = 'python' + str(sys.version_info.major)
+ info.update({
+ "language": "python",
+ "prefix": sys.prefix,
+ "executable": os.path.join(sys.prefix, "bin", name),
+ })
+ return info
+)";
+ PythonScript get_info(script);
+ auto info_json = unwrapIgnoringErrors(As<PythonDictionary>(get_info(info)));
+ if (!info_json)
+ return nullptr;
+ return info_json.CreateStructuredDictionary();
+}
+
void ScriptInterpreterPython::SharedLibraryDirectoryHelper(
FileSpec &this_file) {
// When we're loaded from python, this_file will point to the file inside the
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
index 83cc15da56c94..8cfc24e71283a 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
@@ -46,6 +46,7 @@ class ScriptInterpreterPython : public ScriptInterpreter,
: ScriptInterpreter(debugger, lldb::eScriptLanguagePython),
IOHandlerDelegateMultiline("DONE") {}
+ StructuredData::DictionarySP GetInterpreterInfo() override;
static void Initialize();
static void Terminate();
static llvm::StringRef GetPluginNameStatic() { return "script-python"; }
diff --git a/lldb/test/API/functionalities/paths/TestPaths.py b/lldb/test/API/functionalities/paths/TestPaths.py
index 8ef20c54974b6..da26da28a562e 100644
--- a/lldb/test/API/functionalities/paths/TestPaths.py
+++ b/lldb/test/API/functionalities/paths/TestPaths.py
@@ -5,6 +5,8 @@
import lldb
import os
+import sys
+import json
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
@@ -42,6 +44,21 @@ def test_paths(self):
self.assertTrue(any([os.path.exists(os.path.join(shlib_dir, f)) for f in
filenames]), "shlib_dir = " + shlib_dir)
+ @no_debug_info_test
+ def test_interpreter_info(self):
+ info_sd = self.dbg.GetScriptInterpreterInfo(self.dbg.GetScriptingLanguage("python"))
+ self.assertTrue(info_sd.IsValid())
+ stream = lldb.SBStream()
+ self.assertTrue(info_sd.GetAsJSON(stream).Success())
+ info = json.loads(stream.GetData())
+ prefix = info['prefix']
+ self.assertEqual(os.path.realpath(sys.prefix), os.path.realpath(prefix))
+ self.assertEqual(
+ os.path.realpath(os.path.join(info['lldb-pythonpath'], 'lldb')),
+ os.path.realpath(os.path.dirname(lldb.__file__)))
+ self.assertTrue(os.path.exists(info['executable']))
+ self.assertEqual(info['language'], 'python')
+
@no_debug_info_test
def test_directory_doesnt_end_with_slash(self):
diff --git a/lldb/test/Shell/Driver/TestHelp.test b/lldb/test/Shell/Driver/TestHelp.test
index fc53e80bdc4d5..8ce6097cd7410 100644
--- a/lldb/test/Shell/Driver/TestHelp.test
+++ b/lldb/test/Shell/Driver/TestHelp.test
@@ -62,6 +62,7 @@ CHECK: -r
CHECK: SCRIPTING
CHECK: -l
+CHECK: --print-script-interpreter-info
CHECK: --python-path
CHECK: -P
CHECK: --script-language
diff --git a/lldb/tools/driver/Driver.cpp b/lldb/tools/driver/Driver.cpp
index df070ebe4db8d..a51c124f96158 100644
--- a/lldb/tools/driver/Driver.cpp
+++ b/lldb/tools/driver/Driver.cpp
@@ -18,6 +18,7 @@
#include "lldb/API/SBReproducer.h"
#include "lldb/API/SBStream.h"
#include "lldb/API/SBStringList.h"
+#include "lldb/API/SBStructuredData.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Format.h"
@@ -201,6 +202,9 @@ SBError Driver::ProcessArgs(const opt::InputArgList &args, bool &exiting) {
if (args.hasArg(OPT_python_path)) {
m_option_data.m_print_python_path = true;
}
+ if (args.hasArg(OPT_print_script_interpreter_info)) {
+ m_option_data.m_print_script_interpreter_info = true;
+ }
if (args.hasArg(OPT_batch)) {
m_option_data.m_batch = true;
@@ -398,6 +402,22 @@ SBError Driver::ProcessArgs(const opt::InputArgList &args, bool &exiting) {
return error;
}
+ if (m_option_data.m_print_script_interpreter_info) {
+ SBStructuredData info =
+ m_debugger.GetScriptInterpreterInfo(m_debugger.GetScriptLanguage());
+ if (!info) {
+ error.SetErrorString("no script interpreter.");
+ } else {
+ SBStream stream;
+ error = info.GetAsJSON(stream);
+ if (error.Success()) {
+ llvm::outs() << stream.GetData() << '\n';
+ }
+ }
+ exiting = true;
+ return error;
+ }
+
return error;
}
diff --git a/lldb/tools/driver/Driver.h b/lldb/tools/driver/Driver.h
index 2d91491a25400..d5779b3c2c91b 100644
--- a/lldb/tools/driver/Driver.h
+++ b/lldb/tools/driver/Driver.h
@@ -79,6 +79,7 @@ class Driver : public lldb::SBBroadcaster {
bool m_source_quietly = false;
bool m_print_version = false;
bool m_print_python_path = false;
+ bool m_print_script_interpreter_info = false;
bool m_wait_for = false;
bool m_repl = false;
bool m_batch = false;
diff --git a/lldb/tools/driver/Options.td b/lldb/tools/driver/Options.td
index be2b4bfa30044..d59ac314d5944 100644
--- a/lldb/tools/driver/Options.td
+++ b/lldb/tools/driver/Options.td
@@ -48,6 +48,10 @@ def: Flag<["-"], "P">,
HelpText<"Alias for --python-path">,
Group<grp_scripting>;
+def print_script_interpreter_info: F<"print-script-interpreter-info">,
+ HelpText<"Prints out a json dictionary with information about the scripting language interpreter.">,
+ Group<grp_scripting>;
+
def script_language: Separate<["--", "-"], "script-language">,
MetaVarName<"<language>">,
HelpText<"Tells the debugger to use the specified scripting language for user-defined scripts.">,
More information about the lldb-commits
mailing list