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/Core/PluginManager.h"
10 #include "lldb/Host/Config.h"
11 #include "lldb/Utility/Log.h"
12 #include "lldb/Utility/Status.h"
13 #include "lldb/lldb-enumerations.h"
14 
15 #if LLDB_ENABLE_PYTHON
16 
17 // clang-format off
18 // LLDB Python header must be included first
19 #include "../lldb-python.h"
20 
21 #include "../SWIGPythonBridge.h"
22 #include "../ScriptInterpreterPythonImpl.h"
23 #include "ScriptedThreadPythonInterface.h"
24 #include "ScriptedProcessPythonInterface.h"
25 
26 // Included in this position to prevent redefinition of pid_t on Windows.
27 #include "lldb/Target/Process.h"
28 //clang-format off
29 
30 #include <optional>
31 
32 using namespace lldb;
33 using namespace lldb_private;
34 using namespace lldb_private::python;
35 using Locker = ScriptInterpreterPythonImpl::Locker;
36 
37 ScriptedProcessPythonInterface::ScriptedProcessPythonInterface(
38     ScriptInterpreterPythonImpl &interpreter)
39     : ScriptedProcessInterface(), ScriptedPythonInterface(interpreter) {}
40 
41 llvm::Expected<StructuredData::GenericSP>
42 ScriptedProcessPythonInterface::CreatePluginObject(
43     llvm::StringRef class_name, ExecutionContext &exe_ctx,
44     StructuredData::DictionarySP args_sp, StructuredData::Generic *script_obj) {
45   ExecutionContextRefSP exe_ctx_ref_sp =
46       std::make_shared<ExecutionContextRef>(exe_ctx);
47   StructuredDataImpl sd_impl(args_sp);
48   return ScriptedPythonInterface::CreatePluginObject(class_name, script_obj,
49                                                      exe_ctx_ref_sp, sd_impl);
50 }
51 
52 StructuredData::DictionarySP ScriptedProcessPythonInterface::GetCapabilities() {
53   Status error;
54   StructuredData::DictionarySP dict =
55       Dispatch<StructuredData::DictionarySP>("get_capabilities", error);
56 
57   if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, dict,
58                                                     error))
59     return {};
60 
61   return dict;
62 }
63 
64 Status
65 ScriptedProcessPythonInterface::Attach(const ProcessAttachInfo &attach_info) {
66   lldb::ProcessAttachInfoSP attach_info_sp =
67       std::make_shared<ProcessAttachInfo>(attach_info);
68   return GetStatusFromMethod("attach", attach_info_sp);
69 }
70 
71 Status ScriptedProcessPythonInterface::Launch() {
72   return GetStatusFromMethod("launch");
73 }
74 
75 Status ScriptedProcessPythonInterface::Resume() {
76   // When calling ScriptedProcess.Resume from lldb we should always stop.
77   return GetStatusFromMethod("resume", /*should_stop=*/true);
78 }
79 
80 std::optional<MemoryRegionInfo>
81 ScriptedProcessPythonInterface::GetMemoryRegionContainingAddress(
82     lldb::addr_t address, Status &error) {
83   auto mem_region = Dispatch<std::optional<MemoryRegionInfo>>(
84       "get_memory_region_containing_address", error, address);
85 
86   if (error.Fail()) {
87     return ErrorWithMessage<MemoryRegionInfo>(LLVM_PRETTY_FUNCTION,
88                                               error.AsCString(), error);
89   }
90 
91   return mem_region;
92 }
93 
94 StructuredData::DictionarySP ScriptedProcessPythonInterface::GetThreadsInfo() {
95   Status error;
96   StructuredData::DictionarySP dict =
97       Dispatch<StructuredData::DictionarySP>("get_threads_info", error);
98 
99   if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, dict,
100                                                     error))
101     return {};
102 
103   return dict;
104 }
105 
106 bool ScriptedProcessPythonInterface::CreateBreakpoint(lldb::addr_t addr,
107                                                       Status &error) {
108   Status py_error;
109   StructuredData::ObjectSP obj =
110       Dispatch("create_breakpoint", py_error, addr, error);
111 
112   // If there was an error on the python call, surface it to the user.
113   if (py_error.Fail())
114     error = std::move(py_error);
115 
116   if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
117                                                     error))
118     return {};
119 
120   return obj->GetBooleanValue();
121 }
122 
123 lldb::DataExtractorSP ScriptedProcessPythonInterface::ReadMemoryAtAddress(
124     lldb::addr_t address, size_t size, Status &error) {
125   Status py_error;
126   lldb::DataExtractorSP data_sp = Dispatch<lldb::DataExtractorSP>(
127       "read_memory_at_address", py_error, address, size, error);
128 
129   // If there was an error on the python call, surface it to the user.
130   if (py_error.Fail())
131     error = std::move(py_error);
132 
133   return data_sp;
134 }
135 
136 lldb::offset_t ScriptedProcessPythonInterface::WriteMemoryAtAddress(
137     lldb::addr_t addr, lldb::DataExtractorSP data_sp, Status &error) {
138   Status py_error;
139   StructuredData::ObjectSP obj =
140       Dispatch("write_memory_at_address", py_error, addr, data_sp, error);
141 
142   if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
143                                                     error))
144     return LLDB_INVALID_OFFSET;
145 
146   // If there was an error on the python call, surface it to the user.
147   if (py_error.Fail())
148     error = std::move(py_error);
149 
150   return obj->GetUnsignedIntegerValue(LLDB_INVALID_OFFSET);
151 }
152 
153 StructuredData::ArraySP ScriptedProcessPythonInterface::GetLoadedImages() {
154   Status error;
155   StructuredData::ArraySP array =
156       Dispatch<StructuredData::ArraySP>("get_loaded_images", error);
157 
158   if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, array,
159                                                     error))
160     return {};
161 
162   return array;
163 }
164 
165 lldb::pid_t ScriptedProcessPythonInterface::GetProcessID() {
166   Status error;
167   StructuredData::ObjectSP obj = Dispatch("get_process_id", error);
168 
169   if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
170                                                     error))
171     return LLDB_INVALID_PROCESS_ID;
172 
173   return obj->GetUnsignedIntegerValue(LLDB_INVALID_PROCESS_ID);
174 }
175 
176 bool ScriptedProcessPythonInterface::IsAlive() {
177   Status error;
178   StructuredData::ObjectSP obj = Dispatch("is_alive", error);
179 
180   if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
181                                                     error))
182     return {};
183 
184   return obj->GetBooleanValue();
185 }
186 
187 std::optional<std::string>
188 ScriptedProcessPythonInterface::GetScriptedThreadPluginName() {
189   Status error;
190   StructuredData::ObjectSP obj = Dispatch("get_scripted_thread_plugin", error);
191 
192   if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
193                                                     error))
194     return {};
195 
196   return obj->GetStringValue().str();
197 }
198 
199 lldb::ScriptedThreadInterfaceSP
200 ScriptedProcessPythonInterface::CreateScriptedThreadInterface() {
201   return m_interpreter.CreateScriptedThreadInterface();
202 }
203 
204 StructuredData::DictionarySP ScriptedProcessPythonInterface::GetMetadata() {
205   Status error;
206   StructuredData::DictionarySP dict =
207       Dispatch<StructuredData::DictionarySP>("get_process_metadata", error);
208 
209   if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, dict,
210                                                     error))
211     return {};
212 
213   return dict;
214 }
215 
216 void ScriptedProcessPythonInterface::Initialize() {
217   const std::vector<llvm::StringRef> ci_usages = {
218       "process attach -C <script-name> [-k key -v value ...]",
219       "process launch -C <script-name> [-k key -v value ...]"};
220   const std::vector<llvm::StringRef> api_usages = {
221       "SBAttachInfo.SetScriptedProcessClassName",
222       "SBAttachInfo.SetScriptedProcessDictionary",
223       "SBTarget.Attach",
224       "SBLaunchInfo.SetScriptedProcessClassName",
225       "SBLaunchInfo.SetScriptedProcessDictionary",
226       "SBTarget.Launch"};
227   PluginManager::RegisterPlugin(
228       GetPluginNameStatic(), llvm::StringRef("Mock process state"),
229       CreateInstance, eScriptLanguagePython, {ci_usages, api_usages});
230 }
231 
232 void ScriptedProcessPythonInterface::Terminate() {
233   PluginManager::UnregisterPlugin(CreateInstance);
234 }
235 
236 #endif
237