LLDB mainline
OperatingSystemPython.cpp
Go to the documentation of this file.
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
14
18#include "lldb/Core/Debugger.h"
19#include "lldb/Core/Module.h"
25#include "lldb/Target/Process.h"
27#include "lldb/Target/Target.h"
28#include "lldb/Target/Thread.h"
36#include "llvm/Support/FormatVariadic.h"
37
38#include <memory>
39
40using namespace lldb;
41using namespace lldb_private;
42
43LLDB_PLUGIN_DEFINE(OperatingSystemPython)
44
45void OperatingSystemPython::Initialize() {
46 PluginManager::RegisterPlugin(GetPluginNameStatic(),
47 GetPluginDescriptionStatic(), CreateInstance,
48 nullptr);
49}
50
51void OperatingSystemPython::Terminate() {
52 PluginManager::UnregisterPlugin(CreateInstance);
53}
54
55OperatingSystem *OperatingSystemPython::CreateInstance(Process *process,
56 bool force) {
57 // Python OperatingSystem plug-ins must be requested by name, so force must
58 // be true
59 FileSpec python_os_plugin_spec(process->GetPythonOSPluginPath());
60 if (python_os_plugin_spec &&
61 FileSystem::Instance().Exists(python_os_plugin_spec)) {
62 std::unique_ptr<OperatingSystemPython> os_up(
63 new OperatingSystemPython(process, python_os_plugin_spec));
64 if (os_up.get() && os_up->IsValid())
65 return os_up.release();
66 }
67 return nullptr;
68}
69
70llvm::StringRef OperatingSystemPython::GetPluginDescriptionStatic() {
71 return "Operating system plug-in that gathers OS information from a python "
72 "class that implements the necessary OperatingSystem functionality.";
73}
74
75OperatingSystemPython::OperatingSystemPython(lldb_private::Process *process,
76 const FileSpec &python_module_path)
77 : OperatingSystem(process), m_thread_list_valobj_sp(),
78 m_interpreter(nullptr), m_script_object_sp() {
79 if (!process)
80 return;
81 TargetSP target_sp = process->CalculateTarget();
82 if (!target_sp)
83 return;
84 m_interpreter = target_sp->GetDebugger().GetScriptInterpreter();
85 if (!m_interpreter)
86 return;
87
88 std::string os_plugin_class_name(python_module_path.GetFilename());
89 if (os_plugin_class_name.empty())
90 return;
91
92 LoadScriptOptions options;
93 char python_module_path_cstr[PATH_MAX];
94 python_module_path.GetPath(python_module_path_cstr,
95 sizeof(python_module_path_cstr));
97 if (!m_interpreter->LoadScriptingModule(python_module_path_cstr, options,
98 error))
99 return;
100
101 // Strip the ".py" extension if there is one
102 size_t py_extension_pos = os_plugin_class_name.rfind(".py");
103 if (py_extension_pos != std::string::npos)
104 os_plugin_class_name.erase(py_extension_pos);
105 // Add ".OperatingSystemPlugIn" to the module name to get a string like
106 // "modulename.OperatingSystemPlugIn"
107 os_plugin_class_name += ".OperatingSystemPlugIn";
108
109 auto operating_system_interface =
110 m_interpreter->CreateOperatingSystemInterface();
111 if (!operating_system_interface)
112 // FIXME: We should pass an Status& to raise the error to the user.
113 // return llvm::createStringError(
114 // llvm::inconvertibleErrorCode(),
115 // "Failed to create scripted thread interface.");
116 return;
117
118 ExecutionContext exe_ctx(process);
119 ScriptedMetadata scripted_metadata(os_plugin_class_name, nullptr);
120 auto obj_or_err = operating_system_interface->CreatePluginObject(
121 scripted_metadata, exe_ctx, nullptr);
122
123 if (!obj_or_err) {
124 std::string msg = llvm::toString(obj_or_err.takeError());
125 if (process)
127 llvm::formatv("failed to create OperatingSystemPython: {0}", msg)
128 .str(),
129 process->GetTarget().GetDebugger().GetID());
130 return;
131 }
132
133 StructuredData::GenericSP owned_script_object_sp = *obj_or_err;
134 if (!owned_script_object_sp->IsValid())
135 // return llvm::createStringError(llvm::inconvertibleErrorCode(),
136 // "Created script object is invalid.");
137 return;
138
139 m_script_object_sp = owned_script_object_sp;
140 m_operating_system_interface_sp = operating_system_interface;
141}
142
143OperatingSystemPython::~OperatingSystemPython() = default;
144
145DynamicRegisterInfoSP OperatingSystemPython::GetDynamicRegisterInfo() {
146 if (!m_interpreter || !m_operating_system_interface_sp)
147 return nullptr;
148
149 Log *log = GetLog(LLDBLog::OS);
150
151 LLDB_LOGF(log,
152 "OperatingSystemPython::GetDynamicRegisterInfo() fetching "
153 "thread register definitions from python for pid %" PRIu64,
154 m_process->GetID());
155
157 m_operating_system_interface_sp->GetRegisterInfo();
158 if (!dictionary)
159 return nullptr;
160
162 *dictionary, m_process->GetTarget().GetArchitecture());
163 assert(register_info_sp);
164 assert(register_info_sp->GetNumRegisters() > 0);
165 assert(register_info_sp->GetNumRegisterSets() > 0);
166
167 return register_info_sp;
168}
169
170bool OperatingSystemPython::UpdateThreadList(ThreadList &old_thread_list,
171 ThreadList &core_thread_list,
172 ThreadList &new_thread_list) {
173 if (!m_interpreter || !m_operating_system_interface_sp)
174 return false;
175
176 Log *log = GetLog(LLDBLog::OS);
177
178 LLDB_LOGF(log,
179 "OperatingSystemPython::UpdateThreadList() fetching thread "
180 "data from python for pid %" PRIu64,
181 m_process->GetID());
182
183 // The threads that are in "core_thread_list" upon entry are the threads from
184 // the lldb_private::Process subclass, no memory threads will be in this
185 // list.
186 StructuredData::ArraySP threads_list =
187 m_operating_system_interface_sp->GetThreadInfo();
188
189 const uint32_t num_cores = core_thread_list.GetSize(false);
190
191 // Make a map so we can keep track of which cores were used from the
192 // core_thread list. Any real threads/cores that weren't used should later be
193 // put back into the "new_thread_list".
194 std::vector<bool> core_used_map(num_cores, false);
195 if (threads_list) {
196 if (log) {
197 StreamString strm;
198 threads_list->Dump(strm);
199 LLDB_LOGF(log, "threads_list = %s", strm.GetData());
200 }
201
202 const uint32_t num_threads = threads_list->GetSize();
203 for (uint32_t i = 0; i < num_threads; ++i) {
204 StructuredData::ObjectSP thread_dict_obj =
205 threads_list->GetItemAtIndex(i);
206 if (auto thread_dict = thread_dict_obj->GetAsDictionary()) {
207 ThreadSP thread_sp(CreateThreadFromThreadInfo(
208 *thread_dict, core_thread_list, old_thread_list, core_used_map,
209 nullptr));
210 if (thread_sp)
211 new_thread_list.AddThread(thread_sp);
212 }
213 }
214 }
215
216 // Any real core threads that didn't end up backing a memory thread should
217 // still be in the main thread list, and they should be inserted at the
218 // beginning of the list
219 uint32_t insert_idx = 0;
220 for (uint32_t core_idx = 0; core_idx < num_cores; ++core_idx) {
221 if (!core_used_map[core_idx]) {
222 new_thread_list.InsertThread(
223 core_thread_list.GetThreadAtIndex(core_idx, false), insert_idx);
224 ++insert_idx;
225 }
226 }
227
228 return new_thread_list.GetSize(false) > 0;
229}
230
231ThreadSP OperatingSystemPython::CreateThreadFromThreadInfo(
232 StructuredData::Dictionary &thread_dict, ThreadList &core_thread_list,
233 ThreadList &old_thread_list, std::vector<bool> &core_used_map,
234 bool *did_create_ptr) {
235 ThreadSP thread_sp;
237 if (!thread_dict.GetValueForKeyAsInteger("tid", tid))
238 return ThreadSP();
239
240 uint32_t core_number;
241 addr_t reg_data_addr;
242 llvm::StringRef name;
243 llvm::StringRef queue;
244
245 thread_dict.GetValueForKeyAsInteger("core", core_number, UINT32_MAX);
246 thread_dict.GetValueForKeyAsInteger("register_data_addr", reg_data_addr,
248 thread_dict.GetValueForKeyAsString("name", name);
249 thread_dict.GetValueForKeyAsString("queue", queue);
250
251 // See if a thread already exists for "tid"
252 thread_sp = old_thread_list.FindThreadByID(tid, false);
253 if (thread_sp) {
254 // A thread already does exist for "tid", make sure it was an operating
255 // system
256 // plug-in generated thread.
257 if (!IsOperatingSystemPluginThread(thread_sp)) {
258 // We have thread ID overlap between the protocol threads and the
259 // operating system threads, clear the thread so we create an operating
260 // system thread for this.
261 thread_sp.reset();
262 }
263 }
264
265 if (!thread_sp) {
266 if (did_create_ptr)
267 *did_create_ptr = true;
268 thread_sp = std::make_shared<ThreadMemoryProvidingNameAndQueue>(
269 *m_process, tid, name, queue, reg_data_addr);
270 }
271
272 if (core_number < core_thread_list.GetSize(false)) {
273 ThreadSP core_thread_sp(
274 core_thread_list.GetThreadAtIndex(core_number, false));
275 if (core_thread_sp) {
276 // Keep track of which cores were set as the backing thread for memory
277 // threads...
278 if (core_number < core_used_map.size())
279 core_used_map[core_number] = true;
280
281 ThreadSP backing_core_thread_sp(core_thread_sp->GetBackingThread());
282 if (backing_core_thread_sp) {
283 thread_sp->SetBackingThread(backing_core_thread_sp);
284 } else {
285 thread_sp->SetBackingThread(core_thread_sp);
286 }
287 }
288 }
289 return thread_sp;
290}
291
292void OperatingSystemPython::ThreadWasSelected(Thread *thread) {}
293
295OperatingSystemPython::CreateRegisterContextForThread(Thread *thread,
296 addr_t reg_data_addr) {
297 RegisterContextSP reg_ctx_sp;
298 if (!m_interpreter || !m_script_object_sp || !thread)
299 return reg_ctx_sp;
300
301 if (!IsOperatingSystemPluginThread(thread->shared_from_this()))
302 return reg_ctx_sp;
303
304 Log *log = GetLog(LLDBLog::Thread);
305
306 if (reg_data_addr != LLDB_INVALID_ADDRESS) {
307 // The registers data is in contiguous memory, just create the register
308 // context using the address provided
309 LLDB_LOGF(log,
310 "OperatingSystemPython::CreateRegisterContextForThread (tid "
311 "= 0x%" PRIx64 ", 0x%" PRIx64 ", reg_data_addr = 0x%" PRIx64
312 ") creating memory register context",
313 thread->GetID(), thread->GetProtocolID(), reg_data_addr);
314 reg_ctx_sp = std::make_shared<RegisterContextMemory>(
315 *thread, 0, GetDynamicRegisterInfo(), reg_data_addr);
316 } else {
317 // No register data address is provided, query the python plug-in to let it
318 // make up the data as it sees fit
319 LLDB_LOGF(log,
320 "OperatingSystemPython::CreateRegisterContextForThread (tid "
321 "= 0x%" PRIx64 ", 0x%" PRIx64
322 ") fetching register data from python",
323 thread->GetID(), thread->GetProtocolID());
324
325 std::optional<std::string> reg_context_data =
326 m_operating_system_interface_sp->GetRegisterContextForTID(
327 thread->GetID());
328 if (reg_context_data) {
329 std::string value = *reg_context_data;
330 DataBufferSP data_sp(new DataBufferHeap(value.c_str(), value.length()));
331 if (data_sp->GetByteSize()) {
332 RegisterContextMemory *reg_ctx_memory = new RegisterContextMemory(
333 *thread, 0, GetDynamicRegisterInfo(), LLDB_INVALID_ADDRESS);
334 if (reg_ctx_memory) {
335 reg_ctx_sp.reset(reg_ctx_memory);
336 reg_ctx_memory->SetAllRegisterData(data_sp);
337 }
338 }
339 }
340 }
341 // if we still have no register data, fallback on a dummy context to avoid
342 // crashing
343 if (!reg_ctx_sp) {
344 LLDB_LOGF(log,
345 "OperatingSystemPython::CreateRegisterContextForThread (tid "
346 "= 0x%" PRIx64 ") forcing a dummy register context",
347 thread->GetID());
348 Target &target = m_process->GetTarget();
349 reg_ctx_sp = std::make_shared<RegisterContextDummy>(
350 *thread, 0, target.GetArchitecture().GetAddressByteSize());
351 }
352 return reg_ctx_sp;
353}
354
356OperatingSystemPython::CreateThreadStopReason(lldb_private::Thread *thread) {
357 // We should have gotten the thread stop info from the dictionary of data for
358 // the thread in the initial call to get_thread_info(), this should have been
359 // cached so we can return it here
361 stop_info_sp; //(StopInfo::CreateStopReasonWithSignal (*thread, SIGSTOP));
362 return stop_info_sp;
363}
364
365lldb::ThreadSP OperatingSystemPython::CreateThread(lldb::tid_t tid,
366 addr_t context) {
367 Log *log = GetLog(LLDBLog::Thread);
368
369 LLDB_LOGF(log,
370 "OperatingSystemPython::CreateThread (tid = 0x%" PRIx64
371 ", context = 0x%" PRIx64 ") fetching register data from python",
372 tid, context);
373
374 if (m_interpreter && m_script_object_sp) {
375
376 StructuredData::DictionarySP thread_info_dict =
377 m_operating_system_interface_sp->CreateThread(tid, context);
378
379 std::vector<bool> core_used_map;
380 if (thread_info_dict) {
381 ThreadList core_threads(*m_process);
382 ThreadList &thread_list = m_process->GetThreadList();
383 bool did_create = false;
384 ThreadSP thread_sp(
385 CreateThreadFromThreadInfo(*thread_info_dict, core_threads,
386 thread_list, core_used_map, &did_create));
387 if (did_create)
388 thread_list.AddThread(thread_sp);
389 return thread_sp;
390 }
391 }
392 return ThreadSP();
393}
394
395bool OperatingSystemPython::DoesPluginReportAllThreads() {
396 // If the python plugin has a "DoesPluginReportAllThreads" method, use it.
397 if (std::optional<bool> plugin_answer =
398 m_operating_system_interface_sp->DoesPluginReportAllThreads())
399 return *plugin_answer;
400 return m_process->GetOSPluginReportsAllThreads();
401}
402
403#endif // #if LLDB_ENABLE_PYTHON
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOGF(log,...)
Definition Log.h:389
#define LLDB_PLUGIN_DEFINE(PluginName)
void SetAllRegisterData(const lldb::DataBufferSP &data_sp)
uint32_t GetAddressByteSize() const
Returns the size in bytes of an address of the current architecture.
Definition ArchSpec.cpp:889
A subclass of DataBuffer that stores a data buffer on the heap.
static void ReportError(std::string message, std::optional< lldb::user_id_t > debugger_id=std::nullopt, std::once_flag *once=nullptr)
Report error events.
static std::unique_ptr< DynamicRegisterInfo > Create(const StructuredData::Dictionary &dict, const ArchSpec &arch)
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
static FileSystem & Instance()
A plug-in interface definition class for halted OS helpers.
static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description, ABICreateInstance create_callback)
static bool UnregisterPlugin(ABICreateInstance create_callback)
FileSpec GetPythonOSPluginPath() const
Definition Process.cpp:225
A plug-in interface definition class for debugging a process.
Definition Process.h:360
lldb::TargetSP CalculateTarget() override
Definition Process.cpp:4841
Target & GetTarget()
Get the target object pointer for this module.
Definition Process.h:1259
const char * GetData() const
bool GetValueForKeyAsInteger(llvm::StringRef key, IntType &result) const
bool GetValueForKeyAsString(llvm::StringRef key, llvm::StringRef &result) const
std::shared_ptr< Generic > GenericSP
std::shared_ptr< Dictionary > DictionarySP
std::shared_ptr< Object > ObjectSP
std::shared_ptr< Array > ArraySP
Debugger & GetDebugger() const
Definition Target.h:1337
const ArchSpec & GetArchitecture() const
Definition Target.h:1296
void AddThread(const lldb::ThreadSP &thread_sp)
void InsertThread(const lldb::ThreadSP &thread_sp, uint32_t idx)
uint32_t GetSize(bool can_update=true)
lldb::ThreadSP GetThreadAtIndex(uint32_t idx, bool can_update=true)
lldb::ThreadSP FindThreadByID(lldb::tid_t tid, bool can_update=true)
#define LLDB_INVALID_THREAD_ID
#define LLDB_INVALID_ADDRESS
#define UINT32_MAX
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition Log.h:338
std::shared_ptr< lldb_private::DynamicRegisterInfo > DynamicRegisterInfoSP
std::shared_ptr< lldb_private::Thread > ThreadSP
std::shared_ptr< lldb_private::DataBuffer > DataBufferSP
std::shared_ptr< lldb_private::StopInfo > StopInfoSP
uint64_t addr_t
Definition lldb-types.h:80
std::shared_ptr< lldb_private::RegisterContext > RegisterContextSP
uint64_t tid_t
Definition lldb-types.h:85
lldb::user_id_t GetID() const
Get accessor for the user ID.
Definition UserID.h:47
#define PATH_MAX