1dda28197Spatrick //===-- CommandObjectProcess.cpp ------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "CommandObjectProcess.h"
10*f6aab3d8Srobert #include "CommandObjectBreakpoint.h"
11be691f3bSpatrick #include "CommandObjectTrace.h"
12be691f3bSpatrick #include "CommandOptionsProcessLaunch.h"
13061da546Spatrick #include "lldb/Breakpoint/Breakpoint.h"
14*f6aab3d8Srobert #include "lldb/Breakpoint/BreakpointIDList.h"
15061da546Spatrick #include "lldb/Breakpoint/BreakpointLocation.h"
16*f6aab3d8Srobert #include "lldb/Breakpoint/BreakpointName.h"
17061da546Spatrick #include "lldb/Breakpoint/BreakpointSite.h"
18061da546Spatrick #include "lldb/Core/Module.h"
19061da546Spatrick #include "lldb/Core/PluginManager.h"
20061da546Spatrick #include "lldb/Host/OptionParser.h"
21061da546Spatrick #include "lldb/Interpreter/CommandInterpreter.h"
22*f6aab3d8Srobert #include "lldb/Interpreter/CommandOptionArgumentTable.h"
23061da546Spatrick #include "lldb/Interpreter/CommandReturnObject.h"
24061da546Spatrick #include "lldb/Interpreter/OptionArgParser.h"
25be691f3bSpatrick #include "lldb/Interpreter/OptionGroupPythonClassWithDict.h"
26061da546Spatrick #include "lldb/Interpreter/Options.h"
27061da546Spatrick #include "lldb/Target/Platform.h"
28061da546Spatrick #include "lldb/Target/Process.h"
29061da546Spatrick #include "lldb/Target/StopInfo.h"
30061da546Spatrick #include "lldb/Target/Target.h"
31061da546Spatrick #include "lldb/Target/Thread.h"
32061da546Spatrick #include "lldb/Target/UnixSignals.h"
33061da546Spatrick #include "lldb/Utility/Args.h"
34061da546Spatrick #include "lldb/Utility/State.h"
35061da546Spatrick 
36*f6aab3d8Srobert #include "llvm/ADT/ScopeExit.h"
37*f6aab3d8Srobert 
38be691f3bSpatrick #include <bitset>
39*f6aab3d8Srobert #include <optional>
40be691f3bSpatrick 
41061da546Spatrick using namespace lldb;
42061da546Spatrick using namespace lldb_private;
43061da546Spatrick 
44061da546Spatrick class CommandObjectProcessLaunchOrAttach : public CommandObjectParsed {
45061da546Spatrick public:
CommandObjectProcessLaunchOrAttach(CommandInterpreter & interpreter,const char * name,const char * help,const char * syntax,uint32_t flags,const char * new_process_action)46061da546Spatrick   CommandObjectProcessLaunchOrAttach(CommandInterpreter &interpreter,
47061da546Spatrick                                      const char *name, const char *help,
48061da546Spatrick                                      const char *syntax, uint32_t flags,
49061da546Spatrick                                      const char *new_process_action)
50061da546Spatrick       : CommandObjectParsed(interpreter, name, help, syntax, flags),
51061da546Spatrick         m_new_process_action(new_process_action) {}
52061da546Spatrick 
53061da546Spatrick   ~CommandObjectProcessLaunchOrAttach() override = default;
54061da546Spatrick 
55061da546Spatrick protected:
StopProcessIfNecessary(Process * process,StateType & state,CommandReturnObject & result)56061da546Spatrick   bool StopProcessIfNecessary(Process *process, StateType &state,
57061da546Spatrick                               CommandReturnObject &result) {
58061da546Spatrick     state = eStateInvalid;
59061da546Spatrick     if (process) {
60061da546Spatrick       state = process->GetState();
61061da546Spatrick 
62061da546Spatrick       if (process->IsAlive() && state != eStateConnected) {
63be691f3bSpatrick         std::string message;
64061da546Spatrick         if (process->GetState() == eStateAttaching)
65be691f3bSpatrick           message =
66be691f3bSpatrick               llvm::formatv("There is a pending attach, abort it and {0}?",
67be691f3bSpatrick                             m_new_process_action);
68061da546Spatrick         else if (process->GetShouldDetach())
69be691f3bSpatrick           message = llvm::formatv(
70be691f3bSpatrick               "There is a running process, detach from it and {0}?",
71be691f3bSpatrick               m_new_process_action);
72061da546Spatrick         else
73be691f3bSpatrick           message =
74be691f3bSpatrick               llvm::formatv("There is a running process, kill it and {0}?",
75be691f3bSpatrick                             m_new_process_action);
76061da546Spatrick 
77061da546Spatrick         if (!m_interpreter.Confirm(message, true)) {
78061da546Spatrick           result.SetStatus(eReturnStatusFailed);
79061da546Spatrick           return false;
80061da546Spatrick         } else {
81061da546Spatrick           if (process->GetShouldDetach()) {
82061da546Spatrick             bool keep_stopped = false;
83061da546Spatrick             Status detach_error(process->Detach(keep_stopped));
84061da546Spatrick             if (detach_error.Success()) {
85061da546Spatrick               result.SetStatus(eReturnStatusSuccessFinishResult);
86061da546Spatrick               process = nullptr;
87061da546Spatrick             } else {
88061da546Spatrick               result.AppendErrorWithFormat(
89061da546Spatrick                   "Failed to detach from process: %s\n",
90061da546Spatrick                   detach_error.AsCString());
91061da546Spatrick             }
92061da546Spatrick           } else {
93061da546Spatrick             Status destroy_error(process->Destroy(false));
94061da546Spatrick             if (destroy_error.Success()) {
95061da546Spatrick               result.SetStatus(eReturnStatusSuccessFinishResult);
96061da546Spatrick               process = nullptr;
97061da546Spatrick             } else {
98061da546Spatrick               result.AppendErrorWithFormat("Failed to kill process: %s\n",
99061da546Spatrick                                            destroy_error.AsCString());
100061da546Spatrick             }
101061da546Spatrick           }
102061da546Spatrick         }
103061da546Spatrick       }
104061da546Spatrick     }
105061da546Spatrick     return result.Succeeded();
106061da546Spatrick   }
107061da546Spatrick 
108061da546Spatrick   std::string m_new_process_action;
109061da546Spatrick };
110061da546Spatrick 
111061da546Spatrick // CommandObjectProcessLaunch
112061da546Spatrick #pragma mark CommandObjectProcessLaunch
113061da546Spatrick class CommandObjectProcessLaunch : public CommandObjectProcessLaunchOrAttach {
114061da546Spatrick public:
CommandObjectProcessLaunch(CommandInterpreter & interpreter)115061da546Spatrick   CommandObjectProcessLaunch(CommandInterpreter &interpreter)
116061da546Spatrick       : CommandObjectProcessLaunchOrAttach(
117061da546Spatrick             interpreter, "process launch",
118061da546Spatrick             "Launch the executable in the debugger.", nullptr,
119061da546Spatrick             eCommandRequiresTarget, "restart"),
120*f6aab3d8Srobert 
121*f6aab3d8Srobert         m_class_options("scripted process", true, 'C', 'k', 'v', 0) {
122be691f3bSpatrick     m_all_options.Append(&m_options);
123be691f3bSpatrick     m_all_options.Append(&m_class_options, LLDB_OPT_SET_1 | LLDB_OPT_SET_2,
124be691f3bSpatrick                          LLDB_OPT_SET_ALL);
125be691f3bSpatrick     m_all_options.Finalize();
126be691f3bSpatrick 
127061da546Spatrick     CommandArgumentEntry arg;
128061da546Spatrick     CommandArgumentData run_args_arg;
129061da546Spatrick 
130061da546Spatrick     // Define the first (and only) variant of this arg.
131061da546Spatrick     run_args_arg.arg_type = eArgTypeRunArgs;
132061da546Spatrick     run_args_arg.arg_repetition = eArgRepeatOptional;
133061da546Spatrick 
134061da546Spatrick     // There is only one variant this argument could be; put it into the
135061da546Spatrick     // argument entry.
136061da546Spatrick     arg.push_back(run_args_arg);
137061da546Spatrick 
138061da546Spatrick     // Push the data for the first argument into the m_arguments vector.
139061da546Spatrick     m_arguments.push_back(arg);
140061da546Spatrick   }
141061da546Spatrick 
142061da546Spatrick   ~CommandObjectProcessLaunch() override = default;
143061da546Spatrick 
144061da546Spatrick   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)145061da546Spatrick   HandleArgumentCompletion(CompletionRequest &request,
146061da546Spatrick                            OptionElementVector &opt_element_vector) override {
147061da546Spatrick 
148061da546Spatrick     CommandCompletions::InvokeCommonCompletionCallbacks(
149061da546Spatrick         GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion,
150061da546Spatrick         request, nullptr);
151061da546Spatrick   }
152061da546Spatrick 
GetOptions()153be691f3bSpatrick   Options *GetOptions() override { return &m_all_options; }
154061da546Spatrick 
GetRepeatCommand(Args & current_command_args,uint32_t index)155*f6aab3d8Srobert   std::optional<std::string> GetRepeatCommand(Args &current_command_args,
156061da546Spatrick                                               uint32_t index) override {
157061da546Spatrick     // No repeat for "process launch"...
158*f6aab3d8Srobert     return std::string("");
159061da546Spatrick   }
160061da546Spatrick 
161061da546Spatrick protected:
DoExecute(Args & launch_args,CommandReturnObject & result)162061da546Spatrick   bool DoExecute(Args &launch_args, CommandReturnObject &result) override {
163061da546Spatrick     Debugger &debugger = GetDebugger();
164061da546Spatrick     Target *target = debugger.GetSelectedTarget().get();
165061da546Spatrick     // If our listener is nullptr, users aren't allows to launch
166061da546Spatrick     ModuleSP exe_module_sp = target->GetExecutableModule();
167061da546Spatrick 
168*f6aab3d8Srobert     // If the target already has an executable module, then use that.  If it
169*f6aab3d8Srobert     // doesn't then someone must be trying to launch using a path that will
170*f6aab3d8Srobert     // make sense to the remote stub, but doesn't exist on the local host.
171*f6aab3d8Srobert     // In that case use the ExecutableFile that was set in the target's
172*f6aab3d8Srobert     // ProcessLaunchInfo.
173*f6aab3d8Srobert     if (exe_module_sp == nullptr && !target->GetProcessLaunchInfo().GetExecutableFile()) {
174061da546Spatrick       result.AppendError("no file in target, create a debug target using the "
175061da546Spatrick                          "'target create' command");
176061da546Spatrick       return false;
177061da546Spatrick     }
178061da546Spatrick 
179061da546Spatrick     StateType state = eStateInvalid;
180061da546Spatrick 
181061da546Spatrick     if (!StopProcessIfNecessary(m_exe_ctx.GetProcessPtr(), state, result))
182061da546Spatrick       return false;
183061da546Spatrick 
184061da546Spatrick     // Determine whether we will disable ASLR or leave it in the default state
185061da546Spatrick     // (i.e. enabled if the platform supports it). First check if the process
186061da546Spatrick     // launch options explicitly turn on/off
187061da546Spatrick     // disabling ASLR.  If so, use that setting;
188061da546Spatrick     // otherwise, use the 'settings target.disable-aslr' setting.
189061da546Spatrick     bool disable_aslr = false;
190061da546Spatrick     if (m_options.disable_aslr != eLazyBoolCalculate) {
191061da546Spatrick       // The user specified an explicit setting on the process launch line.
192061da546Spatrick       // Use it.
193061da546Spatrick       disable_aslr = (m_options.disable_aslr == eLazyBoolYes);
194061da546Spatrick     } else {
195061da546Spatrick       // The user did not explicitly specify whether to disable ASLR.  Fall
196061da546Spatrick       // back to the target.disable-aslr setting.
197061da546Spatrick       disable_aslr = target->GetDisableASLR();
198061da546Spatrick     }
199061da546Spatrick 
200be691f3bSpatrick     if (!m_class_options.GetName().empty()) {
201be691f3bSpatrick       m_options.launch_info.SetProcessPluginName("ScriptedProcess");
202be691f3bSpatrick       m_options.launch_info.SetScriptedProcessClassName(
203be691f3bSpatrick           m_class_options.GetName());
204be691f3bSpatrick       m_options.launch_info.SetScriptedProcessDictionarySP(
205be691f3bSpatrick           m_class_options.GetStructuredData());
206be691f3bSpatrick       target->SetProcessLaunchInfo(m_options.launch_info);
207be691f3bSpatrick     }
208be691f3bSpatrick 
209061da546Spatrick     if (disable_aslr)
210061da546Spatrick       m_options.launch_info.GetFlags().Set(eLaunchFlagDisableASLR);
211061da546Spatrick     else
212061da546Spatrick       m_options.launch_info.GetFlags().Clear(eLaunchFlagDisableASLR);
213061da546Spatrick 
214be691f3bSpatrick     if (target->GetInheritTCC())
215be691f3bSpatrick       m_options.launch_info.GetFlags().Set(eLaunchFlagInheritTCCFromParent);
216be691f3bSpatrick 
217061da546Spatrick     if (target->GetDetachOnError())
218061da546Spatrick       m_options.launch_info.GetFlags().Set(eLaunchFlagDetachOnError);
219061da546Spatrick 
220061da546Spatrick     if (target->GetDisableSTDIO())
221061da546Spatrick       m_options.launch_info.GetFlags().Set(eLaunchFlagDisableSTDIO);
222061da546Spatrick 
223061da546Spatrick     // Merge the launch info environment with the target environment.
224061da546Spatrick     Environment target_env = target->GetEnvironment();
225061da546Spatrick     m_options.launch_info.GetEnvironment().insert(target_env.begin(),
226061da546Spatrick                                                   target_env.end());
227061da546Spatrick 
228*f6aab3d8Srobert     llvm::StringRef target_settings_argv0 = target->GetArg0();
229*f6aab3d8Srobert 
230061da546Spatrick     if (!target_settings_argv0.empty()) {
231061da546Spatrick       m_options.launch_info.GetArguments().AppendArgument(
232061da546Spatrick           target_settings_argv0);
233*f6aab3d8Srobert       if (exe_module_sp)
234061da546Spatrick         m_options.launch_info.SetExecutableFile(
235061da546Spatrick             exe_module_sp->GetPlatformFileSpec(), false);
236*f6aab3d8Srobert       else
237*f6aab3d8Srobert         m_options.launch_info.SetExecutableFile(target->GetProcessLaunchInfo().GetExecutableFile(), false);
238061da546Spatrick     } else {
239*f6aab3d8Srobert       if (exe_module_sp)
240061da546Spatrick         m_options.launch_info.SetExecutableFile(
241061da546Spatrick             exe_module_sp->GetPlatformFileSpec(), true);
242*f6aab3d8Srobert       else
243*f6aab3d8Srobert         m_options.launch_info.SetExecutableFile(target->GetProcessLaunchInfo().GetExecutableFile(), true);
244061da546Spatrick     }
245061da546Spatrick 
246061da546Spatrick     if (launch_args.GetArgumentCount() == 0) {
247061da546Spatrick       m_options.launch_info.GetArguments().AppendArguments(
248061da546Spatrick           target->GetProcessLaunchInfo().GetArguments());
249061da546Spatrick     } else {
250061da546Spatrick       m_options.launch_info.GetArguments().AppendArguments(launch_args);
251061da546Spatrick       // Save the arguments for subsequent runs in the current target.
252061da546Spatrick       target->SetRunArguments(launch_args);
253061da546Spatrick     }
254061da546Spatrick 
255061da546Spatrick     StreamString stream;
256061da546Spatrick     Status error = target->Launch(m_options.launch_info, &stream);
257061da546Spatrick 
258061da546Spatrick     if (error.Success()) {
259061da546Spatrick       ProcessSP process_sp(target->GetProcessSP());
260061da546Spatrick       if (process_sp) {
261061da546Spatrick         // There is a race condition where this thread will return up the call
262061da546Spatrick         // stack to the main command handler and show an (lldb) prompt before
263061da546Spatrick         // HandlePrivateEvent (from PrivateStateThread) has a chance to call
264061da546Spatrick         // PushProcessIOHandler().
265061da546Spatrick         process_sp->SyncIOHandler(0, std::chrono::seconds(2));
266061da546Spatrick 
267061da546Spatrick         llvm::StringRef data = stream.GetString();
268061da546Spatrick         if (!data.empty())
269061da546Spatrick           result.AppendMessage(data);
270*f6aab3d8Srobert         // If we didn't have a local executable, then we wouldn't have had an
271*f6aab3d8Srobert         // executable module before launch.
272*f6aab3d8Srobert         if (!exe_module_sp)
273*f6aab3d8Srobert           exe_module_sp = target->GetExecutableModule();
274*f6aab3d8Srobert         if (!exe_module_sp) {
275*f6aab3d8Srobert           result.AppendWarning("Could not get executable module after launch.");
276*f6aab3d8Srobert         } else {
277*f6aab3d8Srobert 
278061da546Spatrick           const char *archname =
279061da546Spatrick               exe_module_sp->GetArchitecture().GetArchitectureName();
280061da546Spatrick           result.AppendMessageWithFormat(
281061da546Spatrick               "Process %" PRIu64 " launched: '%s' (%s)\n", process_sp->GetID(),
282061da546Spatrick               exe_module_sp->GetFileSpec().GetPath().c_str(), archname);
283*f6aab3d8Srobert         }
284061da546Spatrick         result.SetStatus(eReturnStatusSuccessFinishResult);
285061da546Spatrick         result.SetDidChangeProcessState(true);
286061da546Spatrick       } else {
287061da546Spatrick         result.AppendError(
288061da546Spatrick             "no error returned from Target::Launch, and target has no process");
289061da546Spatrick       }
290061da546Spatrick     } else {
291061da546Spatrick       result.AppendError(error.AsCString());
292061da546Spatrick     }
293061da546Spatrick     return result.Succeeded();
294061da546Spatrick   }
295061da546Spatrick 
296be691f3bSpatrick   CommandOptionsProcessLaunch m_options;
297be691f3bSpatrick   OptionGroupPythonClassWithDict m_class_options;
298be691f3bSpatrick   OptionGroupOptions m_all_options;
299061da546Spatrick };
300061da546Spatrick 
301061da546Spatrick #define LLDB_OPTIONS_process_attach
302061da546Spatrick #include "CommandOptions.inc"
303061da546Spatrick 
304061da546Spatrick #pragma mark CommandObjectProcessAttach
305061da546Spatrick class CommandObjectProcessAttach : public CommandObjectProcessLaunchOrAttach {
306061da546Spatrick public:
307061da546Spatrick   class CommandOptions : public Options {
308061da546Spatrick   public:
CommandOptions()309*f6aab3d8Srobert     CommandOptions() {
310061da546Spatrick       // Keep default values of all options in one place: OptionParsingStarting
311061da546Spatrick       // ()
312061da546Spatrick       OptionParsingStarting(nullptr);
313061da546Spatrick     }
314061da546Spatrick 
315061da546Spatrick     ~CommandOptions() override = default;
316061da546Spatrick 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)317061da546Spatrick     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
318061da546Spatrick                           ExecutionContext *execution_context) override {
319061da546Spatrick       Status error;
320061da546Spatrick       const int short_option = m_getopt_table[option_idx].val;
321061da546Spatrick       switch (short_option) {
322061da546Spatrick       case 'c':
323061da546Spatrick         attach_info.SetContinueOnceAttached(true);
324061da546Spatrick         break;
325061da546Spatrick 
326061da546Spatrick       case 'p': {
327061da546Spatrick         lldb::pid_t pid;
328061da546Spatrick         if (option_arg.getAsInteger(0, pid)) {
329061da546Spatrick           error.SetErrorStringWithFormat("invalid process ID '%s'",
330061da546Spatrick                                          option_arg.str().c_str());
331061da546Spatrick         } else {
332061da546Spatrick           attach_info.SetProcessID(pid);
333061da546Spatrick         }
334061da546Spatrick       } break;
335061da546Spatrick 
336061da546Spatrick       case 'P':
337061da546Spatrick         attach_info.SetProcessPluginName(option_arg);
338061da546Spatrick         break;
339061da546Spatrick 
340061da546Spatrick       case 'n':
341061da546Spatrick         attach_info.GetExecutableFile().SetFile(option_arg,
342061da546Spatrick                                                 FileSpec::Style::native);
343061da546Spatrick         break;
344061da546Spatrick 
345061da546Spatrick       case 'w':
346061da546Spatrick         attach_info.SetWaitForLaunch(true);
347061da546Spatrick         break;
348061da546Spatrick 
349061da546Spatrick       case 'i':
350061da546Spatrick         attach_info.SetIgnoreExisting(false);
351061da546Spatrick         break;
352061da546Spatrick 
353061da546Spatrick       default:
354061da546Spatrick         llvm_unreachable("Unimplemented option");
355061da546Spatrick       }
356061da546Spatrick       return error;
357061da546Spatrick     }
358061da546Spatrick 
OptionParsingStarting(ExecutionContext * execution_context)359061da546Spatrick     void OptionParsingStarting(ExecutionContext *execution_context) override {
360061da546Spatrick       attach_info.Clear();
361061da546Spatrick     }
362061da546Spatrick 
GetDefinitions()363061da546Spatrick     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
364*f6aab3d8Srobert       return llvm::ArrayRef(g_process_attach_options);
365061da546Spatrick     }
366061da546Spatrick 
367061da546Spatrick     ProcessAttachInfo attach_info;
368061da546Spatrick   };
369061da546Spatrick 
CommandObjectProcessAttach(CommandInterpreter & interpreter)370061da546Spatrick   CommandObjectProcessAttach(CommandInterpreter &interpreter)
371061da546Spatrick       : CommandObjectProcessLaunchOrAttach(
372061da546Spatrick             interpreter, "process attach", "Attach to a process.",
373*f6aab3d8Srobert             "process attach <cmd-options>", 0, "attach") {}
374061da546Spatrick 
375061da546Spatrick   ~CommandObjectProcessAttach() override = default;
376061da546Spatrick 
GetOptions()377061da546Spatrick   Options *GetOptions() override { return &m_options; }
378061da546Spatrick 
379061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)380061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
381061da546Spatrick     PlatformSP platform_sp(
382061da546Spatrick         GetDebugger().GetPlatformList().GetSelectedPlatform());
383061da546Spatrick 
384061da546Spatrick     Target *target = GetDebugger().GetSelectedTarget().get();
385061da546Spatrick     // N.B. The attach should be synchronous.  It doesn't help much to get the
386061da546Spatrick     // prompt back between initiating the attach and the target actually
387061da546Spatrick     // stopping.  So even if the interpreter is set to be asynchronous, we wait
388061da546Spatrick     // for the stop ourselves here.
389061da546Spatrick 
390061da546Spatrick     StateType state = eStateInvalid;
391061da546Spatrick     Process *process = m_exe_ctx.GetProcessPtr();
392061da546Spatrick 
393061da546Spatrick     if (!StopProcessIfNecessary(process, state, result))
394061da546Spatrick       return false;
395061da546Spatrick 
396061da546Spatrick     if (target == nullptr) {
397061da546Spatrick       // If there isn't a current target create one.
398061da546Spatrick       TargetSP new_target_sp;
399061da546Spatrick       Status error;
400061da546Spatrick 
401061da546Spatrick       error = GetDebugger().GetTargetList().CreateTarget(
402061da546Spatrick           GetDebugger(), "", "", eLoadDependentsNo,
403061da546Spatrick           nullptr, // No platform options
404061da546Spatrick           new_target_sp);
405061da546Spatrick       target = new_target_sp.get();
406061da546Spatrick       if (target == nullptr || error.Fail()) {
407061da546Spatrick         result.AppendError(error.AsCString("Error creating target"));
408061da546Spatrick         return false;
409061da546Spatrick       }
410061da546Spatrick     }
411061da546Spatrick 
412061da546Spatrick     // Record the old executable module, we want to issue a warning if the
413061da546Spatrick     // process of attaching changed the current executable (like somebody said
414061da546Spatrick     // "file foo" then attached to a PID whose executable was bar.)
415061da546Spatrick 
416061da546Spatrick     ModuleSP old_exec_module_sp = target->GetExecutableModule();
417061da546Spatrick     ArchSpec old_arch_spec = target->GetArchitecture();
418061da546Spatrick 
419061da546Spatrick     StreamString stream;
420*f6aab3d8Srobert     ProcessSP process_sp;
421061da546Spatrick     const auto error = target->Attach(m_options.attach_info, &stream);
422061da546Spatrick     if (error.Success()) {
423*f6aab3d8Srobert       process_sp = target->GetProcessSP();
424061da546Spatrick       if (process_sp) {
425061da546Spatrick         result.AppendMessage(stream.GetString());
426061da546Spatrick         result.SetStatus(eReturnStatusSuccessFinishNoResult);
427061da546Spatrick         result.SetDidChangeProcessState(true);
428061da546Spatrick       } else {
429061da546Spatrick         result.AppendError(
430061da546Spatrick             "no error returned from Target::Attach, and target has no process");
431061da546Spatrick       }
432061da546Spatrick     } else {
433061da546Spatrick       result.AppendErrorWithFormat("attach failed: %s\n", error.AsCString());
434061da546Spatrick     }
435061da546Spatrick 
436061da546Spatrick     if (!result.Succeeded())
437061da546Spatrick       return false;
438061da546Spatrick 
439061da546Spatrick     // Okay, we're done.  Last step is to warn if the executable module has
440061da546Spatrick     // changed:
441061da546Spatrick     char new_path[PATH_MAX];
442061da546Spatrick     ModuleSP new_exec_module_sp(target->GetExecutableModule());
443061da546Spatrick     if (!old_exec_module_sp) {
444061da546Spatrick       // We might not have a module if we attached to a raw pid...
445061da546Spatrick       if (new_exec_module_sp) {
446061da546Spatrick         new_exec_module_sp->GetFileSpec().GetPath(new_path, PATH_MAX);
447061da546Spatrick         result.AppendMessageWithFormat("Executable module set to \"%s\".\n",
448061da546Spatrick                                        new_path);
449061da546Spatrick       }
450061da546Spatrick     } else if (old_exec_module_sp->GetFileSpec() !=
451061da546Spatrick                new_exec_module_sp->GetFileSpec()) {
452061da546Spatrick       char old_path[PATH_MAX];
453061da546Spatrick 
454061da546Spatrick       old_exec_module_sp->GetFileSpec().GetPath(old_path, PATH_MAX);
455061da546Spatrick       new_exec_module_sp->GetFileSpec().GetPath(new_path, PATH_MAX);
456061da546Spatrick 
457061da546Spatrick       result.AppendWarningWithFormat(
458061da546Spatrick           "Executable module changed from \"%s\" to \"%s\".\n", old_path,
459061da546Spatrick           new_path);
460061da546Spatrick     }
461061da546Spatrick 
462061da546Spatrick     if (!old_arch_spec.IsValid()) {
463061da546Spatrick       result.AppendMessageWithFormat(
464061da546Spatrick           "Architecture set to: %s.\n",
465061da546Spatrick           target->GetArchitecture().GetTriple().getTriple().c_str());
466061da546Spatrick     } else if (!old_arch_spec.IsExactMatch(target->GetArchitecture())) {
467061da546Spatrick       result.AppendWarningWithFormat(
468061da546Spatrick           "Architecture changed from %s to %s.\n",
469061da546Spatrick           old_arch_spec.GetTriple().getTriple().c_str(),
470061da546Spatrick           target->GetArchitecture().GetTriple().getTriple().c_str());
471061da546Spatrick     }
472061da546Spatrick 
473061da546Spatrick     // This supports the use-case scenario of immediately continuing the
474061da546Spatrick     // process once attached.
475*f6aab3d8Srobert     if (m_options.attach_info.GetContinueOnceAttached()) {
476*f6aab3d8Srobert       // We have made a process but haven't told the interpreter about it yet,
477*f6aab3d8Srobert       // so CheckRequirements will fail for "process continue".  Set the override
478*f6aab3d8Srobert       // here:
479*f6aab3d8Srobert       ExecutionContext exe_ctx(process_sp);
480*f6aab3d8Srobert       m_interpreter.HandleCommand("process continue", eLazyBoolNo, exe_ctx, result);
481*f6aab3d8Srobert     }
482061da546Spatrick 
483061da546Spatrick     return result.Succeeded();
484061da546Spatrick   }
485061da546Spatrick 
486061da546Spatrick   CommandOptions m_options;
487061da546Spatrick };
488061da546Spatrick 
489061da546Spatrick // CommandObjectProcessContinue
490061da546Spatrick 
491061da546Spatrick #define LLDB_OPTIONS_process_continue
492061da546Spatrick #include "CommandOptions.inc"
493061da546Spatrick 
494061da546Spatrick #pragma mark CommandObjectProcessContinue
495061da546Spatrick 
496061da546Spatrick class CommandObjectProcessContinue : public CommandObjectParsed {
497061da546Spatrick public:
CommandObjectProcessContinue(CommandInterpreter & interpreter)498061da546Spatrick   CommandObjectProcessContinue(CommandInterpreter &interpreter)
499061da546Spatrick       : CommandObjectParsed(
500061da546Spatrick             interpreter, "process continue",
501061da546Spatrick             "Continue execution of all threads in the current process.",
502061da546Spatrick             "process continue",
503061da546Spatrick             eCommandRequiresProcess | eCommandTryTargetAPILock |
504*f6aab3d8Srobert                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {}
505061da546Spatrick 
506061da546Spatrick   ~CommandObjectProcessContinue() override = default;
507061da546Spatrick 
508061da546Spatrick protected:
509061da546Spatrick   class CommandOptions : public Options {
510061da546Spatrick   public:
CommandOptions()511*f6aab3d8Srobert     CommandOptions() {
512061da546Spatrick       // Keep default values of all options in one place: OptionParsingStarting
513061da546Spatrick       // ()
514061da546Spatrick       OptionParsingStarting(nullptr);
515061da546Spatrick     }
516061da546Spatrick 
517061da546Spatrick     ~CommandOptions() override = default;
518061da546Spatrick 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * exe_ctx)519061da546Spatrick     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
520*f6aab3d8Srobert                           ExecutionContext *exe_ctx) override {
521061da546Spatrick       Status error;
522061da546Spatrick       const int short_option = m_getopt_table[option_idx].val;
523061da546Spatrick       switch (short_option) {
524061da546Spatrick       case 'i':
525061da546Spatrick         if (option_arg.getAsInteger(0, m_ignore))
526061da546Spatrick           error.SetErrorStringWithFormat(
527061da546Spatrick               "invalid value for ignore option: \"%s\", should be a number.",
528061da546Spatrick               option_arg.str().c_str());
529061da546Spatrick         break;
530*f6aab3d8Srobert       case 'b':
531*f6aab3d8Srobert         m_run_to_bkpt_args.AppendArgument(option_arg);
532*f6aab3d8Srobert         m_any_bkpts_specified = true;
533*f6aab3d8Srobert       break;
534061da546Spatrick       default:
535061da546Spatrick         llvm_unreachable("Unimplemented option");
536061da546Spatrick       }
537061da546Spatrick       return error;
538061da546Spatrick     }
539061da546Spatrick 
OptionParsingStarting(ExecutionContext * execution_context)540061da546Spatrick     void OptionParsingStarting(ExecutionContext *execution_context) override {
541061da546Spatrick       m_ignore = 0;
542*f6aab3d8Srobert       m_run_to_bkpt_args.Clear();
543*f6aab3d8Srobert       m_any_bkpts_specified = false;
544061da546Spatrick     }
545061da546Spatrick 
GetDefinitions()546061da546Spatrick     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
547*f6aab3d8Srobert       return llvm::ArrayRef(g_process_continue_options);
548061da546Spatrick     }
549061da546Spatrick 
550*f6aab3d8Srobert     uint32_t m_ignore = 0;
551*f6aab3d8Srobert     Args m_run_to_bkpt_args;
552*f6aab3d8Srobert     bool m_any_bkpts_specified = false;
553061da546Spatrick   };
554061da546Spatrick 
555*f6aab3d8Srobert 
DoExecute(Args & command,CommandReturnObject & result)556061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
557061da546Spatrick     Process *process = m_exe_ctx.GetProcessPtr();
558061da546Spatrick     bool synchronous_execution = m_interpreter.GetSynchronous();
559061da546Spatrick     StateType state = process->GetState();
560061da546Spatrick     if (state == eStateStopped) {
561061da546Spatrick       if (m_options.m_ignore > 0) {
562061da546Spatrick         ThreadSP sel_thread_sp(GetDefaultThread()->shared_from_this());
563061da546Spatrick         if (sel_thread_sp) {
564061da546Spatrick           StopInfoSP stop_info_sp = sel_thread_sp->GetStopInfo();
565061da546Spatrick           if (stop_info_sp &&
566061da546Spatrick               stop_info_sp->GetStopReason() == eStopReasonBreakpoint) {
567061da546Spatrick             lldb::break_id_t bp_site_id =
568061da546Spatrick                 (lldb::break_id_t)stop_info_sp->GetValue();
569061da546Spatrick             BreakpointSiteSP bp_site_sp(
570061da546Spatrick                 process->GetBreakpointSiteList().FindByID(bp_site_id));
571061da546Spatrick             if (bp_site_sp) {
572061da546Spatrick               const size_t num_owners = bp_site_sp->GetNumberOfOwners();
573061da546Spatrick               for (size_t i = 0; i < num_owners; i++) {
574061da546Spatrick                 Breakpoint &bp_ref =
575061da546Spatrick                     bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint();
576061da546Spatrick                 if (!bp_ref.IsInternal()) {
577061da546Spatrick                   bp_ref.SetIgnoreCount(m_options.m_ignore);
578061da546Spatrick                 }
579061da546Spatrick               }
580061da546Spatrick             }
581061da546Spatrick           }
582061da546Spatrick         }
583061da546Spatrick       }
584061da546Spatrick 
585*f6aab3d8Srobert       Target *target = m_exe_ctx.GetTargetPtr();
586*f6aab3d8Srobert       BreakpointIDList run_to_bkpt_ids;
587*f6aab3d8Srobert       // Don't pass an empty run_to_breakpoint list, as Verify will look for the
588*f6aab3d8Srobert       // default breakpoint.
589*f6aab3d8Srobert       if (m_options.m_run_to_bkpt_args.GetArgumentCount() > 0)
590*f6aab3d8Srobert         CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
591*f6aab3d8Srobert             m_options.m_run_to_bkpt_args, target, result, &run_to_bkpt_ids,
592*f6aab3d8Srobert             BreakpointName::Permissions::disablePerm);
593*f6aab3d8Srobert       if (!result.Succeeded()) {
594*f6aab3d8Srobert         return false;
595*f6aab3d8Srobert       }
596*f6aab3d8Srobert       result.Clear();
597*f6aab3d8Srobert       if (m_options.m_any_bkpts_specified && run_to_bkpt_ids.GetSize() == 0) {
598*f6aab3d8Srobert         result.AppendError("continue-to breakpoints did not specify any actual "
599*f6aab3d8Srobert                            "breakpoints or locations");
600*f6aab3d8Srobert         return false;
601*f6aab3d8Srobert       }
602*f6aab3d8Srobert 
603*f6aab3d8Srobert       // First figure out which breakpoints & locations were specified by the
604*f6aab3d8Srobert       // user:
605*f6aab3d8Srobert       size_t num_run_to_bkpt_ids = run_to_bkpt_ids.GetSize();
606*f6aab3d8Srobert       std::vector<break_id_t> bkpts_disabled;
607*f6aab3d8Srobert       std::vector<BreakpointID> locs_disabled;
608*f6aab3d8Srobert       if (num_run_to_bkpt_ids != 0) {
609*f6aab3d8Srobert         // Go through the ID's specified, and separate the breakpoints from are
610*f6aab3d8Srobert         // the breakpoint.location specifications since the latter require
611*f6aab3d8Srobert         // special handling.  We also figure out whether there's at least one
612*f6aab3d8Srobert         // specifier in the set that is enabled.
613*f6aab3d8Srobert         BreakpointList &bkpt_list = target->GetBreakpointList();
614*f6aab3d8Srobert         std::unordered_set<break_id_t> bkpts_seen;
615*f6aab3d8Srobert         std::unordered_set<break_id_t> bkpts_with_locs_seen;
616*f6aab3d8Srobert         BreakpointIDList with_locs;
617*f6aab3d8Srobert         bool any_enabled = false;
618*f6aab3d8Srobert 
619*f6aab3d8Srobert         for (size_t idx = 0; idx < num_run_to_bkpt_ids; idx++) {
620*f6aab3d8Srobert           BreakpointID bkpt_id = run_to_bkpt_ids.GetBreakpointIDAtIndex(idx);
621*f6aab3d8Srobert           break_id_t bp_id = bkpt_id.GetBreakpointID();
622*f6aab3d8Srobert           break_id_t loc_id = bkpt_id.GetLocationID();
623*f6aab3d8Srobert           BreakpointSP bp_sp
624*f6aab3d8Srobert               = bkpt_list.FindBreakpointByID(bp_id);
625*f6aab3d8Srobert           // Note, VerifyBreakpointOrLocationIDs checks for existence, so we
626*f6aab3d8Srobert           // don't need to do it again here.
627*f6aab3d8Srobert           if (bp_sp->IsEnabled()) {
628*f6aab3d8Srobert             if (loc_id == LLDB_INVALID_BREAK_ID) {
629*f6aab3d8Srobert               // A breakpoint (without location) was specified.  Make sure that
630*f6aab3d8Srobert               // at least one of the locations is enabled.
631*f6aab3d8Srobert               size_t num_locations = bp_sp->GetNumLocations();
632*f6aab3d8Srobert               for (size_t loc_idx = 0; loc_idx < num_locations; loc_idx++) {
633*f6aab3d8Srobert                 BreakpointLocationSP loc_sp
634*f6aab3d8Srobert                     = bp_sp->GetLocationAtIndex(loc_idx);
635*f6aab3d8Srobert                 if (loc_sp->IsEnabled()) {
636*f6aab3d8Srobert                   any_enabled = true;
637*f6aab3d8Srobert                   break;
638*f6aab3d8Srobert                 }
639*f6aab3d8Srobert               }
640*f6aab3d8Srobert             } else {
641*f6aab3d8Srobert               // A location was specified, check if it was enabled:
642*f6aab3d8Srobert               BreakpointLocationSP loc_sp = bp_sp->FindLocationByID(loc_id);
643*f6aab3d8Srobert               if (loc_sp->IsEnabled())
644*f6aab3d8Srobert                 any_enabled = true;
645*f6aab3d8Srobert             }
646*f6aab3d8Srobert 
647*f6aab3d8Srobert             // Then sort the bp & bp.loc entries for later use:
648*f6aab3d8Srobert             if (bkpt_id.GetLocationID() == LLDB_INVALID_BREAK_ID)
649*f6aab3d8Srobert               bkpts_seen.insert(bkpt_id.GetBreakpointID());
650*f6aab3d8Srobert             else {
651*f6aab3d8Srobert               bkpts_with_locs_seen.insert(bkpt_id.GetBreakpointID());
652*f6aab3d8Srobert               with_locs.AddBreakpointID(bkpt_id);
653*f6aab3d8Srobert             }
654*f6aab3d8Srobert           }
655*f6aab3d8Srobert         }
656*f6aab3d8Srobert         // Do all the error checking here so once we start disabling we don't
657*f6aab3d8Srobert         // have to back out half-way through.
658*f6aab3d8Srobert 
659*f6aab3d8Srobert         // Make sure at least one of the specified breakpoints is enabled.
660*f6aab3d8Srobert         if (!any_enabled) {
661*f6aab3d8Srobert           result.AppendError("at least one of the continue-to breakpoints must "
662*f6aab3d8Srobert                              "be enabled.");
663*f6aab3d8Srobert           return false;
664*f6aab3d8Srobert         }
665*f6aab3d8Srobert 
666*f6aab3d8Srobert         // Also, if you specify BOTH a breakpoint and one of it's locations,
667*f6aab3d8Srobert         // we flag that as an error, since it won't do what you expect, the
668*f6aab3d8Srobert         // breakpoint directive will mean "run to all locations", which is not
669*f6aab3d8Srobert         // what the location directive means...
670*f6aab3d8Srobert         for (break_id_t bp_id : bkpts_with_locs_seen) {
671*f6aab3d8Srobert           if (bkpts_seen.count(bp_id)) {
672*f6aab3d8Srobert             result.AppendErrorWithFormatv("can't specify both a breakpoint and "
673*f6aab3d8Srobert                                "one of its locations: {0}", bp_id);
674*f6aab3d8Srobert           }
675*f6aab3d8Srobert         }
676*f6aab3d8Srobert 
677*f6aab3d8Srobert         // Now go through the breakpoints in the target, disabling all the ones
678*f6aab3d8Srobert         // that the user didn't mention:
679*f6aab3d8Srobert         for (BreakpointSP bp_sp : bkpt_list.Breakpoints()) {
680*f6aab3d8Srobert           break_id_t bp_id = bp_sp->GetID();
681*f6aab3d8Srobert           // Handle the case where no locations were specified.  Note we don't
682*f6aab3d8Srobert           // have to worry about the case where a breakpoint and one of its
683*f6aab3d8Srobert           // locations are both in the lists, we've already disallowed that.
684*f6aab3d8Srobert           if (!bkpts_with_locs_seen.count(bp_id)) {
685*f6aab3d8Srobert             if (!bkpts_seen.count(bp_id) && bp_sp->IsEnabled()) {
686*f6aab3d8Srobert               bkpts_disabled.push_back(bp_id);
687*f6aab3d8Srobert               bp_sp->SetEnabled(false);
688*f6aab3d8Srobert             }
689*f6aab3d8Srobert             continue;
690*f6aab3d8Srobert           }
691*f6aab3d8Srobert           // Next, handle the case where a location was specified:
692*f6aab3d8Srobert           // Run through all the locations of this breakpoint and disable
693*f6aab3d8Srobert           // the ones that aren't on our "with locations" BreakpointID list:
694*f6aab3d8Srobert           size_t num_locations = bp_sp->GetNumLocations();
695*f6aab3d8Srobert           BreakpointID tmp_id(bp_id, LLDB_INVALID_BREAK_ID);
696*f6aab3d8Srobert           for (size_t loc_idx = 0; loc_idx < num_locations; loc_idx++) {
697*f6aab3d8Srobert             BreakpointLocationSP loc_sp = bp_sp->GetLocationAtIndex(loc_idx);
698*f6aab3d8Srobert             tmp_id.SetBreakpointLocationID(loc_idx);
699*f6aab3d8Srobert             size_t position = 0;
700*f6aab3d8Srobert             if (!with_locs.FindBreakpointID(tmp_id, &position)
701*f6aab3d8Srobert                 && loc_sp->IsEnabled()) {
702*f6aab3d8Srobert               locs_disabled.push_back(tmp_id);
703*f6aab3d8Srobert               loc_sp->SetEnabled(false);
704*f6aab3d8Srobert             }
705*f6aab3d8Srobert           }
706*f6aab3d8Srobert         }
707*f6aab3d8Srobert       }
708*f6aab3d8Srobert 
709061da546Spatrick       { // Scope for thread list mutex:
710061da546Spatrick         std::lock_guard<std::recursive_mutex> guard(
711061da546Spatrick             process->GetThreadList().GetMutex());
712061da546Spatrick         const uint32_t num_threads = process->GetThreadList().GetSize();
713061da546Spatrick 
714061da546Spatrick         // Set the actions that the threads should each take when resuming
715061da546Spatrick         for (uint32_t idx = 0; idx < num_threads; ++idx) {
716061da546Spatrick           const bool override_suspend = false;
717061da546Spatrick           process->GetThreadList().GetThreadAtIndex(idx)->SetResumeState(
718061da546Spatrick               eStateRunning, override_suspend);
719061da546Spatrick         }
720061da546Spatrick       }
721061da546Spatrick 
722061da546Spatrick       const uint32_t iohandler_id = process->GetIOHandlerID();
723061da546Spatrick 
724061da546Spatrick       StreamString stream;
725061da546Spatrick       Status error;
726*f6aab3d8Srobert       // For now we can only do -b with synchronous:
727*f6aab3d8Srobert       bool old_sync = GetDebugger().GetAsyncExecution();
728*f6aab3d8Srobert 
729*f6aab3d8Srobert       if (run_to_bkpt_ids.GetSize() != 0) {
730*f6aab3d8Srobert         GetDebugger().SetAsyncExecution(false);
731*f6aab3d8Srobert         synchronous_execution = true;
732*f6aab3d8Srobert       }
733061da546Spatrick       if (synchronous_execution)
734061da546Spatrick         error = process->ResumeSynchronous(&stream);
735061da546Spatrick       else
736061da546Spatrick         error = process->Resume();
737061da546Spatrick 
738*f6aab3d8Srobert       if (run_to_bkpt_ids.GetSize() != 0) {
739*f6aab3d8Srobert         GetDebugger().SetAsyncExecution(old_sync);
740*f6aab3d8Srobert       }
741*f6aab3d8Srobert 
742*f6aab3d8Srobert       // Now re-enable the breakpoints we disabled:
743*f6aab3d8Srobert       BreakpointList &bkpt_list = target->GetBreakpointList();
744*f6aab3d8Srobert       for (break_id_t bp_id : bkpts_disabled) {
745*f6aab3d8Srobert         BreakpointSP bp_sp = bkpt_list.FindBreakpointByID(bp_id);
746*f6aab3d8Srobert         if (bp_sp)
747*f6aab3d8Srobert           bp_sp->SetEnabled(true);
748*f6aab3d8Srobert       }
749*f6aab3d8Srobert       for (const BreakpointID &bkpt_id : locs_disabled) {
750*f6aab3d8Srobert         BreakpointSP bp_sp
751*f6aab3d8Srobert             = bkpt_list.FindBreakpointByID(bkpt_id.GetBreakpointID());
752*f6aab3d8Srobert         if (bp_sp) {
753*f6aab3d8Srobert           BreakpointLocationSP loc_sp
754*f6aab3d8Srobert               = bp_sp->FindLocationByID(bkpt_id.GetLocationID());
755*f6aab3d8Srobert           if (loc_sp)
756*f6aab3d8Srobert             loc_sp->SetEnabled(true);
757*f6aab3d8Srobert         }
758*f6aab3d8Srobert       }
759*f6aab3d8Srobert 
760061da546Spatrick       if (error.Success()) {
761061da546Spatrick         // There is a race condition where this thread will return up the call
762061da546Spatrick         // stack to the main command handler and show an (lldb) prompt before
763061da546Spatrick         // HandlePrivateEvent (from PrivateStateThread) has a chance to call
764061da546Spatrick         // PushProcessIOHandler().
765061da546Spatrick         process->SyncIOHandler(iohandler_id, std::chrono::seconds(2));
766061da546Spatrick 
767061da546Spatrick         result.AppendMessageWithFormat("Process %" PRIu64 " resuming\n",
768061da546Spatrick                                        process->GetID());
769061da546Spatrick         if (synchronous_execution) {
770061da546Spatrick           // If any state changed events had anything to say, add that to the
771061da546Spatrick           // result
772061da546Spatrick           result.AppendMessage(stream.GetString());
773061da546Spatrick 
774061da546Spatrick           result.SetDidChangeProcessState(true);
775061da546Spatrick           result.SetStatus(eReturnStatusSuccessFinishNoResult);
776061da546Spatrick         } else {
777061da546Spatrick           result.SetStatus(eReturnStatusSuccessContinuingNoResult);
778061da546Spatrick         }
779061da546Spatrick       } else {
780061da546Spatrick         result.AppendErrorWithFormat("Failed to resume process: %s.\n",
781061da546Spatrick                                      error.AsCString());
782061da546Spatrick       }
783061da546Spatrick     } else {
784061da546Spatrick       result.AppendErrorWithFormat(
785061da546Spatrick           "Process cannot be continued from its current state (%s).\n",
786061da546Spatrick           StateAsCString(state));
787061da546Spatrick     }
788061da546Spatrick     return result.Succeeded();
789061da546Spatrick   }
790061da546Spatrick 
GetOptions()791061da546Spatrick   Options *GetOptions() override { return &m_options; }
792061da546Spatrick 
793061da546Spatrick   CommandOptions m_options;
794061da546Spatrick };
795061da546Spatrick 
796061da546Spatrick // CommandObjectProcessDetach
797061da546Spatrick #define LLDB_OPTIONS_process_detach
798061da546Spatrick #include "CommandOptions.inc"
799061da546Spatrick 
800061da546Spatrick #pragma mark CommandObjectProcessDetach
801061da546Spatrick 
802061da546Spatrick class CommandObjectProcessDetach : public CommandObjectParsed {
803061da546Spatrick public:
804061da546Spatrick   class CommandOptions : public Options {
805061da546Spatrick   public:
CommandOptions()806*f6aab3d8Srobert     CommandOptions() { OptionParsingStarting(nullptr); }
807061da546Spatrick 
808061da546Spatrick     ~CommandOptions() override = default;
809061da546Spatrick 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)810061da546Spatrick     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
811061da546Spatrick                           ExecutionContext *execution_context) override {
812061da546Spatrick       Status error;
813061da546Spatrick       const int short_option = m_getopt_table[option_idx].val;
814061da546Spatrick 
815061da546Spatrick       switch (short_option) {
816061da546Spatrick       case 's':
817061da546Spatrick         bool tmp_result;
818061da546Spatrick         bool success;
819061da546Spatrick         tmp_result = OptionArgParser::ToBoolean(option_arg, false, &success);
820061da546Spatrick         if (!success)
821061da546Spatrick           error.SetErrorStringWithFormat("invalid boolean option: \"%s\"",
822061da546Spatrick                                          option_arg.str().c_str());
823061da546Spatrick         else {
824061da546Spatrick           if (tmp_result)
825061da546Spatrick             m_keep_stopped = eLazyBoolYes;
826061da546Spatrick           else
827061da546Spatrick             m_keep_stopped = eLazyBoolNo;
828061da546Spatrick         }
829061da546Spatrick         break;
830061da546Spatrick       default:
831061da546Spatrick         llvm_unreachable("Unimplemented option");
832061da546Spatrick       }
833061da546Spatrick       return error;
834061da546Spatrick     }
835061da546Spatrick 
OptionParsingStarting(ExecutionContext * execution_context)836061da546Spatrick     void OptionParsingStarting(ExecutionContext *execution_context) override {
837061da546Spatrick       m_keep_stopped = eLazyBoolCalculate;
838061da546Spatrick     }
839061da546Spatrick 
GetDefinitions()840061da546Spatrick     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
841*f6aab3d8Srobert       return llvm::ArrayRef(g_process_detach_options);
842061da546Spatrick     }
843061da546Spatrick 
844061da546Spatrick     // Instance variables to hold the values for command options.
845061da546Spatrick     LazyBool m_keep_stopped;
846061da546Spatrick   };
847061da546Spatrick 
CommandObjectProcessDetach(CommandInterpreter & interpreter)848061da546Spatrick   CommandObjectProcessDetach(CommandInterpreter &interpreter)
849061da546Spatrick       : CommandObjectParsed(interpreter, "process detach",
850061da546Spatrick                             "Detach from the current target process.",
851061da546Spatrick                             "process detach",
852061da546Spatrick                             eCommandRequiresProcess | eCommandTryTargetAPILock |
853*f6aab3d8Srobert                                 eCommandProcessMustBeLaunched) {}
854061da546Spatrick 
855061da546Spatrick   ~CommandObjectProcessDetach() override = default;
856061da546Spatrick 
GetOptions()857061da546Spatrick   Options *GetOptions() override { return &m_options; }
858061da546Spatrick 
859061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)860061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
861061da546Spatrick     Process *process = m_exe_ctx.GetProcessPtr();
862061da546Spatrick     // FIXME: This will be a Command Option:
863061da546Spatrick     bool keep_stopped;
864061da546Spatrick     if (m_options.m_keep_stopped == eLazyBoolCalculate) {
865061da546Spatrick       // Check the process default:
866061da546Spatrick       keep_stopped = process->GetDetachKeepsStopped();
867061da546Spatrick     } else if (m_options.m_keep_stopped == eLazyBoolYes)
868061da546Spatrick       keep_stopped = true;
869061da546Spatrick     else
870061da546Spatrick       keep_stopped = false;
871061da546Spatrick 
872061da546Spatrick     Status error(process->Detach(keep_stopped));
873061da546Spatrick     if (error.Success()) {
874061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishResult);
875061da546Spatrick     } else {
876061da546Spatrick       result.AppendErrorWithFormat("Detach failed: %s\n", error.AsCString());
877061da546Spatrick       return false;
878061da546Spatrick     }
879061da546Spatrick     return result.Succeeded();
880061da546Spatrick   }
881061da546Spatrick 
882061da546Spatrick   CommandOptions m_options;
883061da546Spatrick };
884061da546Spatrick 
885061da546Spatrick // CommandObjectProcessConnect
886061da546Spatrick #define LLDB_OPTIONS_process_connect
887061da546Spatrick #include "CommandOptions.inc"
888061da546Spatrick 
889061da546Spatrick #pragma mark CommandObjectProcessConnect
890061da546Spatrick 
891061da546Spatrick class CommandObjectProcessConnect : public CommandObjectParsed {
892061da546Spatrick public:
893061da546Spatrick   class CommandOptions : public Options {
894061da546Spatrick   public:
CommandOptions()895*f6aab3d8Srobert     CommandOptions() {
896061da546Spatrick       // Keep default values of all options in one place: OptionParsingStarting
897061da546Spatrick       // ()
898061da546Spatrick       OptionParsingStarting(nullptr);
899061da546Spatrick     }
900061da546Spatrick 
901061da546Spatrick     ~CommandOptions() override = default;
902061da546Spatrick 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)903061da546Spatrick     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
904061da546Spatrick                           ExecutionContext *execution_context) override {
905061da546Spatrick       Status error;
906061da546Spatrick       const int short_option = m_getopt_table[option_idx].val;
907061da546Spatrick 
908061da546Spatrick       switch (short_option) {
909061da546Spatrick       case 'p':
910dda28197Spatrick         plugin_name.assign(std::string(option_arg));
911061da546Spatrick         break;
912061da546Spatrick 
913061da546Spatrick       default:
914061da546Spatrick         llvm_unreachable("Unimplemented option");
915061da546Spatrick       }
916061da546Spatrick       return error;
917061da546Spatrick     }
918061da546Spatrick 
OptionParsingStarting(ExecutionContext * execution_context)919061da546Spatrick     void OptionParsingStarting(ExecutionContext *execution_context) override {
920061da546Spatrick       plugin_name.clear();
921061da546Spatrick     }
922061da546Spatrick 
GetDefinitions()923061da546Spatrick     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
924*f6aab3d8Srobert       return llvm::ArrayRef(g_process_connect_options);
925061da546Spatrick     }
926061da546Spatrick 
927061da546Spatrick     // Instance variables to hold the values for command options.
928061da546Spatrick 
929061da546Spatrick     std::string plugin_name;
930061da546Spatrick   };
931061da546Spatrick 
CommandObjectProcessConnect(CommandInterpreter & interpreter)932061da546Spatrick   CommandObjectProcessConnect(CommandInterpreter &interpreter)
933061da546Spatrick       : CommandObjectParsed(interpreter, "process connect",
934061da546Spatrick                             "Connect to a remote debug service.",
935*f6aab3d8Srobert                             "process connect <remote-url>", 0) {
936*f6aab3d8Srobert     CommandArgumentData connect_arg{eArgTypeConnectURL, eArgRepeatPlain};
937*f6aab3d8Srobert     m_arguments.push_back({connect_arg});
938*f6aab3d8Srobert   }
939061da546Spatrick 
940061da546Spatrick   ~CommandObjectProcessConnect() override = default;
941061da546Spatrick 
GetOptions()942061da546Spatrick   Options *GetOptions() override { return &m_options; }
943061da546Spatrick 
944061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)945061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
946061da546Spatrick     if (command.GetArgumentCount() != 1) {
947061da546Spatrick       result.AppendErrorWithFormat(
948061da546Spatrick           "'%s' takes exactly one argument:\nUsage: %s\n", m_cmd_name.c_str(),
949061da546Spatrick           m_cmd_syntax.c_str());
950061da546Spatrick       return false;
951061da546Spatrick     }
952061da546Spatrick 
953061da546Spatrick     Process *process = m_exe_ctx.GetProcessPtr();
954061da546Spatrick     if (process && process->IsAlive()) {
955061da546Spatrick       result.AppendErrorWithFormat(
956061da546Spatrick           "Process %" PRIu64
957061da546Spatrick           " is currently being debugged, kill the process before connecting.\n",
958061da546Spatrick           process->GetID());
959061da546Spatrick       return false;
960061da546Spatrick     }
961061da546Spatrick 
962061da546Spatrick     const char *plugin_name = nullptr;
963061da546Spatrick     if (!m_options.plugin_name.empty())
964061da546Spatrick       plugin_name = m_options.plugin_name.c_str();
965061da546Spatrick 
966061da546Spatrick     Status error;
967061da546Spatrick     Debugger &debugger = GetDebugger();
968061da546Spatrick     PlatformSP platform_sp = m_interpreter.GetPlatform(true);
969dda28197Spatrick     ProcessSP process_sp =
970dda28197Spatrick         debugger.GetAsyncExecution()
971dda28197Spatrick             ? platform_sp->ConnectProcess(
972061da546Spatrick                   command.GetArgumentAtIndex(0), plugin_name, debugger,
973dda28197Spatrick                   debugger.GetSelectedTarget().get(), error)
974dda28197Spatrick             : platform_sp->ConnectProcessSynchronous(
975dda28197Spatrick                   command.GetArgumentAtIndex(0), plugin_name, debugger,
976dda28197Spatrick                   result.GetOutputStream(), debugger.GetSelectedTarget().get(),
977dda28197Spatrick                   error);
978061da546Spatrick     if (error.Fail() || process_sp == nullptr) {
979061da546Spatrick       result.AppendError(error.AsCString("Error connecting to the process"));
980061da546Spatrick       return false;
981061da546Spatrick     }
982061da546Spatrick     return true;
983061da546Spatrick   }
984061da546Spatrick 
985061da546Spatrick   CommandOptions m_options;
986061da546Spatrick };
987061da546Spatrick 
988061da546Spatrick // CommandObjectProcessPlugin
989061da546Spatrick #pragma mark CommandObjectProcessPlugin
990061da546Spatrick 
991061da546Spatrick class CommandObjectProcessPlugin : public CommandObjectProxy {
992061da546Spatrick public:
CommandObjectProcessPlugin(CommandInterpreter & interpreter)993061da546Spatrick   CommandObjectProcessPlugin(CommandInterpreter &interpreter)
994061da546Spatrick       : CommandObjectProxy(
995061da546Spatrick             interpreter, "process plugin",
996061da546Spatrick             "Send a custom command to the current target process plug-in.",
997061da546Spatrick             "process plugin <args>", 0) {}
998061da546Spatrick 
999061da546Spatrick   ~CommandObjectProcessPlugin() override = default;
1000061da546Spatrick 
GetProxyCommandObject()1001061da546Spatrick   CommandObject *GetProxyCommandObject() override {
1002061da546Spatrick     Process *process = m_interpreter.GetExecutionContext().GetProcessPtr();
1003061da546Spatrick     if (process)
1004061da546Spatrick       return process->GetPluginCommandObject();
1005061da546Spatrick     return nullptr;
1006061da546Spatrick   }
1007061da546Spatrick };
1008061da546Spatrick 
1009061da546Spatrick // CommandObjectProcessLoad
1010061da546Spatrick #define LLDB_OPTIONS_process_load
1011061da546Spatrick #include "CommandOptions.inc"
1012061da546Spatrick 
1013061da546Spatrick #pragma mark CommandObjectProcessLoad
1014061da546Spatrick 
1015061da546Spatrick class CommandObjectProcessLoad : public CommandObjectParsed {
1016061da546Spatrick public:
1017061da546Spatrick   class CommandOptions : public Options {
1018061da546Spatrick   public:
CommandOptions()1019*f6aab3d8Srobert     CommandOptions() {
1020061da546Spatrick       // Keep default values of all options in one place: OptionParsingStarting
1021061da546Spatrick       // ()
1022061da546Spatrick       OptionParsingStarting(nullptr);
1023061da546Spatrick     }
1024061da546Spatrick 
1025061da546Spatrick     ~CommandOptions() override = default;
1026061da546Spatrick 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1027061da546Spatrick     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1028061da546Spatrick                           ExecutionContext *execution_context) override {
1029061da546Spatrick       Status error;
1030061da546Spatrick       const int short_option = m_getopt_table[option_idx].val;
1031061da546Spatrick       switch (short_option) {
1032061da546Spatrick       case 'i':
1033061da546Spatrick         do_install = true;
1034061da546Spatrick         if (!option_arg.empty())
1035061da546Spatrick           install_path.SetFile(option_arg, FileSpec::Style::native);
1036061da546Spatrick         break;
1037061da546Spatrick       default:
1038061da546Spatrick         llvm_unreachable("Unimplemented option");
1039061da546Spatrick       }
1040061da546Spatrick       return error;
1041061da546Spatrick     }
1042061da546Spatrick 
OptionParsingStarting(ExecutionContext * execution_context)1043061da546Spatrick     void OptionParsingStarting(ExecutionContext *execution_context) override {
1044061da546Spatrick       do_install = false;
1045061da546Spatrick       install_path.Clear();
1046061da546Spatrick     }
1047061da546Spatrick 
GetDefinitions()1048061da546Spatrick     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1049*f6aab3d8Srobert       return llvm::ArrayRef(g_process_load_options);
1050061da546Spatrick     }
1051061da546Spatrick 
1052061da546Spatrick     // Instance variables to hold the values for command options.
1053061da546Spatrick     bool do_install;
1054061da546Spatrick     FileSpec install_path;
1055061da546Spatrick   };
1056061da546Spatrick 
CommandObjectProcessLoad(CommandInterpreter & interpreter)1057061da546Spatrick   CommandObjectProcessLoad(CommandInterpreter &interpreter)
1058061da546Spatrick       : CommandObjectParsed(interpreter, "process load",
1059061da546Spatrick                             "Load a shared library into the current process.",
1060061da546Spatrick                             "process load <filename> [<filename> ...]",
1061061da546Spatrick                             eCommandRequiresProcess | eCommandTryTargetAPILock |
1062061da546Spatrick                                 eCommandProcessMustBeLaunched |
1063*f6aab3d8Srobert                                 eCommandProcessMustBePaused) {
1064*f6aab3d8Srobert     CommandArgumentData file_arg{eArgTypePath, eArgRepeatPlus};
1065*f6aab3d8Srobert     m_arguments.push_back({file_arg});
1066*f6aab3d8Srobert   }
1067061da546Spatrick 
1068061da546Spatrick   ~CommandObjectProcessLoad() override = default;
1069061da546Spatrick 
1070be691f3bSpatrick   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1071be691f3bSpatrick   HandleArgumentCompletion(CompletionRequest &request,
1072be691f3bSpatrick                            OptionElementVector &opt_element_vector) override {
1073be691f3bSpatrick     if (!m_exe_ctx.HasProcessScope())
1074be691f3bSpatrick       return;
1075be691f3bSpatrick 
1076be691f3bSpatrick     CommandCompletions::InvokeCommonCompletionCallbacks(
1077be691f3bSpatrick         GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion,
1078be691f3bSpatrick         request, nullptr);
1079be691f3bSpatrick   }
1080be691f3bSpatrick 
GetOptions()1081061da546Spatrick   Options *GetOptions() override { return &m_options; }
1082061da546Spatrick 
1083061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)1084061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
1085061da546Spatrick     Process *process = m_exe_ctx.GetProcessPtr();
1086061da546Spatrick 
1087061da546Spatrick     for (auto &entry : command.entries()) {
1088061da546Spatrick       Status error;
1089061da546Spatrick       PlatformSP platform = process->GetTarget().GetPlatform();
1090061da546Spatrick       llvm::StringRef image_path = entry.ref();
1091061da546Spatrick       uint32_t image_token = LLDB_INVALID_IMAGE_TOKEN;
1092061da546Spatrick 
1093061da546Spatrick       if (!m_options.do_install) {
1094061da546Spatrick         FileSpec image_spec(image_path);
1095061da546Spatrick         platform->ResolveRemotePath(image_spec, image_spec);
1096061da546Spatrick         image_token =
1097061da546Spatrick             platform->LoadImage(process, FileSpec(), image_spec, error);
1098061da546Spatrick       } else if (m_options.install_path) {
1099061da546Spatrick         FileSpec image_spec(image_path);
1100061da546Spatrick         FileSystem::Instance().Resolve(image_spec);
1101061da546Spatrick         platform->ResolveRemotePath(m_options.install_path,
1102061da546Spatrick                                     m_options.install_path);
1103061da546Spatrick         image_token = platform->LoadImage(process, image_spec,
1104061da546Spatrick                                           m_options.install_path, error);
1105061da546Spatrick       } else {
1106061da546Spatrick         FileSpec image_spec(image_path);
1107061da546Spatrick         FileSystem::Instance().Resolve(image_spec);
1108061da546Spatrick         image_token =
1109061da546Spatrick             platform->LoadImage(process, image_spec, FileSpec(), error);
1110061da546Spatrick       }
1111061da546Spatrick 
1112061da546Spatrick       if (image_token != LLDB_INVALID_IMAGE_TOKEN) {
1113061da546Spatrick         result.AppendMessageWithFormat(
1114061da546Spatrick             "Loading \"%s\"...ok\nImage %u loaded.\n", image_path.str().c_str(),
1115061da546Spatrick             image_token);
1116061da546Spatrick         result.SetStatus(eReturnStatusSuccessFinishResult);
1117061da546Spatrick       } else {
1118061da546Spatrick         result.AppendErrorWithFormat("failed to load '%s': %s",
1119061da546Spatrick                                      image_path.str().c_str(),
1120061da546Spatrick                                      error.AsCString());
1121061da546Spatrick       }
1122061da546Spatrick     }
1123061da546Spatrick     return result.Succeeded();
1124061da546Spatrick   }
1125061da546Spatrick 
1126061da546Spatrick   CommandOptions m_options;
1127061da546Spatrick };
1128061da546Spatrick 
1129061da546Spatrick // CommandObjectProcessUnload
1130061da546Spatrick #pragma mark CommandObjectProcessUnload
1131061da546Spatrick 
1132061da546Spatrick class CommandObjectProcessUnload : public CommandObjectParsed {
1133061da546Spatrick public:
CommandObjectProcessUnload(CommandInterpreter & interpreter)1134061da546Spatrick   CommandObjectProcessUnload(CommandInterpreter &interpreter)
1135061da546Spatrick       : CommandObjectParsed(
1136061da546Spatrick             interpreter, "process unload",
1137061da546Spatrick             "Unload a shared library from the current process using the index "
1138061da546Spatrick             "returned by a previous call to \"process load\".",
1139061da546Spatrick             "process unload <index>",
1140061da546Spatrick             eCommandRequiresProcess | eCommandTryTargetAPILock |
1141*f6aab3d8Srobert                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {
1142*f6aab3d8Srobert     CommandArgumentData load_idx_arg{eArgTypeUnsignedInteger, eArgRepeatPlain};
1143*f6aab3d8Srobert     m_arguments.push_back({load_idx_arg});
1144*f6aab3d8Srobert   }
1145061da546Spatrick 
1146061da546Spatrick   ~CommandObjectProcessUnload() override = default;
1147061da546Spatrick 
1148be691f3bSpatrick   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1149be691f3bSpatrick   HandleArgumentCompletion(CompletionRequest &request,
1150be691f3bSpatrick                            OptionElementVector &opt_element_vector) override {
1151be691f3bSpatrick 
1152be691f3bSpatrick     if (request.GetCursorIndex() || !m_exe_ctx.HasProcessScope())
1153be691f3bSpatrick       return;
1154be691f3bSpatrick 
1155be691f3bSpatrick     Process *process = m_exe_ctx.GetProcessPtr();
1156be691f3bSpatrick 
1157be691f3bSpatrick     const std::vector<lldb::addr_t> &tokens = process->GetImageTokens();
1158be691f3bSpatrick     const size_t token_num = tokens.size();
1159be691f3bSpatrick     for (size_t i = 0; i < token_num; ++i) {
1160be691f3bSpatrick       if (tokens[i] == LLDB_INVALID_IMAGE_TOKEN)
1161be691f3bSpatrick         continue;
1162be691f3bSpatrick       request.TryCompleteCurrentArg(std::to_string(i));
1163be691f3bSpatrick     }
1164be691f3bSpatrick   }
1165be691f3bSpatrick 
1166061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)1167061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
1168061da546Spatrick     Process *process = m_exe_ctx.GetProcessPtr();
1169061da546Spatrick 
1170061da546Spatrick     for (auto &entry : command.entries()) {
1171061da546Spatrick       uint32_t image_token;
1172061da546Spatrick       if (entry.ref().getAsInteger(0, image_token)) {
1173061da546Spatrick         result.AppendErrorWithFormat("invalid image index argument '%s'",
1174061da546Spatrick                                      entry.ref().str().c_str());
1175061da546Spatrick         break;
1176061da546Spatrick       } else {
1177061da546Spatrick         Status error(process->GetTarget().GetPlatform()->UnloadImage(
1178061da546Spatrick             process, image_token));
1179061da546Spatrick         if (error.Success()) {
1180061da546Spatrick           result.AppendMessageWithFormat(
1181061da546Spatrick               "Unloading shared library with index %u...ok\n", image_token);
1182061da546Spatrick           result.SetStatus(eReturnStatusSuccessFinishResult);
1183061da546Spatrick         } else {
1184061da546Spatrick           result.AppendErrorWithFormat("failed to unload image: %s",
1185061da546Spatrick                                        error.AsCString());
1186061da546Spatrick           break;
1187061da546Spatrick         }
1188061da546Spatrick       }
1189061da546Spatrick     }
1190061da546Spatrick     return result.Succeeded();
1191061da546Spatrick   }
1192061da546Spatrick };
1193061da546Spatrick 
1194061da546Spatrick // CommandObjectProcessSignal
1195061da546Spatrick #pragma mark CommandObjectProcessSignal
1196061da546Spatrick 
1197061da546Spatrick class CommandObjectProcessSignal : public CommandObjectParsed {
1198061da546Spatrick public:
CommandObjectProcessSignal(CommandInterpreter & interpreter)1199061da546Spatrick   CommandObjectProcessSignal(CommandInterpreter &interpreter)
1200061da546Spatrick       : CommandObjectParsed(
1201061da546Spatrick             interpreter, "process signal",
1202061da546Spatrick             "Send a UNIX signal to the current target process.", nullptr,
1203061da546Spatrick             eCommandRequiresProcess | eCommandTryTargetAPILock) {
1204061da546Spatrick     CommandArgumentEntry arg;
1205061da546Spatrick     CommandArgumentData signal_arg;
1206061da546Spatrick 
1207061da546Spatrick     // Define the first (and only) variant of this arg.
1208061da546Spatrick     signal_arg.arg_type = eArgTypeUnixSignal;
1209061da546Spatrick     signal_arg.arg_repetition = eArgRepeatPlain;
1210061da546Spatrick 
1211061da546Spatrick     // There is only one variant this argument could be; put it into the
1212061da546Spatrick     // argument entry.
1213061da546Spatrick     arg.push_back(signal_arg);
1214061da546Spatrick 
1215061da546Spatrick     // Push the data for the first argument into the m_arguments vector.
1216061da546Spatrick     m_arguments.push_back(arg);
1217061da546Spatrick   }
1218061da546Spatrick 
1219061da546Spatrick   ~CommandObjectProcessSignal() override = default;
1220061da546Spatrick 
1221dda28197Spatrick   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1222dda28197Spatrick   HandleArgumentCompletion(CompletionRequest &request,
1223dda28197Spatrick                            OptionElementVector &opt_element_vector) override {
1224dda28197Spatrick     if (!m_exe_ctx.HasProcessScope() || request.GetCursorIndex() != 0)
1225dda28197Spatrick       return;
1226dda28197Spatrick 
1227dda28197Spatrick     UnixSignalsSP signals = m_exe_ctx.GetProcessPtr()->GetUnixSignals();
1228dda28197Spatrick     int signo = signals->GetFirstSignalNumber();
1229dda28197Spatrick     while (signo != LLDB_INVALID_SIGNAL_NUMBER) {
1230be691f3bSpatrick       request.TryCompleteCurrentArg(signals->GetSignalAsCString(signo));
1231dda28197Spatrick       signo = signals->GetNextSignalNumber(signo);
1232dda28197Spatrick     }
1233dda28197Spatrick   }
1234dda28197Spatrick 
1235061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)1236061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
1237061da546Spatrick     Process *process = m_exe_ctx.GetProcessPtr();
1238061da546Spatrick 
1239061da546Spatrick     if (command.GetArgumentCount() == 1) {
1240061da546Spatrick       int signo = LLDB_INVALID_SIGNAL_NUMBER;
1241061da546Spatrick 
1242061da546Spatrick       const char *signal_name = command.GetArgumentAtIndex(0);
1243dda28197Spatrick       if (::isxdigit(signal_name[0])) {
1244dda28197Spatrick         if (!llvm::to_integer(signal_name, signo))
1245dda28197Spatrick           signo = LLDB_INVALID_SIGNAL_NUMBER;
1246dda28197Spatrick       } else
1247061da546Spatrick         signo = process->GetUnixSignals()->GetSignalNumberFromName(signal_name);
1248061da546Spatrick 
1249061da546Spatrick       if (signo == LLDB_INVALID_SIGNAL_NUMBER) {
1250061da546Spatrick         result.AppendErrorWithFormat("Invalid signal argument '%s'.\n",
1251061da546Spatrick                                      command.GetArgumentAtIndex(0));
1252061da546Spatrick       } else {
1253061da546Spatrick         Status error(process->Signal(signo));
1254061da546Spatrick         if (error.Success()) {
1255061da546Spatrick           result.SetStatus(eReturnStatusSuccessFinishResult);
1256061da546Spatrick         } else {
1257061da546Spatrick           result.AppendErrorWithFormat("Failed to send signal %i: %s\n", signo,
1258061da546Spatrick                                        error.AsCString());
1259061da546Spatrick         }
1260061da546Spatrick       }
1261061da546Spatrick     } else {
1262061da546Spatrick       result.AppendErrorWithFormat(
1263061da546Spatrick           "'%s' takes exactly one signal number argument:\nUsage: %s\n",
1264061da546Spatrick           m_cmd_name.c_str(), m_cmd_syntax.c_str());
1265061da546Spatrick     }
1266061da546Spatrick     return result.Succeeded();
1267061da546Spatrick   }
1268061da546Spatrick };
1269061da546Spatrick 
1270061da546Spatrick // CommandObjectProcessInterrupt
1271061da546Spatrick #pragma mark CommandObjectProcessInterrupt
1272061da546Spatrick 
1273061da546Spatrick class CommandObjectProcessInterrupt : public CommandObjectParsed {
1274061da546Spatrick public:
CommandObjectProcessInterrupt(CommandInterpreter & interpreter)1275061da546Spatrick   CommandObjectProcessInterrupt(CommandInterpreter &interpreter)
1276061da546Spatrick       : CommandObjectParsed(interpreter, "process interrupt",
1277061da546Spatrick                             "Interrupt the current target process.",
1278061da546Spatrick                             "process interrupt",
1279061da546Spatrick                             eCommandRequiresProcess | eCommandTryTargetAPILock |
1280061da546Spatrick                                 eCommandProcessMustBeLaunched) {}
1281061da546Spatrick 
1282061da546Spatrick   ~CommandObjectProcessInterrupt() override = default;
1283061da546Spatrick 
1284061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)1285061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
1286061da546Spatrick     Process *process = m_exe_ctx.GetProcessPtr();
1287061da546Spatrick     if (process == nullptr) {
1288061da546Spatrick       result.AppendError("no process to halt");
1289061da546Spatrick       return false;
1290061da546Spatrick     }
1291061da546Spatrick 
1292061da546Spatrick     bool clear_thread_plans = true;
1293061da546Spatrick     Status error(process->Halt(clear_thread_plans));
1294061da546Spatrick     if (error.Success()) {
1295061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishResult);
1296061da546Spatrick     } else {
1297061da546Spatrick       result.AppendErrorWithFormat("Failed to halt process: %s\n",
1298061da546Spatrick                                    error.AsCString());
1299061da546Spatrick     }
1300061da546Spatrick     return result.Succeeded();
1301061da546Spatrick   }
1302061da546Spatrick };
1303061da546Spatrick 
1304061da546Spatrick // CommandObjectProcessKill
1305061da546Spatrick #pragma mark CommandObjectProcessKill
1306061da546Spatrick 
1307061da546Spatrick class CommandObjectProcessKill : public CommandObjectParsed {
1308061da546Spatrick public:
CommandObjectProcessKill(CommandInterpreter & interpreter)1309061da546Spatrick   CommandObjectProcessKill(CommandInterpreter &interpreter)
1310061da546Spatrick       : CommandObjectParsed(interpreter, "process kill",
1311061da546Spatrick                             "Terminate the current target process.",
1312061da546Spatrick                             "process kill",
1313061da546Spatrick                             eCommandRequiresProcess | eCommandTryTargetAPILock |
1314061da546Spatrick                                 eCommandProcessMustBeLaunched) {}
1315061da546Spatrick 
1316061da546Spatrick   ~CommandObjectProcessKill() override = default;
1317061da546Spatrick 
1318061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)1319061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
1320061da546Spatrick     Process *process = m_exe_ctx.GetProcessPtr();
1321061da546Spatrick     if (process == nullptr) {
1322061da546Spatrick       result.AppendError("no process to kill");
1323061da546Spatrick       return false;
1324061da546Spatrick     }
1325061da546Spatrick 
1326061da546Spatrick     Status error(process->Destroy(true));
1327061da546Spatrick     if (error.Success()) {
1328061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishResult);
1329061da546Spatrick     } else {
1330061da546Spatrick       result.AppendErrorWithFormat("Failed to kill process: %s\n",
1331061da546Spatrick                                    error.AsCString());
1332061da546Spatrick     }
1333061da546Spatrick     return result.Succeeded();
1334061da546Spatrick   }
1335061da546Spatrick };
1336061da546Spatrick 
1337be691f3bSpatrick #define LLDB_OPTIONS_process_save_core
1338be691f3bSpatrick #include "CommandOptions.inc"
1339be691f3bSpatrick 
1340061da546Spatrick class CommandObjectProcessSaveCore : public CommandObjectParsed {
1341061da546Spatrick public:
CommandObjectProcessSaveCore(CommandInterpreter & interpreter)1342061da546Spatrick   CommandObjectProcessSaveCore(CommandInterpreter &interpreter)
1343*f6aab3d8Srobert       : CommandObjectParsed(
1344*f6aab3d8Srobert             interpreter, "process save-core",
1345061da546Spatrick             "Save the current process as a core file using an "
1346061da546Spatrick             "appropriate file type.",
1347*f6aab3d8Srobert             "process save-core [-s corefile-style -p plugin-name] FILE",
1348061da546Spatrick             eCommandRequiresProcess | eCommandTryTargetAPILock |
1349*f6aab3d8Srobert                 eCommandProcessMustBeLaunched) {
1350*f6aab3d8Srobert     CommandArgumentData file_arg{eArgTypePath, eArgRepeatPlain};
1351*f6aab3d8Srobert     m_arguments.push_back({file_arg});
1352*f6aab3d8Srobert   }
1353061da546Spatrick 
1354061da546Spatrick   ~CommandObjectProcessSaveCore() override = default;
1355061da546Spatrick 
GetOptions()1356be691f3bSpatrick   Options *GetOptions() override { return &m_options; }
1357be691f3bSpatrick 
1358be691f3bSpatrick   class CommandOptions : public Options {
1359be691f3bSpatrick   public:
1360*f6aab3d8Srobert     CommandOptions() = default;
1361be691f3bSpatrick 
1362be691f3bSpatrick     ~CommandOptions() override = default;
1363be691f3bSpatrick 
GetDefinitions()1364be691f3bSpatrick     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1365*f6aab3d8Srobert       return llvm::ArrayRef(g_process_save_core_options);
1366be691f3bSpatrick     }
1367be691f3bSpatrick 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1368be691f3bSpatrick     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1369be691f3bSpatrick                           ExecutionContext *execution_context) override {
1370be691f3bSpatrick       const int short_option = m_getopt_table[option_idx].val;
1371be691f3bSpatrick       Status error;
1372be691f3bSpatrick 
1373be691f3bSpatrick       switch (short_option) {
1374*f6aab3d8Srobert       case 'p':
1375*f6aab3d8Srobert         m_requested_plugin_name = option_arg.str();
1376*f6aab3d8Srobert         break;
1377be691f3bSpatrick       case 's':
1378be691f3bSpatrick         m_requested_save_core_style =
1379be691f3bSpatrick             (lldb::SaveCoreStyle)OptionArgParser::ToOptionEnum(
1380be691f3bSpatrick                 option_arg, GetDefinitions()[option_idx].enum_values,
1381be691f3bSpatrick                 eSaveCoreUnspecified, error);
1382be691f3bSpatrick         break;
1383be691f3bSpatrick       default:
1384be691f3bSpatrick         llvm_unreachable("Unimplemented option");
1385be691f3bSpatrick       }
1386be691f3bSpatrick 
1387be691f3bSpatrick       return {};
1388be691f3bSpatrick     }
1389be691f3bSpatrick 
OptionParsingStarting(ExecutionContext * execution_context)1390be691f3bSpatrick     void OptionParsingStarting(ExecutionContext *execution_context) override {
1391be691f3bSpatrick       m_requested_save_core_style = eSaveCoreUnspecified;
1392*f6aab3d8Srobert       m_requested_plugin_name.clear();
1393be691f3bSpatrick     }
1394be691f3bSpatrick 
1395be691f3bSpatrick     // Instance variables to hold the values for command options.
1396*f6aab3d8Srobert     SaveCoreStyle m_requested_save_core_style = eSaveCoreUnspecified;
1397*f6aab3d8Srobert     std::string m_requested_plugin_name;
1398be691f3bSpatrick   };
1399be691f3bSpatrick 
1400061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)1401061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
1402061da546Spatrick     ProcessSP process_sp = m_exe_ctx.GetProcessSP();
1403061da546Spatrick     if (process_sp) {
1404061da546Spatrick       if (command.GetArgumentCount() == 1) {
1405061da546Spatrick         FileSpec output_file(command.GetArgumentAtIndex(0));
1406be691f3bSpatrick         SaveCoreStyle corefile_style = m_options.m_requested_save_core_style;
1407be691f3bSpatrick         Status error =
1408*f6aab3d8Srobert             PluginManager::SaveCore(process_sp, output_file, corefile_style,
1409*f6aab3d8Srobert                                     m_options.m_requested_plugin_name);
1410061da546Spatrick         if (error.Success()) {
1411*f6aab3d8Srobert           if (corefile_style == SaveCoreStyle::eSaveCoreDirtyOnly ||
1412*f6aab3d8Srobert               corefile_style == SaveCoreStyle::eSaveCoreStackOnly) {
1413be691f3bSpatrick             result.AppendMessageWithFormat(
1414*f6aab3d8Srobert                 "\nModified-memory or stack-memory only corefile "
1415*f6aab3d8Srobert                 "created.  This corefile may \n"
1416*f6aab3d8Srobert                 "not show library/framework/app binaries "
1417be691f3bSpatrick                 "on a different system, or when \n"
1418be691f3bSpatrick                 "those binaries have "
1419be691f3bSpatrick                 "been updated/modified. Copies are not included\n"
1420be691f3bSpatrick                 "in this corefile.  Use --style full to include all "
1421be691f3bSpatrick                 "process memory.\n");
1422be691f3bSpatrick           }
1423061da546Spatrick           result.SetStatus(eReturnStatusSuccessFinishResult);
1424061da546Spatrick         } else {
1425061da546Spatrick           result.AppendErrorWithFormat(
1426061da546Spatrick               "Failed to save core file for process: %s\n", error.AsCString());
1427061da546Spatrick         }
1428061da546Spatrick       } else {
1429061da546Spatrick         result.AppendErrorWithFormat("'%s' takes one arguments:\nUsage: %s\n",
1430061da546Spatrick                                      m_cmd_name.c_str(), m_cmd_syntax.c_str());
1431061da546Spatrick       }
1432061da546Spatrick     } else {
1433061da546Spatrick       result.AppendError("invalid process");
1434061da546Spatrick       return false;
1435061da546Spatrick     }
1436061da546Spatrick 
1437061da546Spatrick     return result.Succeeded();
1438061da546Spatrick   }
1439be691f3bSpatrick 
1440be691f3bSpatrick   CommandOptions m_options;
1441061da546Spatrick };
1442061da546Spatrick 
1443061da546Spatrick // CommandObjectProcessStatus
1444061da546Spatrick #pragma mark CommandObjectProcessStatus
1445dda28197Spatrick #define LLDB_OPTIONS_process_status
1446dda28197Spatrick #include "CommandOptions.inc"
1447061da546Spatrick 
1448061da546Spatrick class CommandObjectProcessStatus : public CommandObjectParsed {
1449061da546Spatrick public:
CommandObjectProcessStatus(CommandInterpreter & interpreter)1450061da546Spatrick   CommandObjectProcessStatus(CommandInterpreter &interpreter)
1451061da546Spatrick       : CommandObjectParsed(
1452061da546Spatrick             interpreter, "process status",
1453061da546Spatrick             "Show status and stop location for the current target process.",
1454061da546Spatrick             "process status",
1455*f6aab3d8Srobert             eCommandRequiresProcess | eCommandTryTargetAPILock) {}
1456061da546Spatrick 
1457061da546Spatrick   ~CommandObjectProcessStatus() override = default;
1458061da546Spatrick 
GetOptions()1459dda28197Spatrick   Options *GetOptions() override { return &m_options; }
1460dda28197Spatrick 
1461dda28197Spatrick   class CommandOptions : public Options {
1462dda28197Spatrick   public:
1463*f6aab3d8Srobert     CommandOptions() = default;
1464dda28197Spatrick 
1465dda28197Spatrick     ~CommandOptions() override = default;
1466dda28197Spatrick 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1467dda28197Spatrick     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1468dda28197Spatrick                           ExecutionContext *execution_context) override {
1469dda28197Spatrick       const int short_option = m_getopt_table[option_idx].val;
1470dda28197Spatrick 
1471dda28197Spatrick       switch (short_option) {
1472dda28197Spatrick       case 'v':
1473dda28197Spatrick         m_verbose = true;
1474dda28197Spatrick         break;
1475dda28197Spatrick       default:
1476dda28197Spatrick         llvm_unreachable("Unimplemented option");
1477dda28197Spatrick       }
1478dda28197Spatrick 
1479dda28197Spatrick       return {};
1480dda28197Spatrick     }
1481dda28197Spatrick 
OptionParsingStarting(ExecutionContext * execution_context)1482dda28197Spatrick     void OptionParsingStarting(ExecutionContext *execution_context) override {
1483dda28197Spatrick       m_verbose = false;
1484dda28197Spatrick     }
1485dda28197Spatrick 
GetDefinitions()1486dda28197Spatrick     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1487*f6aab3d8Srobert       return llvm::ArrayRef(g_process_status_options);
1488dda28197Spatrick     }
1489dda28197Spatrick 
1490dda28197Spatrick     // Instance variables to hold the values for command options.
1491be691f3bSpatrick     bool m_verbose = false;
1492dda28197Spatrick   };
1493dda28197Spatrick 
1494dda28197Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)1495061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
1496061da546Spatrick     Stream &strm = result.GetOutputStream();
1497061da546Spatrick     result.SetStatus(eReturnStatusSuccessFinishNoResult);
1498dda28197Spatrick 
1499061da546Spatrick     // No need to check "process" for validity as eCommandRequiresProcess
1500061da546Spatrick     // ensures it is valid
1501061da546Spatrick     Process *process = m_exe_ctx.GetProcessPtr();
1502061da546Spatrick     const bool only_threads_with_stop_reason = true;
1503061da546Spatrick     const uint32_t start_frame = 0;
1504061da546Spatrick     const uint32_t num_frames = 1;
1505061da546Spatrick     const uint32_t num_frames_with_source = 1;
1506061da546Spatrick     const bool stop_format = true;
1507061da546Spatrick     process->GetStatus(strm);
1508061da546Spatrick     process->GetThreadStatus(strm, only_threads_with_stop_reason, start_frame,
1509061da546Spatrick                              num_frames, num_frames_with_source, stop_format);
1510dda28197Spatrick 
1511dda28197Spatrick     if (m_options.m_verbose) {
1512be691f3bSpatrick       addr_t code_mask = process->GetCodeAddressMask();
1513be691f3bSpatrick       addr_t data_mask = process->GetDataAddressMask();
1514be691f3bSpatrick       if (code_mask != 0) {
1515be691f3bSpatrick         int bits = std::bitset<64>(~code_mask).count();
1516be691f3bSpatrick         result.AppendMessageWithFormat(
1517be691f3bSpatrick             "Addressable code address mask: 0x%" PRIx64 "\n", code_mask);
1518be691f3bSpatrick         result.AppendMessageWithFormat(
1519be691f3bSpatrick             "Addressable data address mask: 0x%" PRIx64 "\n", data_mask);
1520be691f3bSpatrick         result.AppendMessageWithFormat(
1521be691f3bSpatrick             "Number of bits used in addressing (code): %d\n", bits);
1522be691f3bSpatrick       }
1523be691f3bSpatrick 
1524dda28197Spatrick       PlatformSP platform_sp = process->GetTarget().GetPlatform();
1525dda28197Spatrick       if (!platform_sp) {
1526dda28197Spatrick         result.AppendError("Couldn'retrieve the target's platform");
1527061da546Spatrick         return result.Succeeded();
1528061da546Spatrick       }
1529dda28197Spatrick 
1530dda28197Spatrick       auto expected_crash_info =
1531dda28197Spatrick           platform_sp->FetchExtendedCrashInformation(*process);
1532dda28197Spatrick 
1533dda28197Spatrick       if (!expected_crash_info) {
1534dda28197Spatrick         result.AppendError(llvm::toString(expected_crash_info.takeError()));
1535dda28197Spatrick         return result.Succeeded();
1536dda28197Spatrick       }
1537dda28197Spatrick 
1538dda28197Spatrick       StructuredData::DictionarySP crash_info_sp = *expected_crash_info;
1539dda28197Spatrick 
1540dda28197Spatrick       if (crash_info_sp) {
1541*f6aab3d8Srobert         strm.EOL();
1542dda28197Spatrick         strm.PutCString("Extended Crash Information:\n");
1543*f6aab3d8Srobert         crash_info_sp->GetDescription(strm);
1544dda28197Spatrick       }
1545dda28197Spatrick     }
1546dda28197Spatrick 
1547dda28197Spatrick     return result.Succeeded();
1548dda28197Spatrick   }
1549dda28197Spatrick 
1550dda28197Spatrick private:
1551dda28197Spatrick   CommandOptions m_options;
1552061da546Spatrick };
1553061da546Spatrick 
1554061da546Spatrick // CommandObjectProcessHandle
1555061da546Spatrick #define LLDB_OPTIONS_process_handle
1556061da546Spatrick #include "CommandOptions.inc"
1557061da546Spatrick 
1558061da546Spatrick #pragma mark CommandObjectProcessHandle
1559061da546Spatrick 
1560061da546Spatrick class CommandObjectProcessHandle : public CommandObjectParsed {
1561061da546Spatrick public:
1562061da546Spatrick   class CommandOptions : public Options {
1563061da546Spatrick   public:
CommandOptions()1564*f6aab3d8Srobert     CommandOptions() { OptionParsingStarting(nullptr); }
1565061da546Spatrick 
1566061da546Spatrick     ~CommandOptions() override = default;
1567061da546Spatrick 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1568061da546Spatrick     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1569061da546Spatrick                           ExecutionContext *execution_context) override {
1570061da546Spatrick       Status error;
1571061da546Spatrick       const int short_option = m_getopt_table[option_idx].val;
1572061da546Spatrick 
1573061da546Spatrick       switch (short_option) {
1574*f6aab3d8Srobert       case 'c':
1575*f6aab3d8Srobert         do_clear = true;
1576*f6aab3d8Srobert         break;
1577*f6aab3d8Srobert       case 'd':
1578*f6aab3d8Srobert         dummy = true;
1579*f6aab3d8Srobert         break;
1580061da546Spatrick       case 's':
1581dda28197Spatrick         stop = std::string(option_arg);
1582061da546Spatrick         break;
1583061da546Spatrick       case 'n':
1584dda28197Spatrick         notify = std::string(option_arg);
1585061da546Spatrick         break;
1586061da546Spatrick       case 'p':
1587dda28197Spatrick         pass = std::string(option_arg);
1588061da546Spatrick         break;
1589*f6aab3d8Srobert       case 't':
1590*f6aab3d8Srobert         only_target_values = true;
1591*f6aab3d8Srobert         break;
1592061da546Spatrick       default:
1593061da546Spatrick         llvm_unreachable("Unimplemented option");
1594061da546Spatrick       }
1595061da546Spatrick       return error;
1596061da546Spatrick     }
1597061da546Spatrick 
OptionParsingStarting(ExecutionContext * execution_context)1598061da546Spatrick     void OptionParsingStarting(ExecutionContext *execution_context) override {
1599061da546Spatrick       stop.clear();
1600061da546Spatrick       notify.clear();
1601061da546Spatrick       pass.clear();
1602*f6aab3d8Srobert       only_target_values = false;
1603*f6aab3d8Srobert       do_clear = false;
1604*f6aab3d8Srobert       dummy = false;
1605061da546Spatrick     }
1606061da546Spatrick 
GetDefinitions()1607061da546Spatrick     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1608*f6aab3d8Srobert       return llvm::ArrayRef(g_process_handle_options);
1609061da546Spatrick     }
1610061da546Spatrick 
1611061da546Spatrick     // Instance variables to hold the values for command options.
1612061da546Spatrick 
1613061da546Spatrick     std::string stop;
1614061da546Spatrick     std::string notify;
1615061da546Spatrick     std::string pass;
1616*f6aab3d8Srobert     bool only_target_values = false;
1617*f6aab3d8Srobert     bool do_clear = false;
1618*f6aab3d8Srobert     bool dummy = false;
1619061da546Spatrick   };
1620061da546Spatrick 
CommandObjectProcessHandle(CommandInterpreter & interpreter)1621061da546Spatrick   CommandObjectProcessHandle(CommandInterpreter &interpreter)
1622061da546Spatrick       : CommandObjectParsed(interpreter, "process handle",
1623061da546Spatrick                             "Manage LLDB handling of OS signals for the "
1624061da546Spatrick                             "current target process.  Defaults to showing "
1625061da546Spatrick                             "current policy.",
1626*f6aab3d8Srobert                             nullptr) {
1627*f6aab3d8Srobert     SetHelpLong("\nIf no signals are specified but one or more actions are, "
1628*f6aab3d8Srobert                 "and there is a live process, update them all.  If no action "
1629*f6aab3d8Srobert                 "is specified, list the current values.\n"
1630*f6aab3d8Srobert                 "If you specify actions with no target (e.g. in an init file) "
1631*f6aab3d8Srobert                 "or in a target with no process "
1632*f6aab3d8Srobert                 "the values will get copied into subsequent targets, but "
1633*f6aab3d8Srobert                 "lldb won't be able to spell-check the options since it can't "
1634*f6aab3d8Srobert                 "know which signal set will later be in force."
1635*f6aab3d8Srobert                 "\nYou can see the signal modifications held by the target"
1636*f6aab3d8Srobert                 "by passing the -t option."
1637*f6aab3d8Srobert                 "\nYou can also clear the target modification for a signal"
1638*f6aab3d8Srobert                 "by passing the -c option");
1639061da546Spatrick     CommandArgumentEntry arg;
1640061da546Spatrick     CommandArgumentData signal_arg;
1641061da546Spatrick 
1642061da546Spatrick     signal_arg.arg_type = eArgTypeUnixSignal;
1643061da546Spatrick     signal_arg.arg_repetition = eArgRepeatStar;
1644061da546Spatrick 
1645061da546Spatrick     arg.push_back(signal_arg);
1646061da546Spatrick 
1647061da546Spatrick     m_arguments.push_back(arg);
1648061da546Spatrick   }
1649061da546Spatrick 
1650061da546Spatrick   ~CommandObjectProcessHandle() override = default;
1651061da546Spatrick 
GetOptions()1652061da546Spatrick   Options *GetOptions() override { return &m_options; }
1653061da546Spatrick 
VerifyCommandOptionValue(const std::string & option,int & real_value)1654061da546Spatrick   bool VerifyCommandOptionValue(const std::string &option, int &real_value) {
1655061da546Spatrick     bool okay = true;
1656061da546Spatrick     bool success = false;
1657061da546Spatrick     bool tmp_value = OptionArgParser::ToBoolean(option, false, &success);
1658061da546Spatrick 
1659061da546Spatrick     if (success && tmp_value)
1660061da546Spatrick       real_value = 1;
1661061da546Spatrick     else if (success && !tmp_value)
1662061da546Spatrick       real_value = 0;
1663061da546Spatrick     else {
1664061da546Spatrick       // If the value isn't 'true' or 'false', it had better be 0 or 1.
1665dda28197Spatrick       if (!llvm::to_integer(option, real_value))
1666dda28197Spatrick         real_value = 3;
1667061da546Spatrick       if (real_value != 0 && real_value != 1)
1668061da546Spatrick         okay = false;
1669061da546Spatrick     }
1670061da546Spatrick 
1671061da546Spatrick     return okay;
1672061da546Spatrick   }
1673061da546Spatrick 
PrintSignalHeader(Stream & str)1674061da546Spatrick   void PrintSignalHeader(Stream &str) {
1675061da546Spatrick     str.Printf("NAME         PASS   STOP   NOTIFY\n");
1676061da546Spatrick     str.Printf("===========  =====  =====  ======\n");
1677061da546Spatrick   }
1678061da546Spatrick 
PrintSignal(Stream & str,int32_t signo,const char * sig_name,const UnixSignalsSP & signals_sp)1679061da546Spatrick   void PrintSignal(Stream &str, int32_t signo, const char *sig_name,
1680061da546Spatrick                    const UnixSignalsSP &signals_sp) {
1681061da546Spatrick     bool stop;
1682061da546Spatrick     bool suppress;
1683061da546Spatrick     bool notify;
1684061da546Spatrick 
1685061da546Spatrick     str.Printf("%-11s  ", sig_name);
1686061da546Spatrick     if (signals_sp->GetSignalInfo(signo, suppress, stop, notify)) {
1687061da546Spatrick       bool pass = !suppress;
1688061da546Spatrick       str.Printf("%s  %s  %s", (pass ? "true " : "false"),
1689061da546Spatrick                  (stop ? "true " : "false"), (notify ? "true " : "false"));
1690061da546Spatrick     }
1691061da546Spatrick     str.Printf("\n");
1692061da546Spatrick   }
1693061da546Spatrick 
PrintSignalInformation(Stream & str,Args & signal_args,int num_valid_signals,const UnixSignalsSP & signals_sp)1694061da546Spatrick   void PrintSignalInformation(Stream &str, Args &signal_args,
1695061da546Spatrick                               int num_valid_signals,
1696061da546Spatrick                               const UnixSignalsSP &signals_sp) {
1697061da546Spatrick     PrintSignalHeader(str);
1698061da546Spatrick 
1699061da546Spatrick     if (num_valid_signals > 0) {
1700061da546Spatrick       size_t num_args = signal_args.GetArgumentCount();
1701061da546Spatrick       for (size_t i = 0; i < num_args; ++i) {
1702061da546Spatrick         int32_t signo = signals_sp->GetSignalNumberFromName(
1703061da546Spatrick             signal_args.GetArgumentAtIndex(i));
1704061da546Spatrick         if (signo != LLDB_INVALID_SIGNAL_NUMBER)
1705061da546Spatrick           PrintSignal(str, signo, signal_args.GetArgumentAtIndex(i),
1706061da546Spatrick                       signals_sp);
1707061da546Spatrick       }
1708061da546Spatrick     } else // Print info for ALL signals
1709061da546Spatrick     {
1710061da546Spatrick       int32_t signo = signals_sp->GetFirstSignalNumber();
1711061da546Spatrick       while (signo != LLDB_INVALID_SIGNAL_NUMBER) {
1712061da546Spatrick         PrintSignal(str, signo, signals_sp->GetSignalAsCString(signo),
1713061da546Spatrick                     signals_sp);
1714061da546Spatrick         signo = signals_sp->GetNextSignalNumber(signo);
1715061da546Spatrick       }
1716061da546Spatrick     }
1717061da546Spatrick   }
1718061da546Spatrick 
1719061da546Spatrick protected:
DoExecute(Args & signal_args,CommandReturnObject & result)1720061da546Spatrick   bool DoExecute(Args &signal_args, CommandReturnObject &result) override {
1721*f6aab3d8Srobert     Target &target = GetSelectedOrDummyTarget();
1722061da546Spatrick 
1723*f6aab3d8Srobert     // Any signals that are being set should be added to the Target's
1724*f6aab3d8Srobert     // DummySignals so they will get applied on rerun, etc.
1725*f6aab3d8Srobert     // If we have a process, however, we can do a more accurate job of vetting
1726*f6aab3d8Srobert     // the user's options.
1727*f6aab3d8Srobert     ProcessSP process_sp = target.GetProcessSP();
1728061da546Spatrick 
1729061da546Spatrick     int stop_action = -1;   // -1 means leave the current setting alone
1730061da546Spatrick     int pass_action = -1;   // -1 means leave the current setting alone
1731061da546Spatrick     int notify_action = -1; // -1 means leave the current setting alone
1732061da546Spatrick 
1733061da546Spatrick     if (!m_options.stop.empty() &&
1734061da546Spatrick         !VerifyCommandOptionValue(m_options.stop, stop_action)) {
1735061da546Spatrick       result.AppendError("Invalid argument for command option --stop; must be "
1736061da546Spatrick                          "true or false.\n");
1737061da546Spatrick       return false;
1738061da546Spatrick     }
1739061da546Spatrick 
1740061da546Spatrick     if (!m_options.notify.empty() &&
1741061da546Spatrick         !VerifyCommandOptionValue(m_options.notify, notify_action)) {
1742061da546Spatrick       result.AppendError("Invalid argument for command option --notify; must "
1743061da546Spatrick                          "be true or false.\n");
1744061da546Spatrick       return false;
1745061da546Spatrick     }
1746061da546Spatrick 
1747061da546Spatrick     if (!m_options.pass.empty() &&
1748061da546Spatrick         !VerifyCommandOptionValue(m_options.pass, pass_action)) {
1749061da546Spatrick       result.AppendError("Invalid argument for command option --pass; must be "
1750061da546Spatrick                          "true or false.\n");
1751061da546Spatrick       return false;
1752061da546Spatrick     }
1753061da546Spatrick 
1754*f6aab3d8Srobert     bool no_actions = (stop_action == -1 && pass_action == -1
1755*f6aab3d8Srobert         && notify_action == -1);
1756*f6aab3d8Srobert     if (m_options.only_target_values && !no_actions) {
1757*f6aab3d8Srobert       result.AppendError("-t is for reporting, not setting, target values.");
1758*f6aab3d8Srobert       return false;
1759*f6aab3d8Srobert     }
1760*f6aab3d8Srobert 
1761061da546Spatrick     size_t num_args = signal_args.GetArgumentCount();
1762*f6aab3d8Srobert     UnixSignalsSP signals_sp;
1763*f6aab3d8Srobert     if (process_sp)
1764*f6aab3d8Srobert       signals_sp = process_sp->GetUnixSignals();
1765*f6aab3d8Srobert 
1766061da546Spatrick     int num_signals_set = 0;
1767061da546Spatrick 
1768*f6aab3d8Srobert     // If we were just asked to print the target values, do that here and
1769*f6aab3d8Srobert     // return:
1770*f6aab3d8Srobert     if (m_options.only_target_values) {
1771*f6aab3d8Srobert       target.PrintDummySignals(result.GetOutputStream(), signal_args);
1772*f6aab3d8Srobert       result.SetStatus(eReturnStatusSuccessFinishResult);
1773*f6aab3d8Srobert       return true;
1774*f6aab3d8Srobert     }
1775*f6aab3d8Srobert 
1776*f6aab3d8Srobert     // This handles clearing values:
1777*f6aab3d8Srobert     if (m_options.do_clear) {
1778*f6aab3d8Srobert       target.ClearDummySignals(signal_args);
1779*f6aab3d8Srobert       if (m_options.dummy)
1780*f6aab3d8Srobert         GetDummyTarget().ClearDummySignals(signal_args);
1781*f6aab3d8Srobert       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1782*f6aab3d8Srobert       return true;
1783*f6aab3d8Srobert     }
1784*f6aab3d8Srobert 
1785*f6aab3d8Srobert     // This rest handles setting values:
1786061da546Spatrick     if (num_args > 0) {
1787061da546Spatrick       for (const auto &arg : signal_args) {
1788*f6aab3d8Srobert         // Do the process first.  If we have a process we can catch
1789*f6aab3d8Srobert         // invalid signal names, which we do here.
1790*f6aab3d8Srobert         if (signals_sp) {
1791061da546Spatrick           int32_t signo = signals_sp->GetSignalNumberFromName(arg.c_str());
1792061da546Spatrick           if (signo != LLDB_INVALID_SIGNAL_NUMBER) {
1793061da546Spatrick             // Casting the actions as bools here should be okay, because
1794061da546Spatrick             // VerifyCommandOptionValue guarantees the value is either 0 or 1.
1795061da546Spatrick             if (stop_action != -1)
1796061da546Spatrick               signals_sp->SetShouldStop(signo, stop_action);
1797061da546Spatrick             if (pass_action != -1) {
1798061da546Spatrick               bool suppress = !pass_action;
1799061da546Spatrick               signals_sp->SetShouldSuppress(signo, suppress);
1800061da546Spatrick             }
1801061da546Spatrick             if (notify_action != -1)
1802061da546Spatrick               signals_sp->SetShouldNotify(signo, notify_action);
1803061da546Spatrick             ++num_signals_set;
1804061da546Spatrick           } else {
1805061da546Spatrick             result.AppendErrorWithFormat("Invalid signal name '%s'\n",
1806061da546Spatrick                                           arg.c_str());
1807*f6aab3d8Srobert             continue;
1808061da546Spatrick           }
1809*f6aab3d8Srobert         } else {
1810*f6aab3d8Srobert           // If there's no process we can't check, so we just set them all.
1811*f6aab3d8Srobert           // But since the map signal name -> signal number across all platforms
1812*f6aab3d8Srobert           // is not 1-1, we can't sensibly set signal actions by number before
1813*f6aab3d8Srobert           // we have a process.  Check that here:
1814*f6aab3d8Srobert           int32_t signo;
1815*f6aab3d8Srobert           if (llvm::to_integer(arg.c_str(), signo)) {
1816*f6aab3d8Srobert             result.AppendErrorWithFormat("Can't set signal handling by signal "
1817*f6aab3d8Srobert                                          "number with no process");
1818*f6aab3d8Srobert             return false;
1819*f6aab3d8Srobert           }
1820*f6aab3d8Srobert          num_signals_set = num_args;
1821*f6aab3d8Srobert         }
1822*f6aab3d8Srobert         auto set_lazy_bool = [] (int action) -> LazyBool {
1823*f6aab3d8Srobert           LazyBool lazy;
1824*f6aab3d8Srobert           if (action == -1)
1825*f6aab3d8Srobert             lazy = eLazyBoolCalculate;
1826*f6aab3d8Srobert           else if (action)
1827*f6aab3d8Srobert             lazy = eLazyBoolYes;
1828*f6aab3d8Srobert           else
1829*f6aab3d8Srobert             lazy = eLazyBoolNo;
1830*f6aab3d8Srobert           return lazy;
1831*f6aab3d8Srobert         };
1832*f6aab3d8Srobert 
1833*f6aab3d8Srobert         // If there were no actions, we're just listing, don't add the dummy:
1834*f6aab3d8Srobert         if (!no_actions)
1835*f6aab3d8Srobert           target.AddDummySignal(arg.ref(),
1836*f6aab3d8Srobert                                 set_lazy_bool(pass_action),
1837*f6aab3d8Srobert                                 set_lazy_bool(notify_action),
1838*f6aab3d8Srobert                                 set_lazy_bool(stop_action));
1839061da546Spatrick       }
1840061da546Spatrick     } else {
1841061da546Spatrick       // No signal specified, if any command options were specified, update ALL
1842*f6aab3d8Srobert       // signals.  But we can't do this without a process since we don't know
1843*f6aab3d8Srobert       // all the possible signals that might be valid for this target.
1844*f6aab3d8Srobert       if (((notify_action != -1) || (stop_action != -1) || (pass_action != -1))
1845*f6aab3d8Srobert           && process_sp) {
1846061da546Spatrick         if (m_interpreter.Confirm(
1847061da546Spatrick                 "Do you really want to update all the signals?", false)) {
1848061da546Spatrick           int32_t signo = signals_sp->GetFirstSignalNumber();
1849061da546Spatrick           while (signo != LLDB_INVALID_SIGNAL_NUMBER) {
1850061da546Spatrick             if (notify_action != -1)
1851061da546Spatrick               signals_sp->SetShouldNotify(signo, notify_action);
1852061da546Spatrick             if (stop_action != -1)
1853061da546Spatrick               signals_sp->SetShouldStop(signo, stop_action);
1854061da546Spatrick             if (pass_action != -1) {
1855061da546Spatrick               bool suppress = !pass_action;
1856061da546Spatrick               signals_sp->SetShouldSuppress(signo, suppress);
1857061da546Spatrick             }
1858061da546Spatrick             signo = signals_sp->GetNextSignalNumber(signo);
1859061da546Spatrick           }
1860061da546Spatrick         }
1861061da546Spatrick       }
1862061da546Spatrick     }
1863061da546Spatrick 
1864*f6aab3d8Srobert     if (signals_sp)
1865061da546Spatrick       PrintSignalInformation(result.GetOutputStream(), signal_args,
1866061da546Spatrick                              num_signals_set, signals_sp);
1867*f6aab3d8Srobert     else
1868*f6aab3d8Srobert       target.PrintDummySignals(result.GetOutputStream(),
1869*f6aab3d8Srobert           signal_args);
1870061da546Spatrick 
1871061da546Spatrick     if (num_signals_set > 0)
1872*f6aab3d8Srobert       result.SetStatus(eReturnStatusSuccessFinishResult);
1873061da546Spatrick     else
1874061da546Spatrick       result.SetStatus(eReturnStatusFailed);
1875061da546Spatrick 
1876061da546Spatrick     return result.Succeeded();
1877061da546Spatrick   }
1878061da546Spatrick 
1879061da546Spatrick   CommandOptions m_options;
1880061da546Spatrick };
1881061da546Spatrick 
1882be691f3bSpatrick // Next are the subcommands of CommandObjectMultiwordProcessTrace
1883be691f3bSpatrick 
1884be691f3bSpatrick // CommandObjectProcessTraceStart
1885be691f3bSpatrick class CommandObjectProcessTraceStart : public CommandObjectTraceProxy {
1886be691f3bSpatrick public:
CommandObjectProcessTraceStart(CommandInterpreter & interpreter)1887be691f3bSpatrick   CommandObjectProcessTraceStart(CommandInterpreter &interpreter)
1888be691f3bSpatrick       : CommandObjectTraceProxy(
1889be691f3bSpatrick             /*live_debug_session_only*/ true, interpreter,
1890be691f3bSpatrick             "process trace start",
1891be691f3bSpatrick             "Start tracing this process with the corresponding trace "
1892be691f3bSpatrick             "plug-in.",
1893be691f3bSpatrick             "process trace start [<trace-options>]") {}
1894be691f3bSpatrick 
1895be691f3bSpatrick protected:
GetDelegateCommand(Trace & trace)1896be691f3bSpatrick   lldb::CommandObjectSP GetDelegateCommand(Trace &trace) override {
1897be691f3bSpatrick     return trace.GetProcessTraceStartCommand(m_interpreter);
1898be691f3bSpatrick   }
1899be691f3bSpatrick };
1900be691f3bSpatrick 
1901be691f3bSpatrick // CommandObjectProcessTraceStop
1902be691f3bSpatrick class CommandObjectProcessTraceStop : public CommandObjectParsed {
1903be691f3bSpatrick public:
CommandObjectProcessTraceStop(CommandInterpreter & interpreter)1904be691f3bSpatrick   CommandObjectProcessTraceStop(CommandInterpreter &interpreter)
1905be691f3bSpatrick       : CommandObjectParsed(interpreter, "process trace stop",
1906be691f3bSpatrick                             "Stop tracing this process. This does not affect "
1907be691f3bSpatrick                             "traces started with the "
1908be691f3bSpatrick                             "\"thread trace start\" command.",
1909be691f3bSpatrick                             "process trace stop",
1910be691f3bSpatrick                             eCommandRequiresProcess | eCommandTryTargetAPILock |
1911be691f3bSpatrick                                 eCommandProcessMustBeLaunched |
1912be691f3bSpatrick                                 eCommandProcessMustBePaused |
1913be691f3bSpatrick                                 eCommandProcessMustBeTraced) {}
1914be691f3bSpatrick 
1915be691f3bSpatrick   ~CommandObjectProcessTraceStop() override = default;
1916be691f3bSpatrick 
DoExecute(Args & command,CommandReturnObject & result)1917be691f3bSpatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
1918be691f3bSpatrick     ProcessSP process_sp = m_exe_ctx.GetProcessSP();
1919be691f3bSpatrick 
1920be691f3bSpatrick     TraceSP trace_sp = process_sp->GetTarget().GetTrace();
1921be691f3bSpatrick 
1922be691f3bSpatrick     if (llvm::Error err = trace_sp->Stop())
1923be691f3bSpatrick       result.AppendError(toString(std::move(err)));
1924be691f3bSpatrick     else
1925be691f3bSpatrick       result.SetStatus(eReturnStatusSuccessFinishResult);
1926be691f3bSpatrick 
1927be691f3bSpatrick     return result.Succeeded();
1928be691f3bSpatrick   }
1929be691f3bSpatrick };
1930be691f3bSpatrick 
1931be691f3bSpatrick // CommandObjectMultiwordProcessTrace
1932be691f3bSpatrick class CommandObjectMultiwordProcessTrace : public CommandObjectMultiword {
1933be691f3bSpatrick public:
CommandObjectMultiwordProcessTrace(CommandInterpreter & interpreter)1934be691f3bSpatrick   CommandObjectMultiwordProcessTrace(CommandInterpreter &interpreter)
1935be691f3bSpatrick       : CommandObjectMultiword(
1936be691f3bSpatrick             interpreter, "trace", "Commands for tracing the current process.",
1937be691f3bSpatrick             "process trace <subcommand> [<subcommand objects>]") {
1938be691f3bSpatrick     LoadSubCommand("start", CommandObjectSP(new CommandObjectProcessTraceStart(
1939be691f3bSpatrick                                 interpreter)));
1940be691f3bSpatrick     LoadSubCommand("stop", CommandObjectSP(
1941be691f3bSpatrick                                new CommandObjectProcessTraceStop(interpreter)));
1942be691f3bSpatrick   }
1943be691f3bSpatrick 
1944be691f3bSpatrick   ~CommandObjectMultiwordProcessTrace() override = default;
1945be691f3bSpatrick };
1946be691f3bSpatrick 
1947061da546Spatrick // CommandObjectMultiwordProcess
1948061da546Spatrick 
CommandObjectMultiwordProcess(CommandInterpreter & interpreter)1949061da546Spatrick CommandObjectMultiwordProcess::CommandObjectMultiwordProcess(
1950061da546Spatrick     CommandInterpreter &interpreter)
1951061da546Spatrick     : CommandObjectMultiword(
1952061da546Spatrick           interpreter, "process",
1953061da546Spatrick           "Commands for interacting with processes on the current platform.",
1954061da546Spatrick           "process <subcommand> [<subcommand-options>]") {
1955061da546Spatrick   LoadSubCommand("attach",
1956061da546Spatrick                  CommandObjectSP(new CommandObjectProcessAttach(interpreter)));
1957061da546Spatrick   LoadSubCommand("launch",
1958061da546Spatrick                  CommandObjectSP(new CommandObjectProcessLaunch(interpreter)));
1959061da546Spatrick   LoadSubCommand("continue", CommandObjectSP(new CommandObjectProcessContinue(
1960061da546Spatrick                                  interpreter)));
1961061da546Spatrick   LoadSubCommand("connect",
1962061da546Spatrick                  CommandObjectSP(new CommandObjectProcessConnect(interpreter)));
1963061da546Spatrick   LoadSubCommand("detach",
1964061da546Spatrick                  CommandObjectSP(new CommandObjectProcessDetach(interpreter)));
1965061da546Spatrick   LoadSubCommand("load",
1966061da546Spatrick                  CommandObjectSP(new CommandObjectProcessLoad(interpreter)));
1967061da546Spatrick   LoadSubCommand("unload",
1968061da546Spatrick                  CommandObjectSP(new CommandObjectProcessUnload(interpreter)));
1969061da546Spatrick   LoadSubCommand("signal",
1970061da546Spatrick                  CommandObjectSP(new CommandObjectProcessSignal(interpreter)));
1971061da546Spatrick   LoadSubCommand("handle",
1972061da546Spatrick                  CommandObjectSP(new CommandObjectProcessHandle(interpreter)));
1973061da546Spatrick   LoadSubCommand("status",
1974061da546Spatrick                  CommandObjectSP(new CommandObjectProcessStatus(interpreter)));
1975061da546Spatrick   LoadSubCommand("interrupt", CommandObjectSP(new CommandObjectProcessInterrupt(
1976061da546Spatrick                                   interpreter)));
1977061da546Spatrick   LoadSubCommand("kill",
1978061da546Spatrick                  CommandObjectSP(new CommandObjectProcessKill(interpreter)));
1979061da546Spatrick   LoadSubCommand("plugin",
1980061da546Spatrick                  CommandObjectSP(new CommandObjectProcessPlugin(interpreter)));
1981061da546Spatrick   LoadSubCommand("save-core", CommandObjectSP(new CommandObjectProcessSaveCore(
1982061da546Spatrick                                   interpreter)));
1983be691f3bSpatrick   LoadSubCommand(
1984be691f3bSpatrick       "trace",
1985be691f3bSpatrick       CommandObjectSP(new CommandObjectMultiwordProcessTrace(interpreter)));
1986061da546Spatrick }
1987061da546Spatrick 
1988061da546Spatrick CommandObjectMultiwordProcess::~CommandObjectMultiwordProcess() = default;
1989