Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
39642 views
1
//===-- ScriptedProcess.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 "ScriptedProcess.h"
10
11
#include "lldb/Core/Debugger.h"
12
#include "lldb/Core/Module.h"
13
#include "lldb/Core/PluginManager.h"
14
15
#include "lldb/Host/OptionParser.h"
16
#include "lldb/Host/ThreadLauncher.h"
17
#include "lldb/Interpreter/CommandInterpreter.h"
18
#include "lldb/Interpreter/OptionArgParser.h"
19
#include "lldb/Interpreter/OptionGroupBoolean.h"
20
#include "lldb/Interpreter/ScriptInterpreter.h"
21
#include "lldb/Target/MemoryRegionInfo.h"
22
#include "lldb/Target/Queue.h"
23
#include "lldb/Target/RegisterContext.h"
24
#include "lldb/Utility/LLDBLog.h"
25
#include "lldb/Utility/ScriptedMetadata.h"
26
#include "lldb/Utility/State.h"
27
28
#include <mutex>
29
30
LLDB_PLUGIN_DEFINE(ScriptedProcess)
31
32
using namespace lldb;
33
using namespace lldb_private;
34
35
llvm::StringRef ScriptedProcess::GetPluginDescriptionStatic() {
36
return "Scripted Process plug-in.";
37
}
38
39
static constexpr lldb::ScriptLanguage g_supported_script_languages[] = {
40
ScriptLanguage::eScriptLanguagePython,
41
};
42
43
bool ScriptedProcess::IsScriptLanguageSupported(lldb::ScriptLanguage language) {
44
llvm::ArrayRef<lldb::ScriptLanguage> supported_languages =
45
llvm::ArrayRef(g_supported_script_languages);
46
47
return llvm::is_contained(supported_languages, language);
48
}
49
50
lldb::ProcessSP ScriptedProcess::CreateInstance(lldb::TargetSP target_sp,
51
lldb::ListenerSP listener_sp,
52
const FileSpec *file,
53
bool can_connect) {
54
if (!target_sp ||
55
!IsScriptLanguageSupported(target_sp->GetDebugger().GetScriptLanguage()))
56
return nullptr;
57
58
ScriptedMetadata scripted_metadata(target_sp->GetProcessLaunchInfo());
59
60
Status error;
61
auto process_sp = std::shared_ptr<ScriptedProcess>(
62
new ScriptedProcess(target_sp, listener_sp, scripted_metadata, error));
63
64
if (error.Fail() || !process_sp || !process_sp->m_interface_up) {
65
LLDB_LOGF(GetLog(LLDBLog::Process), "%s", error.AsCString());
66
return nullptr;
67
}
68
69
return process_sp;
70
}
71
72
bool ScriptedProcess::CanDebug(lldb::TargetSP target_sp,
73
bool plugin_specified_by_name) {
74
return true;
75
}
76
77
ScriptedProcess::ScriptedProcess(lldb::TargetSP target_sp,
78
lldb::ListenerSP listener_sp,
79
const ScriptedMetadata &scripted_metadata,
80
Status &error)
81
: Process(target_sp, listener_sp), m_scripted_metadata(scripted_metadata) {
82
83
if (!target_sp) {
84
error.SetErrorStringWithFormat("ScriptedProcess::%s () - ERROR: %s",
85
__FUNCTION__, "Invalid target");
86
return;
87
}
88
89
ScriptInterpreter *interpreter =
90
target_sp->GetDebugger().GetScriptInterpreter();
91
92
if (!interpreter) {
93
error.SetErrorStringWithFormat("ScriptedProcess::%s () - ERROR: %s",
94
__FUNCTION__,
95
"Debugger has no Script Interpreter");
96
return;
97
}
98
99
// Create process instance interface
100
m_interface_up = interpreter->CreateScriptedProcessInterface();
101
if (!m_interface_up) {
102
error.SetErrorStringWithFormat(
103
"ScriptedProcess::%s () - ERROR: %s", __FUNCTION__,
104
"Script interpreter couldn't create Scripted Process Interface");
105
return;
106
}
107
108
ExecutionContext exe_ctx(target_sp, /*get_process=*/false);
109
110
// Create process script object
111
auto obj_or_err = GetInterface().CreatePluginObject(
112
m_scripted_metadata.GetClassName(), exe_ctx,
113
m_scripted_metadata.GetArgsSP());
114
115
if (!obj_or_err) {
116
llvm::consumeError(obj_or_err.takeError());
117
error.SetErrorString("Failed to create script object.");
118
return;
119
}
120
121
StructuredData::GenericSP object_sp = *obj_or_err;
122
123
if (!object_sp || !object_sp->IsValid()) {
124
error.SetErrorStringWithFormat("ScriptedProcess::%s () - ERROR: %s",
125
__FUNCTION__,
126
"Failed to create valid script object");
127
return;
128
}
129
}
130
131
ScriptedProcess::~ScriptedProcess() {
132
Clear();
133
// If the interface is not valid, we can't call Finalize(). When that happens
134
// it means that the Scripted Process instanciation failed and the
135
// CreateProcess function returns a nullptr, so no one besides this class
136
// should have access to that bogus process object.
137
if (!m_interface_up)
138
return;
139
// We need to call finalize on the process before destroying ourselves to
140
// make sure all of the broadcaster cleanup goes as planned. If we destruct
141
// this class, then Process::~Process() might have problems trying to fully
142
// destroy the broadcaster.
143
Finalize(true /* destructing */);
144
}
145
146
void ScriptedProcess::Initialize() {
147
static llvm::once_flag g_once_flag;
148
149
llvm::call_once(g_once_flag, []() {
150
PluginManager::RegisterPlugin(GetPluginNameStatic(),
151
GetPluginDescriptionStatic(), CreateInstance);
152
});
153
}
154
155
void ScriptedProcess::Terminate() {
156
PluginManager::UnregisterPlugin(ScriptedProcess::CreateInstance);
157
}
158
159
Status ScriptedProcess::DoLoadCore() {
160
ProcessLaunchInfo launch_info = GetTarget().GetProcessLaunchInfo();
161
162
return DoLaunch(nullptr, launch_info);
163
}
164
165
Status ScriptedProcess::DoLaunch(Module *exe_module,
166
ProcessLaunchInfo &launch_info) {
167
LLDB_LOGF(GetLog(LLDBLog::Process), "ScriptedProcess::%s launching process", __FUNCTION__);
168
169
/* MARK: This doesn't reflect how lldb actually launches a process.
170
In reality, it attaches to debugserver, then resume the process.
171
That's not true in all cases. If debugserver is remote, lldb
172
asks debugserver to launch the process for it. */
173
Status error = GetInterface().Launch();
174
SetPrivateState(eStateStopped);
175
return error;
176
}
177
178
void ScriptedProcess::DidLaunch() { m_pid = GetInterface().GetProcessID(); }
179
180
void ScriptedProcess::DidResume() {
181
// Update the PID again, in case the user provided a placeholder pid at launch
182
m_pid = GetInterface().GetProcessID();
183
}
184
185
Status ScriptedProcess::DoResume() {
186
LLDB_LOGF(GetLog(LLDBLog::Process), "ScriptedProcess::%s resuming process", __FUNCTION__);
187
188
return GetInterface().Resume();
189
}
190
191
Status ScriptedProcess::DoAttach(const ProcessAttachInfo &attach_info) {
192
Status error = GetInterface().Attach(attach_info);
193
SetPrivateState(eStateRunning);
194
SetPrivateState(eStateStopped);
195
if (error.Fail())
196
return error;
197
// NOTE: We need to set the PID before finishing to attach otherwise we will
198
// hit an assert when calling the attach completion handler.
199
DidLaunch();
200
201
return {};
202
}
203
204
Status
205
ScriptedProcess::DoAttachToProcessWithID(lldb::pid_t pid,
206
const ProcessAttachInfo &attach_info) {
207
return DoAttach(attach_info);
208
}
209
210
Status ScriptedProcess::DoAttachToProcessWithName(
211
const char *process_name, const ProcessAttachInfo &attach_info) {
212
return DoAttach(attach_info);
213
}
214
215
void ScriptedProcess::DidAttach(ArchSpec &process_arch) {
216
process_arch = GetArchitecture();
217
}
218
219
Status ScriptedProcess::DoDestroy() { return Status(); }
220
221
bool ScriptedProcess::IsAlive() { return GetInterface().IsAlive(); }
222
223
size_t ScriptedProcess::DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
224
Status &error) {
225
lldb::DataExtractorSP data_extractor_sp =
226
GetInterface().ReadMemoryAtAddress(addr, size, error);
227
228
if (!data_extractor_sp || !data_extractor_sp->GetByteSize() || error.Fail())
229
return 0;
230
231
offset_t bytes_copied = data_extractor_sp->CopyByteOrderedData(
232
0, data_extractor_sp->GetByteSize(), buf, size, GetByteOrder());
233
234
if (!bytes_copied || bytes_copied == LLDB_INVALID_OFFSET)
235
return ScriptedInterface::ErrorWithMessage<size_t>(
236
LLVM_PRETTY_FUNCTION, "Failed to copy read memory to buffer.", error);
237
238
// FIXME: We should use the diagnostic system to report a warning if the
239
// `bytes_copied` is different from `size`.
240
241
return bytes_copied;
242
}
243
244
size_t ScriptedProcess::DoWriteMemory(lldb::addr_t vm_addr, const void *buf,
245
size_t size, Status &error) {
246
lldb::DataExtractorSP data_extractor_sp = std::make_shared<DataExtractor>(
247
buf, size, GetByteOrder(), GetAddressByteSize());
248
249
if (!data_extractor_sp || !data_extractor_sp->GetByteSize())
250
return 0;
251
252
lldb::offset_t bytes_written =
253
GetInterface().WriteMemoryAtAddress(vm_addr, data_extractor_sp, error);
254
255
if (!bytes_written || bytes_written == LLDB_INVALID_OFFSET)
256
return ScriptedInterface::ErrorWithMessage<size_t>(
257
LLVM_PRETTY_FUNCTION, "Failed to copy write buffer to memory.", error);
258
259
// FIXME: We should use the diagnostic system to report a warning if the
260
// `bytes_written` is different from `size`.
261
262
return bytes_written;
263
}
264
265
Status ScriptedProcess::EnableBreakpointSite(BreakpointSite *bp_site) {
266
assert(bp_site != nullptr);
267
268
if (bp_site->IsEnabled()) {
269
return {};
270
}
271
272
if (bp_site->HardwareRequired()) {
273
return Status("Scripted Processes don't support hardware breakpoints");
274
}
275
276
Status error;
277
GetInterface().CreateBreakpoint(bp_site->GetLoadAddress(), error);
278
279
return error;
280
}
281
282
ArchSpec ScriptedProcess::GetArchitecture() {
283
return GetTarget().GetArchitecture();
284
}
285
286
Status ScriptedProcess::DoGetMemoryRegionInfo(lldb::addr_t load_addr,
287
MemoryRegionInfo &region) {
288
Status error;
289
if (auto region_or_err =
290
GetInterface().GetMemoryRegionContainingAddress(load_addr, error))
291
region = *region_or_err;
292
293
return error;
294
}
295
296
Status ScriptedProcess::GetMemoryRegions(MemoryRegionInfos &region_list) {
297
Status error;
298
lldb::addr_t address = 0;
299
300
while (auto region_or_err =
301
GetInterface().GetMemoryRegionContainingAddress(address, error)) {
302
if (error.Fail())
303
break;
304
305
MemoryRegionInfo &mem_region = *region_or_err;
306
auto range = mem_region.GetRange();
307
address += range.GetRangeBase() + range.GetByteSize();
308
region_list.push_back(mem_region);
309
}
310
311
return error;
312
}
313
314
void ScriptedProcess::Clear() { Process::m_thread_list.Clear(); }
315
316
bool ScriptedProcess::DoUpdateThreadList(ThreadList &old_thread_list,
317
ThreadList &new_thread_list) {
318
// TODO: Implement
319
// This is supposed to get the current set of threads, if any of them are in
320
// old_thread_list then they get copied to new_thread_list, and then any
321
// actually new threads will get added to new_thread_list.
322
m_thread_plans.ClearThreadCache();
323
324
Status error;
325
StructuredData::DictionarySP thread_info_sp = GetInterface().GetThreadsInfo();
326
327
if (!thread_info_sp)
328
return ScriptedInterface::ErrorWithMessage<bool>(
329
LLVM_PRETTY_FUNCTION,
330
"Couldn't fetch thread list from Scripted Process.", error);
331
332
// Because `StructuredData::Dictionary` uses a `std::map<ConstString,
333
// ObjectSP>` for storage, each item is sorted based on the key alphabetical
334
// order. Since `GetThreadsInfo` provides thread indices as the key element,
335
// thread info comes ordered alphabetically, instead of numerically, so we
336
// need to sort the thread indices before creating thread.
337
338
StructuredData::ArraySP keys = thread_info_sp->GetKeys();
339
340
std::map<size_t, StructuredData::ObjectSP> sorted_threads;
341
auto sort_keys = [&sorted_threads,
342
&thread_info_sp](StructuredData::Object *item) -> bool {
343
if (!item)
344
return false;
345
346
llvm::StringRef key = item->GetStringValue();
347
size_t idx = 0;
348
349
// Make sure the provided index is actually an integer
350
if (!llvm::to_integer(key, idx))
351
return false;
352
353
sorted_threads[idx] = thread_info_sp->GetValueForKey(key);
354
return true;
355
};
356
357
size_t thread_count = thread_info_sp->GetSize();
358
359
if (!keys->ForEach(sort_keys) || sorted_threads.size() != thread_count)
360
// Might be worth showing the unsorted thread list instead of return early.
361
return ScriptedInterface::ErrorWithMessage<bool>(
362
LLVM_PRETTY_FUNCTION, "Couldn't sort thread list.", error);
363
364
auto create_scripted_thread =
365
[this, &error, &new_thread_list](
366
const std::pair<size_t, StructuredData::ObjectSP> pair) -> bool {
367
size_t idx = pair.first;
368
StructuredData::ObjectSP object_sp = pair.second;
369
370
if (!object_sp)
371
return ScriptedInterface::ErrorWithMessage<bool>(
372
LLVM_PRETTY_FUNCTION, "Invalid thread info object", error);
373
374
auto thread_or_error =
375
ScriptedThread::Create(*this, object_sp->GetAsGeneric());
376
377
if (!thread_or_error)
378
return ScriptedInterface::ErrorWithMessage<bool>(
379
LLVM_PRETTY_FUNCTION, toString(thread_or_error.takeError()), error);
380
381
ThreadSP thread_sp = thread_or_error.get();
382
lldbassert(thread_sp && "Couldn't initialize scripted thread.");
383
384
RegisterContextSP reg_ctx_sp = thread_sp->GetRegisterContext();
385
if (!reg_ctx_sp)
386
return ScriptedInterface::ErrorWithMessage<bool>(
387
LLVM_PRETTY_FUNCTION,
388
llvm::Twine("Invalid Register Context for thread " + llvm::Twine(idx))
389
.str(),
390
error);
391
392
new_thread_list.AddThread(thread_sp);
393
394
return true;
395
};
396
397
llvm::for_each(sorted_threads, create_scripted_thread);
398
399
return new_thread_list.GetSize(false) > 0;
400
}
401
402
void ScriptedProcess::RefreshStateAfterStop() {
403
// Let all threads recover from stopping and do any clean up based on the
404
// previous thread state (if any).
405
m_thread_list.RefreshStateAfterStop();
406
}
407
408
bool ScriptedProcess::GetProcessInfo(ProcessInstanceInfo &info) {
409
info.Clear();
410
info.SetProcessID(GetID());
411
info.SetArchitecture(GetArchitecture());
412
lldb::ModuleSP module_sp = GetTarget().GetExecutableModule();
413
if (module_sp) {
414
const bool add_exe_file_as_first_arg = false;
415
info.SetExecutableFile(GetTarget().GetExecutableModule()->GetFileSpec(),
416
add_exe_file_as_first_arg);
417
}
418
return true;
419
}
420
421
lldb_private::StructuredData::ObjectSP
422
ScriptedProcess::GetLoadedDynamicLibrariesInfos() {
423
Status error;
424
auto error_with_message = [&error](llvm::StringRef message) {
425
return ScriptedInterface::ErrorWithMessage<bool>(LLVM_PRETTY_FUNCTION,
426
message.data(), error);
427
};
428
429
StructuredData::ArraySP loaded_images_sp = GetInterface().GetLoadedImages();
430
431
if (!loaded_images_sp || !loaded_images_sp->GetSize())
432
return ScriptedInterface::ErrorWithMessage<StructuredData::ObjectSP>(
433
LLVM_PRETTY_FUNCTION, "No loaded images.", error);
434
435
ModuleList module_list;
436
Target &target = GetTarget();
437
438
auto reload_image = [&target, &module_list, &error_with_message](
439
StructuredData::Object *obj) -> bool {
440
StructuredData::Dictionary *dict = obj->GetAsDictionary();
441
442
if (!dict)
443
return error_with_message("Couldn't cast image object into dictionary.");
444
445
ModuleSpec module_spec;
446
llvm::StringRef value;
447
448
bool has_path = dict->HasKey("path");
449
bool has_uuid = dict->HasKey("uuid");
450
if (!has_path && !has_uuid)
451
return error_with_message("Dictionary should have key 'path' or 'uuid'");
452
if (!dict->HasKey("load_addr"))
453
return error_with_message("Dictionary is missing key 'load_addr'");
454
455
if (has_path) {
456
dict->GetValueForKeyAsString("path", value);
457
module_spec.GetFileSpec().SetPath(value);
458
}
459
460
if (has_uuid) {
461
dict->GetValueForKeyAsString("uuid", value);
462
module_spec.GetUUID().SetFromStringRef(value);
463
}
464
module_spec.GetArchitecture() = target.GetArchitecture();
465
466
ModuleSP module_sp =
467
target.GetOrCreateModule(module_spec, true /* notify */);
468
469
if (!module_sp)
470
return error_with_message("Couldn't create or get module.");
471
472
lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
473
lldb::offset_t slide = LLDB_INVALID_OFFSET;
474
dict->GetValueForKeyAsInteger("load_addr", load_addr);
475
dict->GetValueForKeyAsInteger("slide", slide);
476
if (load_addr == LLDB_INVALID_ADDRESS)
477
return error_with_message(
478
"Couldn't get valid load address or slide offset.");
479
480
if (slide != LLDB_INVALID_OFFSET)
481
load_addr += slide;
482
483
bool changed = false;
484
module_sp->SetLoadAddress(target, load_addr, false /*=value_is_offset*/,
485
changed);
486
487
if (!changed && !module_sp->GetObjectFile())
488
return error_with_message("Couldn't set the load address for module.");
489
490
dict->GetValueForKeyAsString("path", value);
491
FileSpec objfile(value);
492
module_sp->SetFileSpecAndObjectName(objfile, objfile.GetFilename());
493
494
return module_list.AppendIfNeeded(module_sp);
495
};
496
497
if (!loaded_images_sp->ForEach(reload_image))
498
return ScriptedInterface::ErrorWithMessage<StructuredData::ObjectSP>(
499
LLVM_PRETTY_FUNCTION, "Couldn't reload all images.", error);
500
501
target.ModulesDidLoad(module_list);
502
503
return loaded_images_sp;
504
}
505
506
lldb_private::StructuredData::DictionarySP ScriptedProcess::GetMetadata() {
507
StructuredData::DictionarySP metadata_sp = GetInterface().GetMetadata();
508
509
Status error;
510
if (!metadata_sp || !metadata_sp->GetSize())
511
return ScriptedInterface::ErrorWithMessage<StructuredData::DictionarySP>(
512
LLVM_PRETTY_FUNCTION, "No metadata.", error);
513
514
return metadata_sp;
515
}
516
517
void ScriptedProcess::UpdateQueueListIfNeeded() {
518
CheckScriptedInterface();
519
for (ThreadSP thread_sp : Threads()) {
520
if (const char *queue_name = thread_sp->GetQueueName()) {
521
QueueSP queue_sp = std::make_shared<Queue>(
522
m_process->shared_from_this(), thread_sp->GetQueueID(), queue_name);
523
m_queue_list.AddQueue(queue_sp);
524
}
525
}
526
}
527
528
ScriptedProcessInterface &ScriptedProcess::GetInterface() const {
529
CheckScriptedInterface();
530
return *m_interface_up;
531
}
532
533
void *ScriptedProcess::GetImplementation() {
534
StructuredData::GenericSP object_instance_sp =
535
GetInterface().GetScriptObjectInstance();
536
if (object_instance_sp &&
537
object_instance_sp->GetType() == eStructuredDataTypeGeneric)
538
return object_instance_sp->GetAsGeneric()->GetValue();
539
return nullptr;
540
}
541
542