1 | //===-- CommandObjectProcess.cpp ------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "CommandObjectProcess.h" |
10 | #include "CommandObjectBreakpoint.h" |
11 | #include "CommandObjectTrace.h" |
12 | #include "CommandOptionsProcessAttach.h" |
13 | #include "CommandOptionsProcessLaunch.h" |
14 | #include "lldb/Breakpoint/Breakpoint.h" |
15 | #include "lldb/Breakpoint/BreakpointIDList.h" |
16 | #include "lldb/Breakpoint/BreakpointLocation.h" |
17 | #include "lldb/Breakpoint/BreakpointName.h" |
18 | #include "lldb/Breakpoint/BreakpointSite.h" |
19 | #include "lldb/Core/Module.h" |
20 | #include "lldb/Core/PluginManager.h" |
21 | #include "lldb/Host/OptionParser.h" |
22 | #include "lldb/Interpreter/CommandInterpreter.h" |
23 | #include "lldb/Interpreter/CommandOptionArgumentTable.h" |
24 | #include "lldb/Interpreter/CommandReturnObject.h" |
25 | #include "lldb/Interpreter/OptionArgParser.h" |
26 | #include "lldb/Interpreter/OptionGroupPythonClassWithDict.h" |
27 | #include "lldb/Interpreter/Options.h" |
28 | #include "lldb/Target/Platform.h" |
29 | #include "lldb/Target/Process.h" |
30 | #include "lldb/Target/StopInfo.h" |
31 | #include "lldb/Target/Target.h" |
32 | #include "lldb/Target/Thread.h" |
33 | #include "lldb/Target/UnixSignals.h" |
34 | #include "lldb/Utility/Args.h" |
35 | #include "lldb/Utility/ScriptedMetadata.h" |
36 | #include "lldb/Utility/State.h" |
37 | |
38 | #include "llvm/ADT/ScopeExit.h" |
39 | |
40 | #include <bitset> |
41 | #include <optional> |
42 | |
43 | using namespace lldb; |
44 | using namespace lldb_private; |
45 | |
46 | class CommandObjectProcessLaunchOrAttach : public CommandObjectParsed { |
47 | public: |
48 | CommandObjectProcessLaunchOrAttach(CommandInterpreter &interpreter, |
49 | const char *name, const char *help, |
50 | const char *syntax, uint32_t flags, |
51 | const char *new_process_action) |
52 | : CommandObjectParsed(interpreter, name, help, syntax, flags), |
53 | m_new_process_action(new_process_action) {} |
54 | |
55 | ~CommandObjectProcessLaunchOrAttach() override = default; |
56 | |
57 | protected: |
58 | bool StopProcessIfNecessary(Process *process, StateType &state, |
59 | CommandReturnObject &result) { |
60 | state = eStateInvalid; |
61 | if (process) { |
62 | state = process->GetState(); |
63 | |
64 | if (process->IsAlive() && state != eStateConnected) { |
65 | std::string message; |
66 | if (process->GetState() == eStateAttaching) |
67 | message = |
68 | llvm::formatv(Fmt: "There is a pending attach, abort it and {0}?" , |
69 | Vals&: m_new_process_action); |
70 | else if (process->GetShouldDetach()) |
71 | message = llvm::formatv( |
72 | Fmt: "There is a running process, detach from it and {0}?" , |
73 | Vals&: m_new_process_action); |
74 | else |
75 | message = |
76 | llvm::formatv(Fmt: "There is a running process, kill it and {0}?" , |
77 | Vals&: m_new_process_action); |
78 | |
79 | if (!m_interpreter.Confirm(message, default_answer: true)) { |
80 | result.SetStatus(eReturnStatusFailed); |
81 | return false; |
82 | } else { |
83 | if (process->GetShouldDetach()) { |
84 | bool keep_stopped = false; |
85 | Status detach_error(process->Detach(keep_stopped)); |
86 | if (detach_error.Success()) { |
87 | result.SetStatus(eReturnStatusSuccessFinishResult); |
88 | process = nullptr; |
89 | } else { |
90 | result.AppendErrorWithFormat( |
91 | format: "Failed to detach from process: %s\n" , |
92 | detach_error.AsCString()); |
93 | } |
94 | } else { |
95 | Status destroy_error(process->Destroy(force_kill: false)); |
96 | if (destroy_error.Success()) { |
97 | result.SetStatus(eReturnStatusSuccessFinishResult); |
98 | process = nullptr; |
99 | } else { |
100 | result.AppendErrorWithFormat(format: "Failed to kill process: %s\n" , |
101 | destroy_error.AsCString()); |
102 | } |
103 | } |
104 | } |
105 | } |
106 | } |
107 | return result.Succeeded(); |
108 | } |
109 | |
110 | std::string m_new_process_action; |
111 | }; |
112 | |
113 | // CommandObjectProcessLaunch |
114 | #pragma mark CommandObjectProcessLaunch |
115 | class CommandObjectProcessLaunch : public CommandObjectProcessLaunchOrAttach { |
116 | public: |
117 | CommandObjectProcessLaunch(CommandInterpreter &interpreter) |
118 | : CommandObjectProcessLaunchOrAttach( |
119 | interpreter, "process launch" , |
120 | "Launch the executable in the debugger." , nullptr, |
121 | eCommandRequiresTarget, "restart" ), |
122 | |
123 | m_class_options("scripted process" , true, 'C', 'k', 'v', 0) { |
124 | m_all_options.Append(group: &m_options); |
125 | m_all_options.Append(group: &m_class_options, LLDB_OPT_SET_1 | LLDB_OPT_SET_2, |
126 | LLDB_OPT_SET_ALL); |
127 | m_all_options.Finalize(); |
128 | |
129 | CommandArgumentEntry arg; |
130 | CommandArgumentData run_args_arg; |
131 | |
132 | // Define the first (and only) variant of this arg. |
133 | run_args_arg.arg_type = eArgTypeRunArgs; |
134 | run_args_arg.arg_repetition = eArgRepeatOptional; |
135 | |
136 | // There is only one variant this argument could be; put it into the |
137 | // argument entry. |
138 | arg.push_back(x: run_args_arg); |
139 | |
140 | // Push the data for the first argument into the m_arguments vector. |
141 | m_arguments.push_back(x: arg); |
142 | } |
143 | |
144 | ~CommandObjectProcessLaunch() override = default; |
145 | |
146 | void |
147 | HandleArgumentCompletion(CompletionRequest &request, |
148 | OptionElementVector &opt_element_vector) override { |
149 | |
150 | lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( |
151 | interpreter&: GetCommandInterpreter(), completion_mask: lldb::eDiskFileCompletion, request, searcher: nullptr); |
152 | } |
153 | |
154 | Options *GetOptions() override { return &m_all_options; } |
155 | |
156 | std::optional<std::string> GetRepeatCommand(Args ¤t_command_args, |
157 | uint32_t index) override { |
158 | // No repeat for "process launch"... |
159 | return std::string("" ); |
160 | } |
161 | |
162 | protected: |
163 | void DoExecute(Args &launch_args, CommandReturnObject &result) override { |
164 | Debugger &debugger = GetDebugger(); |
165 | Target *target = debugger.GetSelectedTarget().get(); |
166 | // If our listener is nullptr, users aren't allows to launch |
167 | ModuleSP exe_module_sp = target->GetExecutableModule(); |
168 | |
169 | // If the target already has an executable module, then use that. If it |
170 | // doesn't then someone must be trying to launch using a path that will |
171 | // make sense to the remote stub, but doesn't exist on the local host. |
172 | // In that case use the ExecutableFile that was set in the target's |
173 | // ProcessLaunchInfo. |
174 | if (exe_module_sp == nullptr && !target->GetProcessLaunchInfo().GetExecutableFile()) { |
175 | result.AppendError(in_string: "no file in target, create a debug target using the " |
176 | "'target create' command" ); |
177 | return; |
178 | } |
179 | |
180 | StateType state = eStateInvalid; |
181 | |
182 | if (!StopProcessIfNecessary(process: m_exe_ctx.GetProcessPtr(), state, result)) |
183 | return; |
184 | |
185 | // Determine whether we will disable ASLR or leave it in the default state |
186 | // (i.e. enabled if the platform supports it). First check if the process |
187 | // launch options explicitly turn on/off |
188 | // disabling ASLR. If so, use that setting; |
189 | // otherwise, use the 'settings target.disable-aslr' setting. |
190 | bool disable_aslr = false; |
191 | if (m_options.disable_aslr != eLazyBoolCalculate) { |
192 | // The user specified an explicit setting on the process launch line. |
193 | // Use it. |
194 | disable_aslr = (m_options.disable_aslr == eLazyBoolYes); |
195 | } else { |
196 | // The user did not explicitly specify whether to disable ASLR. Fall |
197 | // back to the target.disable-aslr setting. |
198 | disable_aslr = target->GetDisableASLR(); |
199 | } |
200 | |
201 | if (!m_class_options.GetName().empty()) { |
202 | m_options.launch_info.SetProcessPluginName("ScriptedProcess" ); |
203 | ScriptedMetadataSP metadata_sp = std::make_shared<ScriptedMetadata>( |
204 | args: m_class_options.GetName(), args: m_class_options.GetStructuredData()); |
205 | m_options.launch_info.SetScriptedMetadata(metadata_sp); |
206 | target->SetProcessLaunchInfo(m_options.launch_info); |
207 | } |
208 | |
209 | if (disable_aslr) |
210 | m_options.launch_info.GetFlags().Set(eLaunchFlagDisableASLR); |
211 | else |
212 | m_options.launch_info.GetFlags().Clear(mask: eLaunchFlagDisableASLR); |
213 | |
214 | if (target->GetInheritTCC()) |
215 | m_options.launch_info.GetFlags().Set(eLaunchFlagInheritTCCFromParent); |
216 | |
217 | if (target->GetDetachOnError()) |
218 | m_options.launch_info.GetFlags().Set(eLaunchFlagDetachOnError); |
219 | |
220 | if (target->GetDisableSTDIO()) |
221 | m_options.launch_info.GetFlags().Set(eLaunchFlagDisableSTDIO); |
222 | |
223 | // Merge the launch info environment with the target environment. |
224 | Environment target_env = target->GetEnvironment(); |
225 | m_options.launch_info.GetEnvironment().insert(first: target_env.begin(), |
226 | last: target_env.end()); |
227 | |
228 | llvm::StringRef target_settings_argv0 = target->GetArg0(); |
229 | |
230 | if (!target_settings_argv0.empty()) { |
231 | m_options.launch_info.GetArguments().AppendArgument( |
232 | arg_str: target_settings_argv0); |
233 | if (exe_module_sp) |
234 | m_options.launch_info.SetExecutableFile( |
235 | exe_file: exe_module_sp->GetPlatformFileSpec(), add_exe_file_as_first_arg: false); |
236 | else |
237 | m_options.launch_info.SetExecutableFile(exe_file: target->GetProcessLaunchInfo().GetExecutableFile(), add_exe_file_as_first_arg: false); |
238 | } else { |
239 | if (exe_module_sp) |
240 | m_options.launch_info.SetExecutableFile( |
241 | exe_file: exe_module_sp->GetPlatformFileSpec(), add_exe_file_as_first_arg: true); |
242 | else |
243 | m_options.launch_info.SetExecutableFile(exe_file: target->GetProcessLaunchInfo().GetExecutableFile(), add_exe_file_as_first_arg: true); |
244 | } |
245 | |
246 | if (launch_args.GetArgumentCount() == 0) { |
247 | m_options.launch_info.GetArguments().AppendArguments( |
248 | rhs: target->GetProcessLaunchInfo().GetArguments()); |
249 | } else { |
250 | m_options.launch_info.GetArguments().AppendArguments(rhs: launch_args); |
251 | // Save the arguments for subsequent runs in the current target. |
252 | target->SetRunArguments(launch_args); |
253 | } |
254 | |
255 | StreamString stream; |
256 | Status error = target->Launch(launch_info&: m_options.launch_info, stream: &stream); |
257 | |
258 | if (error.Success()) { |
259 | ProcessSP process_sp(target->GetProcessSP()); |
260 | if (process_sp) { |
261 | // There is a race condition where this thread will return up the call |
262 | // stack to the main command handler and show an (lldb) prompt before |
263 | // HandlePrivateEvent (from PrivateStateThread) has a chance to call |
264 | // PushProcessIOHandler(). |
265 | process_sp->SyncIOHandler(iohandler_id: 0, timeout: std::chrono::seconds(2)); |
266 | |
267 | // If we didn't have a local executable, then we wouldn't have had an |
268 | // executable module before launch. |
269 | if (!exe_module_sp) |
270 | exe_module_sp = target->GetExecutableModule(); |
271 | if (!exe_module_sp) { |
272 | result.AppendWarning(in_string: "Could not get executable module after launch." ); |
273 | } else { |
274 | |
275 | const char *archname = |
276 | exe_module_sp->GetArchitecture().GetArchitectureName(); |
277 | result.AppendMessageWithFormat( |
278 | format: "Process %" PRIu64 " launched: '%s' (%s)\n" , process_sp->GetID(), |
279 | exe_module_sp->GetFileSpec().GetPath().c_str(), archname); |
280 | } |
281 | result.SetStatus(eReturnStatusSuccessFinishResult); |
282 | // This message will refer to an event that happened after the process |
283 | // launched. |
284 | llvm::StringRef data = stream.GetString(); |
285 | if (!data.empty()) |
286 | result.AppendMessage(in_string: data); |
287 | result.SetDidChangeProcessState(true); |
288 | } else { |
289 | result.AppendError( |
290 | in_string: "no error returned from Target::Launch, and target has no process" ); |
291 | } |
292 | } else { |
293 | result.AppendError(in_string: error.AsCString()); |
294 | } |
295 | } |
296 | |
297 | CommandOptionsProcessLaunch m_options; |
298 | OptionGroupPythonClassWithDict m_class_options; |
299 | OptionGroupOptions m_all_options; |
300 | }; |
301 | |
302 | #define LLDB_OPTIONS_process_attach |
303 | #include "CommandOptions.inc" |
304 | |
305 | #pragma mark CommandObjectProcessAttach |
306 | class CommandObjectProcessAttach : public CommandObjectProcessLaunchOrAttach { |
307 | public: |
308 | CommandObjectProcessAttach(CommandInterpreter &interpreter) |
309 | : CommandObjectProcessLaunchOrAttach( |
310 | interpreter, "process attach" , "Attach to a process." , |
311 | "process attach <cmd-options>" , 0, "attach" ), |
312 | m_class_options("scripted process" , true, 'C', 'k', 'v', 0) { |
313 | m_all_options.Append(group: &m_options); |
314 | m_all_options.Append(group: &m_class_options, LLDB_OPT_SET_1 | LLDB_OPT_SET_2, |
315 | LLDB_OPT_SET_ALL); |
316 | m_all_options.Finalize(); |
317 | } |
318 | |
319 | ~CommandObjectProcessAttach() override = default; |
320 | |
321 | Options *GetOptions() override { return &m_all_options; } |
322 | |
323 | protected: |
324 | void DoExecute(Args &command, CommandReturnObject &result) override { |
325 | PlatformSP platform_sp( |
326 | GetDebugger().GetPlatformList().GetSelectedPlatform()); |
327 | |
328 | Target *target = GetDebugger().GetSelectedTarget().get(); |
329 | // N.B. The attach should be synchronous. It doesn't help much to get the |
330 | // prompt back between initiating the attach and the target actually |
331 | // stopping. So even if the interpreter is set to be asynchronous, we wait |
332 | // for the stop ourselves here. |
333 | |
334 | StateType state = eStateInvalid; |
335 | Process *process = m_exe_ctx.GetProcessPtr(); |
336 | |
337 | if (!StopProcessIfNecessary(process, state, result)) |
338 | return; |
339 | |
340 | if (target == nullptr) { |
341 | // If there isn't a current target create one. |
342 | TargetSP new_target_sp; |
343 | Status error; |
344 | |
345 | error = GetDebugger().GetTargetList().CreateTarget( |
346 | debugger&: GetDebugger(), user_exe_path: "" , triple_str: "" , get_dependent_modules: eLoadDependentsNo, |
347 | platform_options: nullptr, // No platform options |
348 | target_sp&: new_target_sp); |
349 | target = new_target_sp.get(); |
350 | if (target == nullptr || error.Fail()) { |
351 | result.AppendError(in_string: error.AsCString(default_error_str: "Error creating target" )); |
352 | return; |
353 | } |
354 | } |
355 | |
356 | if (!m_class_options.GetName().empty()) { |
357 | m_options.attach_info.SetProcessPluginName("ScriptedProcess" ); |
358 | ScriptedMetadataSP metadata_sp = std::make_shared<ScriptedMetadata>( |
359 | m_class_options.GetName(), m_class_options.GetStructuredData()); |
360 | m_options.attach_info.SetScriptedMetadata(metadata_sp); |
361 | } |
362 | |
363 | // Record the old executable module, we want to issue a warning if the |
364 | // process of attaching changed the current executable (like somebody said |
365 | // "file foo" then attached to a PID whose executable was bar.) |
366 | |
367 | ModuleSP old_exec_module_sp = target->GetExecutableModule(); |
368 | ArchSpec old_arch_spec = target->GetArchitecture(); |
369 | |
370 | StreamString stream; |
371 | ProcessSP process_sp; |
372 | const auto error = target->Attach(attach_info&: m_options.attach_info, stream: &stream); |
373 | if (error.Success()) { |
374 | process_sp = target->GetProcessSP(); |
375 | if (process_sp) { |
376 | result.AppendMessage(in_string: stream.GetString()); |
377 | result.SetStatus(eReturnStatusSuccessFinishNoResult); |
378 | result.SetDidChangeProcessState(true); |
379 | } else { |
380 | result.AppendError( |
381 | in_string: "no error returned from Target::Attach, and target has no process" ); |
382 | } |
383 | } else { |
384 | result.AppendErrorWithFormat(format: "attach failed: %s\n" , error.AsCString()); |
385 | } |
386 | |
387 | if (!result.Succeeded()) |
388 | return; |
389 | |
390 | // Okay, we're done. Last step is to warn if the executable module has |
391 | // changed: |
392 | char new_path[PATH_MAX]; |
393 | ModuleSP new_exec_module_sp(target->GetExecutableModule()); |
394 | if (!old_exec_module_sp) { |
395 | // We might not have a module if we attached to a raw pid... |
396 | if (new_exec_module_sp) { |
397 | new_exec_module_sp->GetFileSpec().GetPath(path: new_path, PATH_MAX); |
398 | result.AppendMessageWithFormat(format: "Executable module set to \"%s\".\n" , |
399 | new_path); |
400 | } |
401 | } else if (old_exec_module_sp->GetFileSpec() != |
402 | new_exec_module_sp->GetFileSpec()) { |
403 | char old_path[PATH_MAX]; |
404 | |
405 | old_exec_module_sp->GetFileSpec().GetPath(path: old_path, PATH_MAX); |
406 | new_exec_module_sp->GetFileSpec().GetPath(path: new_path, PATH_MAX); |
407 | |
408 | result.AppendWarningWithFormat( |
409 | format: "Executable module changed from \"%s\" to \"%s\".\n" , old_path, |
410 | new_path); |
411 | } |
412 | |
413 | if (!old_arch_spec.IsValid()) { |
414 | result.AppendMessageWithFormat( |
415 | format: "Architecture set to: %s.\n" , |
416 | target->GetArchitecture().GetTriple().getTriple().c_str()); |
417 | } else if (!old_arch_spec.IsExactMatch(rhs: target->GetArchitecture())) { |
418 | result.AppendWarningWithFormat( |
419 | format: "Architecture changed from %s to %s.\n" , |
420 | old_arch_spec.GetTriple().getTriple().c_str(), |
421 | target->GetArchitecture().GetTriple().getTriple().c_str()); |
422 | } |
423 | |
424 | // This supports the use-case scenario of immediately continuing the |
425 | // process once attached. |
426 | if (m_options.attach_info.GetContinueOnceAttached()) { |
427 | // We have made a process but haven't told the interpreter about it yet, |
428 | // so CheckRequirements will fail for "process continue". Set the override |
429 | // here: |
430 | ExecutionContext exe_ctx(process_sp); |
431 | m_interpreter.HandleCommand(command_line: "process continue" , add_to_history: eLazyBoolNo, override_context: exe_ctx, result); |
432 | } |
433 | } |
434 | |
435 | CommandOptionsProcessAttach m_options; |
436 | OptionGroupPythonClassWithDict m_class_options; |
437 | OptionGroupOptions m_all_options; |
438 | }; |
439 | |
440 | // CommandObjectProcessContinue |
441 | |
442 | #define LLDB_OPTIONS_process_continue |
443 | #include "CommandOptions.inc" |
444 | |
445 | #pragma mark CommandObjectProcessContinue |
446 | |
447 | class CommandObjectProcessContinue : public CommandObjectParsed { |
448 | public: |
449 | CommandObjectProcessContinue(CommandInterpreter &interpreter) |
450 | : CommandObjectParsed( |
451 | interpreter, "process continue" , |
452 | "Continue execution of all threads in the current process." , |
453 | "process continue" , |
454 | eCommandRequiresProcess | eCommandTryTargetAPILock | |
455 | eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {} |
456 | |
457 | ~CommandObjectProcessContinue() override = default; |
458 | |
459 | protected: |
460 | class CommandOptions : public Options { |
461 | public: |
462 | CommandOptions() { |
463 | // Keep default values of all options in one place: OptionParsingStarting |
464 | // () |
465 | OptionParsingStarting(execution_context: nullptr); |
466 | } |
467 | |
468 | ~CommandOptions() override = default; |
469 | |
470 | Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, |
471 | ExecutionContext *exe_ctx) override { |
472 | Status error; |
473 | const int short_option = m_getopt_table[option_idx].val; |
474 | switch (short_option) { |
475 | case 'i': |
476 | if (option_arg.getAsInteger(Radix: 0, Result&: m_ignore)) |
477 | error.SetErrorStringWithFormat( |
478 | "invalid value for ignore option: \"%s\", should be a number." , |
479 | option_arg.str().c_str()); |
480 | break; |
481 | case 'b': |
482 | m_run_to_bkpt_args.AppendArgument(arg_str: option_arg); |
483 | m_any_bkpts_specified = true; |
484 | break; |
485 | default: |
486 | llvm_unreachable("Unimplemented option" ); |
487 | } |
488 | return error; |
489 | } |
490 | |
491 | void OptionParsingStarting(ExecutionContext *execution_context) override { |
492 | m_ignore = 0; |
493 | m_run_to_bkpt_args.Clear(); |
494 | m_any_bkpts_specified = false; |
495 | } |
496 | |
497 | llvm::ArrayRef<OptionDefinition> GetDefinitions() override { |
498 | return llvm::ArrayRef(g_process_continue_options); |
499 | } |
500 | |
501 | uint32_t m_ignore = 0; |
502 | Args m_run_to_bkpt_args; |
503 | bool m_any_bkpts_specified = false; |
504 | }; |
505 | |
506 | void DoExecute(Args &command, CommandReturnObject &result) override { |
507 | Process *process = m_exe_ctx.GetProcessPtr(); |
508 | bool synchronous_execution = m_interpreter.GetSynchronous(); |
509 | StateType state = process->GetState(); |
510 | if (state == eStateStopped) { |
511 | if (m_options.m_ignore > 0) { |
512 | ThreadSP sel_thread_sp(GetDefaultThread()->shared_from_this()); |
513 | if (sel_thread_sp) { |
514 | StopInfoSP stop_info_sp = sel_thread_sp->GetStopInfo(); |
515 | if (stop_info_sp && |
516 | stop_info_sp->GetStopReason() == eStopReasonBreakpoint) { |
517 | lldb::break_id_t bp_site_id = |
518 | (lldb::break_id_t)stop_info_sp->GetValue(); |
519 | BreakpointSiteSP bp_site_sp( |
520 | process->GetBreakpointSiteList().FindByID(site_id: bp_site_id)); |
521 | if (bp_site_sp) { |
522 | const size_t num_owners = bp_site_sp->GetNumberOfConstituents(); |
523 | for (size_t i = 0; i < num_owners; i++) { |
524 | Breakpoint &bp_ref = |
525 | bp_site_sp->GetConstituentAtIndex(idx: i)->GetBreakpoint(); |
526 | if (!bp_ref.IsInternal()) { |
527 | bp_ref.SetIgnoreCount(m_options.m_ignore); |
528 | } |
529 | } |
530 | } |
531 | } |
532 | } |
533 | } |
534 | |
535 | Target *target = m_exe_ctx.GetTargetPtr(); |
536 | BreakpointIDList run_to_bkpt_ids; |
537 | // Don't pass an empty run_to_breakpoint list, as Verify will look for the |
538 | // default breakpoint. |
539 | if (m_options.m_run_to_bkpt_args.GetArgumentCount() > 0) |
540 | CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs( |
541 | args&: m_options.m_run_to_bkpt_args, target, result, valid_ids: &run_to_bkpt_ids, |
542 | purpose: BreakpointName::Permissions::disablePerm); |
543 | if (!result.Succeeded()) { |
544 | return; |
545 | } |
546 | result.Clear(); |
547 | if (m_options.m_any_bkpts_specified && run_to_bkpt_ids.GetSize() == 0) { |
548 | result.AppendError(in_string: "continue-to breakpoints did not specify any actual " |
549 | "breakpoints or locations" ); |
550 | return; |
551 | } |
552 | |
553 | // First figure out which breakpoints & locations were specified by the |
554 | // user: |
555 | size_t num_run_to_bkpt_ids = run_to_bkpt_ids.GetSize(); |
556 | std::vector<break_id_t> bkpts_disabled; |
557 | std::vector<BreakpointID> locs_disabled; |
558 | if (num_run_to_bkpt_ids != 0) { |
559 | // Go through the ID's specified, and separate the breakpoints from are |
560 | // the breakpoint.location specifications since the latter require |
561 | // special handling. We also figure out whether there's at least one |
562 | // specifier in the set that is enabled. |
563 | BreakpointList &bkpt_list = target->GetBreakpointList(); |
564 | std::unordered_set<break_id_t> bkpts_seen; |
565 | std::unordered_set<break_id_t> bkpts_with_locs_seen; |
566 | BreakpointIDList with_locs; |
567 | bool any_enabled = false; |
568 | |
569 | for (size_t idx = 0; idx < num_run_to_bkpt_ids; idx++) { |
570 | BreakpointID bkpt_id = run_to_bkpt_ids.GetBreakpointIDAtIndex(index: idx); |
571 | break_id_t bp_id = bkpt_id.GetBreakpointID(); |
572 | break_id_t loc_id = bkpt_id.GetLocationID(); |
573 | BreakpointSP bp_sp |
574 | = bkpt_list.FindBreakpointByID(breakID: bp_id); |
575 | // Note, VerifyBreakpointOrLocationIDs checks for existence, so we |
576 | // don't need to do it again here. |
577 | if (bp_sp->IsEnabled()) { |
578 | if (loc_id == LLDB_INVALID_BREAK_ID) { |
579 | // A breakpoint (without location) was specified. Make sure that |
580 | // at least one of the locations is enabled. |
581 | size_t num_locations = bp_sp->GetNumLocations(); |
582 | for (size_t loc_idx = 0; loc_idx < num_locations; loc_idx++) { |
583 | BreakpointLocationSP loc_sp |
584 | = bp_sp->GetLocationAtIndex(index: loc_idx); |
585 | if (loc_sp->IsEnabled()) { |
586 | any_enabled = true; |
587 | break; |
588 | } |
589 | } |
590 | } else { |
591 | // A location was specified, check if it was enabled: |
592 | BreakpointLocationSP loc_sp = bp_sp->FindLocationByID(bp_loc_id: loc_id); |
593 | if (loc_sp->IsEnabled()) |
594 | any_enabled = true; |
595 | } |
596 | |
597 | // Then sort the bp & bp.loc entries for later use: |
598 | if (bkpt_id.GetLocationID() == LLDB_INVALID_BREAK_ID) |
599 | bkpts_seen.insert(x: bkpt_id.GetBreakpointID()); |
600 | else { |
601 | bkpts_with_locs_seen.insert(x: bkpt_id.GetBreakpointID()); |
602 | with_locs.AddBreakpointID(bp_id: bkpt_id); |
603 | } |
604 | } |
605 | } |
606 | // Do all the error checking here so once we start disabling we don't |
607 | // have to back out half-way through. |
608 | |
609 | // Make sure at least one of the specified breakpoints is enabled. |
610 | if (!any_enabled) { |
611 | result.AppendError(in_string: "at least one of the continue-to breakpoints must " |
612 | "be enabled." ); |
613 | return; |
614 | } |
615 | |
616 | // Also, if you specify BOTH a breakpoint and one of it's locations, |
617 | // we flag that as an error, since it won't do what you expect, the |
618 | // breakpoint directive will mean "run to all locations", which is not |
619 | // what the location directive means... |
620 | for (break_id_t bp_id : bkpts_with_locs_seen) { |
621 | if (bkpts_seen.count(x: bp_id)) { |
622 | result.AppendErrorWithFormatv(format: "can't specify both a breakpoint and " |
623 | "one of its locations: {0}" , args&: bp_id); |
624 | } |
625 | } |
626 | |
627 | // Now go through the breakpoints in the target, disabling all the ones |
628 | // that the user didn't mention: |
629 | for (BreakpointSP bp_sp : bkpt_list.Breakpoints()) { |
630 | break_id_t bp_id = bp_sp->GetID(); |
631 | // Handle the case where no locations were specified. Note we don't |
632 | // have to worry about the case where a breakpoint and one of its |
633 | // locations are both in the lists, we've already disallowed that. |
634 | if (!bkpts_with_locs_seen.count(x: bp_id)) { |
635 | if (!bkpts_seen.count(x: bp_id) && bp_sp->IsEnabled()) { |
636 | bkpts_disabled.push_back(x: bp_id); |
637 | bp_sp->SetEnabled(false); |
638 | } |
639 | continue; |
640 | } |
641 | // Next, handle the case where a location was specified: |
642 | // Run through all the locations of this breakpoint and disable |
643 | // the ones that aren't on our "with locations" BreakpointID list: |
644 | size_t num_locations = bp_sp->GetNumLocations(); |
645 | BreakpointID tmp_id(bp_id, LLDB_INVALID_BREAK_ID); |
646 | for (size_t loc_idx = 0; loc_idx < num_locations; loc_idx++) { |
647 | BreakpointLocationSP loc_sp = bp_sp->GetLocationAtIndex(index: loc_idx); |
648 | tmp_id.SetBreakpointLocationID(loc_idx); |
649 | if (!with_locs.Contains(bp_id: tmp_id) && loc_sp->IsEnabled()) { |
650 | locs_disabled.push_back(x: tmp_id); |
651 | loc_sp->SetEnabled(false); |
652 | } |
653 | } |
654 | } |
655 | } |
656 | |
657 | { // Scope for thread list mutex: |
658 | std::lock_guard<std::recursive_mutex> guard( |
659 | process->GetThreadList().GetMutex()); |
660 | const uint32_t num_threads = process->GetThreadList().GetSize(); |
661 | |
662 | // Set the actions that the threads should each take when resuming |
663 | for (uint32_t idx = 0; idx < num_threads; ++idx) { |
664 | const bool override_suspend = false; |
665 | process->GetThreadList().GetThreadAtIndex(idx)->SetResumeState( |
666 | state: eStateRunning, override_suspend); |
667 | } |
668 | } |
669 | |
670 | const uint32_t iohandler_id = process->GetIOHandlerID(); |
671 | |
672 | StreamString stream; |
673 | Status error; |
674 | // For now we can only do -b with synchronous: |
675 | bool old_sync = GetDebugger().GetAsyncExecution(); |
676 | |
677 | if (run_to_bkpt_ids.GetSize() != 0) { |
678 | GetDebugger().SetAsyncExecution(false); |
679 | synchronous_execution = true; |
680 | } |
681 | if (synchronous_execution) |
682 | error = process->ResumeSynchronous(stream: &stream); |
683 | else |
684 | error = process->Resume(); |
685 | |
686 | if (run_to_bkpt_ids.GetSize() != 0) { |
687 | GetDebugger().SetAsyncExecution(old_sync); |
688 | } |
689 | |
690 | // Now re-enable the breakpoints we disabled: |
691 | BreakpointList &bkpt_list = target->GetBreakpointList(); |
692 | for (break_id_t bp_id : bkpts_disabled) { |
693 | BreakpointSP bp_sp = bkpt_list.FindBreakpointByID(breakID: bp_id); |
694 | if (bp_sp) |
695 | bp_sp->SetEnabled(true); |
696 | } |
697 | for (const BreakpointID &bkpt_id : locs_disabled) { |
698 | BreakpointSP bp_sp |
699 | = bkpt_list.FindBreakpointByID(breakID: bkpt_id.GetBreakpointID()); |
700 | if (bp_sp) { |
701 | BreakpointLocationSP loc_sp |
702 | = bp_sp->FindLocationByID(bp_loc_id: bkpt_id.GetLocationID()); |
703 | if (loc_sp) |
704 | loc_sp->SetEnabled(true); |
705 | } |
706 | } |
707 | |
708 | if (error.Success()) { |
709 | // There is a race condition where this thread will return up the call |
710 | // stack to the main command handler and show an (lldb) prompt before |
711 | // HandlePrivateEvent (from PrivateStateThread) has a chance to call |
712 | // PushProcessIOHandler(). |
713 | process->SyncIOHandler(iohandler_id, timeout: std::chrono::seconds(2)); |
714 | |
715 | result.AppendMessageWithFormat(format: "Process %" PRIu64 " resuming\n" , |
716 | process->GetID()); |
717 | if (synchronous_execution) { |
718 | // If any state changed events had anything to say, add that to the |
719 | // result |
720 | result.AppendMessage(in_string: stream.GetString()); |
721 | |
722 | result.SetDidChangeProcessState(true); |
723 | result.SetStatus(eReturnStatusSuccessFinishNoResult); |
724 | } else { |
725 | result.SetStatus(eReturnStatusSuccessContinuingNoResult); |
726 | } |
727 | } else { |
728 | result.AppendErrorWithFormat(format: "Failed to resume process: %s.\n" , |
729 | error.AsCString()); |
730 | } |
731 | } else { |
732 | result.AppendErrorWithFormat( |
733 | format: "Process cannot be continued from its current state (%s).\n" , |
734 | StateAsCString(state)); |
735 | } |
736 | } |
737 | |
738 | Options *GetOptions() override { return &m_options; } |
739 | |
740 | CommandOptions m_options; |
741 | }; |
742 | |
743 | // CommandObjectProcessDetach |
744 | #define LLDB_OPTIONS_process_detach |
745 | #include "CommandOptions.inc" |
746 | |
747 | #pragma mark CommandObjectProcessDetach |
748 | |
749 | class CommandObjectProcessDetach : public CommandObjectParsed { |
750 | public: |
751 | class CommandOptions : public Options { |
752 | public: |
753 | CommandOptions() { OptionParsingStarting(execution_context: nullptr); } |
754 | |
755 | ~CommandOptions() override = default; |
756 | |
757 | Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, |
758 | ExecutionContext *execution_context) override { |
759 | Status error; |
760 | const int short_option = m_getopt_table[option_idx].val; |
761 | |
762 | switch (short_option) { |
763 | case 's': |
764 | bool tmp_result; |
765 | bool success; |
766 | tmp_result = OptionArgParser::ToBoolean(s: option_arg, fail_value: false, success_ptr: &success); |
767 | if (!success) |
768 | error.SetErrorStringWithFormat("invalid boolean option: \"%s\"" , |
769 | option_arg.str().c_str()); |
770 | else { |
771 | if (tmp_result) |
772 | m_keep_stopped = eLazyBoolYes; |
773 | else |
774 | m_keep_stopped = eLazyBoolNo; |
775 | } |
776 | break; |
777 | default: |
778 | llvm_unreachable("Unimplemented option" ); |
779 | } |
780 | return error; |
781 | } |
782 | |
783 | void OptionParsingStarting(ExecutionContext *execution_context) override { |
784 | m_keep_stopped = eLazyBoolCalculate; |
785 | } |
786 | |
787 | llvm::ArrayRef<OptionDefinition> GetDefinitions() override { |
788 | return llvm::ArrayRef(g_process_detach_options); |
789 | } |
790 | |
791 | // Instance variables to hold the values for command options. |
792 | LazyBool m_keep_stopped; |
793 | }; |
794 | |
795 | CommandObjectProcessDetach(CommandInterpreter &interpreter) |
796 | : CommandObjectParsed(interpreter, "process detach" , |
797 | "Detach from the current target process." , |
798 | "process detach" , |
799 | eCommandRequiresProcess | eCommandTryTargetAPILock | |
800 | eCommandProcessMustBeLaunched) {} |
801 | |
802 | ~CommandObjectProcessDetach() override = default; |
803 | |
804 | Options *GetOptions() override { return &m_options; } |
805 | |
806 | protected: |
807 | void DoExecute(Args &command, CommandReturnObject &result) override { |
808 | Process *process = m_exe_ctx.GetProcessPtr(); |
809 | // FIXME: This will be a Command Option: |
810 | bool keep_stopped; |
811 | if (m_options.m_keep_stopped == eLazyBoolCalculate) { |
812 | // Check the process default: |
813 | keep_stopped = process->GetDetachKeepsStopped(); |
814 | } else if (m_options.m_keep_stopped == eLazyBoolYes) |
815 | keep_stopped = true; |
816 | else |
817 | keep_stopped = false; |
818 | |
819 | Status error(process->Detach(keep_stopped)); |
820 | if (error.Success()) { |
821 | result.SetStatus(eReturnStatusSuccessFinishResult); |
822 | } else { |
823 | result.AppendErrorWithFormat(format: "Detach failed: %s\n" , error.AsCString()); |
824 | } |
825 | } |
826 | |
827 | CommandOptions m_options; |
828 | }; |
829 | |
830 | // CommandObjectProcessConnect |
831 | #define LLDB_OPTIONS_process_connect |
832 | #include "CommandOptions.inc" |
833 | |
834 | #pragma mark CommandObjectProcessConnect |
835 | |
836 | class CommandObjectProcessConnect : public CommandObjectParsed { |
837 | public: |
838 | class CommandOptions : public Options { |
839 | public: |
840 | CommandOptions() { |
841 | // Keep default values of all options in one place: OptionParsingStarting |
842 | // () |
843 | OptionParsingStarting(execution_context: nullptr); |
844 | } |
845 | |
846 | ~CommandOptions() override = default; |
847 | |
848 | Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, |
849 | ExecutionContext *execution_context) override { |
850 | Status error; |
851 | const int short_option = m_getopt_table[option_idx].val; |
852 | |
853 | switch (short_option) { |
854 | case 'p': |
855 | plugin_name.assign(str: std::string(option_arg)); |
856 | break; |
857 | |
858 | default: |
859 | llvm_unreachable("Unimplemented option" ); |
860 | } |
861 | return error; |
862 | } |
863 | |
864 | void OptionParsingStarting(ExecutionContext *execution_context) override { |
865 | plugin_name.clear(); |
866 | } |
867 | |
868 | llvm::ArrayRef<OptionDefinition> GetDefinitions() override { |
869 | return llvm::ArrayRef(g_process_connect_options); |
870 | } |
871 | |
872 | // Instance variables to hold the values for command options. |
873 | |
874 | std::string plugin_name; |
875 | }; |
876 | |
877 | CommandObjectProcessConnect(CommandInterpreter &interpreter) |
878 | : CommandObjectParsed(interpreter, "process connect" , |
879 | "Connect to a remote debug service." , |
880 | "process connect <remote-url>" , 0) { |
881 | CommandArgumentData connect_arg{eArgTypeConnectURL, eArgRepeatPlain}; |
882 | m_arguments.push_back(x: {connect_arg}); |
883 | } |
884 | |
885 | ~CommandObjectProcessConnect() override = default; |
886 | |
887 | Options *GetOptions() override { return &m_options; } |
888 | |
889 | protected: |
890 | void DoExecute(Args &command, CommandReturnObject &result) override { |
891 | if (command.GetArgumentCount() != 1) { |
892 | result.AppendErrorWithFormat( |
893 | format: "'%s' takes exactly one argument:\nUsage: %s\n" , m_cmd_name.c_str(), |
894 | m_cmd_syntax.c_str()); |
895 | return; |
896 | } |
897 | |
898 | Process *process = m_exe_ctx.GetProcessPtr(); |
899 | if (process && process->IsAlive()) { |
900 | result.AppendErrorWithFormat( |
901 | format: "Process %" PRIu64 |
902 | " is currently being debugged, kill the process before connecting.\n" , |
903 | process->GetID()); |
904 | return; |
905 | } |
906 | |
907 | const char *plugin_name = nullptr; |
908 | if (!m_options.plugin_name.empty()) |
909 | plugin_name = m_options.plugin_name.c_str(); |
910 | |
911 | Status error; |
912 | Debugger &debugger = GetDebugger(); |
913 | PlatformSP platform_sp = m_interpreter.GetPlatform(prefer_target_platform: true); |
914 | ProcessSP process_sp = |
915 | debugger.GetAsyncExecution() |
916 | ? platform_sp->ConnectProcess( |
917 | connect_url: command.GetArgumentAtIndex(idx: 0), plugin_name, debugger, |
918 | target: debugger.GetSelectedTarget().get(), error) |
919 | : platform_sp->ConnectProcessSynchronous( |
920 | connect_url: command.GetArgumentAtIndex(idx: 0), plugin_name, debugger, |
921 | stream&: result.GetOutputStream(), target: debugger.GetSelectedTarget().get(), |
922 | error); |
923 | if (error.Fail() || process_sp == nullptr) { |
924 | result.AppendError(in_string: error.AsCString(default_error_str: "Error connecting to the process" )); |
925 | } |
926 | } |
927 | |
928 | CommandOptions m_options; |
929 | }; |
930 | |
931 | // CommandObjectProcessPlugin |
932 | #pragma mark CommandObjectProcessPlugin |
933 | |
934 | class CommandObjectProcessPlugin : public CommandObjectProxy { |
935 | public: |
936 | CommandObjectProcessPlugin(CommandInterpreter &interpreter) |
937 | : CommandObjectProxy( |
938 | interpreter, "process plugin" , |
939 | "Send a custom command to the current target process plug-in." , |
940 | "process plugin <args>" , 0) {} |
941 | |
942 | ~CommandObjectProcessPlugin() override = default; |
943 | |
944 | CommandObject *GetProxyCommandObject() override { |
945 | Process *process = m_interpreter.GetExecutionContext().GetProcessPtr(); |
946 | if (process) |
947 | return process->GetPluginCommandObject(); |
948 | return nullptr; |
949 | } |
950 | }; |
951 | |
952 | // CommandObjectProcessLoad |
953 | #define LLDB_OPTIONS_process_load |
954 | #include "CommandOptions.inc" |
955 | |
956 | #pragma mark CommandObjectProcessLoad |
957 | |
958 | class CommandObjectProcessLoad : public CommandObjectParsed { |
959 | public: |
960 | class CommandOptions : public Options { |
961 | public: |
962 | CommandOptions() { |
963 | // Keep default values of all options in one place: OptionParsingStarting |
964 | // () |
965 | OptionParsingStarting(execution_context: nullptr); |
966 | } |
967 | |
968 | ~CommandOptions() override = default; |
969 | |
970 | Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, |
971 | ExecutionContext *execution_context) override { |
972 | Status error; |
973 | const int short_option = m_getopt_table[option_idx].val; |
974 | switch (short_option) { |
975 | case 'i': |
976 | do_install = true; |
977 | if (!option_arg.empty()) |
978 | install_path.SetFile(path: option_arg, style: FileSpec::Style::native); |
979 | break; |
980 | default: |
981 | llvm_unreachable("Unimplemented option" ); |
982 | } |
983 | return error; |
984 | } |
985 | |
986 | void OptionParsingStarting(ExecutionContext *execution_context) override { |
987 | do_install = false; |
988 | install_path.Clear(); |
989 | } |
990 | |
991 | llvm::ArrayRef<OptionDefinition> GetDefinitions() override { |
992 | return llvm::ArrayRef(g_process_load_options); |
993 | } |
994 | |
995 | // Instance variables to hold the values for command options. |
996 | bool do_install; |
997 | FileSpec install_path; |
998 | }; |
999 | |
1000 | CommandObjectProcessLoad(CommandInterpreter &interpreter) |
1001 | : CommandObjectParsed(interpreter, "process load" , |
1002 | "Load a shared library into the current process." , |
1003 | "process load <filename> [<filename> ...]" , |
1004 | eCommandRequiresProcess | eCommandTryTargetAPILock | |
1005 | eCommandProcessMustBeLaunched | |
1006 | eCommandProcessMustBePaused) { |
1007 | CommandArgumentData file_arg{eArgTypePath, eArgRepeatPlus}; |
1008 | m_arguments.push_back(x: {file_arg}); |
1009 | } |
1010 | |
1011 | ~CommandObjectProcessLoad() override = default; |
1012 | |
1013 | void |
1014 | HandleArgumentCompletion(CompletionRequest &request, |
1015 | OptionElementVector &opt_element_vector) override { |
1016 | if (!m_exe_ctx.HasProcessScope()) |
1017 | return; |
1018 | |
1019 | lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( |
1020 | interpreter&: GetCommandInterpreter(), completion_mask: lldb::eDiskFileCompletion, request, searcher: nullptr); |
1021 | } |
1022 | |
1023 | Options *GetOptions() override { return &m_options; } |
1024 | |
1025 | protected: |
1026 | void DoExecute(Args &command, CommandReturnObject &result) override { |
1027 | Process *process = m_exe_ctx.GetProcessPtr(); |
1028 | |
1029 | for (auto &entry : command.entries()) { |
1030 | Status error; |
1031 | PlatformSP platform = process->GetTarget().GetPlatform(); |
1032 | llvm::StringRef image_path = entry.ref(); |
1033 | uint32_t image_token = LLDB_INVALID_IMAGE_TOKEN; |
1034 | |
1035 | if (!m_options.do_install) { |
1036 | FileSpec image_spec(image_path); |
1037 | platform->ResolveRemotePath(image_spec, image_spec); |
1038 | image_token = |
1039 | platform->LoadImage(process, FileSpec(), image_spec, error); |
1040 | } else if (m_options.install_path) { |
1041 | FileSpec image_spec(image_path); |
1042 | FileSystem::Instance().Resolve(image_spec); |
1043 | platform->ResolveRemotePath(m_options.install_path, |
1044 | m_options.install_path); |
1045 | image_token = platform->LoadImage(process, image_spec, |
1046 | m_options.install_path, error); |
1047 | } else { |
1048 | FileSpec image_spec(image_path); |
1049 | FileSystem::Instance().Resolve(image_spec); |
1050 | image_token = |
1051 | platform->LoadImage(process, image_spec, FileSpec(), error); |
1052 | } |
1053 | |
1054 | if (image_token != LLDB_INVALID_IMAGE_TOKEN) { |
1055 | result.AppendMessageWithFormat( |
1056 | "Loading \"%s\"...ok\nImage %u loaded.\n" , image_path.str().c_str(), |
1057 | image_token); |
1058 | result.SetStatus(eReturnStatusSuccessFinishResult); |
1059 | } else { |
1060 | result.AppendErrorWithFormat("failed to load '%s': %s" , |
1061 | image_path.str().c_str(), |
1062 | error.AsCString()); |
1063 | } |
1064 | } |
1065 | } |
1066 | |
1067 | CommandOptions m_options; |
1068 | }; |
1069 | |
1070 | // CommandObjectProcessUnload |
1071 | #pragma mark CommandObjectProcessUnload |
1072 | |
1073 | class CommandObjectProcessUnload : public CommandObjectParsed { |
1074 | public: |
1075 | CommandObjectProcessUnload(CommandInterpreter &interpreter) |
1076 | : CommandObjectParsed( |
1077 | interpreter, "process unload" , |
1078 | "Unload a shared library from the current process using the index " |
1079 | "returned by a previous call to \"process load\"." , |
1080 | "process unload <index>" , |
1081 | eCommandRequiresProcess | eCommandTryTargetAPILock | |
1082 | eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) { |
1083 | CommandArgumentData load_idx_arg{eArgTypeUnsignedInteger, eArgRepeatPlain}; |
1084 | m_arguments.push_back(x: {load_idx_arg}); |
1085 | } |
1086 | |
1087 | ~CommandObjectProcessUnload() override = default; |
1088 | |
1089 | void |
1090 | HandleArgumentCompletion(CompletionRequest &request, |
1091 | OptionElementVector &opt_element_vector) override { |
1092 | |
1093 | if (request.GetCursorIndex() || !m_exe_ctx.HasProcessScope()) |
1094 | return; |
1095 | |
1096 | Process *process = m_exe_ctx.GetProcessPtr(); |
1097 | |
1098 | const std::vector<lldb::addr_t> &tokens = process->GetImageTokens(); |
1099 | const size_t token_num = tokens.size(); |
1100 | for (size_t i = 0; i < token_num; ++i) { |
1101 | if (tokens[i] == LLDB_INVALID_IMAGE_TOKEN) |
1102 | continue; |
1103 | request.TryCompleteCurrentArg(completion: std::to_string(val: i)); |
1104 | } |
1105 | } |
1106 | |
1107 | protected: |
1108 | void DoExecute(Args &command, CommandReturnObject &result) override { |
1109 | Process *process = m_exe_ctx.GetProcessPtr(); |
1110 | |
1111 | for (auto &entry : command.entries()) { |
1112 | uint32_t image_token; |
1113 | if (entry.ref().getAsInteger(Radix: 0, Result&: image_token)) { |
1114 | result.AppendErrorWithFormat(format: "invalid image index argument '%s'" , |
1115 | entry.ref().str().c_str()); |
1116 | break; |
1117 | } else { |
1118 | Status error(process->GetTarget().GetPlatform()->UnloadImage( |
1119 | process, image_token)); |
1120 | if (error.Success()) { |
1121 | result.AppendMessageWithFormat( |
1122 | format: "Unloading shared library with index %u...ok\n" , image_token); |
1123 | result.SetStatus(eReturnStatusSuccessFinishResult); |
1124 | } else { |
1125 | result.AppendErrorWithFormat(format: "failed to unload image: %s" , |
1126 | error.AsCString()); |
1127 | break; |
1128 | } |
1129 | } |
1130 | } |
1131 | } |
1132 | }; |
1133 | |
1134 | // CommandObjectProcessSignal |
1135 | #pragma mark CommandObjectProcessSignal |
1136 | |
1137 | class CommandObjectProcessSignal : public CommandObjectParsed { |
1138 | public: |
1139 | CommandObjectProcessSignal(CommandInterpreter &interpreter) |
1140 | : CommandObjectParsed( |
1141 | interpreter, "process signal" , |
1142 | "Send a UNIX signal to the current target process." , nullptr, |
1143 | eCommandRequiresProcess | eCommandTryTargetAPILock) { |
1144 | CommandArgumentEntry arg; |
1145 | CommandArgumentData signal_arg; |
1146 | |
1147 | // Define the first (and only) variant of this arg. |
1148 | signal_arg.arg_type = eArgTypeUnixSignal; |
1149 | signal_arg.arg_repetition = eArgRepeatPlain; |
1150 | |
1151 | // There is only one variant this argument could be; put it into the |
1152 | // argument entry. |
1153 | arg.push_back(x: signal_arg); |
1154 | |
1155 | // Push the data for the first argument into the m_arguments vector. |
1156 | m_arguments.push_back(x: arg); |
1157 | } |
1158 | |
1159 | ~CommandObjectProcessSignal() override = default; |
1160 | |
1161 | void |
1162 | HandleArgumentCompletion(CompletionRequest &request, |
1163 | OptionElementVector &opt_element_vector) override { |
1164 | if (!m_exe_ctx.HasProcessScope() || request.GetCursorIndex() != 0) |
1165 | return; |
1166 | |
1167 | UnixSignalsSP signals = m_exe_ctx.GetProcessPtr()->GetUnixSignals(); |
1168 | int signo = signals->GetFirstSignalNumber(); |
1169 | while (signo != LLDB_INVALID_SIGNAL_NUMBER) { |
1170 | request.TryCompleteCurrentArg(completion: signals->GetSignalAsStringRef(signo)); |
1171 | signo = signals->GetNextSignalNumber(current_signal: signo); |
1172 | } |
1173 | } |
1174 | |
1175 | protected: |
1176 | void DoExecute(Args &command, CommandReturnObject &result) override { |
1177 | Process *process = m_exe_ctx.GetProcessPtr(); |
1178 | |
1179 | if (command.GetArgumentCount() == 1) { |
1180 | int signo = LLDB_INVALID_SIGNAL_NUMBER; |
1181 | |
1182 | const char *signal_name = command.GetArgumentAtIndex(idx: 0); |
1183 | if (::isxdigit(signal_name[0])) { |
1184 | if (!llvm::to_integer(S: signal_name, Num&: signo)) |
1185 | signo = LLDB_INVALID_SIGNAL_NUMBER; |
1186 | } else |
1187 | signo = process->GetUnixSignals()->GetSignalNumberFromName(name: signal_name); |
1188 | |
1189 | if (signo == LLDB_INVALID_SIGNAL_NUMBER) { |
1190 | result.AppendErrorWithFormat(format: "Invalid signal argument '%s'.\n" , |
1191 | command.GetArgumentAtIndex(idx: 0)); |
1192 | } else { |
1193 | Status error(process->Signal(signal: signo)); |
1194 | if (error.Success()) { |
1195 | result.SetStatus(eReturnStatusSuccessFinishResult); |
1196 | } else { |
1197 | result.AppendErrorWithFormat(format: "Failed to send signal %i: %s\n" , signo, |
1198 | error.AsCString()); |
1199 | } |
1200 | } |
1201 | } else { |
1202 | result.AppendErrorWithFormat( |
1203 | format: "'%s' takes exactly one signal number argument:\nUsage: %s\n" , |
1204 | m_cmd_name.c_str(), m_cmd_syntax.c_str()); |
1205 | } |
1206 | } |
1207 | }; |
1208 | |
1209 | // CommandObjectProcessInterrupt |
1210 | #pragma mark CommandObjectProcessInterrupt |
1211 | |
1212 | class CommandObjectProcessInterrupt : public CommandObjectParsed { |
1213 | public: |
1214 | CommandObjectProcessInterrupt(CommandInterpreter &interpreter) |
1215 | : CommandObjectParsed(interpreter, "process interrupt" , |
1216 | "Interrupt the current target process." , |
1217 | "process interrupt" , |
1218 | eCommandRequiresProcess | eCommandTryTargetAPILock | |
1219 | eCommandProcessMustBeLaunched) {} |
1220 | |
1221 | ~CommandObjectProcessInterrupt() override = default; |
1222 | |
1223 | protected: |
1224 | void DoExecute(Args &command, CommandReturnObject &result) override { |
1225 | Process *process = m_exe_ctx.GetProcessPtr(); |
1226 | if (process == nullptr) { |
1227 | result.AppendError(in_string: "no process to halt" ); |
1228 | return; |
1229 | } |
1230 | |
1231 | bool clear_thread_plans = true; |
1232 | Status error(process->Halt(clear_thread_plans)); |
1233 | if (error.Success()) { |
1234 | result.SetStatus(eReturnStatusSuccessFinishResult); |
1235 | } else { |
1236 | result.AppendErrorWithFormat(format: "Failed to halt process: %s\n" , |
1237 | error.AsCString()); |
1238 | } |
1239 | } |
1240 | }; |
1241 | |
1242 | // CommandObjectProcessKill |
1243 | #pragma mark CommandObjectProcessKill |
1244 | |
1245 | class CommandObjectProcessKill : public CommandObjectParsed { |
1246 | public: |
1247 | CommandObjectProcessKill(CommandInterpreter &interpreter) |
1248 | : CommandObjectParsed(interpreter, "process kill" , |
1249 | "Terminate the current target process." , |
1250 | "process kill" , |
1251 | eCommandRequiresProcess | eCommandTryTargetAPILock | |
1252 | eCommandProcessMustBeLaunched) {} |
1253 | |
1254 | ~CommandObjectProcessKill() override = default; |
1255 | |
1256 | protected: |
1257 | void DoExecute(Args &command, CommandReturnObject &result) override { |
1258 | Process *process = m_exe_ctx.GetProcessPtr(); |
1259 | if (process == nullptr) { |
1260 | result.AppendError(in_string: "no process to kill" ); |
1261 | return; |
1262 | } |
1263 | |
1264 | Status error(process->Destroy(force_kill: true)); |
1265 | if (error.Success()) { |
1266 | result.SetStatus(eReturnStatusSuccessFinishResult); |
1267 | } else { |
1268 | result.AppendErrorWithFormat(format: "Failed to kill process: %s\n" , |
1269 | error.AsCString()); |
1270 | } |
1271 | } |
1272 | }; |
1273 | |
1274 | #define LLDB_OPTIONS_process_save_core |
1275 | #include "CommandOptions.inc" |
1276 | |
1277 | class CommandObjectProcessSaveCore : public CommandObjectParsed { |
1278 | public: |
1279 | CommandObjectProcessSaveCore(CommandInterpreter &interpreter) |
1280 | : CommandObjectParsed( |
1281 | interpreter, "process save-core" , |
1282 | "Save the current process as a core file using an " |
1283 | "appropriate file type." , |
1284 | "process save-core [-s corefile-style -p plugin-name] FILE" , |
1285 | eCommandRequiresProcess | eCommandTryTargetAPILock | |
1286 | eCommandProcessMustBeLaunched) { |
1287 | CommandArgumentData file_arg{eArgTypePath, eArgRepeatPlain}; |
1288 | m_arguments.push_back(x: {file_arg}); |
1289 | } |
1290 | |
1291 | ~CommandObjectProcessSaveCore() override = default; |
1292 | |
1293 | Options *GetOptions() override { return &m_options; } |
1294 | |
1295 | void |
1296 | HandleArgumentCompletion(CompletionRequest &request, |
1297 | OptionElementVector &opt_element_vector) override { |
1298 | CommandCompletions::InvokeCommonCompletionCallbacks( |
1299 | interpreter&: GetCommandInterpreter(), completion_mask: lldb::eDiskFileCompletion, request, searcher: nullptr); |
1300 | } |
1301 | |
1302 | class CommandOptions : public Options { |
1303 | public: |
1304 | CommandOptions() = default; |
1305 | |
1306 | ~CommandOptions() override = default; |
1307 | |
1308 | llvm::ArrayRef<OptionDefinition> GetDefinitions() override { |
1309 | return llvm::ArrayRef(g_process_save_core_options); |
1310 | } |
1311 | |
1312 | Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, |
1313 | ExecutionContext *execution_context) override { |
1314 | const int short_option = m_getopt_table[option_idx].val; |
1315 | Status error; |
1316 | |
1317 | switch (short_option) { |
1318 | case 'p': |
1319 | m_requested_plugin_name = option_arg.str(); |
1320 | break; |
1321 | case 's': |
1322 | m_requested_save_core_style = |
1323 | (lldb::SaveCoreStyle)OptionArgParser::ToOptionEnum( |
1324 | s: option_arg, enum_values: GetDefinitions()[option_idx].enum_values, |
1325 | fail_value: eSaveCoreUnspecified, error); |
1326 | break; |
1327 | default: |
1328 | llvm_unreachable("Unimplemented option" ); |
1329 | } |
1330 | |
1331 | return {}; |
1332 | } |
1333 | |
1334 | void OptionParsingStarting(ExecutionContext *execution_context) override { |
1335 | m_requested_save_core_style = eSaveCoreUnspecified; |
1336 | m_requested_plugin_name.clear(); |
1337 | } |
1338 | |
1339 | // Instance variables to hold the values for command options. |
1340 | SaveCoreStyle m_requested_save_core_style = eSaveCoreUnspecified; |
1341 | std::string m_requested_plugin_name; |
1342 | }; |
1343 | |
1344 | protected: |
1345 | void DoExecute(Args &command, CommandReturnObject &result) override { |
1346 | ProcessSP process_sp = m_exe_ctx.GetProcessSP(); |
1347 | if (process_sp) { |
1348 | if (command.GetArgumentCount() == 1) { |
1349 | FileSpec output_file(command.GetArgumentAtIndex(idx: 0)); |
1350 | FileSystem::Instance().Resolve(file_spec&: output_file); |
1351 | SaveCoreStyle corefile_style = m_options.m_requested_save_core_style; |
1352 | Status error = |
1353 | PluginManager::SaveCore(process_sp, outfile: output_file, core_style&: corefile_style, |
1354 | plugin_name: m_options.m_requested_plugin_name); |
1355 | if (error.Success()) { |
1356 | if (corefile_style == SaveCoreStyle::eSaveCoreDirtyOnly || |
1357 | corefile_style == SaveCoreStyle::eSaveCoreStackOnly) { |
1358 | result.AppendMessageWithFormat( |
1359 | format: "\nModified-memory or stack-memory only corefile " |
1360 | "created. This corefile may \n" |
1361 | "not show library/framework/app binaries " |
1362 | "on a different system, or when \n" |
1363 | "those binaries have " |
1364 | "been updated/modified. Copies are not included\n" |
1365 | "in this corefile. Use --style full to include all " |
1366 | "process memory.\n" ); |
1367 | } |
1368 | result.SetStatus(eReturnStatusSuccessFinishResult); |
1369 | } else { |
1370 | result.AppendErrorWithFormat( |
1371 | format: "Failed to save core file for process: %s\n" , error.AsCString()); |
1372 | } |
1373 | } else { |
1374 | result.AppendErrorWithFormat(format: "'%s' takes one arguments:\nUsage: %s\n" , |
1375 | m_cmd_name.c_str(), m_cmd_syntax.c_str()); |
1376 | } |
1377 | } else { |
1378 | result.AppendError(in_string: "invalid process" ); |
1379 | } |
1380 | } |
1381 | |
1382 | CommandOptions m_options; |
1383 | }; |
1384 | |
1385 | // CommandObjectProcessStatus |
1386 | #pragma mark CommandObjectProcessStatus |
1387 | #define LLDB_OPTIONS_process_status |
1388 | #include "CommandOptions.inc" |
1389 | |
1390 | class CommandObjectProcessStatus : public CommandObjectParsed { |
1391 | public: |
1392 | CommandObjectProcessStatus(CommandInterpreter &interpreter) |
1393 | : CommandObjectParsed( |
1394 | interpreter, "process status" , |
1395 | "Show status and stop location for the current target process." , |
1396 | "process status" , |
1397 | eCommandRequiresProcess | eCommandTryTargetAPILock) {} |
1398 | |
1399 | ~CommandObjectProcessStatus() override = default; |
1400 | |
1401 | Options *GetOptions() override { return &m_options; } |
1402 | |
1403 | class CommandOptions : public Options { |
1404 | public: |
1405 | CommandOptions() = default; |
1406 | |
1407 | ~CommandOptions() override = default; |
1408 | |
1409 | Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, |
1410 | ExecutionContext *execution_context) override { |
1411 | const int short_option = m_getopt_table[option_idx].val; |
1412 | |
1413 | switch (short_option) { |
1414 | case 'v': |
1415 | m_verbose = true; |
1416 | break; |
1417 | default: |
1418 | llvm_unreachable("Unimplemented option" ); |
1419 | } |
1420 | |
1421 | return {}; |
1422 | } |
1423 | |
1424 | void OptionParsingStarting(ExecutionContext *execution_context) override { |
1425 | m_verbose = false; |
1426 | } |
1427 | |
1428 | llvm::ArrayRef<OptionDefinition> GetDefinitions() override { |
1429 | return llvm::ArrayRef(g_process_status_options); |
1430 | } |
1431 | |
1432 | // Instance variables to hold the values for command options. |
1433 | bool m_verbose = false; |
1434 | }; |
1435 | |
1436 | protected: |
1437 | void DoExecute(Args &command, CommandReturnObject &result) override { |
1438 | Stream &strm = result.GetOutputStream(); |
1439 | result.SetStatus(eReturnStatusSuccessFinishNoResult); |
1440 | |
1441 | // No need to check "process" for validity as eCommandRequiresProcess |
1442 | // ensures it is valid |
1443 | Process *process = m_exe_ctx.GetProcessPtr(); |
1444 | const bool only_threads_with_stop_reason = true; |
1445 | const uint32_t start_frame = 0; |
1446 | const uint32_t num_frames = 1; |
1447 | const uint32_t num_frames_with_source = 1; |
1448 | const bool stop_format = true; |
1449 | process->GetStatus(ostrm&: strm); |
1450 | process->GetThreadStatus(ostrm&: strm, only_threads_with_stop_reason, start_frame, |
1451 | num_frames, num_frames_with_source, stop_format); |
1452 | |
1453 | if (m_options.m_verbose) { |
1454 | addr_t code_mask = process->GetCodeAddressMask(); |
1455 | addr_t data_mask = process->GetDataAddressMask(); |
1456 | if (code_mask != 0) { |
1457 | int bits = std::bitset<64>(~code_mask).count(); |
1458 | result.AppendMessageWithFormat( |
1459 | format: "Addressable code address mask: 0x%" PRIx64 "\n" , code_mask); |
1460 | result.AppendMessageWithFormat( |
1461 | format: "Addressable data address mask: 0x%" PRIx64 "\n" , data_mask); |
1462 | result.AppendMessageWithFormat( |
1463 | format: "Number of bits used in addressing (code): %d\n" , bits); |
1464 | } |
1465 | |
1466 | PlatformSP platform_sp = process->GetTarget().GetPlatform(); |
1467 | if (!platform_sp) { |
1468 | result.AppendError(in_string: "Couldn'retrieve the target's platform" ); |
1469 | return; |
1470 | } |
1471 | |
1472 | auto expected_crash_info = |
1473 | platform_sp->FetchExtendedCrashInformation(process&: *process); |
1474 | |
1475 | if (!expected_crash_info) { |
1476 | result.AppendError(in_string: llvm::toString(E: expected_crash_info.takeError())); |
1477 | return; |
1478 | } |
1479 | |
1480 | StructuredData::DictionarySP crash_info_sp = *expected_crash_info; |
1481 | |
1482 | if (crash_info_sp) { |
1483 | strm.EOL(); |
1484 | strm.PutCString(cstr: "Extended Crash Information:\n" ); |
1485 | crash_info_sp->GetDescription(s&: strm); |
1486 | } |
1487 | } |
1488 | } |
1489 | |
1490 | private: |
1491 | CommandOptions m_options; |
1492 | }; |
1493 | |
1494 | // CommandObjectProcessHandle |
1495 | #define LLDB_OPTIONS_process_handle |
1496 | #include "CommandOptions.inc" |
1497 | |
1498 | #pragma mark CommandObjectProcessHandle |
1499 | |
1500 | class CommandObjectProcessHandle : public CommandObjectParsed { |
1501 | public: |
1502 | class CommandOptions : public Options { |
1503 | public: |
1504 | CommandOptions() { OptionParsingStarting(execution_context: nullptr); } |
1505 | |
1506 | ~CommandOptions() override = default; |
1507 | |
1508 | Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, |
1509 | ExecutionContext *execution_context) override { |
1510 | Status error; |
1511 | const int short_option = m_getopt_table[option_idx].val; |
1512 | |
1513 | switch (short_option) { |
1514 | case 'c': |
1515 | do_clear = true; |
1516 | break; |
1517 | case 'd': |
1518 | dummy = true; |
1519 | break; |
1520 | case 's': |
1521 | stop = std::string(option_arg); |
1522 | break; |
1523 | case 'n': |
1524 | notify = std::string(option_arg); |
1525 | break; |
1526 | case 'p': |
1527 | pass = std::string(option_arg); |
1528 | break; |
1529 | case 't': |
1530 | only_target_values = true; |
1531 | break; |
1532 | default: |
1533 | llvm_unreachable("Unimplemented option" ); |
1534 | } |
1535 | return error; |
1536 | } |
1537 | |
1538 | void OptionParsingStarting(ExecutionContext *execution_context) override { |
1539 | stop.clear(); |
1540 | notify.clear(); |
1541 | pass.clear(); |
1542 | only_target_values = false; |
1543 | do_clear = false; |
1544 | dummy = false; |
1545 | } |
1546 | |
1547 | llvm::ArrayRef<OptionDefinition> GetDefinitions() override { |
1548 | return llvm::ArrayRef(g_process_handle_options); |
1549 | } |
1550 | |
1551 | // Instance variables to hold the values for command options. |
1552 | |
1553 | std::string stop; |
1554 | std::string notify; |
1555 | std::string pass; |
1556 | bool only_target_values = false; |
1557 | bool do_clear = false; |
1558 | bool dummy = false; |
1559 | }; |
1560 | |
1561 | CommandObjectProcessHandle(CommandInterpreter &interpreter) |
1562 | : CommandObjectParsed(interpreter, "process handle" , |
1563 | "Manage LLDB handling of OS signals for the " |
1564 | "current target process. Defaults to showing " |
1565 | "current policy." , |
1566 | nullptr) { |
1567 | SetHelpLong("\nIf no signals are specified but one or more actions are, " |
1568 | "and there is a live process, update them all. If no action " |
1569 | "is specified, list the current values.\n" |
1570 | "If you specify actions with no target (e.g. in an init file) " |
1571 | "or in a target with no process " |
1572 | "the values will get copied into subsequent targets, but " |
1573 | "lldb won't be able to spell-check the options since it can't " |
1574 | "know which signal set will later be in force." |
1575 | "\nYou can see the signal modifications held by the target" |
1576 | "by passing the -t option." |
1577 | "\nYou can also clear the target modification for a signal" |
1578 | "by passing the -c option" ); |
1579 | CommandArgumentEntry arg; |
1580 | CommandArgumentData signal_arg; |
1581 | |
1582 | signal_arg.arg_type = eArgTypeUnixSignal; |
1583 | signal_arg.arg_repetition = eArgRepeatStar; |
1584 | |
1585 | arg.push_back(x: signal_arg); |
1586 | |
1587 | m_arguments.push_back(x: arg); |
1588 | } |
1589 | |
1590 | ~CommandObjectProcessHandle() override = default; |
1591 | |
1592 | Options *GetOptions() override { return &m_options; } |
1593 | |
1594 | void PrintSignalHeader(Stream &str) { |
1595 | str.Printf(format: "NAME PASS STOP NOTIFY\n" ); |
1596 | str.Printf(format: "=========== ===== ===== ======\n" ); |
1597 | } |
1598 | |
1599 | void PrintSignal(Stream &str, int32_t signo, llvm::StringRef sig_name, |
1600 | const UnixSignalsSP &signals_sp) { |
1601 | bool stop; |
1602 | bool suppress; |
1603 | bool notify; |
1604 | |
1605 | str.Format("{0, -11} " , sig_name); |
1606 | if (signals_sp->GetSignalInfo(signo, should_suppress&: suppress, should_stop&: stop, should_notify&: notify)) { |
1607 | bool pass = !suppress; |
1608 | str.Printf(format: "%s %s %s" , (pass ? "true " : "false" ), |
1609 | (stop ? "true " : "false" ), (notify ? "true " : "false" )); |
1610 | } |
1611 | str.Printf(format: "\n" ); |
1612 | } |
1613 | |
1614 | void PrintSignalInformation(Stream &str, Args &signal_args, |
1615 | int num_valid_signals, |
1616 | const UnixSignalsSP &signals_sp) { |
1617 | PrintSignalHeader(str); |
1618 | |
1619 | if (num_valid_signals > 0) { |
1620 | size_t num_args = signal_args.GetArgumentCount(); |
1621 | for (size_t i = 0; i < num_args; ++i) { |
1622 | int32_t signo = signals_sp->GetSignalNumberFromName( |
1623 | name: signal_args.GetArgumentAtIndex(idx: i)); |
1624 | if (signo != LLDB_INVALID_SIGNAL_NUMBER) |
1625 | PrintSignal(str, signo, sig_name: signal_args.GetArgumentAtIndex(idx: i), |
1626 | signals_sp); |
1627 | } |
1628 | } else // Print info for ALL signals |
1629 | { |
1630 | int32_t signo = signals_sp->GetFirstSignalNumber(); |
1631 | while (signo != LLDB_INVALID_SIGNAL_NUMBER) { |
1632 | PrintSignal(str, signo, sig_name: signals_sp->GetSignalAsStringRef(signo), |
1633 | signals_sp); |
1634 | signo = signals_sp->GetNextSignalNumber(current_signal: signo); |
1635 | } |
1636 | } |
1637 | } |
1638 | |
1639 | protected: |
1640 | void DoExecute(Args &signal_args, CommandReturnObject &result) override { |
1641 | Target &target = GetSelectedOrDummyTarget(); |
1642 | |
1643 | // Any signals that are being set should be added to the Target's |
1644 | // DummySignals so they will get applied on rerun, etc. |
1645 | // If we have a process, however, we can do a more accurate job of vetting |
1646 | // the user's options. |
1647 | ProcessSP process_sp = target.GetProcessSP(); |
1648 | |
1649 | std::optional<bool> stop_action = {}; |
1650 | std::optional<bool> pass_action = {}; |
1651 | std::optional<bool> notify_action = {}; |
1652 | |
1653 | if (!m_options.stop.empty()) { |
1654 | bool success = false; |
1655 | bool value = OptionArgParser::ToBoolean(s: m_options.stop, fail_value: false, success_ptr: &success); |
1656 | if (!success) { |
1657 | result.AppendError( |
1658 | in_string: "Invalid argument for command option --stop; must be " |
1659 | "true or false.\n" ); |
1660 | return; |
1661 | } |
1662 | |
1663 | stop_action = value; |
1664 | } |
1665 | |
1666 | if (!m_options.pass.empty()) { |
1667 | bool success = false; |
1668 | bool value = OptionArgParser::ToBoolean(s: m_options.pass, fail_value: false, success_ptr: &success); |
1669 | if (!success) { |
1670 | result.AppendError( |
1671 | in_string: "Invalid argument for command option --pass; must be " |
1672 | "true or false.\n" ); |
1673 | return; |
1674 | } |
1675 | pass_action = value; |
1676 | } |
1677 | |
1678 | if (!m_options.notify.empty()) { |
1679 | bool success = false; |
1680 | bool value = |
1681 | OptionArgParser::ToBoolean(s: m_options.notify, fail_value: false, success_ptr: &success); |
1682 | if (!success) { |
1683 | result.AppendError(in_string: "Invalid argument for command option --notify; must " |
1684 | "be true or false.\n" ); |
1685 | return; |
1686 | } |
1687 | notify_action = value; |
1688 | } |
1689 | |
1690 | if (!m_options.notify.empty() && !notify_action.has_value()) { |
1691 | } |
1692 | |
1693 | bool no_actions = (!stop_action.has_value() && !pass_action.has_value() && |
1694 | !notify_action.has_value()); |
1695 | if (m_options.only_target_values && !no_actions) { |
1696 | result.AppendError(in_string: "-t is for reporting, not setting, target values." ); |
1697 | return; |
1698 | } |
1699 | |
1700 | size_t num_args = signal_args.GetArgumentCount(); |
1701 | UnixSignalsSP signals_sp; |
1702 | if (process_sp) |
1703 | signals_sp = process_sp->GetUnixSignals(); |
1704 | |
1705 | int num_signals_set = 0; |
1706 | |
1707 | // If we were just asked to print the target values, do that here and |
1708 | // return: |
1709 | if (m_options.only_target_values) { |
1710 | target.PrintDummySignals(strm&: result.GetOutputStream(), signals&: signal_args); |
1711 | result.SetStatus(eReturnStatusSuccessFinishResult); |
1712 | return; |
1713 | } |
1714 | |
1715 | // This handles clearing values: |
1716 | if (m_options.do_clear) { |
1717 | target.ClearDummySignals(signal_names&: signal_args); |
1718 | if (m_options.dummy) |
1719 | GetDummyTarget().ClearDummySignals(signal_names&: signal_args); |
1720 | result.SetStatus(eReturnStatusSuccessFinishNoResult); |
1721 | return; |
1722 | } |
1723 | |
1724 | // This rest handles setting values: |
1725 | if (num_args > 0) { |
1726 | for (const auto &arg : signal_args) { |
1727 | // Do the process first. If we have a process we can catch |
1728 | // invalid signal names, which we do here. |
1729 | if (signals_sp) { |
1730 | int32_t signo = signals_sp->GetSignalNumberFromName(arg.c_str()); |
1731 | if (signo != LLDB_INVALID_SIGNAL_NUMBER) { |
1732 | if (stop_action.has_value()) |
1733 | signals_sp->SetShouldStop(signo, *stop_action); |
1734 | if (pass_action.has_value()) { |
1735 | bool suppress = !*pass_action; |
1736 | signals_sp->SetShouldSuppress(signo, suppress); |
1737 | } |
1738 | if (notify_action.has_value()) |
1739 | signals_sp->SetShouldNotify(signo, *notify_action); |
1740 | ++num_signals_set; |
1741 | } else { |
1742 | result.AppendErrorWithFormat("Invalid signal name '%s'\n" , |
1743 | arg.c_str()); |
1744 | continue; |
1745 | } |
1746 | } else { |
1747 | // If there's no process we can't check, so we just set them all. |
1748 | // But since the map signal name -> signal number across all platforms |
1749 | // is not 1-1, we can't sensibly set signal actions by number before |
1750 | // we have a process. Check that here: |
1751 | int32_t signo; |
1752 | if (llvm::to_integer(arg.c_str(), signo)) { |
1753 | result.AppendErrorWithFormat("Can't set signal handling by signal " |
1754 | "number with no process" ); |
1755 | return; |
1756 | } |
1757 | num_signals_set = num_args; |
1758 | } |
1759 | auto set_lazy_bool = [](std::optional<bool> action) -> LazyBool { |
1760 | if (!action.has_value()) |
1761 | return eLazyBoolCalculate; |
1762 | return (*action) ? eLazyBoolYes : eLazyBoolNo; |
1763 | }; |
1764 | |
1765 | // If there were no actions, we're just listing, don't add the dummy: |
1766 | if (!no_actions) |
1767 | target.AddDummySignal(arg.ref(), set_lazy_bool(pass_action), |
1768 | set_lazy_bool(notify_action), |
1769 | set_lazy_bool(stop_action)); |
1770 | } |
1771 | } else { |
1772 | // No signal specified, if any command options were specified, update ALL |
1773 | // signals. But we can't do this without a process since we don't know |
1774 | // all the possible signals that might be valid for this target. |
1775 | if ((notify_action.has_value() || stop_action.has_value() || |
1776 | pass_action.has_value()) && |
1777 | process_sp) { |
1778 | if (m_interpreter.Confirm( |
1779 | message: "Do you really want to update all the signals?" , default_answer: false)) { |
1780 | int32_t signo = signals_sp->GetFirstSignalNumber(); |
1781 | while (signo != LLDB_INVALID_SIGNAL_NUMBER) { |
1782 | if (notify_action.has_value()) |
1783 | signals_sp->SetShouldNotify(signo, value: *notify_action); |
1784 | if (stop_action.has_value()) |
1785 | signals_sp->SetShouldStop(signo, value: *stop_action); |
1786 | if (pass_action.has_value()) { |
1787 | bool suppress = !*pass_action; |
1788 | signals_sp->SetShouldSuppress(signo, value: suppress); |
1789 | } |
1790 | signo = signals_sp->GetNextSignalNumber(current_signal: signo); |
1791 | } |
1792 | } |
1793 | } |
1794 | } |
1795 | |
1796 | if (signals_sp) |
1797 | PrintSignalInformation(str&: result.GetOutputStream(), signal_args, |
1798 | num_valid_signals: num_signals_set, signals_sp); |
1799 | else |
1800 | target.PrintDummySignals(strm&: result.GetOutputStream(), |
1801 | signals&: signal_args); |
1802 | |
1803 | if (num_signals_set > 0) |
1804 | result.SetStatus(eReturnStatusSuccessFinishResult); |
1805 | else |
1806 | result.SetStatus(eReturnStatusFailed); |
1807 | } |
1808 | |
1809 | CommandOptions m_options; |
1810 | }; |
1811 | |
1812 | // Next are the subcommands of CommandObjectMultiwordProcessTrace |
1813 | |
1814 | // CommandObjectProcessTraceStart |
1815 | class CommandObjectProcessTraceStart : public CommandObjectTraceProxy { |
1816 | public: |
1817 | CommandObjectProcessTraceStart(CommandInterpreter &interpreter) |
1818 | : CommandObjectTraceProxy( |
1819 | /*live_debug_session_only*/ true, interpreter, |
1820 | "process trace start" , |
1821 | "Start tracing this process with the corresponding trace " |
1822 | "plug-in." , |
1823 | "process trace start [<trace-options>]" ) {} |
1824 | |
1825 | protected: |
1826 | lldb::CommandObjectSP GetDelegateCommand(Trace &trace) override { |
1827 | return trace.GetProcessTraceStartCommand(interpreter&: m_interpreter); |
1828 | } |
1829 | }; |
1830 | |
1831 | // CommandObjectProcessTraceStop |
1832 | class CommandObjectProcessTraceStop : public CommandObjectParsed { |
1833 | public: |
1834 | CommandObjectProcessTraceStop(CommandInterpreter &interpreter) |
1835 | : CommandObjectParsed(interpreter, "process trace stop" , |
1836 | "Stop tracing this process. This does not affect " |
1837 | "traces started with the " |
1838 | "\"thread trace start\" command." , |
1839 | "process trace stop" , |
1840 | eCommandRequiresProcess | eCommandTryTargetAPILock | |
1841 | eCommandProcessMustBeLaunched | |
1842 | eCommandProcessMustBePaused | |
1843 | eCommandProcessMustBeTraced) {} |
1844 | |
1845 | ~CommandObjectProcessTraceStop() override = default; |
1846 | |
1847 | void DoExecute(Args &command, CommandReturnObject &result) override { |
1848 | ProcessSP process_sp = m_exe_ctx.GetProcessSP(); |
1849 | |
1850 | TraceSP trace_sp = process_sp->GetTarget().GetTrace(); |
1851 | |
1852 | if (llvm::Error err = trace_sp->Stop()) |
1853 | result.AppendError(in_string: toString(E: std::move(err))); |
1854 | else |
1855 | result.SetStatus(eReturnStatusSuccessFinishResult); |
1856 | } |
1857 | }; |
1858 | |
1859 | // CommandObjectMultiwordProcessTrace |
1860 | class CommandObjectMultiwordProcessTrace : public CommandObjectMultiword { |
1861 | public: |
1862 | CommandObjectMultiwordProcessTrace(CommandInterpreter &interpreter) |
1863 | : CommandObjectMultiword( |
1864 | interpreter, "trace" , "Commands for tracing the current process." , |
1865 | "process trace <subcommand> [<subcommand objects>]" ) { |
1866 | LoadSubCommand(cmd_name: "start" , command_obj: CommandObjectSP(new CommandObjectProcessTraceStart( |
1867 | interpreter))); |
1868 | LoadSubCommand(cmd_name: "stop" , command_obj: CommandObjectSP( |
1869 | new CommandObjectProcessTraceStop(interpreter))); |
1870 | } |
1871 | |
1872 | ~CommandObjectMultiwordProcessTrace() override = default; |
1873 | }; |
1874 | |
1875 | // CommandObjectMultiwordProcess |
1876 | |
1877 | CommandObjectMultiwordProcess::CommandObjectMultiwordProcess( |
1878 | CommandInterpreter &interpreter) |
1879 | : CommandObjectMultiword( |
1880 | interpreter, "process" , |
1881 | "Commands for interacting with processes on the current platform." , |
1882 | "process <subcommand> [<subcommand-options>]" ) { |
1883 | LoadSubCommand(cmd_name: "attach" , |
1884 | command_obj: CommandObjectSP(new CommandObjectProcessAttach(interpreter))); |
1885 | LoadSubCommand(cmd_name: "launch" , |
1886 | command_obj: CommandObjectSP(new CommandObjectProcessLaunch(interpreter))); |
1887 | LoadSubCommand(cmd_name: "continue" , command_obj: CommandObjectSP(new CommandObjectProcessContinue( |
1888 | interpreter))); |
1889 | LoadSubCommand(cmd_name: "connect" , |
1890 | command_obj: CommandObjectSP(new CommandObjectProcessConnect(interpreter))); |
1891 | LoadSubCommand(cmd_name: "detach" , |
1892 | command_obj: CommandObjectSP(new CommandObjectProcessDetach(interpreter))); |
1893 | LoadSubCommand(cmd_name: "load" , |
1894 | command_obj: CommandObjectSP(new CommandObjectProcessLoad(interpreter))); |
1895 | LoadSubCommand(cmd_name: "unload" , |
1896 | command_obj: CommandObjectSP(new CommandObjectProcessUnload(interpreter))); |
1897 | LoadSubCommand(cmd_name: "signal" , |
1898 | command_obj: CommandObjectSP(new CommandObjectProcessSignal(interpreter))); |
1899 | LoadSubCommand(cmd_name: "handle" , |
1900 | command_obj: CommandObjectSP(new CommandObjectProcessHandle(interpreter))); |
1901 | LoadSubCommand(cmd_name: "status" , |
1902 | command_obj: CommandObjectSP(new CommandObjectProcessStatus(interpreter))); |
1903 | LoadSubCommand(cmd_name: "interrupt" , command_obj: CommandObjectSP(new CommandObjectProcessInterrupt( |
1904 | interpreter))); |
1905 | LoadSubCommand(cmd_name: "kill" , |
1906 | command_obj: CommandObjectSP(new CommandObjectProcessKill(interpreter))); |
1907 | LoadSubCommand(cmd_name: "plugin" , |
1908 | command_obj: CommandObjectSP(new CommandObjectProcessPlugin(interpreter))); |
1909 | LoadSubCommand(cmd_name: "save-core" , command_obj: CommandObjectSP(new CommandObjectProcessSaveCore( |
1910 | interpreter))); |
1911 | LoadSubCommand( |
1912 | cmd_name: "trace" , |
1913 | command_obj: CommandObjectSP(new CommandObjectMultiwordProcessTrace(interpreter))); |
1914 | } |
1915 | |
1916 | CommandObjectMultiwordProcess::~CommandObjectMultiwordProcess() = default; |
1917 | |