11f6a57c1SMed Ismail Bennani //===-- ScriptedProcessPythonInterface.cpp --------------------------------===//
21f6a57c1SMed Ismail Bennani //
31f6a57c1SMed Ismail Bennani // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
41f6a57c1SMed Ismail Bennani // See https://llvm.org/LICENSE.txt for license information.
51f6a57c1SMed Ismail Bennani // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61f6a57c1SMed Ismail Bennani //
71f6a57c1SMed Ismail Bennani //===----------------------------------------------------------------------===//
81f6a57c1SMed Ismail Bennani 
91f6a57c1SMed Ismail Bennani #include "lldb/Host/Config.h"
101f6a57c1SMed Ismail Bennani #include "lldb/lldb-enumerations.h"
111f6a57c1SMed Ismail Bennani 
121f6a57c1SMed Ismail Bennani #if LLDB_ENABLE_PYTHON
131f6a57c1SMed Ismail Bennani 
141f6a57c1SMed Ismail Bennani // LLDB Python header must be included first
151f6a57c1SMed Ismail Bennani #include "lldb-python.h"
161f6a57c1SMed Ismail Bennani 
171f6a57c1SMed Ismail Bennani #include "SWIGPythonBridge.h"
181f6a57c1SMed Ismail Bennani #include "ScriptInterpreterPythonImpl.h"
191f6a57c1SMed Ismail Bennani #include "ScriptedProcessPythonInterface.h"
201f6a57c1SMed Ismail Bennani 
211f6a57c1SMed Ismail Bennani using namespace lldb;
221f6a57c1SMed Ismail Bennani using namespace lldb_private;
231f6a57c1SMed Ismail Bennani using namespace lldb_private::python;
241f6a57c1SMed Ismail Bennani using Locker = ScriptInterpreterPythonImpl::Locker;
251f6a57c1SMed Ismail Bennani 
261f6a57c1SMed Ismail Bennani StructuredData::GenericSP ScriptedProcessPythonInterface::CreatePluginObject(
271f6a57c1SMed Ismail Bennani     const llvm::StringRef class_name, lldb::TargetSP target_sp,
281f6a57c1SMed Ismail Bennani     StructuredData::DictionarySP args_sp) {
291f6a57c1SMed Ismail Bennani   if (class_name.empty())
301f6a57c1SMed Ismail Bennani     return {};
311f6a57c1SMed Ismail Bennani 
321f6a57c1SMed Ismail Bennani   std::string error_string;
331f6a57c1SMed Ismail Bennani   StructuredDataImpl *args_impl = nullptr;
341f6a57c1SMed Ismail Bennani   if (args_sp) {
351f6a57c1SMed Ismail Bennani     args_impl = new StructuredDataImpl();
361f6a57c1SMed Ismail Bennani     args_impl->SetObjectSP(args_sp);
371f6a57c1SMed Ismail Bennani   }
381f6a57c1SMed Ismail Bennani 
391f6a57c1SMed Ismail Bennani   void *ret_val;
401f6a57c1SMed Ismail Bennani 
411f6a57c1SMed Ismail Bennani   {
421f6a57c1SMed Ismail Bennani 
431f6a57c1SMed Ismail Bennani     Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
441f6a57c1SMed Ismail Bennani                    Locker::FreeLock);
451f6a57c1SMed Ismail Bennani 
461f6a57c1SMed Ismail Bennani     ret_val = LLDBSwigPythonCreateScriptedProcess(
471f6a57c1SMed Ismail Bennani         class_name.str().c_str(), m_interpreter.GetDictionaryName(), target_sp,
481f6a57c1SMed Ismail Bennani         args_impl, error_string);
491f6a57c1SMed Ismail Bennani   }
501f6a57c1SMed Ismail Bennani 
511f6a57c1SMed Ismail Bennani   m_object_instance_sp =
521f6a57c1SMed Ismail Bennani       StructuredData::GenericSP(new StructuredPythonObject(ret_val));
531f6a57c1SMed Ismail Bennani 
541f6a57c1SMed Ismail Bennani   return m_object_instance_sp;
551f6a57c1SMed Ismail Bennani }
561f6a57c1SMed Ismail Bennani 
571f6a57c1SMed Ismail Bennani Status ScriptedProcessPythonInterface::Launch() {
58*312b43daSMed Ismail Bennani   return GetStatusFromMethod("launch");
591f6a57c1SMed Ismail Bennani }
601f6a57c1SMed Ismail Bennani 
611f6a57c1SMed Ismail Bennani Status ScriptedProcessPythonInterface::Resume() {
62*312b43daSMed Ismail Bennani   return GetStatusFromMethod("resume");
631f6a57c1SMed Ismail Bennani }
641f6a57c1SMed Ismail Bennani 
65*312b43daSMed Ismail Bennani bool ScriptedProcessPythonInterface::ShouldStop() {
66*312b43daSMed Ismail Bennani   return GetGenericInteger("shuold_stop");
67*312b43daSMed Ismail Bennani }
68*312b43daSMed Ismail Bennani 
69*312b43daSMed Ismail Bennani Status ScriptedProcessPythonInterface::Stop() {
70*312b43daSMed Ismail Bennani   return GetStatusFromMethod("stop");
71*312b43daSMed Ismail Bennani }
72*312b43daSMed Ismail Bennani 
73*312b43daSMed Ismail Bennani Status ScriptedProcessPythonInterface::GetStatusFromMethod(
74*312b43daSMed Ismail Bennani     llvm::StringRef method_name) {
751f6a57c1SMed Ismail Bennani   Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
761f6a57c1SMed Ismail Bennani                  Locker::FreeLock);
771f6a57c1SMed Ismail Bennani 
781f6a57c1SMed Ismail Bennani   if (!m_object_instance_sp)
791f6a57c1SMed Ismail Bennani     return Status("Python object ill-formed.");
801f6a57c1SMed Ismail Bennani 
811f6a57c1SMed Ismail Bennani   if (!m_object_instance_sp)
821f6a57c1SMed Ismail Bennani     return Status("Cannot convert Python object to StructuredData::Generic.");
831f6a57c1SMed Ismail Bennani   PythonObject implementor(PyRefType::Borrowed,
841f6a57c1SMed Ismail Bennani                            (PyObject *)m_object_instance_sp->GetValue());
851f6a57c1SMed Ismail Bennani 
861f6a57c1SMed Ismail Bennani   if (!implementor.IsAllocated())
871f6a57c1SMed Ismail Bennani     return Status("Python implementor not allocated.");
881f6a57c1SMed Ismail Bennani 
891f6a57c1SMed Ismail Bennani   PythonObject pmeth(
901f6a57c1SMed Ismail Bennani       PyRefType::Owned,
911f6a57c1SMed Ismail Bennani       PyObject_GetAttrString(implementor.get(), method_name.str().c_str()));
921f6a57c1SMed Ismail Bennani 
931f6a57c1SMed Ismail Bennani   if (PyErr_Occurred())
941f6a57c1SMed Ismail Bennani     PyErr_Clear();
951f6a57c1SMed Ismail Bennani 
961f6a57c1SMed Ismail Bennani   if (!pmeth.IsAllocated())
971f6a57c1SMed Ismail Bennani     return Status("Python method not allocated.");
981f6a57c1SMed Ismail Bennani 
991f6a57c1SMed Ismail Bennani   if (PyCallable_Check(pmeth.get()) == 0) {
1001f6a57c1SMed Ismail Bennani     if (PyErr_Occurred())
1011f6a57c1SMed Ismail Bennani       PyErr_Clear();
1021f6a57c1SMed Ismail Bennani     return Status("Python method not callable.");
1031f6a57c1SMed Ismail Bennani   }
1041f6a57c1SMed Ismail Bennani 
1051f6a57c1SMed Ismail Bennani   if (PyErr_Occurred())
1061f6a57c1SMed Ismail Bennani     PyErr_Clear();
1071f6a57c1SMed Ismail Bennani 
1081f6a57c1SMed Ismail Bennani   PythonObject py_return(PyRefType::Owned,
1091f6a57c1SMed Ismail Bennani                          PyObject_CallMethod(implementor.get(),
1101f6a57c1SMed Ismail Bennani                                              method_name.str().c_str(),
1111f6a57c1SMed Ismail Bennani                                              nullptr));
1121f6a57c1SMed Ismail Bennani 
1131f6a57c1SMed Ismail Bennani   if (PyErr_Occurred()) {
1141f6a57c1SMed Ismail Bennani     PyErr_Print();
1151f6a57c1SMed Ismail Bennani     PyErr_Clear();
1161f6a57c1SMed Ismail Bennani     return Status("Python method could not be called.");
1171f6a57c1SMed Ismail Bennani   }
1181f6a57c1SMed Ismail Bennani 
1191f6a57c1SMed Ismail Bennani   if (PyObject *py_ret_ptr = py_return.get()) {
1201f6a57c1SMed Ismail Bennani     lldb::SBError *sb_error =
1211f6a57c1SMed Ismail Bennani         (lldb::SBError *)LLDBSWIGPython_CastPyObjectToSBError(py_ret_ptr);
1221f6a57c1SMed Ismail Bennani 
1231f6a57c1SMed Ismail Bennani     if (!sb_error)
1241f6a57c1SMed Ismail Bennani       return Status("Couldn't cast lldb::SBError to lldb::Status.");
1251f6a57c1SMed Ismail Bennani 
1261f6a57c1SMed Ismail Bennani     Status status = m_interpreter.GetStatusFromSBError(*sb_error);
1271f6a57c1SMed Ismail Bennani 
1281f6a57c1SMed Ismail Bennani     if (status.Fail())
1291f6a57c1SMed Ismail Bennani       return Status("error: %s", status.AsCString());
1301f6a57c1SMed Ismail Bennani 
1311f6a57c1SMed Ismail Bennani     return status;
1321f6a57c1SMed Ismail Bennani   }
1331f6a57c1SMed Ismail Bennani 
1341f6a57c1SMed Ismail Bennani   return Status("Returned object is null.");
1351f6a57c1SMed Ismail Bennani }
1361f6a57c1SMed Ismail Bennani 
1371f6a57c1SMed Ismail Bennani size_t
1381f6a57c1SMed Ismail Bennani ScriptedProcessPythonInterface::GetGenericInteger(llvm::StringRef method_name) {
1391f6a57c1SMed Ismail Bennani   Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
1401f6a57c1SMed Ismail Bennani                  Locker::FreeLock);
1411f6a57c1SMed Ismail Bennani 
1421f6a57c1SMed Ismail Bennani   if (!m_object_instance_sp)
1431f6a57c1SMed Ismail Bennani     return LLDB_INVALID_ADDRESS;
1441f6a57c1SMed Ismail Bennani 
1451f6a57c1SMed Ismail Bennani   if (!m_object_instance_sp)
1461f6a57c1SMed Ismail Bennani     return LLDB_INVALID_ADDRESS;
1471f6a57c1SMed Ismail Bennani   PythonObject implementor(PyRefType::Borrowed,
1481f6a57c1SMed Ismail Bennani                            (PyObject *)m_object_instance_sp->GetValue());
1491f6a57c1SMed Ismail Bennani 
1501f6a57c1SMed Ismail Bennani   if (!implementor.IsAllocated())
1511f6a57c1SMed Ismail Bennani     return LLDB_INVALID_ADDRESS;
1521f6a57c1SMed Ismail Bennani 
1531f6a57c1SMed Ismail Bennani   PythonObject pmeth(
1541f6a57c1SMed Ismail Bennani       PyRefType::Owned,
1551f6a57c1SMed Ismail Bennani       PyObject_GetAttrString(implementor.get(), method_name.str().c_str()));
1561f6a57c1SMed Ismail Bennani 
1571f6a57c1SMed Ismail Bennani   if (PyErr_Occurred())
1581f6a57c1SMed Ismail Bennani     PyErr_Clear();
1591f6a57c1SMed Ismail Bennani 
1601f6a57c1SMed Ismail Bennani   if (!pmeth.IsAllocated())
1611f6a57c1SMed Ismail Bennani     return LLDB_INVALID_ADDRESS;
1621f6a57c1SMed Ismail Bennani 
1631f6a57c1SMed Ismail Bennani   if (PyCallable_Check(pmeth.get()) == 0) {
1641f6a57c1SMed Ismail Bennani     if (PyErr_Occurred())
1651f6a57c1SMed Ismail Bennani       PyErr_Clear();
1661f6a57c1SMed Ismail Bennani     return LLDB_INVALID_ADDRESS;
1671f6a57c1SMed Ismail Bennani   }
1681f6a57c1SMed Ismail Bennani 
1691f6a57c1SMed Ismail Bennani   if (PyErr_Occurred())
1701f6a57c1SMed Ismail Bennani     PyErr_Clear();
1711f6a57c1SMed Ismail Bennani 
1721f6a57c1SMed Ismail Bennani   PythonObject py_return(PyRefType::Owned,
1731f6a57c1SMed Ismail Bennani                          PyObject_CallMethod(implementor.get(),
1741f6a57c1SMed Ismail Bennani                                              method_name.str().c_str(),
1751f6a57c1SMed Ismail Bennani                                              nullptr));
1761f6a57c1SMed Ismail Bennani 
1771f6a57c1SMed Ismail Bennani   if (PyErr_Occurred()) {
1781f6a57c1SMed Ismail Bennani     PyErr_Print();
1791f6a57c1SMed Ismail Bennani     PyErr_Clear();
1801f6a57c1SMed Ismail Bennani   }
1811f6a57c1SMed Ismail Bennani 
1821f6a57c1SMed Ismail Bennani   if (py_return.get()) {
1831f6a57c1SMed Ismail Bennani     auto size = py_return.AsUnsignedLongLong();
1841f6a57c1SMed Ismail Bennani     return (size) ? *size : LLDB_INVALID_ADDRESS;
1851f6a57c1SMed Ismail Bennani   }
1861f6a57c1SMed Ismail Bennani   return LLDB_INVALID_ADDRESS;
1871f6a57c1SMed Ismail Bennani }
1881f6a57c1SMed Ismail Bennani 
1891f6a57c1SMed Ismail Bennani lldb::MemoryRegionInfoSP
1901f6a57c1SMed Ismail Bennani ScriptedProcessPythonInterface::GetMemoryRegionContainingAddress(
1911f6a57c1SMed Ismail Bennani     lldb::addr_t address) {
1921f6a57c1SMed Ismail Bennani   // TODO: Implement
1931f6a57c1SMed Ismail Bennani   return nullptr;
1941f6a57c1SMed Ismail Bennani }
1951f6a57c1SMed Ismail Bennani 
1961f6a57c1SMed Ismail Bennani StructuredData::DictionarySP
1971f6a57c1SMed Ismail Bennani ScriptedProcessPythonInterface::GetThreadWithID(lldb::tid_t tid) {
1981f6a57c1SMed Ismail Bennani   // TODO: Implement
1991f6a57c1SMed Ismail Bennani   return nullptr;
2001f6a57c1SMed Ismail Bennani }
2011f6a57c1SMed Ismail Bennani 
2021f6a57c1SMed Ismail Bennani StructuredData::DictionarySP
2031f6a57c1SMed Ismail Bennani ScriptedProcessPythonInterface::GetRegistersForThread(lldb::tid_t tid) {
2041f6a57c1SMed Ismail Bennani   // TODO: Implement
2051f6a57c1SMed Ismail Bennani   return nullptr;
2061f6a57c1SMed Ismail Bennani }
2071f6a57c1SMed Ismail Bennani 
2081f6a57c1SMed Ismail Bennani lldb::DataExtractorSP ScriptedProcessPythonInterface::ReadMemoryAtAddress(
2091f6a57c1SMed Ismail Bennani     lldb::addr_t address, size_t size, Status &error) {
2101f6a57c1SMed Ismail Bennani   Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
2111f6a57c1SMed Ismail Bennani                  Locker::FreeLock);
2121f6a57c1SMed Ismail Bennani 
2131f6a57c1SMed Ismail Bennani   auto error_with_message = [&error](llvm::StringRef message) {
2141f6a57c1SMed Ismail Bennani     error.SetErrorString(message);
2151f6a57c1SMed Ismail Bennani     return nullptr;
2161f6a57c1SMed Ismail Bennani   };
2171f6a57c1SMed Ismail Bennani 
2181f6a57c1SMed Ismail Bennani   static char callee_name[] = "read_memory_at_address";
2191f6a57c1SMed Ismail Bennani   std::string param_format = GetPythonValueFormatString(address);
2201f6a57c1SMed Ismail Bennani   param_format += GetPythonValueFormatString(size);
2211f6a57c1SMed Ismail Bennani 
2221f6a57c1SMed Ismail Bennani   if (!m_object_instance_sp)
2231f6a57c1SMed Ismail Bennani     return error_with_message("Python object ill-formed.");
2241f6a57c1SMed Ismail Bennani 
2251f6a57c1SMed Ismail Bennani   if (!m_object_instance_sp)
2261f6a57c1SMed Ismail Bennani     return error_with_message("Python method not callable.");
2271f6a57c1SMed Ismail Bennani 
2281f6a57c1SMed Ismail Bennani   PythonObject implementor(PyRefType::Borrowed,
2291f6a57c1SMed Ismail Bennani                            (PyObject *)m_object_instance_sp->GetValue());
2301f6a57c1SMed Ismail Bennani 
2311f6a57c1SMed Ismail Bennani   if (!implementor.IsAllocated())
2321f6a57c1SMed Ismail Bennani     return error_with_message("Python implementor not allocated.");
2331f6a57c1SMed Ismail Bennani 
2341f6a57c1SMed Ismail Bennani   PythonObject pmeth(PyRefType::Owned,
2351f6a57c1SMed Ismail Bennani                      PyObject_GetAttrString(implementor.get(), callee_name));
2361f6a57c1SMed Ismail Bennani 
2371f6a57c1SMed Ismail Bennani   if (PyErr_Occurred())
2381f6a57c1SMed Ismail Bennani     PyErr_Clear();
2391f6a57c1SMed Ismail Bennani 
2401f6a57c1SMed Ismail Bennani   if (!pmeth.IsAllocated())
2411f6a57c1SMed Ismail Bennani     return error_with_message("Python method not allocated.");
2421f6a57c1SMed Ismail Bennani 
2431f6a57c1SMed Ismail Bennani   if (PyCallable_Check(pmeth.get()) == 0) {
2441f6a57c1SMed Ismail Bennani     if (PyErr_Occurred())
2451f6a57c1SMed Ismail Bennani       PyErr_Clear();
2461f6a57c1SMed Ismail Bennani     return error_with_message("Python method not callable.");
2471f6a57c1SMed Ismail Bennani   }
2481f6a57c1SMed Ismail Bennani 
2491f6a57c1SMed Ismail Bennani   if (PyErr_Occurred())
2501f6a57c1SMed Ismail Bennani     PyErr_Clear();
2511f6a57c1SMed Ismail Bennani 
2521f6a57c1SMed Ismail Bennani   PythonObject py_return(PyRefType::Owned,
2531f6a57c1SMed Ismail Bennani                          PyObject_CallMethod(implementor.get(), callee_name,
2541f6a57c1SMed Ismail Bennani                                              param_format.c_str(), address,
2551f6a57c1SMed Ismail Bennani                                              size));
2561f6a57c1SMed Ismail Bennani 
2571f6a57c1SMed Ismail Bennani   if (PyErr_Occurred()) {
2581f6a57c1SMed Ismail Bennani     PyErr_Print();
2591f6a57c1SMed Ismail Bennani     PyErr_Clear();
2601f6a57c1SMed Ismail Bennani     return error_with_message("Python method could not be called.");
2611f6a57c1SMed Ismail Bennani   }
2621f6a57c1SMed Ismail Bennani 
2631f6a57c1SMed Ismail Bennani   if (PyObject *py_ret_ptr = py_return.get()) {
2641f6a57c1SMed Ismail Bennani     lldb::SBData *sb_data =
2651f6a57c1SMed Ismail Bennani         (lldb::SBData *)LLDBSWIGPython_CastPyObjectToSBData(py_ret_ptr);
2661f6a57c1SMed Ismail Bennani 
2671f6a57c1SMed Ismail Bennani     if (!sb_data)
2681f6a57c1SMed Ismail Bennani       return error_with_message(
2691f6a57c1SMed Ismail Bennani           "Couldn't cast lldb::SBData to lldb::DataExtractor.");
2701f6a57c1SMed Ismail Bennani 
2711f6a57c1SMed Ismail Bennani     return m_interpreter.GetDataExtractorFromSBData(*sb_data);
2721f6a57c1SMed Ismail Bennani   }
2731f6a57c1SMed Ismail Bennani 
2741f6a57c1SMed Ismail Bennani   return error_with_message("Returned object is null.");
2751f6a57c1SMed Ismail Bennani }
2761f6a57c1SMed Ismail Bennani 
2771f6a57c1SMed Ismail Bennani StructuredData::DictionarySP ScriptedProcessPythonInterface::GetLoadedImages() {
2781f6a57c1SMed Ismail Bennani   // TODO: Implement
2791f6a57c1SMed Ismail Bennani   return nullptr;
2801f6a57c1SMed Ismail Bennani }
2811f6a57c1SMed Ismail Bennani 
2821f6a57c1SMed Ismail Bennani lldb::pid_t ScriptedProcessPythonInterface::GetProcessID() {
2831f6a57c1SMed Ismail Bennani   size_t pid = GetGenericInteger("get_process_id");
2841f6a57c1SMed Ismail Bennani 
2851f6a57c1SMed Ismail Bennani   return (pid >= std::numeric_limits<lldb::pid_t>::max())
2861f6a57c1SMed Ismail Bennani              ? LLDB_INVALID_PROCESS_ID
2871f6a57c1SMed Ismail Bennani              : pid;
2881f6a57c1SMed Ismail Bennani }
2891f6a57c1SMed Ismail Bennani 
2901f6a57c1SMed Ismail Bennani bool ScriptedProcessPythonInterface::IsAlive() {
2911f6a57c1SMed Ismail Bennani   return GetGenericInteger("is_alive");
2921f6a57c1SMed Ismail Bennani }
2931f6a57c1SMed Ismail Bennani 
2941f6a57c1SMed Ismail Bennani #endif
295