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