Index: lldb/bindings/python/CMakeLists.txt =================================================================== --- lldb/bindings/python/CMakeLists.txt +++ lldb/bindings/python/CMakeLists.txt @@ -109,6 +109,13 @@ FILES "${LLDB_SOURCE_DIR}/examples/python/scripted_process/scripted_process.py") + create_python_package( + ${swig_target} + ${lldb_python_target_dir} + "plugins" + FILES + "${LLDB_SOURCE_DIR}/examples/python/scripted_process/scripted_platform.py") + if(APPLE) create_python_package( ${swig_target} Index: lldb/bindings/python/python-wrapper.swig =================================================================== --- lldb/bindings/python/python-wrapper.swig +++ lldb/bindings/python/python-wrapper.swig @@ -314,6 +314,48 @@ return PythonObject(); } +PythonObject lldb_private::LLDBSwigPythonCreateScriptedPlatform( + const char *python_class_name, const char *session_dictionary_name, + const lldb_private::StructuredDataImpl &args_impl, + std::string &error_string) { + if (python_class_name == NULL || python_class_name[0] == '\0' || + !session_dictionary_name) + return PythonObject(); + + PyErr_Cleaner py_err_cleaner(true); + + auto dict = PythonModule::MainModule().ResolveName( + session_dictionary_name); + auto pfunc = PythonObject::ResolveNameWithDictionary( + python_class_name, dict); + + if (!pfunc.IsAllocated()) { + error_string.append("could not find script class: "); + error_string.append(python_class_name); + return PythonObject(); + } + + llvm::Expected arg_info = pfunc.GetArgInfo(); + if (!arg_info) { + llvm::handleAllErrors( + arg_info.takeError(), + [&](PythonException &E) { error_string.append(E.ReadBacktrace()); }, + [&](const llvm::ErrorInfoBase &E) { + error_string.append(E.message()); + }); + return PythonObject(); + } + + PythonObject result = {}; + if (arg_info.get().max_positional_args == 1) { + result = pfunc(ToSWIGWrapper(args_impl)); + } else { + error_string.assign("wrong number of arguments in __init__, should be 1 " + "(not including self)"); + } + return result; +} + PythonObject lldb_private::LLDBSwigPythonCreateScriptedThreadPlan( const char *python_class_name, const char *session_dictionary_name, const lldb_private::StructuredDataImpl &args_impl, Index: lldb/examples/python/scripted_process/scripted_platform.py =================================================================== --- /dev/null +++ lldb/examples/python/scripted_process/scripted_platform.py @@ -0,0 +1,83 @@ +from abc import ABCMeta, abstractmethod + +import lldb + +class ScriptedPlatform(metaclass=ABCMeta): + + """ + The base class for a scripted platform. + + Most of the base class methods are `@abstractmethod` that need to be + overwritten by the inheriting class. + + DISCLAIMER: THIS INTERFACE IS STILL UNDER DEVELOPMENT AND NOT STABLE. + THE METHODS EXPOSED MIGHT CHANGE IN THE FUTURE. + """ + + processes = None + + @abstractmethod + def __init__(self, args): + """ Construct a scripted platform. + + Args: + args (lldb.SBStructuredData): A Dictionary holding arbitrary + key/value pairs used by the scripted platform. + """ + processes = [] + + @abstractmethod + def list_processes(self): + """ Get a list of processes that can be ran on the platform. + + processes = { + 420: { + name: a.out, + arch: aarch64, + pid: 420, + parent_pid: 42 (optional), + uid: 0 (optional), + gid: 0 (optional), + }, + } + + Returns: + Dict: The processes represented as a dictionary, with at least the + process ID, name, architecture. Optionally, the user can also + provide the parent process ID and the user and group IDs. + The dictionary can be empty. + """ + pass + + def get_process_info(self, pid): + """ Get the dictionary describing the process. + + Returns: + Dict: The dictionary of process info that matched process ID. + None if the process doesn't exists + """ + pass + + @abstractmethod + def launch_process(self, launch_info): + """ Launch a scripted process. + + Args: + launch_info (lldb.SBLaunchInfo): The information related to the process launch. + + Returns: + lldb.SBError: A status object notifying if the launch succeeded. + """ + pass + + @abstractmethod + def kill_process(self, pid): + """ Kill a scripted process. + + Args: + pid (int): Process ID for the process to be killed. + + Returns: + lldb.SBError: A status object notifying if the shutdown succeeded. + """ + pass Index: lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h =================================================================== --- lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h +++ lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h @@ -105,6 +105,10 @@ const lldb::ProcessSP &process_sp, const StructuredDataImpl &args_impl, std::string &error_string); +python::PythonObject LLDBSwigPythonCreateScriptedPlatform( + const char *python_class_name, const char *session_dictionary_name, + const StructuredDataImpl &args_impl, std::string &error_string); + llvm::Expected LLDBSwigPythonBreakpointCallbackFunction( const char *python_function_name, const char *session_dictionary_name, const lldb::StackFrameSP &sb_frame, Index: lldb/test/API/functionalities/scripted_platform/my_scripted_platform.py =================================================================== --- /dev/null +++ lldb/test/API/functionalities/scripted_platform/my_scripted_platform.py @@ -0,0 +1,38 @@ +import os + +import lldb +from lldb.plugins.scripted_platform import ScriptedPlatform + +class MyScriptedPlatform(ScriptedPlatform): + + def __init__(self, args): + self.processes = {} + + proc = {} + proc['name'] = 'a.out' + proc['arch'] = 'arm64-apple-macosx' + proc['pid'] = 420 + proc['parent'] = 42 + proc['uid'] = 501 + proc['gid'] = 20 + self.processes[420] = proc + + def list_processes(self): + return self.processes + + def get_process_info(self, pid): + return self.processes[pid] + + def launch_process(self, launch_info): + return lldb.SBError() + + def kill_process(self, pid): + return lldb.SBError() + +def __lldb_init_module(debugger, dict): + if not 'SKIP_SCRIPTED_PLATFORM_SELECT' in os.environ: + debugger.HandleCommand( + "platform select scripted-platform -C %s.%s" % (__name__, MyScriptedPlatform.__name__)) + else: + print("Name of the class that will manage the scripted platform: '%s.%s'" + % (__name__, MyScriptedPlatform.__name__)) Index: lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp =================================================================== --- lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp +++ lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp @@ -213,6 +213,12 @@ return python::PythonObject(); } +python::PythonObject lldb_private::LLDBSwigPythonCreateScriptedPlatform( + const char *python_class_name, const char *session_dictionary_name, + const StructuredDataImpl &args_impl, std::string &error_string) { + return python::PythonObject(); +} + python::PythonObject lldb_private::LLDBSWIGPython_CreateFrameRecognizer( const char *python_class_name, const char *session_dictionary_name) { return python::PythonObject();