1 //===-- ScriptedProcessPythonInterface.cpp --------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "lldb/Host/Config.h"
10 #include "lldb/lldb-enumerations.h"
11 
12 #if LLDB_ENABLE_PYTHON
13 
14 // LLDB Python header must be included first
15 #include "lldb-python.h"
16 
17 #include "SWIGPythonBridge.h"
18 #include "ScriptInterpreterPythonImpl.h"
19 #include "ScriptedProcessPythonInterface.h"
20 
21 using namespace lldb;
22 using namespace lldb_private;
23 using namespace lldb_private::python;
24 using Locker = ScriptInterpreterPythonImpl::Locker;
25 
26 StructuredData::GenericSP ScriptedProcessPythonInterface::CreatePluginObject(
27     const llvm::StringRef class_name, lldb::TargetSP target_sp,
28     StructuredData::DictionarySP args_sp) {
29   if (class_name.empty())
30     return {};
31 
32   std::string error_string;
33   StructuredDataImpl *args_impl = nullptr;
34   if (args_sp) {
35     args_impl = new StructuredDataImpl();
36     args_impl->SetObjectSP(args_sp);
37   }
38 
39   void *ret_val;
40 
41   {
42 
43     Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
44                    Locker::FreeLock);
45 
46     ret_val = LLDBSwigPythonCreateScriptedProcess(
47         class_name.str().c_str(), m_interpreter.GetDictionaryName(), target_sp,
48         args_impl, error_string);
49   }
50 
51   m_object_instance_sp =
52       StructuredData::GenericSP(new StructuredPythonObject(ret_val));
53 
54   return m_object_instance_sp;
55 }
56 
57 Status ScriptedProcessPythonInterface::Launch() {
58   return LaunchOrResume("launch");
59 }
60 
61 Status ScriptedProcessPythonInterface::Resume() {
62   return LaunchOrResume("resume");
63 }
64 
65 Status
66 ScriptedProcessPythonInterface::LaunchOrResume(llvm::StringRef method_name) {
67   Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
68                  Locker::FreeLock);
69 
70   if (!m_object_instance_sp)
71     return Status("Python object ill-formed.");
72 
73   if (!m_object_instance_sp)
74     return Status("Cannot convert Python object to StructuredData::Generic.");
75   PythonObject implementor(PyRefType::Borrowed,
76                            (PyObject *)m_object_instance_sp->GetValue());
77 
78   if (!implementor.IsAllocated())
79     return Status("Python implementor not allocated.");
80 
81   PythonObject pmeth(
82       PyRefType::Owned,
83       PyObject_GetAttrString(implementor.get(), method_name.str().c_str()));
84 
85   if (PyErr_Occurred())
86     PyErr_Clear();
87 
88   if (!pmeth.IsAllocated())
89     return Status("Python method not allocated.");
90 
91   if (PyCallable_Check(pmeth.get()) == 0) {
92     if (PyErr_Occurred())
93       PyErr_Clear();
94     return Status("Python method not callable.");
95   }
96 
97   if (PyErr_Occurred())
98     PyErr_Clear();
99 
100   PythonObject py_return(PyRefType::Owned,
101                          PyObject_CallMethod(implementor.get(),
102                                              method_name.str().c_str(),
103                                              nullptr));
104 
105   if (PyErr_Occurred()) {
106     PyErr_Print();
107     PyErr_Clear();
108     return Status("Python method could not be called.");
109   }
110 
111   if (PyObject *py_ret_ptr = py_return.get()) {
112     lldb::SBError *sb_error =
113         (lldb::SBError *)LLDBSWIGPython_CastPyObjectToSBError(py_ret_ptr);
114 
115     if (!sb_error)
116       return Status("Couldn't cast lldb::SBError to lldb::Status.");
117 
118     Status status = m_interpreter.GetStatusFromSBError(*sb_error);
119 
120     if (status.Fail())
121       return Status("error: %s", status.AsCString());
122 
123     return status;
124   }
125 
126   return Status("Returned object is null.");
127 }
128 
129 size_t
130 ScriptedProcessPythonInterface::GetGenericInteger(llvm::StringRef method_name) {
131   Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
132                  Locker::FreeLock);
133 
134   if (!m_object_instance_sp)
135     return LLDB_INVALID_ADDRESS;
136 
137   if (!m_object_instance_sp)
138     return LLDB_INVALID_ADDRESS;
139   PythonObject implementor(PyRefType::Borrowed,
140                            (PyObject *)m_object_instance_sp->GetValue());
141 
142   if (!implementor.IsAllocated())
143     return LLDB_INVALID_ADDRESS;
144 
145   PythonObject pmeth(
146       PyRefType::Owned,
147       PyObject_GetAttrString(implementor.get(), method_name.str().c_str()));
148 
149   if (PyErr_Occurred())
150     PyErr_Clear();
151 
152   if (!pmeth.IsAllocated())
153     return LLDB_INVALID_ADDRESS;
154 
155   if (PyCallable_Check(pmeth.get()) == 0) {
156     if (PyErr_Occurred())
157       PyErr_Clear();
158     return LLDB_INVALID_ADDRESS;
159   }
160 
161   if (PyErr_Occurred())
162     PyErr_Clear();
163 
164   PythonObject py_return(PyRefType::Owned,
165                          PyObject_CallMethod(implementor.get(),
166                                              method_name.str().c_str(),
167                                              nullptr));
168 
169   if (PyErr_Occurred()) {
170     PyErr_Print();
171     PyErr_Clear();
172   }
173 
174   if (py_return.get()) {
175     auto size = py_return.AsUnsignedLongLong();
176     return (size) ? *size : LLDB_INVALID_ADDRESS;
177   }
178   return LLDB_INVALID_ADDRESS;
179 }
180 
181 lldb::MemoryRegionInfoSP
182 ScriptedProcessPythonInterface::GetMemoryRegionContainingAddress(
183     lldb::addr_t address) {
184   // TODO: Implement
185   return nullptr;
186 }
187 
188 StructuredData::DictionarySP
189 ScriptedProcessPythonInterface::GetThreadWithID(lldb::tid_t tid) {
190   // TODO: Implement
191   return nullptr;
192 }
193 
194 StructuredData::DictionarySP
195 ScriptedProcessPythonInterface::GetRegistersForThread(lldb::tid_t tid) {
196   // TODO: Implement
197   return nullptr;
198 }
199 
200 lldb::DataExtractorSP ScriptedProcessPythonInterface::ReadMemoryAtAddress(
201     lldb::addr_t address, size_t size, Status &error) {
202   Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
203                  Locker::FreeLock);
204 
205   auto error_with_message = [&error](llvm::StringRef message) {
206     error.SetErrorString(message);
207     return nullptr;
208   };
209 
210   static char callee_name[] = "read_memory_at_address";
211   std::string param_format = GetPythonValueFormatString(address);
212   param_format += GetPythonValueFormatString(size);
213 
214   if (!m_object_instance_sp)
215     return error_with_message("Python object ill-formed.");
216 
217   if (!m_object_instance_sp)
218     return error_with_message("Python method not callable.");
219 
220   PythonObject implementor(PyRefType::Borrowed,
221                            (PyObject *)m_object_instance_sp->GetValue());
222 
223   if (!implementor.IsAllocated())
224     return error_with_message("Python implementor not allocated.");
225 
226   PythonObject pmeth(PyRefType::Owned,
227                      PyObject_GetAttrString(implementor.get(), callee_name));
228 
229   if (PyErr_Occurred())
230     PyErr_Clear();
231 
232   if (!pmeth.IsAllocated())
233     return error_with_message("Python method not allocated.");
234 
235   if (PyCallable_Check(pmeth.get()) == 0) {
236     if (PyErr_Occurred())
237       PyErr_Clear();
238     return error_with_message("Python method not callable.");
239   }
240 
241   if (PyErr_Occurred())
242     PyErr_Clear();
243 
244   PythonObject py_return(PyRefType::Owned,
245                          PyObject_CallMethod(implementor.get(), callee_name,
246                                              param_format.c_str(), address,
247                                              size));
248 
249   if (PyErr_Occurred()) {
250     PyErr_Print();
251     PyErr_Clear();
252     return error_with_message("Python method could not be called.");
253   }
254 
255   if (PyObject *py_ret_ptr = py_return.get()) {
256     lldb::SBData *sb_data =
257         (lldb::SBData *)LLDBSWIGPython_CastPyObjectToSBData(py_ret_ptr);
258 
259     if (!sb_data)
260       return error_with_message(
261           "Couldn't cast lldb::SBData to lldb::DataExtractor.");
262 
263     return m_interpreter.GetDataExtractorFromSBData(*sb_data);
264   }
265 
266   return error_with_message("Returned object is null.");
267 }
268 
269 StructuredData::DictionarySP ScriptedProcessPythonInterface::GetLoadedImages() {
270   // TODO: Implement
271   return nullptr;
272 }
273 
274 lldb::pid_t ScriptedProcessPythonInterface::GetProcessID() {
275   size_t pid = GetGenericInteger("get_process_id");
276 
277   return (pid >= std::numeric_limits<lldb::pid_t>::max())
278              ? LLDB_INVALID_PROCESS_ID
279              : pid;
280 }
281 
282 bool ScriptedProcessPythonInterface::IsAlive() {
283   return GetGenericInteger("is_alive");
284   ;
285 }
286 
287 #endif
288