Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp
39638 views
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
void OperatingSystemPython::Initialize() {
45
PluginManager::RegisterPlugin(GetPluginNameStatic(),
46
GetPluginDescriptionStatic(), CreateInstance,
47
nullptr);
48
}
49
50
void OperatingSystemPython::Terminate() {
51
PluginManager::UnregisterPlugin(CreateInstance);
52
}
53
54
OperatingSystem *OperatingSystemPython::CreateInstance(Process *process,
55
bool force) {
56
// Python OperatingSystem plug-ins must be requested by name, so force must
57
// be true
58
FileSpec python_os_plugin_spec(process->GetPythonOSPluginPath());
59
if (python_os_plugin_spec &&
60
FileSystem::Instance().Exists(python_os_plugin_spec)) {
61
std::unique_ptr<OperatingSystemPython> os_up(
62
new OperatingSystemPython(process, python_os_plugin_spec));
63
if (os_up.get() && os_up->IsValid())
64
return os_up.release();
65
}
66
return nullptr;
67
}
68
69
llvm::StringRef OperatingSystemPython::GetPluginDescriptionStatic() {
70
return "Operating system plug-in that gathers OS information from a python "
71
"class that implements the necessary OperatingSystem functionality.";
72
}
73
74
OperatingSystemPython::OperatingSystemPython(lldb_private::Process *process,
75
const FileSpec &python_module_path)
76
: OperatingSystem(process), m_thread_list_valobj_sp(), m_register_info_up(),
77
m_interpreter(nullptr), m_script_object_sp() {
78
if (!process)
79
return;
80
TargetSP target_sp = process->CalculateTarget();
81
if (!target_sp)
82
return;
83
m_interpreter = target_sp->GetDebugger().GetScriptInterpreter();
84
if (!m_interpreter)
85
return;
86
87
std::string os_plugin_class_name(
88
python_module_path.GetFilename().AsCString(""));
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));
96
Status error;
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
auto obj_or_err = operating_system_interface->CreatePluginObject(
120
os_plugin_class_name, exe_ctx, nullptr);
121
122
if (!obj_or_err) {
123
llvm::consumeError(obj_or_err.takeError());
124
return;
125
}
126
127
StructuredData::GenericSP owned_script_object_sp = *obj_or_err;
128
if (!owned_script_object_sp->IsValid())
129
// return llvm::createStringError(llvm::inconvertibleErrorCode(),
130
// "Created script object is invalid.");
131
return;
132
133
m_script_object_sp = owned_script_object_sp;
134
m_operating_system_interface_sp = operating_system_interface;
135
}
136
137
OperatingSystemPython::~OperatingSystemPython() = default;
138
139
DynamicRegisterInfo *OperatingSystemPython::GetDynamicRegisterInfo() {
140
if (m_register_info_up == nullptr) {
141
if (!m_interpreter || !m_operating_system_interface_sp)
142
return nullptr;
143
Log *log = GetLog(LLDBLog::OS);
144
145
LLDB_LOGF(log,
146
"OperatingSystemPython::GetDynamicRegisterInfo() fetching "
147
"thread register definitions from python for pid %" PRIu64,
148
m_process->GetID());
149
150
StructuredData::DictionarySP dictionary =
151
m_operating_system_interface_sp->GetRegisterInfo();
152
if (!dictionary)
153
return nullptr;
154
155
m_register_info_up = DynamicRegisterInfo::Create(
156
*dictionary, m_process->GetTarget().GetArchitecture());
157
assert(m_register_info_up);
158
assert(m_register_info_up->GetNumRegisters() > 0);
159
assert(m_register_info_up->GetNumRegisterSets() > 0);
160
}
161
return m_register_info_up.get();
162
}
163
164
bool OperatingSystemPython::UpdateThreadList(ThreadList &old_thread_list,
165
ThreadList &core_thread_list,
166
ThreadList &new_thread_list) {
167
if (!m_interpreter || !m_operating_system_interface_sp)
168
return false;
169
170
Log *log = GetLog(LLDBLog::OS);
171
172
LLDB_LOGF(log,
173
"OperatingSystemPython::UpdateThreadList() fetching thread "
174
"data from python for pid %" PRIu64,
175
m_process->GetID());
176
177
// The threads that are in "core_thread_list" upon entry are the threads from
178
// the lldb_private::Process subclass, no memory threads will be in this
179
// list.
180
StructuredData::ArraySP threads_list =
181
m_operating_system_interface_sp->GetThreadInfo();
182
183
const uint32_t num_cores = core_thread_list.GetSize(false);
184
185
// Make a map so we can keep track of which cores were used from the
186
// core_thread list. Any real threads/cores that weren't used should later be
187
// put back into the "new_thread_list".
188
std::vector<bool> core_used_map(num_cores, false);
189
if (threads_list) {
190
if (log) {
191
StreamString strm;
192
threads_list->Dump(strm);
193
LLDB_LOGF(log, "threads_list = %s", strm.GetData());
194
}
195
196
const uint32_t num_threads = threads_list->GetSize();
197
for (uint32_t i = 0; i < num_threads; ++i) {
198
StructuredData::ObjectSP thread_dict_obj =
199
threads_list->GetItemAtIndex(i);
200
if (auto thread_dict = thread_dict_obj->GetAsDictionary()) {
201
ThreadSP thread_sp(CreateThreadFromThreadInfo(
202
*thread_dict, core_thread_list, old_thread_list, core_used_map,
203
nullptr));
204
if (thread_sp)
205
new_thread_list.AddThread(thread_sp);
206
}
207
}
208
}
209
210
// Any real core threads that didn't end up backing a memory thread should
211
// still be in the main thread list, and they should be inserted at the
212
// beginning of the list
213
uint32_t insert_idx = 0;
214
for (uint32_t core_idx = 0; core_idx < num_cores; ++core_idx) {
215
if (!core_used_map[core_idx]) {
216
new_thread_list.InsertThread(
217
core_thread_list.GetThreadAtIndex(core_idx, false), insert_idx);
218
++insert_idx;
219
}
220
}
221
222
return new_thread_list.GetSize(false) > 0;
223
}
224
225
ThreadSP OperatingSystemPython::CreateThreadFromThreadInfo(
226
StructuredData::Dictionary &thread_dict, ThreadList &core_thread_list,
227
ThreadList &old_thread_list, std::vector<bool> &core_used_map,
228
bool *did_create_ptr) {
229
ThreadSP thread_sp;
230
tid_t tid = LLDB_INVALID_THREAD_ID;
231
if (!thread_dict.GetValueForKeyAsInteger("tid", tid))
232
return ThreadSP();
233
234
uint32_t core_number;
235
addr_t reg_data_addr;
236
llvm::StringRef name;
237
llvm::StringRef queue;
238
239
thread_dict.GetValueForKeyAsInteger("core", core_number, UINT32_MAX);
240
thread_dict.GetValueForKeyAsInteger("register_data_addr", reg_data_addr,
241
LLDB_INVALID_ADDRESS);
242
thread_dict.GetValueForKeyAsString("name", name);
243
thread_dict.GetValueForKeyAsString("queue", queue);
244
245
// See if a thread already exists for "tid"
246
thread_sp = old_thread_list.FindThreadByID(tid, false);
247
if (thread_sp) {
248
// A thread already does exist for "tid", make sure it was an operating
249
// system
250
// plug-in generated thread.
251
if (!IsOperatingSystemPluginThread(thread_sp)) {
252
// We have thread ID overlap between the protocol threads and the
253
// operating system threads, clear the thread so we create an operating
254
// system thread for this.
255
thread_sp.reset();
256
}
257
}
258
259
if (!thread_sp) {
260
if (did_create_ptr)
261
*did_create_ptr = true;
262
thread_sp = std::make_shared<ThreadMemory>(*m_process, tid, name, queue,
263
reg_data_addr);
264
}
265
266
if (core_number < core_thread_list.GetSize(false)) {
267
ThreadSP core_thread_sp(
268
core_thread_list.GetThreadAtIndex(core_number, false));
269
if (core_thread_sp) {
270
// Keep track of which cores were set as the backing thread for memory
271
// threads...
272
if (core_number < core_used_map.size())
273
core_used_map[core_number] = true;
274
275
ThreadSP backing_core_thread_sp(core_thread_sp->GetBackingThread());
276
if (backing_core_thread_sp) {
277
thread_sp->SetBackingThread(backing_core_thread_sp);
278
} else {
279
thread_sp->SetBackingThread(core_thread_sp);
280
}
281
}
282
}
283
return thread_sp;
284
}
285
286
void OperatingSystemPython::ThreadWasSelected(Thread *thread) {}
287
288
RegisterContextSP
289
OperatingSystemPython::CreateRegisterContextForThread(Thread *thread,
290
addr_t reg_data_addr) {
291
RegisterContextSP reg_ctx_sp;
292
if (!m_interpreter || !m_script_object_sp || !thread)
293
return reg_ctx_sp;
294
295
if (!IsOperatingSystemPluginThread(thread->shared_from_this()))
296
return reg_ctx_sp;
297
298
Log *log = GetLog(LLDBLog::Thread);
299
300
if (reg_data_addr != LLDB_INVALID_ADDRESS) {
301
// The registers data is in contiguous memory, just create the register
302
// context using the address provided
303
LLDB_LOGF(log,
304
"OperatingSystemPython::CreateRegisterContextForThread (tid "
305
"= 0x%" PRIx64 ", 0x%" PRIx64 ", reg_data_addr = 0x%" PRIx64
306
") creating memory register context",
307
thread->GetID(), thread->GetProtocolID(), reg_data_addr);
308
reg_ctx_sp = std::make_shared<RegisterContextMemory>(
309
*thread, 0, *GetDynamicRegisterInfo(), reg_data_addr);
310
} else {
311
// No register data address is provided, query the python plug-in to let it
312
// make up the data as it sees fit
313
LLDB_LOGF(log,
314
"OperatingSystemPython::CreateRegisterContextForThread (tid "
315
"= 0x%" PRIx64 ", 0x%" PRIx64
316
") fetching register data from python",
317
thread->GetID(), thread->GetProtocolID());
318
319
std::optional<std::string> reg_context_data =
320
m_operating_system_interface_sp->GetRegisterContextForTID(
321
thread->GetID());
322
if (reg_context_data) {
323
std::string value = *reg_context_data;
324
DataBufferSP data_sp(new DataBufferHeap(value.c_str(), value.length()));
325
if (data_sp->GetByteSize()) {
326
RegisterContextMemory *reg_ctx_memory = new RegisterContextMemory(
327
*thread, 0, *GetDynamicRegisterInfo(), LLDB_INVALID_ADDRESS);
328
if (reg_ctx_memory) {
329
reg_ctx_sp.reset(reg_ctx_memory);
330
reg_ctx_memory->SetAllRegisterData(data_sp);
331
}
332
}
333
}
334
}
335
// if we still have no register data, fallback on a dummy context to avoid
336
// crashing
337
if (!reg_ctx_sp) {
338
LLDB_LOGF(log,
339
"OperatingSystemPython::CreateRegisterContextForThread (tid "
340
"= 0x%" PRIx64 ") forcing a dummy register context",
341
thread->GetID());
342
Target &target = m_process->GetTarget();
343
reg_ctx_sp = std::make_shared<RegisterContextDummy>(
344
*thread, 0, target.GetArchitecture().GetAddressByteSize());
345
}
346
return reg_ctx_sp;
347
}
348
349
StopInfoSP
350
OperatingSystemPython::CreateThreadStopReason(lldb_private::Thread *thread) {
351
// We should have gotten the thread stop info from the dictionary of data for
352
// the thread in the initial call to get_thread_info(), this should have been
353
// cached so we can return it here
354
StopInfoSP
355
stop_info_sp; //(StopInfo::CreateStopReasonWithSignal (*thread, SIGSTOP));
356
return stop_info_sp;
357
}
358
359
lldb::ThreadSP OperatingSystemPython::CreateThread(lldb::tid_t tid,
360
addr_t context) {
361
Log *log = GetLog(LLDBLog::Thread);
362
363
LLDB_LOGF(log,
364
"OperatingSystemPython::CreateThread (tid = 0x%" PRIx64
365
", context = 0x%" PRIx64 ") fetching register data from python",
366
tid, context);
367
368
if (m_interpreter && m_script_object_sp) {
369
370
StructuredData::DictionarySP thread_info_dict =
371
m_operating_system_interface_sp->CreateThread(tid, context);
372
373
std::vector<bool> core_used_map;
374
if (thread_info_dict) {
375
ThreadList core_threads(*m_process);
376
ThreadList &thread_list = m_process->GetThreadList();
377
bool did_create = false;
378
ThreadSP thread_sp(
379
CreateThreadFromThreadInfo(*thread_info_dict, core_threads,
380
thread_list, core_used_map, &did_create));
381
if (did_create)
382
thread_list.AddThread(thread_sp);
383
return thread_sp;
384
}
385
}
386
return ThreadSP();
387
}
388
389
#endif // #if LLDB_ENABLE_PYTHON
390
391