15ffd83dbSDimitry Andric //===-- CommandObjectQuit.cpp ---------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "CommandObjectQuit.h" 100b57cec5SDimitry Andric 110b57cec5SDimitry Andric #include "lldb/Interpreter/CommandInterpreter.h" 120b57cec5SDimitry Andric #include "lldb/Interpreter/CommandReturnObject.h" 130b57cec5SDimitry Andric #include "lldb/Target/Process.h" 140b57cec5SDimitry Andric #include "lldb/Utility/StreamString.h" 150b57cec5SDimitry Andric 160b57cec5SDimitry Andric using namespace lldb; 170b57cec5SDimitry Andric using namespace lldb_private; 180b57cec5SDimitry Andric 190b57cec5SDimitry Andric // CommandObjectQuit 200b57cec5SDimitry Andric 210b57cec5SDimitry Andric CommandObjectQuit::CommandObjectQuit(CommandInterpreter &interpreter) 220b57cec5SDimitry Andric : CommandObjectParsed(interpreter, "quit", "Quit the LLDB debugger.", 2381ad6265SDimitry Andric "quit [exit-code]") { 24*0fca6ea1SDimitry Andric AddSimpleArgumentList(eArgTypeUnsignedInteger); 2581ad6265SDimitry Andric } 260b57cec5SDimitry Andric 27fe6060f1SDimitry Andric CommandObjectQuit::~CommandObjectQuit() = default; 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric // returns true if there is at least one alive process is_a_detach will be true 300b57cec5SDimitry Andric // if all alive processes will be detached when you quit and false if at least 310b57cec5SDimitry Andric // one process will be killed instead 320b57cec5SDimitry Andric bool CommandObjectQuit::ShouldAskForConfirmation(bool &is_a_detach) { 330b57cec5SDimitry Andric if (!m_interpreter.GetPromptOnQuit()) 340b57cec5SDimitry Andric return false; 350b57cec5SDimitry Andric bool should_prompt = false; 360b57cec5SDimitry Andric is_a_detach = true; 370b57cec5SDimitry Andric for (uint32_t debugger_idx = 0; debugger_idx < Debugger::GetNumDebuggers(); 380b57cec5SDimitry Andric debugger_idx++) { 390b57cec5SDimitry Andric DebuggerSP debugger_sp(Debugger::GetDebuggerAtIndex(debugger_idx)); 400b57cec5SDimitry Andric if (!debugger_sp) 410b57cec5SDimitry Andric continue; 420b57cec5SDimitry Andric const TargetList &target_list(debugger_sp->GetTargetList()); 430b57cec5SDimitry Andric for (uint32_t target_idx = 0; 440b57cec5SDimitry Andric target_idx < static_cast<uint32_t>(target_list.GetNumTargets()); 450b57cec5SDimitry Andric target_idx++) { 460b57cec5SDimitry Andric TargetSP target_sp(target_list.GetTargetAtIndex(target_idx)); 470b57cec5SDimitry Andric if (!target_sp) 480b57cec5SDimitry Andric continue; 490b57cec5SDimitry Andric ProcessSP process_sp(target_sp->GetProcessSP()); 500b57cec5SDimitry Andric if (process_sp && process_sp->IsValid() && process_sp->IsAlive() && 510b57cec5SDimitry Andric process_sp->WarnBeforeDetach()) { 520b57cec5SDimitry Andric should_prompt = true; 530b57cec5SDimitry Andric if (!process_sp->GetShouldDetach()) { 540b57cec5SDimitry Andric // if we need to kill at least one process, just say so and return 550b57cec5SDimitry Andric is_a_detach = false; 560b57cec5SDimitry Andric return should_prompt; 570b57cec5SDimitry Andric } 580b57cec5SDimitry Andric } 590b57cec5SDimitry Andric } 600b57cec5SDimitry Andric } 610b57cec5SDimitry Andric return should_prompt; 620b57cec5SDimitry Andric } 630b57cec5SDimitry Andric 645f757f3fSDimitry Andric void CommandObjectQuit::DoExecute(Args &command, CommandReturnObject &result) { 650b57cec5SDimitry Andric bool is_a_detach = true; 660b57cec5SDimitry Andric if (ShouldAskForConfirmation(is_a_detach)) { 670b57cec5SDimitry Andric StreamString message; 680b57cec5SDimitry Andric message.Printf("Quitting LLDB will %s one or more processes. Do you really " 690b57cec5SDimitry Andric "want to proceed", 700b57cec5SDimitry Andric (is_a_detach ? "detach from" : "kill")); 710b57cec5SDimitry Andric if (!m_interpreter.Confirm(message.GetString(), true)) { 720b57cec5SDimitry Andric result.SetStatus(eReturnStatusFailed); 735f757f3fSDimitry Andric return; 740b57cec5SDimitry Andric } 750b57cec5SDimitry Andric } 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric if (command.GetArgumentCount() > 1) { 780b57cec5SDimitry Andric result.AppendError("Too many arguments for 'quit'. Only an optional exit " 790b57cec5SDimitry Andric "code is allowed"); 805f757f3fSDimitry Andric return; 810b57cec5SDimitry Andric } 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric // We parse the exit code argument if there is one. 840b57cec5SDimitry Andric if (command.GetArgumentCount() == 1) { 850b57cec5SDimitry Andric llvm::StringRef arg = command.GetArgumentAtIndex(0); 860b57cec5SDimitry Andric int exit_code; 870b57cec5SDimitry Andric if (arg.getAsInteger(/*autodetect radix*/ 0, exit_code)) { 880b57cec5SDimitry Andric lldb_private::StreamString s; 890b57cec5SDimitry Andric std::string arg_str = arg.str(); 900b57cec5SDimitry Andric s.Printf("Couldn't parse '%s' as integer for exit code.", arg_str.data()); 910b57cec5SDimitry Andric result.AppendError(s.GetString()); 925f757f3fSDimitry Andric return; 930b57cec5SDimitry Andric } 940b57cec5SDimitry Andric if (!m_interpreter.SetQuitExitCode(exit_code)) { 950b57cec5SDimitry Andric result.AppendError("The current driver doesn't allow custom exit codes" 960b57cec5SDimitry Andric " for the quit command."); 975f757f3fSDimitry Andric return; 980b57cec5SDimitry Andric } 990b57cec5SDimitry Andric } 1000b57cec5SDimitry Andric 1010b57cec5SDimitry Andric const uint32_t event_type = 1020b57cec5SDimitry Andric CommandInterpreter::eBroadcastBitQuitCommandReceived; 1030b57cec5SDimitry Andric m_interpreter.BroadcastEvent(event_type); 1040b57cec5SDimitry Andric result.SetStatus(eReturnStatusQuit); 1050b57cec5SDimitry Andric } 106