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 @@ -229,9 +229,9 @@ return pfunc(ToSWIGWrapper(std::move(debugger_sp)), dict); } -PythonObject lldb_private::LLDBSwigPythonCreateScriptedProcess( +PythonObject lldb_private::LLDBSwigPythonCreateScriptedObject( const char *python_class_name, const char *session_dictionary_name, - const lldb::TargetSP &target_sp, + lldb::ExecutionContextRefSP exe_ctx_sp, const lldb_private::StructuredDataImpl &args_impl, std::string &error_string) { if (python_class_name == NULL || python_class_name[0] == '\0' || @@ -251,8 +251,6 @@ return PythonObject(); } - PythonObject target_arg = ToSWIGWrapper(target_sp); - llvm::Expected arg_info = pfunc.GetArgInfo(); if (!arg_info) { llvm::handleAllErrors( @@ -266,7 +264,7 @@ PythonObject result = {}; if (arg_info.get().max_positional_args == 2) { - result = pfunc(target_arg, ToSWIGWrapper(args_impl)); + result = pfunc(ToSWIGWrapper(exe_ctx_sp), ToSWIGWrapper(args_impl)); } else { error_string.assign("wrong number of arguments in __init__, should be 2 " "(not including self)"); @@ -274,46 +272,6 @@ return result; } -PythonObject lldb_private::LLDBSwigPythonCreateScriptedThread( - const char *python_class_name, const char *session_dictionary_name, - const lldb::ProcessSP &process_sp, const 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(); - } - - if (arg_info.get().max_positional_args == 2) - return pfunc(ToSWIGWrapper(process_sp), ToSWIGWrapper(args_impl)); - - error_string.assign("wrong number of arguments in __init__, should be 2 " - "(not including self)"); - return PythonObject(); -} - 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/crashlog_scripted_process.py =================================================================== --- lldb/examples/python/scripted_process/crashlog_scripted_process.py +++ lldb/examples/python/scripted_process/crashlog_scripted_process.py @@ -62,8 +62,8 @@ self.addr_mask, self.target) - def __init__(self, target: lldb.SBTarget, args : lldb.SBStructuredData): - super().__init__(target, args) + def __init__(self, exe_ctx: lldb.SBExecutionContext, args : lldb.SBStructuredData): + super().__init__(exe_ctx, args) if not self.target or not self.target.IsValid(): # Return error Index: lldb/examples/python/scripted_process/scripted_platform.py =================================================================== --- /dev/null +++ lldb/examples/python/scripted_process/scripted_platform.py @@ -0,0 +1,96 @@ +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, exe_ctx, args): + """ Construct a scripted platform. + + Args: + exe_ctx (lldb.SBExecutionContext): The execution context for the scripted platform + 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 are running or that can be attached to 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 attach_to_process(self, attach_info): + """ Attach to a process. + + Args: + attach_info (lldb.SBAttachInfo): The information related to attach to a process. + + Returns: + lldb.SBError: A status object notifying if the attach succeeded. + """ + pass + + @abstractmethod + def launch_process(self, launch_info): + """ Launch a 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 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/examples/python/scripted_process/scripted_process.py =================================================================== --- lldb/examples/python/scripted_process/scripted_process.py +++ lldb/examples/python/scripted_process/scripted_process.py @@ -20,17 +20,20 @@ metadata = None @abstractmethod - def __init__(self, target, args): + def __init__(self, exe_ctx, args): """ Construct a scripted process. Args: - target (lldb.SBTarget): The target launching the scripted process. + exe_ctx (lldb.SBExecutionContext): The execution context for the scripted process. args (lldb.SBStructuredData): A Dictionary holding arbitrary key/value pairs used by the scripted process. """ + target = None self.target = None self.args = None self.arch = None + if isinstance(exe_ctx, lldb.SBExecutionContext): + target = exe_ctx.target if isinstance(target, lldb.SBTarget) and target.IsValid(): self.target = target triple = self.target.triple Index: lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h =================================================================== --- lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h +++ lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h @@ -96,14 +96,10 @@ // Although these are scripting-language specific, their definition depends on // the public API. -python::PythonObject LLDBSwigPythonCreateScriptedProcess( +python::PythonObject LLDBSwigPythonCreateScriptedObject( const char *python_class_name, const char *session_dictionary_name, - const lldb::TargetSP &target_sp, const StructuredDataImpl &args_impl, - std::string &error_string); - -python::PythonObject LLDBSwigPythonCreateScriptedThread( - const char *python_class_name, const char *session_dictionary_name, - const lldb::ProcessSP &process_sp, const StructuredDataImpl &args_impl, + lldb::ExecutionContextRefSP exe_ctx_sp, + const lldb_private::StructuredDataImpl &args_impl, std::string &error_string); llvm::Expected LLDBSwigPythonBreakpointCallbackFunction( Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp =================================================================== --- lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp +++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp @@ -37,16 +37,18 @@ if (class_name.empty()) return {}; - TargetSP target_sp = exe_ctx.GetTargetSP(); StructuredDataImpl args_impl(args_sp); std::string error_string; Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); - PythonObject ret_val = LLDBSwigPythonCreateScriptedProcess( - class_name.str().c_str(), m_interpreter.GetDictionaryName(), target_sp, - args_impl, error_string); + lldb::ExecutionContextRefSP exe_ctx_ref_sp = + std::make_shared(exe_ctx); + + PythonObject ret_val = LLDBSwigPythonCreateScriptedObject( + class_name.str().c_str(), m_interpreter.GetDictionaryName(), + exe_ctx_ref_sp, args_impl, error_string); m_object_instance_sp = StructuredData::GenericSP(new StructuredPythonObject(std::move(ret_val))); Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptedThreadPythonInterface.cpp =================================================================== --- lldb/source/Plugins/ScriptInterpreter/Python/ScriptedThreadPythonInterface.cpp +++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptedThreadPythonInterface.cpp @@ -35,7 +35,6 @@ if (class_name.empty() && !script_obj) return {}; - ProcessSP process_sp = exe_ctx.GetProcessSP(); StructuredDataImpl args_impl(args_sp); std::string error_string; @@ -44,11 +43,13 @@ PythonObject ret_val; - if (!script_obj) - ret_val = LLDBSwigPythonCreateScriptedThread( - class_name.str().c_str(), m_interpreter.GetDictionaryName(), process_sp, - args_impl, error_string); - else + if (!script_obj) { + lldb::ExecutionContextRefSP exe_ctx_ref_sp = + std::make_shared(exe_ctx); + ret_val = LLDBSwigPythonCreateScriptedObject( + class_name.str().c_str(), m_interpreter.GetDictionaryName(), + exe_ctx_ref_sp, args_impl, error_string); + } else ret_val = PythonObject(PyRefType::Borrowed, static_cast(script_obj->GetValue())); 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, exe_ctx, 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/test/API/functionalities/scripted_process/dummy_scripted_process.py =================================================================== --- lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py +++ lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py @@ -7,8 +7,8 @@ from lldb.plugins.scripted_process import ScriptedThread class DummyScriptedProcess(ScriptedProcess): - def __init__(self, target: lldb.SBTarget, args : lldb.SBStructuredData): - super().__init__(target, args) + def __init__(self, exe_ctx: lldb.SBExecutionContext, args : lldb.SBStructuredData): + super().__init__(exe_ctx, args) self.threads[0] = DummyScriptedThread(self, None) def get_memory_region_containing_address(self, addr: int) -> lldb.SBMemoryRegionInfo: Index: lldb/test/API/functionalities/scripted_process/invalid_scripted_process.py =================================================================== --- lldb/test/API/functionalities/scripted_process/invalid_scripted_process.py +++ lldb/test/API/functionalities/scripted_process/invalid_scripted_process.py @@ -7,8 +7,8 @@ from lldb.plugins.scripted_process import ScriptedThread class InvalidScriptedProcess(ScriptedProcess): - def __init__(self, target: lldb.SBTarget, args : lldb.SBStructuredData): - super().__init__(target, args) + def __init__(self, exe_ctx: lldb.SBExecutionContext, args : lldb.SBStructuredData): + super().__init__(exe_ctx, args) self.threads[0] = InvalidScriptedThread(self, None) def get_memory_region_containing_address(self, addr: int) -> lldb.SBMemoryRegionInfo: Index: lldb/test/API/functionalities/scripted_process/stack_core_scripted_process.py =================================================================== --- lldb/test/API/functionalities/scripted_process/stack_core_scripted_process.py +++ lldb/test/API/functionalities/scripted_process/stack_core_scripted_process.py @@ -13,8 +13,8 @@ return module return None - def __init__(self, target: lldb.SBTarget, args : lldb.SBStructuredData): - super().__init__(target, args) + def __init__(self, exe_ctx: lldb.SBExecutionContext, args : lldb.SBStructuredData): + super().__init__(exe_ctx, args) self.corefile_target = None self.corefile_process = None @@ -25,7 +25,7 @@ idx = self.backing_target_idx.GetIntegerValue(42) if self.backing_target_idx.GetType() == lldb.eStructuredDataTypeString: idx = int(self.backing_target_idx.GetStringValue(100)) - self.corefile_target = target.GetDebugger().GetTargetAtIndex(idx) + self.corefile_target = self.target.GetDebugger().GetTargetAtIndex(idx) self.corefile_process = self.corefile_target.GetProcess() for corefile_thread in self.corefile_process: structured_data = lldb.SBStructuredData() Index: lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp =================================================================== --- lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp +++ lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp @@ -200,16 +200,9 @@ return python::PythonObject(); } -python::PythonObject lldb_private::LLDBSwigPythonCreateScriptedProcess( +python::PythonObject lldb_private::LLDBSwigPythonCreateScriptedObject( const char *python_class_name, const char *session_dictionary_name, - const lldb::TargetSP &target_sp, const StructuredDataImpl &args_impl, - std::string &error_string) { - return python::PythonObject(); -} - -python::PythonObject lldb_private::LLDBSwigPythonCreateScriptedThread( - const char *python_class_name, const char *session_dictionary_name, - const lldb::ProcessSP &process_sp, const StructuredDataImpl &args_impl, + lldb::ExecutionContextRefSP exe_ctx_sp, const StructuredDataImpl &args_impl, std::string &error_string) { return python::PythonObject(); }