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>(args&: exe_ctx); |
47 | StructuredDataImpl sd_impl(args_sp); |
48 | return ScriptedPythonInterface::CreatePluginObject(class_name, script_obj, |
49 | args: exe_ctx_ref_sp, args: sd_impl); |
50 | } |
51 | |
52 | StructuredData::DictionarySP ScriptedProcessPythonInterface::GetCapabilities() { |
53 | Status error; |
54 | StructuredData::DictionarySP dict = |
55 | Dispatch<StructuredData::DictionarySP>(method_name: "get_capabilities" , error); |
56 | |
57 | if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj: 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>(args: attach_info); |
68 | return GetStatusFromMethod(method_name: "attach" , args&: attach_info_sp); |
69 | } |
70 | |
71 | Status ScriptedProcessPythonInterface::Launch() { |
72 | return GetStatusFromMethod(method_name: "launch" ); |
73 | } |
74 | |
75 | Status ScriptedProcessPythonInterface::Resume() { |
76 | // When calling ScriptedProcess.Resume from lldb we should always stop. |
77 | return GetStatusFromMethod(method_name: "resume" , /*should_stop=*/args: 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 | method_name: "get_memory_region_containing_address" , error, args&: address); |
85 | |
86 | if (error.Fail()) { |
87 | return ErrorWithMessage<MemoryRegionInfo>(LLVM_PRETTY_FUNCTION, |
88 | error_msg: 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>(method_name: "get_threads_info" , error); |
98 | |
99 | if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj: 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(method_name: "create_breakpoint" , error&: py_error, args&: addr, args&: 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 | method_name: "read_memory_at_address" , error&: py_error, args&: address, args&: size, args&: 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::( |
137 | lldb::addr_t addr, lldb::DataExtractorSP data_sp, Status &error) { |
138 | Status py_error; |
139 | StructuredData::ObjectSP obj = |
140 | Dispatch(method_name: "write_memory_at_address" , error&: py_error, args&: addr, args&: data_sp, args&: 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>(method_name: "get_loaded_images" , error); |
157 | |
158 | if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj: 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(method_name: "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(method_name: "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(method_name: "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>(method_name: "get_process_metadata" , error); |
208 | |
209 | if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj: 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 | name: GetPluginNameStatic(), description: llvm::StringRef("Mock process state" ), |
229 | create_callback: CreateInstance, language: eScriptLanguagePython, usages: {ci_usages, api_usages}); |
230 | } |
231 | |
232 | void ScriptedProcessPythonInterface::Terminate() { |
233 | PluginManager::UnregisterPlugin(create_callback: CreateInstance); |
234 | } |
235 | |
236 | #endif |
237 | |