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() {
58312b43daSMed Ismail Bennani   return GetStatusFromMethod("launch");
591f6a57c1SMed Ismail Bennani }
601f6a57c1SMed Ismail Bennani 
611f6a57c1SMed Ismail Bennani Status ScriptedProcessPythonInterface::Resume() {
62312b43daSMed Ismail Bennani   return GetStatusFromMethod("resume");
631f6a57c1SMed Ismail Bennani }
641f6a57c1SMed Ismail Bennani 
65312b43daSMed Ismail Bennani bool ScriptedProcessPythonInterface::ShouldStop() {
66*3d4cadfbSMed Ismail Bennani   llvm::Optional<unsigned long long> should_stop =
67*3d4cadfbSMed Ismail Bennani       GetGenericInteger("should_stop");
68*3d4cadfbSMed Ismail Bennani 
69*3d4cadfbSMed Ismail Bennani   if (!should_stop)
70*3d4cadfbSMed Ismail Bennani     return false;
71*3d4cadfbSMed Ismail Bennani 
72*3d4cadfbSMed Ismail Bennani   return static_cast<bool>(*should_stop);
73312b43daSMed Ismail Bennani }
74312b43daSMed Ismail Bennani 
75312b43daSMed Ismail Bennani Status ScriptedProcessPythonInterface::Stop() {
76312b43daSMed Ismail Bennani   return GetStatusFromMethod("stop");
77312b43daSMed Ismail Bennani }
78312b43daSMed Ismail Bennani 
79312b43daSMed Ismail Bennani Status ScriptedProcessPythonInterface::GetStatusFromMethod(
80312b43daSMed Ismail Bennani     llvm::StringRef method_name) {
811f6a57c1SMed Ismail Bennani   Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
821f6a57c1SMed Ismail Bennani                  Locker::FreeLock);
831f6a57c1SMed Ismail Bennani 
841f6a57c1SMed Ismail Bennani   if (!m_object_instance_sp)
851f6a57c1SMed Ismail Bennani     return Status("Python object ill-formed.");
861f6a57c1SMed Ismail Bennani 
871f6a57c1SMed Ismail Bennani   if (!m_object_instance_sp)
881f6a57c1SMed Ismail Bennani     return Status("Cannot convert Python object to StructuredData::Generic.");
891f6a57c1SMed Ismail Bennani   PythonObject implementor(PyRefType::Borrowed,
901f6a57c1SMed Ismail Bennani                            (PyObject *)m_object_instance_sp->GetValue());
911f6a57c1SMed Ismail Bennani 
921f6a57c1SMed Ismail Bennani   if (!implementor.IsAllocated())
931f6a57c1SMed Ismail Bennani     return Status("Python implementor not allocated.");
941f6a57c1SMed Ismail Bennani 
951f6a57c1SMed Ismail Bennani   PythonObject pmeth(
961f6a57c1SMed Ismail Bennani       PyRefType::Owned,
971f6a57c1SMed Ismail Bennani       PyObject_GetAttrString(implementor.get(), method_name.str().c_str()));
981f6a57c1SMed Ismail Bennani 
991f6a57c1SMed Ismail Bennani   if (PyErr_Occurred())
1001f6a57c1SMed Ismail Bennani     PyErr_Clear();
1011f6a57c1SMed Ismail Bennani 
1021f6a57c1SMed Ismail Bennani   if (!pmeth.IsAllocated())
1031f6a57c1SMed Ismail Bennani     return Status("Python method not allocated.");
1041f6a57c1SMed Ismail Bennani 
1051f6a57c1SMed Ismail Bennani   if (PyCallable_Check(pmeth.get()) == 0) {
1061f6a57c1SMed Ismail Bennani     if (PyErr_Occurred())
1071f6a57c1SMed Ismail Bennani       PyErr_Clear();
1081f6a57c1SMed Ismail Bennani     return Status("Python method not callable.");
1091f6a57c1SMed Ismail Bennani   }
1101f6a57c1SMed Ismail Bennani 
1111f6a57c1SMed Ismail Bennani   if (PyErr_Occurred())
1121f6a57c1SMed Ismail Bennani     PyErr_Clear();
1131f6a57c1SMed Ismail Bennani 
1141f6a57c1SMed Ismail Bennani   PythonObject py_return(PyRefType::Owned,
1151f6a57c1SMed Ismail Bennani                          PyObject_CallMethod(implementor.get(),
1161f6a57c1SMed Ismail Bennani                                              method_name.str().c_str(),
1171f6a57c1SMed Ismail Bennani                                              nullptr));
1181f6a57c1SMed Ismail Bennani 
1191f6a57c1SMed Ismail Bennani   if (PyErr_Occurred()) {
1201f6a57c1SMed Ismail Bennani     PyErr_Print();
1211f6a57c1SMed Ismail Bennani     PyErr_Clear();
1221f6a57c1SMed Ismail Bennani     return Status("Python method could not be called.");
1231f6a57c1SMed Ismail Bennani   }
1241f6a57c1SMed Ismail Bennani 
1251f6a57c1SMed Ismail Bennani   if (PyObject *py_ret_ptr = py_return.get()) {
1261f6a57c1SMed Ismail Bennani     lldb::SBError *sb_error =
1271f6a57c1SMed Ismail Bennani         (lldb::SBError *)LLDBSWIGPython_CastPyObjectToSBError(py_ret_ptr);
1281f6a57c1SMed Ismail Bennani 
1291f6a57c1SMed Ismail Bennani     if (!sb_error)
1301f6a57c1SMed Ismail Bennani       return Status("Couldn't cast lldb::SBError to lldb::Status.");
1311f6a57c1SMed Ismail Bennani 
1321f6a57c1SMed Ismail Bennani     Status status = m_interpreter.GetStatusFromSBError(*sb_error);
1331f6a57c1SMed Ismail Bennani 
1341f6a57c1SMed Ismail Bennani     if (status.Fail())
1351f6a57c1SMed Ismail Bennani       return Status("error: %s", status.AsCString());
1361f6a57c1SMed Ismail Bennani 
1371f6a57c1SMed Ismail Bennani     return status;
1381f6a57c1SMed Ismail Bennani   }
1391f6a57c1SMed Ismail Bennani 
1401f6a57c1SMed Ismail Bennani   return Status("Returned object is null.");
1411f6a57c1SMed Ismail Bennani }
1421f6a57c1SMed Ismail Bennani 
143*3d4cadfbSMed Ismail Bennani llvm::Optional<unsigned long long>
1441f6a57c1SMed Ismail Bennani ScriptedProcessPythonInterface::GetGenericInteger(llvm::StringRef method_name) {
1451f6a57c1SMed Ismail Bennani   Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
1461f6a57c1SMed Ismail Bennani                  Locker::FreeLock);
1471f6a57c1SMed Ismail Bennani 
1481f6a57c1SMed Ismail Bennani   if (!m_object_instance_sp)
149*3d4cadfbSMed Ismail Bennani     return llvm::None;
1501f6a57c1SMed Ismail Bennani 
1511f6a57c1SMed Ismail Bennani   if (!m_object_instance_sp)
152*3d4cadfbSMed Ismail Bennani     return llvm::None;
1531f6a57c1SMed Ismail Bennani   PythonObject implementor(PyRefType::Borrowed,
1541f6a57c1SMed Ismail Bennani                            (PyObject *)m_object_instance_sp->GetValue());
1551f6a57c1SMed Ismail Bennani 
1561f6a57c1SMed Ismail Bennani   if (!implementor.IsAllocated())
157*3d4cadfbSMed Ismail Bennani     return llvm::None;
1581f6a57c1SMed Ismail Bennani 
1591f6a57c1SMed Ismail Bennani   PythonObject pmeth(
1601f6a57c1SMed Ismail Bennani       PyRefType::Owned,
1611f6a57c1SMed Ismail Bennani       PyObject_GetAttrString(implementor.get(), method_name.str().c_str()));
1621f6a57c1SMed Ismail Bennani 
1631f6a57c1SMed Ismail Bennani   if (PyErr_Occurred())
1641f6a57c1SMed Ismail Bennani     PyErr_Clear();
1651f6a57c1SMed Ismail Bennani 
1661f6a57c1SMed Ismail Bennani   if (!pmeth.IsAllocated())
167*3d4cadfbSMed Ismail Bennani     return llvm::None;
1681f6a57c1SMed Ismail Bennani 
1691f6a57c1SMed Ismail Bennani   if (PyCallable_Check(pmeth.get()) == 0) {
1701f6a57c1SMed Ismail Bennani     if (PyErr_Occurred())
1711f6a57c1SMed Ismail Bennani       PyErr_Clear();
172*3d4cadfbSMed Ismail Bennani     return llvm::None;
1731f6a57c1SMed Ismail Bennani   }
1741f6a57c1SMed Ismail Bennani 
1751f6a57c1SMed Ismail Bennani   if (PyErr_Occurred())
1761f6a57c1SMed Ismail Bennani     PyErr_Clear();
1771f6a57c1SMed Ismail Bennani 
1781f6a57c1SMed Ismail Bennani   PythonObject py_return(PyRefType::Owned,
1791f6a57c1SMed Ismail Bennani                          PyObject_CallMethod(implementor.get(),
1801f6a57c1SMed Ismail Bennani                                              method_name.str().c_str(),
1811f6a57c1SMed Ismail Bennani                                              nullptr));
1821f6a57c1SMed Ismail Bennani 
1831f6a57c1SMed Ismail Bennani   if (PyErr_Occurred()) {
1841f6a57c1SMed Ismail Bennani     PyErr_Print();
1851f6a57c1SMed Ismail Bennani     PyErr_Clear();
1861f6a57c1SMed Ismail Bennani   }
1871f6a57c1SMed Ismail Bennani 
188*3d4cadfbSMed Ismail Bennani   if (!py_return.get())
189*3d4cadfbSMed Ismail Bennani     return llvm::None;
190*3d4cadfbSMed Ismail Bennani 
191*3d4cadfbSMed Ismail Bennani   llvm::Expected<unsigned long long> size = py_return.AsUnsignedLongLong();
192*3d4cadfbSMed Ismail Bennani   // FIXME: Handle error.
193*3d4cadfbSMed Ismail Bennani   if (!size)
194*3d4cadfbSMed Ismail Bennani     return llvm::None;
195*3d4cadfbSMed Ismail Bennani 
196*3d4cadfbSMed Ismail Bennani   return *size;
1971f6a57c1SMed Ismail Bennani }
1981f6a57c1SMed Ismail Bennani 
1991f6a57c1SMed Ismail Bennani lldb::MemoryRegionInfoSP
2001f6a57c1SMed Ismail Bennani ScriptedProcessPythonInterface::GetMemoryRegionContainingAddress(
2011f6a57c1SMed Ismail Bennani     lldb::addr_t address) {
2021f6a57c1SMed Ismail Bennani   // TODO: Implement
2031f6a57c1SMed Ismail Bennani   return nullptr;
2041f6a57c1SMed Ismail Bennani }
2051f6a57c1SMed Ismail Bennani 
2061f6a57c1SMed Ismail Bennani StructuredData::DictionarySP
2071f6a57c1SMed Ismail Bennani ScriptedProcessPythonInterface::GetThreadWithID(lldb::tid_t tid) {
2081f6a57c1SMed Ismail Bennani   // TODO: Implement
2091f6a57c1SMed Ismail Bennani   return nullptr;
2101f6a57c1SMed Ismail Bennani }
2111f6a57c1SMed Ismail Bennani 
2121f6a57c1SMed Ismail Bennani StructuredData::DictionarySP
2131f6a57c1SMed Ismail Bennani ScriptedProcessPythonInterface::GetRegistersForThread(lldb::tid_t tid) {
2141f6a57c1SMed Ismail Bennani   // TODO: Implement
2151f6a57c1SMed Ismail Bennani   return nullptr;
2161f6a57c1SMed Ismail Bennani }
2171f6a57c1SMed Ismail Bennani 
2181f6a57c1SMed Ismail Bennani lldb::DataExtractorSP ScriptedProcessPythonInterface::ReadMemoryAtAddress(
2191f6a57c1SMed Ismail Bennani     lldb::addr_t address, size_t size, Status &error) {
2201f6a57c1SMed Ismail Bennani   Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
2211f6a57c1SMed Ismail Bennani                  Locker::FreeLock);
2221f6a57c1SMed Ismail Bennani 
2231f6a57c1SMed Ismail Bennani   auto error_with_message = [&error](llvm::StringRef message) {
2241f6a57c1SMed Ismail Bennani     error.SetErrorString(message);
2251f6a57c1SMed Ismail Bennani     return nullptr;
2261f6a57c1SMed Ismail Bennani   };
2271f6a57c1SMed Ismail Bennani 
2281f6a57c1SMed Ismail Bennani   static char callee_name[] = "read_memory_at_address";
2291f6a57c1SMed Ismail Bennani   std::string param_format = GetPythonValueFormatString(address);
2301f6a57c1SMed Ismail Bennani   param_format += GetPythonValueFormatString(size);
2311f6a57c1SMed Ismail Bennani 
2321f6a57c1SMed Ismail Bennani   if (!m_object_instance_sp)
2331f6a57c1SMed Ismail Bennani     return error_with_message("Python object ill-formed.");
2341f6a57c1SMed Ismail Bennani 
2351f6a57c1SMed Ismail Bennani   if (!m_object_instance_sp)
2361f6a57c1SMed Ismail Bennani     return error_with_message("Python method not callable.");
2371f6a57c1SMed Ismail Bennani 
2381f6a57c1SMed Ismail Bennani   PythonObject implementor(PyRefType::Borrowed,
2391f6a57c1SMed Ismail Bennani                            (PyObject *)m_object_instance_sp->GetValue());
2401f6a57c1SMed Ismail Bennani 
2411f6a57c1SMed Ismail Bennani   if (!implementor.IsAllocated())
2421f6a57c1SMed Ismail Bennani     return error_with_message("Python implementor not allocated.");
2431f6a57c1SMed Ismail Bennani 
2441f6a57c1SMed Ismail Bennani   PythonObject pmeth(PyRefType::Owned,
2451f6a57c1SMed Ismail Bennani                      PyObject_GetAttrString(implementor.get(), callee_name));
2461f6a57c1SMed Ismail Bennani 
2471f6a57c1SMed Ismail Bennani   if (PyErr_Occurred())
2481f6a57c1SMed Ismail Bennani     PyErr_Clear();
2491f6a57c1SMed Ismail Bennani 
2501f6a57c1SMed Ismail Bennani   if (!pmeth.IsAllocated())
2511f6a57c1SMed Ismail Bennani     return error_with_message("Python method not allocated.");
2521f6a57c1SMed Ismail Bennani 
2531f6a57c1SMed Ismail Bennani   if (PyCallable_Check(pmeth.get()) == 0) {
2541f6a57c1SMed Ismail Bennani     if (PyErr_Occurred())
2551f6a57c1SMed Ismail Bennani       PyErr_Clear();
2561f6a57c1SMed Ismail Bennani     return error_with_message("Python method not callable.");
2571f6a57c1SMed Ismail Bennani   }
2581f6a57c1SMed Ismail Bennani 
2591f6a57c1SMed Ismail Bennani   if (PyErr_Occurred())
2601f6a57c1SMed Ismail Bennani     PyErr_Clear();
2611f6a57c1SMed Ismail Bennani 
2621f6a57c1SMed Ismail Bennani   PythonObject py_return(PyRefType::Owned,
2631f6a57c1SMed Ismail Bennani                          PyObject_CallMethod(implementor.get(), callee_name,
2641f6a57c1SMed Ismail Bennani                                              param_format.c_str(), address,
2651f6a57c1SMed Ismail Bennani                                              size));
2661f6a57c1SMed Ismail Bennani 
2671f6a57c1SMed Ismail Bennani   if (PyErr_Occurred()) {
2681f6a57c1SMed Ismail Bennani     PyErr_Print();
2691f6a57c1SMed Ismail Bennani     PyErr_Clear();
2701f6a57c1SMed Ismail Bennani     return error_with_message("Python method could not be called.");
2711f6a57c1SMed Ismail Bennani   }
2721f6a57c1SMed Ismail Bennani 
2731f6a57c1SMed Ismail Bennani   if (PyObject *py_ret_ptr = py_return.get()) {
2741f6a57c1SMed Ismail Bennani     lldb::SBData *sb_data =
2751f6a57c1SMed Ismail Bennani         (lldb::SBData *)LLDBSWIGPython_CastPyObjectToSBData(py_ret_ptr);
2761f6a57c1SMed Ismail Bennani 
2771f6a57c1SMed Ismail Bennani     if (!sb_data)
2781f6a57c1SMed Ismail Bennani       return error_with_message(
2791f6a57c1SMed Ismail Bennani           "Couldn't cast lldb::SBData to lldb::DataExtractor.");
2801f6a57c1SMed Ismail Bennani 
2811f6a57c1SMed Ismail Bennani     return m_interpreter.GetDataExtractorFromSBData(*sb_data);
2821f6a57c1SMed Ismail Bennani   }
2831f6a57c1SMed Ismail Bennani 
2841f6a57c1SMed Ismail Bennani   return error_with_message("Returned object is null.");
2851f6a57c1SMed Ismail Bennani }
2861f6a57c1SMed Ismail Bennani 
2871f6a57c1SMed Ismail Bennani StructuredData::DictionarySP ScriptedProcessPythonInterface::GetLoadedImages() {
2881f6a57c1SMed Ismail Bennani   // TODO: Implement
2891f6a57c1SMed Ismail Bennani   return nullptr;
2901f6a57c1SMed Ismail Bennani }
2911f6a57c1SMed Ismail Bennani 
2921f6a57c1SMed Ismail Bennani lldb::pid_t ScriptedProcessPythonInterface::GetProcessID() {
293*3d4cadfbSMed Ismail Bennani   llvm::Optional<unsigned long long> pid = GetGenericInteger("get_process_id");
294*3d4cadfbSMed Ismail Bennani   return (!pid) ? LLDB_INVALID_PROCESS_ID : *pid;
2951f6a57c1SMed Ismail Bennani }
2961f6a57c1SMed Ismail Bennani 
2971f6a57c1SMed Ismail Bennani bool ScriptedProcessPythonInterface::IsAlive() {
298*3d4cadfbSMed Ismail Bennani   llvm::Optional<unsigned long long> is_alive = GetGenericInteger("is_alive");
299*3d4cadfbSMed Ismail Bennani 
300*3d4cadfbSMed Ismail Bennani   if (!is_alive)
301*3d4cadfbSMed Ismail Bennani     return false;
302*3d4cadfbSMed Ismail Bennani 
303*3d4cadfbSMed Ismail Bennani   return static_cast<bool>(*is_alive);
3041f6a57c1SMed Ismail Bennani }
3051f6a57c1SMed Ismail Bennani 
3061f6a57c1SMed Ismail Bennani #endif
307