1 | //===-- CommandObjectQuit.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 "CommandObjectQuit.h" |
10 | |
11 | #include "lldb/Interpreter/CommandInterpreter.h" |
12 | #include "lldb/Interpreter/CommandReturnObject.h" |
13 | #include "lldb/Target/Process.h" |
14 | #include "lldb/Utility/StreamString.h" |
15 | |
16 | using namespace lldb; |
17 | using namespace lldb_private; |
18 | |
19 | // CommandObjectQuit |
20 | |
21 | CommandObjectQuit::CommandObjectQuit(CommandInterpreter &interpreter) |
22 | : CommandObjectParsed(interpreter, "quit" , "Quit the LLDB debugger." , |
23 | "quit [exit-code]" ) { |
24 | AddSimpleArgumentList(arg_type: eArgTypeUnsignedInteger); |
25 | } |
26 | |
27 | CommandObjectQuit::~CommandObjectQuit() = default; |
28 | |
29 | // returns true if there is at least one alive process is_a_detach will be true |
30 | // if all alive processes will be detached when you quit and false if at least |
31 | // one process will be killed instead |
32 | bool CommandObjectQuit::ShouldAskForConfirmation(bool &is_a_detach) { |
33 | if (!m_interpreter.GetPromptOnQuit()) |
34 | return false; |
35 | bool should_prompt = false; |
36 | is_a_detach = true; |
37 | for (uint32_t debugger_idx = 0; debugger_idx < Debugger::GetNumDebuggers(); |
38 | debugger_idx++) { |
39 | DebuggerSP debugger_sp(Debugger::GetDebuggerAtIndex(index: debugger_idx)); |
40 | if (!debugger_sp) |
41 | continue; |
42 | const TargetList &target_list(debugger_sp->GetTargetList()); |
43 | for (uint32_t target_idx = 0; |
44 | target_idx < static_cast<uint32_t>(target_list.GetNumTargets()); |
45 | target_idx++) { |
46 | TargetSP target_sp(target_list.GetTargetAtIndex(index: target_idx)); |
47 | if (!target_sp) |
48 | continue; |
49 | ProcessSP process_sp(target_sp->GetProcessSP()); |
50 | if (process_sp && process_sp->IsValid() && process_sp->IsAlive() && |
51 | process_sp->WarnBeforeDetach()) { |
52 | should_prompt = true; |
53 | if (!process_sp->GetShouldDetach()) { |
54 | // if we need to kill at least one process, just say so and return |
55 | is_a_detach = false; |
56 | return should_prompt; |
57 | } |
58 | } |
59 | } |
60 | } |
61 | return should_prompt; |
62 | } |
63 | |
64 | void CommandObjectQuit::DoExecute(Args &command, CommandReturnObject &result) { |
65 | bool is_a_detach = true; |
66 | if (ShouldAskForConfirmation(is_a_detach)) { |
67 | StreamString message; |
68 | message.Printf(format: "Quitting LLDB will %s one or more processes. Do you really " |
69 | "want to proceed" , |
70 | (is_a_detach ? "detach from" : "kill" )); |
71 | if (!m_interpreter.Confirm(message: message.GetString(), default_answer: true)) { |
72 | result.SetStatus(eReturnStatusFailed); |
73 | return; |
74 | } |
75 | } |
76 | |
77 | if (command.GetArgumentCount() > 1) { |
78 | result.AppendError(in_string: "Too many arguments for 'quit'. Only an optional exit " |
79 | "code is allowed" ); |
80 | return; |
81 | } |
82 | |
83 | // We parse the exit code argument if there is one. |
84 | if (command.GetArgumentCount() == 1) { |
85 | llvm::StringRef arg = command.GetArgumentAtIndex(idx: 0); |
86 | int exit_code; |
87 | if (arg.getAsInteger(/*autodetect radix*/ Radix: 0, Result&: exit_code)) { |
88 | lldb_private::StreamString s; |
89 | std::string arg_str = arg.str(); |
90 | s.Printf(format: "Couldn't parse '%s' as integer for exit code." , arg_str.data()); |
91 | result.AppendError(in_string: s.GetString()); |
92 | return; |
93 | } |
94 | if (!m_interpreter.SetQuitExitCode(exit_code)) { |
95 | result.AppendError(in_string: "The current driver doesn't allow custom exit codes" |
96 | " for the quit command." ); |
97 | return; |
98 | } |
99 | } |
100 | |
101 | const uint32_t event_type = |
102 | CommandInterpreter::eBroadcastBitQuitCommandReceived; |
103 | m_interpreter.BroadcastEvent(event_type); |
104 | result.SetStatus(eReturnStatusQuit); |
105 | } |
106 | |