180814287SRaphael Isemann //===-- CommandObjectQuit.cpp ---------------------------------------------===// 230fdc8d8SChris Lattner // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 630fdc8d8SChris Lattner // 730fdc8d8SChris Lattner //===----------------------------------------------------------------------===// 830fdc8d8SChris Lattner 930fdc8d8SChris Lattner #include "CommandObjectQuit.h" 1030fdc8d8SChris Lattner 1159817b1dSEli Friedman #include "lldb/Interpreter/CommandInterpreter.h" 1259817b1dSEli Friedman #include "lldb/Interpreter/CommandReturnObject.h" 13a78bd7ffSZachary Turner #include "lldb/Target/Process.h" 14c094d23fSRaphael Isemann #include "lldb/Utility/StreamString.h" 1530fdc8d8SChris Lattner 1630fdc8d8SChris Lattner using namespace lldb; 1730fdc8d8SChris Lattner using namespace lldb_private; 1830fdc8d8SChris Lattner 1930fdc8d8SChris Lattner // CommandObjectQuit 2030fdc8d8SChris Lattner 217428a18cSKate Stone CommandObjectQuit::CommandObjectQuit(CommandInterpreter &interpreter) 22b9c1b51eSKate Stone : CommandObjectParsed(interpreter, "quit", "Quit the LLDB debugger.", 23c094d23fSRaphael Isemann "quit [exit-code]") {} 2430fdc8d8SChris Lattner 25*fd2433e1SJonas Devlieghere CommandObjectQuit::~CommandObjectQuit() = default; 2630fdc8d8SChris Lattner 2705097246SAdrian Prantl // returns true if there is at least one alive process is_a_detach will be true 2805097246SAdrian Prantl // if all alive processes will be detached when you quit and false if at least 2905097246SAdrian Prantl // one process will be killed instead 30b9c1b51eSKate Stone bool CommandObjectQuit::ShouldAskForConfirmation(bool &is_a_detach) { 31a6682a41SJonas Devlieghere if (!m_interpreter.GetPromptOnQuit()) 32bcba2b2bSEnrico Granata return false; 33bcba2b2bSEnrico Granata bool should_prompt = false; 34bcba2b2bSEnrico Granata is_a_detach = true; 35b9c1b51eSKate Stone for (uint32_t debugger_idx = 0; debugger_idx < Debugger::GetNumDebuggers(); 36b9c1b51eSKate Stone debugger_idx++) { 37bcba2b2bSEnrico Granata DebuggerSP debugger_sp(Debugger::GetDebuggerAtIndex(debugger_idx)); 38bcba2b2bSEnrico Granata if (!debugger_sp) 39bcba2b2bSEnrico Granata continue; 40bcba2b2bSEnrico Granata const TargetList &target_list(debugger_sp->GetTargetList()); 41bcba2b2bSEnrico Granata for (uint32_t target_idx = 0; 423985c8c6SSaleem Abdulrasool target_idx < static_cast<uint32_t>(target_list.GetNumTargets()); 43b9c1b51eSKate Stone target_idx++) { 44bcba2b2bSEnrico Granata TargetSP target_sp(target_list.GetTargetAtIndex(target_idx)); 45bcba2b2bSEnrico Granata if (!target_sp) 46bcba2b2bSEnrico Granata continue; 47bcba2b2bSEnrico Granata ProcessSP process_sp(target_sp->GetProcessSP()); 48b9c1b51eSKate Stone if (process_sp && process_sp->IsValid() && process_sp->IsAlive() && 49b9c1b51eSKate Stone process_sp->WarnBeforeDetach()) { 50bcba2b2bSEnrico Granata should_prompt = true; 51a6682a41SJonas Devlieghere if (!process_sp->GetShouldDetach()) { 52bcba2b2bSEnrico Granata // if we need to kill at least one process, just say so and return 53bcba2b2bSEnrico Granata is_a_detach = false; 54bcba2b2bSEnrico Granata return should_prompt; 55bcba2b2bSEnrico Granata } 56bcba2b2bSEnrico Granata } 57bcba2b2bSEnrico Granata } 58bcba2b2bSEnrico Granata } 59bcba2b2bSEnrico Granata return should_prompt; 60bcba2b2bSEnrico Granata } 61bcba2b2bSEnrico Granata 62b9c1b51eSKate Stone bool CommandObjectQuit::DoExecute(Args &command, CommandReturnObject &result) { 63bcba2b2bSEnrico Granata bool is_a_detach = true; 64b9c1b51eSKate Stone if (ShouldAskForConfirmation(is_a_detach)) { 65bcba2b2bSEnrico Granata StreamString message; 66b9c1b51eSKate Stone message.Printf("Quitting LLDB will %s one or more processes. Do you really " 67b9c1b51eSKate Stone "want to proceed", 68b9c1b51eSKate Stone (is_a_detach ? "detach from" : "kill")); 69c156427dSZachary Turner if (!m_interpreter.Confirm(message.GetString(), true)) { 70bcba2b2bSEnrico Granata result.SetStatus(eReturnStatusFailed); 71bcba2b2bSEnrico Granata return false; 72bcba2b2bSEnrico Granata } 73bcba2b2bSEnrico Granata } 74c094d23fSRaphael Isemann 75c094d23fSRaphael Isemann if (command.GetArgumentCount() > 1) { 76c094d23fSRaphael Isemann result.AppendError("Too many arguments for 'quit'. Only an optional exit " 77c094d23fSRaphael Isemann "code is allowed"); 78c094d23fSRaphael Isemann return false; 79c094d23fSRaphael Isemann } 80c094d23fSRaphael Isemann 81c094d23fSRaphael Isemann // We parse the exit code argument if there is one. 82c094d23fSRaphael Isemann if (command.GetArgumentCount() == 1) { 83c094d23fSRaphael Isemann llvm::StringRef arg = command.GetArgumentAtIndex(0); 84c094d23fSRaphael Isemann int exit_code; 85c094d23fSRaphael Isemann if (arg.getAsInteger(/*autodetect radix*/ 0, exit_code)) { 86c094d23fSRaphael Isemann lldb_private::StreamString s; 87c094d23fSRaphael Isemann std::string arg_str = arg.str(); 88c094d23fSRaphael Isemann s.Printf("Couldn't parse '%s' as integer for exit code.", arg_str.data()); 89c094d23fSRaphael Isemann result.AppendError(s.GetString()); 90c094d23fSRaphael Isemann return false; 91c094d23fSRaphael Isemann } 92c094d23fSRaphael Isemann if (!m_interpreter.SetQuitExitCode(exit_code)) { 93c094d23fSRaphael Isemann result.AppendError("The current driver doesn't allow custom exit codes" 94c094d23fSRaphael Isemann " for the quit command."); 95c094d23fSRaphael Isemann return false; 96c094d23fSRaphael Isemann } 97c094d23fSRaphael Isemann } 98c094d23fSRaphael Isemann 99b9c1b51eSKate Stone const uint32_t event_type = 100b9c1b51eSKate Stone CommandInterpreter::eBroadcastBitQuitCommandReceived; 10144d93782SGreg Clayton m_interpreter.BroadcastEvent(event_type); 10230fdc8d8SChris Lattner result.SetStatus(eReturnStatusQuit); 1035bb742b1SMed Ismail Bennani 10430fdc8d8SChris Lattner return true; 10530fdc8d8SChris Lattner } 106