xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp (revision be691f3bb6417f04a68938fadbcaee2d5795e764)
1*be691f3bSpatrick //===-- ScriptedProcess.cpp -----------------------------------------------===//
2*be691f3bSpatrick //
3*be691f3bSpatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*be691f3bSpatrick // See https://llvm.org/LICENSE.txt for license information.
5*be691f3bSpatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*be691f3bSpatrick //
7*be691f3bSpatrick //===----------------------------------------------------------------------===//
8*be691f3bSpatrick 
9*be691f3bSpatrick #include "ScriptedProcess.h"
10*be691f3bSpatrick 
11*be691f3bSpatrick #include "lldb/Core/Debugger.h"
12*be691f3bSpatrick #include "lldb/Core/Module.h"
13*be691f3bSpatrick #include "lldb/Core/PluginManager.h"
14*be691f3bSpatrick 
15*be691f3bSpatrick #include "lldb/Host/OptionParser.h"
16*be691f3bSpatrick #include "lldb/Host/ThreadLauncher.h"
17*be691f3bSpatrick #include "lldb/Interpreter/CommandInterpreter.h"
18*be691f3bSpatrick #include "lldb/Interpreter/OptionArgParser.h"
19*be691f3bSpatrick #include "lldb/Interpreter/OptionGroupBoolean.h"
20*be691f3bSpatrick #include "lldb/Interpreter/ScriptInterpreter.h"
21*be691f3bSpatrick #include "lldb/Target/MemoryRegionInfo.h"
22*be691f3bSpatrick #include "lldb/Target/RegisterContext.h"
23*be691f3bSpatrick 
24*be691f3bSpatrick #include "lldb/Utility/Log.h"
25*be691f3bSpatrick #include "lldb/Utility/Logging.h"
26*be691f3bSpatrick #include "lldb/Utility/State.h"
27*be691f3bSpatrick 
28*be691f3bSpatrick #include <mutex>
29*be691f3bSpatrick 
30*be691f3bSpatrick LLDB_PLUGIN_DEFINE(ScriptedProcess)
31*be691f3bSpatrick 
32*be691f3bSpatrick using namespace lldb;
33*be691f3bSpatrick using namespace lldb_private;
34*be691f3bSpatrick 
35*be691f3bSpatrick ConstString ScriptedProcess::GetPluginNameStatic() {
36*be691f3bSpatrick   static ConstString g_name("ScriptedProcess");
37*be691f3bSpatrick   return g_name;
38*be691f3bSpatrick }
39*be691f3bSpatrick 
40*be691f3bSpatrick const char *ScriptedProcess::GetPluginDescriptionStatic() {
41*be691f3bSpatrick   return "Scripted Process plug-in.";
42*be691f3bSpatrick }
43*be691f3bSpatrick 
44*be691f3bSpatrick static constexpr lldb::ScriptLanguage g_supported_script_languages[] = {
45*be691f3bSpatrick     ScriptLanguage::eScriptLanguagePython,
46*be691f3bSpatrick };
47*be691f3bSpatrick 
48*be691f3bSpatrick bool ScriptedProcess::IsScriptLanguageSupported(lldb::ScriptLanguage language) {
49*be691f3bSpatrick   llvm::ArrayRef<lldb::ScriptLanguage> supported_languages =
50*be691f3bSpatrick       llvm::makeArrayRef(g_supported_script_languages);
51*be691f3bSpatrick 
52*be691f3bSpatrick   return llvm::is_contained(supported_languages, language);
53*be691f3bSpatrick }
54*be691f3bSpatrick 
55*be691f3bSpatrick void ScriptedProcess::CheckInterpreterAndScriptObject() const {
56*be691f3bSpatrick   lldbassert(m_interpreter && "Invalid Script Interpreter.");
57*be691f3bSpatrick   lldbassert(m_script_object_sp && "Invalid Script Object.");
58*be691f3bSpatrick }
59*be691f3bSpatrick 
60*be691f3bSpatrick lldb::ProcessSP ScriptedProcess::CreateInstance(lldb::TargetSP target_sp,
61*be691f3bSpatrick                                                 lldb::ListenerSP listener_sp,
62*be691f3bSpatrick                                                 const FileSpec *file,
63*be691f3bSpatrick                                                 bool can_connect) {
64*be691f3bSpatrick   if (!target_sp ||
65*be691f3bSpatrick       !IsScriptLanguageSupported(target_sp->GetDebugger().GetScriptLanguage()))
66*be691f3bSpatrick     return nullptr;
67*be691f3bSpatrick 
68*be691f3bSpatrick   Status error;
69*be691f3bSpatrick   ScriptedProcess::ScriptedProcessInfo scripted_process_info(
70*be691f3bSpatrick       target_sp->GetProcessLaunchInfo());
71*be691f3bSpatrick 
72*be691f3bSpatrick   auto process_sp = std::make_shared<ScriptedProcess>(
73*be691f3bSpatrick       target_sp, listener_sp, scripted_process_info, error);
74*be691f3bSpatrick 
75*be691f3bSpatrick   if (error.Fail() || !process_sp || !process_sp->m_script_object_sp ||
76*be691f3bSpatrick       !process_sp->m_script_object_sp->IsValid()) {
77*be691f3bSpatrick     LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS), "%s",
78*be691f3bSpatrick               error.AsCString());
79*be691f3bSpatrick     return nullptr;
80*be691f3bSpatrick   }
81*be691f3bSpatrick 
82*be691f3bSpatrick   return process_sp;
83*be691f3bSpatrick }
84*be691f3bSpatrick 
85*be691f3bSpatrick bool ScriptedProcess::CanDebug(lldb::TargetSP target_sp,
86*be691f3bSpatrick                                bool plugin_specified_by_name) {
87*be691f3bSpatrick   return true;
88*be691f3bSpatrick }
89*be691f3bSpatrick 
90*be691f3bSpatrick ScriptedProcess::ScriptedProcess(
91*be691f3bSpatrick     lldb::TargetSP target_sp, lldb::ListenerSP listener_sp,
92*be691f3bSpatrick     const ScriptedProcess::ScriptedProcessInfo &scripted_process_info,
93*be691f3bSpatrick     Status &error)
94*be691f3bSpatrick     : Process(target_sp, listener_sp),
95*be691f3bSpatrick       m_scripted_process_info(scripted_process_info) {
96*be691f3bSpatrick 
97*be691f3bSpatrick   if (!target_sp) {
98*be691f3bSpatrick     error.SetErrorStringWithFormat("ScriptedProcess::%s () - ERROR: %s",
99*be691f3bSpatrick                                    __FUNCTION__, "Invalid target");
100*be691f3bSpatrick     return;
101*be691f3bSpatrick   }
102*be691f3bSpatrick 
103*be691f3bSpatrick   m_interpreter = target_sp->GetDebugger().GetScriptInterpreter();
104*be691f3bSpatrick 
105*be691f3bSpatrick   if (!m_interpreter) {
106*be691f3bSpatrick     error.SetErrorStringWithFormat("ScriptedProcess::%s () - ERROR: %s",
107*be691f3bSpatrick                                    __FUNCTION__,
108*be691f3bSpatrick                                    "Debugger has no Script Interpreter");
109*be691f3bSpatrick     return;
110*be691f3bSpatrick   }
111*be691f3bSpatrick 
112*be691f3bSpatrick   StructuredData::ObjectSP object_sp = GetInterface().CreatePluginObject(
113*be691f3bSpatrick       m_scripted_process_info.GetClassName().c_str(), target_sp,
114*be691f3bSpatrick       m_scripted_process_info.GetDictionarySP());
115*be691f3bSpatrick 
116*be691f3bSpatrick   if (!object_sp || !object_sp->IsValid()) {
117*be691f3bSpatrick     error.SetErrorStringWithFormat("ScriptedProcess::%s () - ERROR: %s",
118*be691f3bSpatrick                                    __FUNCTION__,
119*be691f3bSpatrick                                    "Failed to create valid script object");
120*be691f3bSpatrick     return;
121*be691f3bSpatrick   }
122*be691f3bSpatrick 
123*be691f3bSpatrick   m_script_object_sp = object_sp;
124*be691f3bSpatrick }
125*be691f3bSpatrick 
126*be691f3bSpatrick ScriptedProcess::~ScriptedProcess() {
127*be691f3bSpatrick   Clear();
128*be691f3bSpatrick   // We need to call finalize on the process before destroying ourselves to
129*be691f3bSpatrick   // make sure all of the broadcaster cleanup goes as planned. If we destruct
130*be691f3bSpatrick   // this class, then Process::~Process() might have problems trying to fully
131*be691f3bSpatrick   // destroy the broadcaster.
132*be691f3bSpatrick   Finalize();
133*be691f3bSpatrick }
134*be691f3bSpatrick 
135*be691f3bSpatrick void ScriptedProcess::Initialize() {
136*be691f3bSpatrick   static llvm::once_flag g_once_flag;
137*be691f3bSpatrick 
138*be691f3bSpatrick   llvm::call_once(g_once_flag, []() {
139*be691f3bSpatrick     PluginManager::RegisterPlugin(GetPluginNameStatic(),
140*be691f3bSpatrick                                   GetPluginDescriptionStatic(), CreateInstance);
141*be691f3bSpatrick   });
142*be691f3bSpatrick }
143*be691f3bSpatrick 
144*be691f3bSpatrick void ScriptedProcess::Terminate() {
145*be691f3bSpatrick   PluginManager::UnregisterPlugin(ScriptedProcess::CreateInstance);
146*be691f3bSpatrick }
147*be691f3bSpatrick 
148*be691f3bSpatrick ConstString ScriptedProcess::GetPluginName() { return GetPluginNameStatic(); }
149*be691f3bSpatrick 
150*be691f3bSpatrick uint32_t ScriptedProcess::GetPluginVersion() { return 1; }
151*be691f3bSpatrick 
152*be691f3bSpatrick Status ScriptedProcess::DoLoadCore() {
153*be691f3bSpatrick   ProcessLaunchInfo launch_info = GetTarget().GetProcessLaunchInfo();
154*be691f3bSpatrick 
155*be691f3bSpatrick   return DoLaunch(nullptr, launch_info);
156*be691f3bSpatrick }
157*be691f3bSpatrick 
158*be691f3bSpatrick Status ScriptedProcess::DoLaunch(Module *exe_module,
159*be691f3bSpatrick                                  ProcessLaunchInfo &launch_info) {
160*be691f3bSpatrick   CheckInterpreterAndScriptObject();
161*be691f3bSpatrick 
162*be691f3bSpatrick   /* FIXME: This doesn't reflect how lldb actually launches a process.
163*be691f3bSpatrick            In reality, it attaches to debugserver, then resume the process. */
164*be691f3bSpatrick   Status error = GetInterface().Launch();
165*be691f3bSpatrick   SetPrivateState(eStateRunning);
166*be691f3bSpatrick 
167*be691f3bSpatrick   if (error.Fail())
168*be691f3bSpatrick     return error;
169*be691f3bSpatrick 
170*be691f3bSpatrick   // TODO: Fetch next state from stopped event queue then send stop event
171*be691f3bSpatrick   //  const StateType state = SetThreadStopInfo(response);
172*be691f3bSpatrick   //  if (state != eStateInvalid) {
173*be691f3bSpatrick   //    SetPrivateState(state);
174*be691f3bSpatrick 
175*be691f3bSpatrick   SetPrivateState(eStateStopped);
176*be691f3bSpatrick 
177*be691f3bSpatrick   UpdateThreadListIfNeeded();
178*be691f3bSpatrick   GetThreadList();
179*be691f3bSpatrick 
180*be691f3bSpatrick   return {};
181*be691f3bSpatrick }
182*be691f3bSpatrick 
183*be691f3bSpatrick void ScriptedProcess::DidLaunch() {
184*be691f3bSpatrick   CheckInterpreterAndScriptObject();
185*be691f3bSpatrick   m_pid = GetInterface().GetProcessID();
186*be691f3bSpatrick }
187*be691f3bSpatrick 
188*be691f3bSpatrick Status ScriptedProcess::DoResume() {
189*be691f3bSpatrick   CheckInterpreterAndScriptObject();
190*be691f3bSpatrick 
191*be691f3bSpatrick   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
192*be691f3bSpatrick   // FIXME: Fetch data from thread.
193*be691f3bSpatrick   const StateType thread_resume_state = eStateRunning;
194*be691f3bSpatrick   LLDB_LOGF(log, "ScriptedProcess::%s thread_resume_state = %s", __FUNCTION__,
195*be691f3bSpatrick             StateAsCString(thread_resume_state));
196*be691f3bSpatrick 
197*be691f3bSpatrick   bool resume = (thread_resume_state == eStateRunning);
198*be691f3bSpatrick   assert(thread_resume_state == eStateRunning && "invalid thread resume state");
199*be691f3bSpatrick 
200*be691f3bSpatrick   Status error;
201*be691f3bSpatrick   if (resume) {
202*be691f3bSpatrick     LLDB_LOGF(log, "ScriptedProcess::%s sending resume", __FUNCTION__);
203*be691f3bSpatrick 
204*be691f3bSpatrick     SetPrivateState(eStateRunning);
205*be691f3bSpatrick     SetPrivateState(eStateStopped);
206*be691f3bSpatrick     error = GetInterface().Resume();
207*be691f3bSpatrick   }
208*be691f3bSpatrick 
209*be691f3bSpatrick   return error;
210*be691f3bSpatrick }
211*be691f3bSpatrick 
212*be691f3bSpatrick Status ScriptedProcess::DoStop() {
213*be691f3bSpatrick   CheckInterpreterAndScriptObject();
214*be691f3bSpatrick 
215*be691f3bSpatrick   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
216*be691f3bSpatrick 
217*be691f3bSpatrick   if (GetInterface().ShouldStop()) {
218*be691f3bSpatrick     SetPrivateState(eStateStopped);
219*be691f3bSpatrick     LLDB_LOGF(log, "ScriptedProcess::%s Immediate stop", __FUNCTION__);
220*be691f3bSpatrick     return {};
221*be691f3bSpatrick   }
222*be691f3bSpatrick 
223*be691f3bSpatrick   LLDB_LOGF(log, "ScriptedProcess::%s Delayed stop", __FUNCTION__);
224*be691f3bSpatrick   return GetInterface().Stop();
225*be691f3bSpatrick }
226*be691f3bSpatrick 
227*be691f3bSpatrick Status ScriptedProcess::DoDestroy() { return Status(); }
228*be691f3bSpatrick 
229*be691f3bSpatrick bool ScriptedProcess::IsAlive() {
230*be691f3bSpatrick   if (m_interpreter && m_script_object_sp)
231*be691f3bSpatrick     return GetInterface().IsAlive();
232*be691f3bSpatrick   return false;
233*be691f3bSpatrick }
234*be691f3bSpatrick 
235*be691f3bSpatrick size_t ScriptedProcess::DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
236*be691f3bSpatrick                                      Status &error) {
237*be691f3bSpatrick 
238*be691f3bSpatrick   auto error_with_message = [&error](llvm::StringRef message) {
239*be691f3bSpatrick     error.SetErrorString(message);
240*be691f3bSpatrick     return 0;
241*be691f3bSpatrick   };
242*be691f3bSpatrick 
243*be691f3bSpatrick   if (!m_interpreter)
244*be691f3bSpatrick     return error_with_message("No interpreter.");
245*be691f3bSpatrick 
246*be691f3bSpatrick   lldb::DataExtractorSP data_extractor_sp =
247*be691f3bSpatrick       GetInterface().ReadMemoryAtAddress(addr, size, error);
248*be691f3bSpatrick 
249*be691f3bSpatrick   if (!data_extractor_sp || error.Fail())
250*be691f3bSpatrick     return 0;
251*be691f3bSpatrick 
252*be691f3bSpatrick   offset_t bytes_copied = data_extractor_sp->CopyByteOrderedData(
253*be691f3bSpatrick       0, data_extractor_sp->GetByteSize(), buf, size, GetByteOrder());
254*be691f3bSpatrick 
255*be691f3bSpatrick   if (!bytes_copied || bytes_copied == LLDB_INVALID_OFFSET)
256*be691f3bSpatrick     return error_with_message("Failed to copy read memory to buffer.");
257*be691f3bSpatrick 
258*be691f3bSpatrick   return size;
259*be691f3bSpatrick }
260*be691f3bSpatrick 
261*be691f3bSpatrick ArchSpec ScriptedProcess::GetArchitecture() {
262*be691f3bSpatrick   return GetTarget().GetArchitecture();
263*be691f3bSpatrick }
264*be691f3bSpatrick 
265*be691f3bSpatrick Status ScriptedProcess::GetMemoryRegionInfo(lldb::addr_t load_addr,
266*be691f3bSpatrick                                             MemoryRegionInfo &region) {
267*be691f3bSpatrick   // TODO: Implement
268*be691f3bSpatrick   return Status();
269*be691f3bSpatrick }
270*be691f3bSpatrick 
271*be691f3bSpatrick Status ScriptedProcess::GetMemoryRegions(MemoryRegionInfos &region_list) {
272*be691f3bSpatrick   CheckInterpreterAndScriptObject();
273*be691f3bSpatrick 
274*be691f3bSpatrick   lldb::addr_t address = 0;
275*be691f3bSpatrick   lldb::MemoryRegionInfoSP mem_region_sp = nullptr;
276*be691f3bSpatrick 
277*be691f3bSpatrick   while ((mem_region_sp =
278*be691f3bSpatrick               GetInterface().GetMemoryRegionContainingAddress(address))) {
279*be691f3bSpatrick     auto range = mem_region_sp->GetRange();
280*be691f3bSpatrick     address += range.GetRangeBase() + range.GetByteSize();
281*be691f3bSpatrick     region_list.push_back(*mem_region_sp.get());
282*be691f3bSpatrick   }
283*be691f3bSpatrick 
284*be691f3bSpatrick   return {};
285*be691f3bSpatrick }
286*be691f3bSpatrick 
287*be691f3bSpatrick void ScriptedProcess::Clear() { Process::m_thread_list.Clear(); }
288*be691f3bSpatrick 
289*be691f3bSpatrick bool ScriptedProcess::DoUpdateThreadList(ThreadList &old_thread_list,
290*be691f3bSpatrick                                          ThreadList &new_thread_list) {
291*be691f3bSpatrick   // TODO: Implement
292*be691f3bSpatrick   // This is supposed to get the current set of threads, if any of them are in
293*be691f3bSpatrick   // old_thread_list then they get copied to new_thread_list, and then any
294*be691f3bSpatrick   // actually new threads will get added to new_thread_list.
295*be691f3bSpatrick   return new_thread_list.GetSize(false) > 0;
296*be691f3bSpatrick }
297*be691f3bSpatrick 
298*be691f3bSpatrick bool ScriptedProcess::GetProcessInfo(ProcessInstanceInfo &info) {
299*be691f3bSpatrick   info.Clear();
300*be691f3bSpatrick   info.SetProcessID(GetID());
301*be691f3bSpatrick   info.SetArchitecture(GetArchitecture());
302*be691f3bSpatrick   lldb::ModuleSP module_sp = GetTarget().GetExecutableModule();
303*be691f3bSpatrick   if (module_sp) {
304*be691f3bSpatrick     const bool add_exe_file_as_first_arg = false;
305*be691f3bSpatrick     info.SetExecutableFile(GetTarget().GetExecutableModule()->GetFileSpec(),
306*be691f3bSpatrick                            add_exe_file_as_first_arg);
307*be691f3bSpatrick   }
308*be691f3bSpatrick   return true;
309*be691f3bSpatrick }
310*be691f3bSpatrick 
311*be691f3bSpatrick ScriptedProcessInterface &ScriptedProcess::GetInterface() const {
312*be691f3bSpatrick   return m_interpreter->GetScriptedProcessInterface();
313*be691f3bSpatrick }
314