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