/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- OperatingSystemPython.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 | | |
11 | | #if LLDB_ENABLE_PYTHON |
12 | | |
13 | | #include "OperatingSystemPython.h" |
14 | | |
15 | | #include "Plugins/Process/Utility/RegisterContextDummy.h" |
16 | | #include "Plugins/Process/Utility/RegisterContextMemory.h" |
17 | | #include "Plugins/Process/Utility/ThreadMemory.h" |
18 | | #include "lldb/Core/Debugger.h" |
19 | | #include "lldb/Core/Module.h" |
20 | | #include "lldb/Core/PluginManager.h" |
21 | | #include "lldb/Core/ValueObjectVariable.h" |
22 | | #include "lldb/Interpreter/CommandInterpreter.h" |
23 | | #include "lldb/Interpreter/ScriptInterpreter.h" |
24 | | #include "lldb/Symbol/ObjectFile.h" |
25 | | #include "lldb/Symbol/VariableList.h" |
26 | | #include "lldb/Target/Process.h" |
27 | | #include "lldb/Target/StopInfo.h" |
28 | | #include "lldb/Target/Target.h" |
29 | | #include "lldb/Target/Thread.h" |
30 | | #include "lldb/Target/ThreadList.h" |
31 | | #include "lldb/Utility/DataBufferHeap.h" |
32 | | #include "lldb/Utility/LLDBLog.h" |
33 | | #include "lldb/Utility/RegisterValue.h" |
34 | | #include "lldb/Utility/StreamString.h" |
35 | | #include "lldb/Utility/StructuredData.h" |
36 | | |
37 | | #include <memory> |
38 | | |
39 | | using namespace lldb; |
40 | | using namespace lldb_private; |
41 | | |
42 | | LLDB_PLUGIN_DEFINE(OperatingSystemPython) |
43 | | |
44 | 3.92k | void OperatingSystemPython::Initialize() { |
45 | 3.92k | PluginManager::RegisterPlugin(GetPluginNameStatic(), |
46 | 3.92k | GetPluginDescriptionStatic(), CreateInstance, |
47 | 3.92k | nullptr); |
48 | 3.92k | } |
49 | | |
50 | 3.92k | void OperatingSystemPython::Terminate() { |
51 | 3.92k | PluginManager::UnregisterPlugin(CreateInstance); |
52 | 3.92k | } |
53 | | |
54 | | OperatingSystem *OperatingSystemPython::CreateInstance(Process *process, |
55 | 11.6k | bool force) { |
56 | | // Python OperatingSystem plug-ins must be requested by name, so force must |
57 | | // be true |
58 | 11.6k | FileSpec python_os_plugin_spec(process->GetPythonOSPluginPath()); |
59 | 11.6k | if (python_os_plugin_spec && |
60 | 11.6k | FileSystem::Instance().Exists(python_os_plugin_spec)8 ) { |
61 | 8 | std::unique_ptr<OperatingSystemPython> os_up( |
62 | 8 | new OperatingSystemPython(process, python_os_plugin_spec)); |
63 | 8 | if (os_up.get() && os_up->IsValid()) |
64 | 8 | return os_up.release(); |
65 | 8 | } |
66 | 11.6k | return nullptr; |
67 | 11.6k | } |
68 | | |
69 | 3.92k | llvm::StringRef OperatingSystemPython::GetPluginDescriptionStatic() { |
70 | 3.92k | return "Operating system plug-in that gathers OS information from a python " |
71 | 3.92k | "class that implements the necessary OperatingSystem functionality."; |
72 | 3.92k | } |
73 | | |
74 | | OperatingSystemPython::OperatingSystemPython(lldb_private::Process *process, |
75 | | const FileSpec &python_module_path) |
76 | 8 | : OperatingSystem(process), m_thread_list_valobj_sp(), m_register_info_up(), |
77 | 8 | m_interpreter(nullptr), m_python_object_sp() { |
78 | 8 | if (!process) |
79 | 0 | return; |
80 | 8 | TargetSP target_sp = process->CalculateTarget(); |
81 | 8 | if (!target_sp) |
82 | 0 | return; |
83 | 8 | m_interpreter = target_sp->GetDebugger().GetScriptInterpreter(); |
84 | 8 | if (m_interpreter) { |
85 | | |
86 | 8 | std::string os_plugin_class_name( |
87 | 8 | python_module_path.GetFilename().AsCString("")); |
88 | 8 | if (!os_plugin_class_name.empty()) { |
89 | 8 | LoadScriptOptions options; |
90 | 8 | char python_module_path_cstr[PATH_MAX]; |
91 | 8 | python_module_path.GetPath(python_module_path_cstr, |
92 | 8 | sizeof(python_module_path_cstr)); |
93 | 8 | Status error; |
94 | 8 | if (m_interpreter->LoadScriptingModule(python_module_path_cstr, options, |
95 | 8 | error)) { |
96 | | // Strip the ".py" extension if there is one |
97 | 8 | size_t py_extension_pos = os_plugin_class_name.rfind(".py"); |
98 | 8 | if (py_extension_pos != std::string::npos) |
99 | 8 | os_plugin_class_name.erase(py_extension_pos); |
100 | | // Add ".OperatingSystemPlugIn" to the module name to get a string like |
101 | | // "modulename.OperatingSystemPlugIn" |
102 | 8 | os_plugin_class_name += ".OperatingSystemPlugIn"; |
103 | 8 | StructuredData::ObjectSP object_sp = |
104 | 8 | m_interpreter->OSPlugin_CreatePluginObject( |
105 | 8 | os_plugin_class_name.c_str(), process->CalculateProcess()); |
106 | 8 | if (object_sp && object_sp->IsValid()) |
107 | 8 | m_python_object_sp = object_sp; |
108 | 8 | } |
109 | 8 | } |
110 | 8 | } |
111 | 8 | } |
112 | | |
113 | 8 | OperatingSystemPython::~OperatingSystemPython() = default; |
114 | | |
115 | 3 | DynamicRegisterInfo *OperatingSystemPython::GetDynamicRegisterInfo() { |
116 | 3 | if (m_register_info_up == nullptr) { |
117 | 1 | if (!m_interpreter || !m_python_object_sp) |
118 | 0 | return nullptr; |
119 | 1 | Log *log = GetLog(LLDBLog::OS); |
120 | | |
121 | 1 | LLDB_LOGF(log, |
122 | 1 | "OperatingSystemPython::GetDynamicRegisterInfo() fetching " |
123 | 1 | "thread register definitions from python for pid %" PRIu64, |
124 | 1 | m_process->GetID()); |
125 | | |
126 | 1 | StructuredData::DictionarySP dictionary = |
127 | 1 | m_interpreter->OSPlugin_RegisterInfo(m_python_object_sp); |
128 | 1 | if (!dictionary) |
129 | 0 | return nullptr; |
130 | | |
131 | 1 | m_register_info_up = DynamicRegisterInfo::Create( |
132 | 1 | *dictionary, m_process->GetTarget().GetArchitecture()); |
133 | 1 | assert(m_register_info_up); |
134 | 1 | assert(m_register_info_up->GetNumRegisters() > 0); |
135 | 1 | assert(m_register_info_up->GetNumRegisterSets() > 0); |
136 | 1 | } |
137 | 3 | return m_register_info_up.get(); |
138 | 3 | } |
139 | | |
140 | | bool OperatingSystemPython::UpdateThreadList(ThreadList &old_thread_list, |
141 | | ThreadList &core_thread_list, |
142 | 16 | ThreadList &new_thread_list) { |
143 | 16 | if (!m_interpreter || !m_python_object_sp) |
144 | 0 | return false; |
145 | | |
146 | 16 | Log *log = GetLog(LLDBLog::OS); |
147 | | |
148 | | // First thing we have to do is to try to get the API lock, and the |
149 | | // interpreter lock. We're going to change the thread content of the process, |
150 | | // and we're going to use python, which requires the API lock to do it. We |
151 | | // need the interpreter lock to make sure thread_info_dict stays alive. |
152 | | // |
153 | | // If someone already has the API lock, that is ok, we just want to avoid |
154 | | // external code from making new API calls while this call is happening. |
155 | | // |
156 | | // This is a recursive lock so we can grant it to any Python code called on |
157 | | // the stack below us. |
158 | 16 | Target &target = m_process->GetTarget(); |
159 | 16 | std::unique_lock<std::recursive_mutex> api_lock(target.GetAPIMutex(), |
160 | 16 | std::defer_lock); |
161 | 16 | (void)api_lock.try_lock(); // See above. |
162 | 16 | auto interpreter_lock = m_interpreter->AcquireInterpreterLock(); |
163 | | |
164 | 16 | LLDB_LOGF(log, |
165 | 16 | "OperatingSystemPython::UpdateThreadList() fetching thread " |
166 | 16 | "data from python for pid %" PRIu64, |
167 | 16 | m_process->GetID()); |
168 | | |
169 | | // The threads that are in "core_thread_list" upon entry are the threads from |
170 | | // the lldb_private::Process subclass, no memory threads will be in this |
171 | | // list. |
172 | 16 | StructuredData::ArraySP threads_list = |
173 | 16 | m_interpreter->OSPlugin_ThreadsInfo(m_python_object_sp); |
174 | | |
175 | 16 | const uint32_t num_cores = core_thread_list.GetSize(false); |
176 | | |
177 | | // Make a map so we can keep track of which cores were used from the |
178 | | // core_thread list. Any real threads/cores that weren't used should later be |
179 | | // put back into the "new_thread_list". |
180 | 16 | std::vector<bool> core_used_map(num_cores, false); |
181 | 16 | if (threads_list) { |
182 | 16 | if (log) { |
183 | 0 | StreamString strm; |
184 | 0 | threads_list->Dump(strm); |
185 | 0 | LLDB_LOGF(log, "threads_list = %s", strm.GetData()); |
186 | 0 | } |
187 | | |
188 | 16 | const uint32_t num_threads = threads_list->GetSize(); |
189 | 40 | for (uint32_t i = 0; i < num_threads; ++i24 ) { |
190 | 24 | StructuredData::ObjectSP thread_dict_obj = |
191 | 24 | threads_list->GetItemAtIndex(i); |
192 | 24 | if (auto thread_dict = thread_dict_obj->GetAsDictionary()) { |
193 | 24 | ThreadSP thread_sp(CreateThreadFromThreadInfo( |
194 | 24 | *thread_dict, core_thread_list, old_thread_list, core_used_map, |
195 | 24 | nullptr)); |
196 | 24 | if (thread_sp) |
197 | 24 | new_thread_list.AddThread(thread_sp); |
198 | 24 | } |
199 | 24 | } |
200 | 16 | } |
201 | | |
202 | | // Any real core threads that didn't end up backing a memory thread should |
203 | | // still be in the main thread list, and they should be inserted at the |
204 | | // beginning of the list |
205 | 16 | uint32_t insert_idx = 0; |
206 | 43 | for (uint32_t core_idx = 0; core_idx < num_cores; ++core_idx27 ) { |
207 | 27 | if (!core_used_map[core_idx]) { |
208 | 14 | new_thread_list.InsertThread( |
209 | 14 | core_thread_list.GetThreadAtIndex(core_idx, false), insert_idx); |
210 | 14 | ++insert_idx; |
211 | 14 | } |
212 | 27 | } |
213 | | |
214 | 16 | return new_thread_list.GetSize(false) > 0; |
215 | 16 | } |
216 | | |
217 | | ThreadSP OperatingSystemPython::CreateThreadFromThreadInfo( |
218 | | StructuredData::Dictionary &thread_dict, ThreadList &core_thread_list, |
219 | | ThreadList &old_thread_list, std::vector<bool> &core_used_map, |
220 | 24 | bool *did_create_ptr) { |
221 | 24 | ThreadSP thread_sp; |
222 | 24 | tid_t tid = LLDB_INVALID_THREAD_ID; |
223 | 24 | if (!thread_dict.GetValueForKeyAsInteger("tid", tid)) |
224 | 0 | return ThreadSP(); |
225 | | |
226 | 24 | uint32_t core_number; |
227 | 24 | addr_t reg_data_addr; |
228 | 24 | llvm::StringRef name; |
229 | 24 | llvm::StringRef queue; |
230 | | |
231 | 24 | thread_dict.GetValueForKeyAsInteger("core", core_number, UINT32_MAX); |
232 | 24 | thread_dict.GetValueForKeyAsInteger("register_data_addr", reg_data_addr, |
233 | 24 | LLDB_INVALID_ADDRESS); |
234 | 24 | thread_dict.GetValueForKeyAsString("name", name); |
235 | 24 | thread_dict.GetValueForKeyAsString("queue", queue); |
236 | | |
237 | | // See if a thread already exists for "tid" |
238 | 24 | thread_sp = old_thread_list.FindThreadByID(tid, false); |
239 | 24 | if (thread_sp) { |
240 | | // A thread already does exist for "tid", make sure it was an operating |
241 | | // system |
242 | | // plug-in generated thread. |
243 | 6 | if (!IsOperatingSystemPluginThread(thread_sp)) { |
244 | | // We have thread ID overlap between the protocol threads and the |
245 | | // operating system threads, clear the thread so we create an operating |
246 | | // system thread for this. |
247 | 0 | thread_sp.reset(); |
248 | 0 | } |
249 | 6 | } |
250 | | |
251 | 24 | if (!thread_sp) { |
252 | 18 | if (did_create_ptr) |
253 | 0 | *did_create_ptr = true; |
254 | 18 | thread_sp = std::make_shared<ThreadMemory>(*m_process, tid, name, queue, |
255 | 18 | reg_data_addr); |
256 | 18 | } |
257 | | |
258 | 24 | if (core_number < core_thread_list.GetSize(false)) { |
259 | 13 | ThreadSP core_thread_sp( |
260 | 13 | core_thread_list.GetThreadAtIndex(core_number, false)); |
261 | 13 | if (core_thread_sp) { |
262 | | // Keep track of which cores were set as the backing thread for memory |
263 | | // threads... |
264 | 13 | if (core_number < core_used_map.size()) |
265 | 13 | core_used_map[core_number] = true; |
266 | | |
267 | 13 | ThreadSP backing_core_thread_sp(core_thread_sp->GetBackingThread()); |
268 | 13 | if (backing_core_thread_sp) { |
269 | 0 | thread_sp->SetBackingThread(backing_core_thread_sp); |
270 | 13 | } else { |
271 | 13 | thread_sp->SetBackingThread(core_thread_sp); |
272 | 13 | } |
273 | 13 | } |
274 | 13 | } |
275 | 24 | return thread_sp; |
276 | 24 | } |
277 | | |
278 | 0 | void OperatingSystemPython::ThreadWasSelected(Thread *thread) {} |
279 | | |
280 | | RegisterContextSP |
281 | | OperatingSystemPython::CreateRegisterContextForThread(Thread *thread, |
282 | 6 | addr_t reg_data_addr) { |
283 | 6 | RegisterContextSP reg_ctx_sp; |
284 | 6 | if (!m_interpreter || !m_python_object_sp || !thread) |
285 | 0 | return reg_ctx_sp; |
286 | | |
287 | 6 | if (!IsOperatingSystemPluginThread(thread->shared_from_this())) |
288 | 0 | return reg_ctx_sp; |
289 | | |
290 | | // First thing we have to do is to try to get the API lock, and the |
291 | | // interpreter lock. We're going to change the thread content of the process, |
292 | | // and we're going to use python, which requires the API lock to do it. We |
293 | | // need the interpreter lock to make sure thread_info_dict stays alive. |
294 | | // |
295 | | // If someone already has the API lock, that is ok, we just want to avoid |
296 | | // external code from making new API calls while this call is happening. |
297 | | // |
298 | | // This is a recursive lock so we can grant it to any Python code called on |
299 | | // the stack below us. |
300 | 6 | Target &target = m_process->GetTarget(); |
301 | 6 | std::unique_lock<std::recursive_mutex> api_lock(target.GetAPIMutex(), |
302 | 6 | std::defer_lock); |
303 | 6 | (void)api_lock.try_lock(); // See above. |
304 | 6 | auto interpreter_lock = m_interpreter->AcquireInterpreterLock(); |
305 | | |
306 | 6 | Log *log = GetLog(LLDBLog::Thread); |
307 | | |
308 | 6 | if (reg_data_addr != LLDB_INVALID_ADDRESS) { |
309 | | // The registers data is in contiguous memory, just create the register |
310 | | // context using the address provided |
311 | 0 | LLDB_LOGF(log, |
312 | 0 | "OperatingSystemPython::CreateRegisterContextForThread (tid " |
313 | 0 | "= 0x%" PRIx64 ", 0x%" PRIx64 ", reg_data_addr = 0x%" PRIx64 |
314 | 0 | ") creating memory register context", |
315 | 0 | thread->GetID(), thread->GetProtocolID(), reg_data_addr); |
316 | 0 | reg_ctx_sp = std::make_shared<RegisterContextMemory>( |
317 | 0 | *thread, 0, *GetDynamicRegisterInfo(), reg_data_addr); |
318 | 6 | } else { |
319 | | // No register data address is provided, query the python plug-in to let it |
320 | | // make up the data as it sees fit |
321 | 6 | LLDB_LOGF(log, |
322 | 6 | "OperatingSystemPython::CreateRegisterContextForThread (tid " |
323 | 6 | "= 0x%" PRIx64 ", 0x%" PRIx64 |
324 | 6 | ") fetching register data from python", |
325 | 6 | thread->GetID(), thread->GetProtocolID()); |
326 | | |
327 | 6 | StructuredData::StringSP reg_context_data = |
328 | 6 | m_interpreter->OSPlugin_RegisterContextData(m_python_object_sp, |
329 | 6 | thread->GetID()); |
330 | 6 | if (reg_context_data) { |
331 | 3 | std::string value = std::string(reg_context_data->GetValue()); |
332 | 3 | DataBufferSP data_sp(new DataBufferHeap(value.c_str(), value.length())); |
333 | 3 | if (data_sp->GetByteSize()) { |
334 | 3 | RegisterContextMemory *reg_ctx_memory = new RegisterContextMemory( |
335 | 3 | *thread, 0, *GetDynamicRegisterInfo(), LLDB_INVALID_ADDRESS); |
336 | 3 | if (reg_ctx_memory) { |
337 | 3 | reg_ctx_sp.reset(reg_ctx_memory); |
338 | 3 | reg_ctx_memory->SetAllRegisterData(data_sp); |
339 | 3 | } |
340 | 3 | } |
341 | 3 | } |
342 | 6 | } |
343 | | // if we still have no register data, fallback on a dummy context to avoid |
344 | | // crashing |
345 | 6 | if (!reg_ctx_sp) { |
346 | 3 | LLDB_LOGF(log, |
347 | 3 | "OperatingSystemPython::CreateRegisterContextForThread (tid " |
348 | 3 | "= 0x%" PRIx64 ") forcing a dummy register context", |
349 | 3 | thread->GetID()); |
350 | 3 | reg_ctx_sp = std::make_shared<RegisterContextDummy>( |
351 | 3 | *thread, 0, target.GetArchitecture().GetAddressByteSize()); |
352 | 3 | } |
353 | 6 | return reg_ctx_sp; |
354 | 6 | } |
355 | | |
356 | | StopInfoSP |
357 | 8 | OperatingSystemPython::CreateThreadStopReason(lldb_private::Thread *thread) { |
358 | | // We should have gotten the thread stop info from the dictionary of data for |
359 | | // the thread in the initial call to get_thread_info(), this should have been |
360 | | // cached so we can return it here |
361 | 8 | StopInfoSP |
362 | 8 | stop_info_sp; //(StopInfo::CreateStopReasonWithSignal (*thread, SIGSTOP)); |
363 | 8 | return stop_info_sp; |
364 | 8 | } |
365 | | |
366 | | lldb::ThreadSP OperatingSystemPython::CreateThread(lldb::tid_t tid, |
367 | 0 | addr_t context) { |
368 | 0 | Log *log = GetLog(LLDBLog::Thread); |
369 | |
|
370 | 0 | LLDB_LOGF(log, |
371 | 0 | "OperatingSystemPython::CreateThread (tid = 0x%" PRIx64 |
372 | 0 | ", context = 0x%" PRIx64 ") fetching register data from python", |
373 | 0 | tid, context); |
374 | |
|
375 | 0 | if (m_interpreter && m_python_object_sp) { |
376 | | // First thing we have to do is to try to get the API lock, and the |
377 | | // interpreter lock. We're going to change the thread content of the |
378 | | // process, and we're going to use python, which requires the API lock to |
379 | | // do it. We need the interpreter lock to make sure thread_info_dict stays |
380 | | // alive. |
381 | | // |
382 | | // If someone already has the API lock, that is ok, we just want to avoid |
383 | | // external code from making new API calls while this call is happening. |
384 | | // |
385 | | // This is a recursive lock so we can grant it to any Python code called on |
386 | | // the stack below us. |
387 | 0 | Target &target = m_process->GetTarget(); |
388 | 0 | std::unique_lock<std::recursive_mutex> api_lock(target.GetAPIMutex(), |
389 | 0 | std::defer_lock); |
390 | 0 | (void)api_lock.try_lock(); // See above. |
391 | 0 | auto interpreter_lock = m_interpreter->AcquireInterpreterLock(); |
392 | |
|
393 | 0 | StructuredData::DictionarySP thread_info_dict = |
394 | 0 | m_interpreter->OSPlugin_CreateThread(m_python_object_sp, tid, context); |
395 | 0 | std::vector<bool> core_used_map; |
396 | 0 | if (thread_info_dict) { |
397 | 0 | ThreadList core_threads(m_process); |
398 | 0 | ThreadList &thread_list = m_process->GetThreadList(); |
399 | 0 | bool did_create = false; |
400 | 0 | ThreadSP thread_sp( |
401 | 0 | CreateThreadFromThreadInfo(*thread_info_dict, core_threads, |
402 | 0 | thread_list, core_used_map, &did_create)); |
403 | 0 | if (did_create) |
404 | 0 | thread_list.AddThread(thread_sp); |
405 | 0 | return thread_sp; |
406 | 0 | } |
407 | 0 | } |
408 | 0 | return ThreadSP(); |
409 | 0 | } |
410 | | |
411 | | #endif // #if LLDB_ENABLE_PYTHON |