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

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp