Index: lldb/include/lldb/API/SBDebugger.h =================================================================== --- lldb/include/lldb/API/SBDebugger.h +++ lldb/include/lldb/API/SBDebugger.h @@ -297,6 +297,11 @@ int &num_errors, bool &quit_requested, bool &stopped_for_crash); + void RunCommandInterpreter(bool auto_handle_events, bool spawn_thread, + SBCommandInterpreterRunOptions &options, + int &num_errors, bool &quit_requested, + bool &stopped_for_crash, bool &stopped_for_error); + SBError RunREPL(lldb::LanguageType language, const char *repl_options); private: Index: lldb/include/lldb/Interpreter/CommandInterpreter.h =================================================================== --- lldb/include/lldb/Interpreter/CommandInterpreter.h +++ lldb/include/lldb/Interpreter/CommandInterpreter.h @@ -484,6 +484,8 @@ bool GetStoppedForCrash() const { return m_stopped_for_crash; } + bool GetStoppedForError() const { return m_stopped_for_error; } + bool GetSpaceReplPrompts() const; protected: @@ -577,6 +579,7 @@ uint32_t m_num_errors; bool m_quit_requested; bool m_stopped_for_crash; + bool m_stopped_for_error; // The exit code the user has requested when calling the 'quit' command. // No value means the user hasn't set a custom exit code so far. Index: lldb/source/API/SBDebugger.cpp =================================================================== --- lldb/source/API/SBDebugger.cpp +++ lldb/source/API/SBDebugger.cpp @@ -1176,14 +1176,28 @@ bool spawn_thread, SBCommandInterpreterRunOptions &options, int &num_errors, bool &quit_requested, - bool &stopped_for_crash) - -{ + bool &stopped_for_crash) { LLDB_RECORD_METHOD(void, SBDebugger, RunCommandInterpreter, (bool, bool, lldb::SBCommandInterpreterRunOptions &, int &, bool &, bool &), auto_handle_events, spawn_thread, options, num_errors, quit_requested, stopped_for_crash); + bool stopped_for_error; + RunCommandInterpreter(auto_handle_events, spawn_thread, options, num_errors, + quit_requested, stopped_for_crash, stopped_for_error); +} + +void SBDebugger::RunCommandInterpreter(bool auto_handle_events, + bool spawn_thread, + SBCommandInterpreterRunOptions &options, + int &num_errors, bool &quit_requested, + bool &stopped_for_crash, + bool &stopped_for_error) { + LLDB_RECORD_METHOD(void, SBDebugger, RunCommandInterpreter, + (bool, bool, lldb::SBCommandInterpreterRunOptions &, int &, + bool &, bool &, bool &), + auto_handle_events, spawn_thread, options, num_errors, + quit_requested, stopped_for_crash, stopped_for_error); if (m_opaque_sp) { CommandInterpreter &interp = m_opaque_sp->GetCommandInterpreter(); @@ -1192,6 +1206,7 @@ num_errors = interp.GetNumErrors(); quit_requested = interp.GetQuitRequested(); stopped_for_crash = interp.GetStoppedForCrash(); + stopped_for_error = interp.GetStoppedForError(); } } @@ -1768,6 +1783,9 @@ LLDB_REGISTER_METHOD(void, SBDebugger, RunCommandInterpreter, (bool, bool, lldb::SBCommandInterpreterRunOptions &, int &, bool &, bool &)); + LLDB_REGISTER_METHOD(void, SBDebugger, RunCommandInterpreter, + (bool, bool, lldb::SBCommandInterpreterRunOptions &, + int &, bool &, bool &, bool &)); LLDB_REGISTER_METHOD(lldb::SBError, SBDebugger, RunREPL, (lldb::LanguageType, const char *)); LLDB_REGISTER_STATIC_METHOD(lldb::SBDebugger, SBDebugger, FindDebuggerWithID, Index: lldb/source/Interpreter/CommandInterpreter.cpp =================================================================== --- lldb/source/Interpreter/CommandInterpreter.cpp +++ lldb/source/Interpreter/CommandInterpreter.cpp @@ -117,7 +117,7 @@ m_command_io_handler_sp(), m_comment_char('#'), m_batch_command_mode(false), m_truncation_warning(eNoTruncation), m_command_source_depth(0), m_num_errors(0), m_quit_requested(false), - m_stopped_for_crash(false) { + m_stopped_for_crash(false), m_stopped_for_error(false) { SetEventName(eBroadcastBitThreadShouldExit, "thread-should-exit"); SetEventName(eBroadcastBitResetPrompt, "reset-prompt"); SetEventName(eBroadcastBitQuitCommandReceived, "quit"); @@ -2817,8 +2817,10 @@ case eReturnStatusFailed: m_num_errors++; - if (io_handler.GetFlags().Test(eHandleCommandFlagStopOnError)) + if (io_handler.GetFlags().Test(eHandleCommandFlagStopOnError)) { io_handler.SetIsDone(true); + m_stopped_for_error = true; + } break; case eReturnStatusQuit: Index: lldb/test/Shell/Commands/command-source.test =================================================================== --- lldb/test/Shell/Commands/command-source.test +++ lldb/test/Shell/Commands/command-source.test @@ -1,8 +1,8 @@ # Check that stop command source on error. -# RUN: %lldb -x -b -o "command source -e 1 %s" 2>&1 | FileCheck %s --check-prefix STOP +# RUN: not %lldb -x -b -o "command source -e 1 %s" 2>&1 | FileCheck %s --check-prefix STOP # RUN: %lldb -x -b -o "command source -e 0 %s" 2>&1 | FileCheck %s --check-prefix CONTINUE -# RUN: %lldb -x -b -o 'settings set interpreter.stop-command-source-on-error true' -o "command source %s" 2>&1 | FileCheck %s --check-prefix STOP +# RUN: not %lldb -x -b -o 'settings set interpreter.stop-command-source-on-error true' -o "command source %s" 2>&1 | FileCheck %s --check-prefix STOP # RUN: %lldb -x -b -o 'settings set interpreter.stop-command-source-on-error false' -o "command source %s" 2>&1 | FileCheck %s --check-prefix CONTINUE bogus Index: lldb/test/Shell/Driver/TestProcessAttach.test =================================================================== --- lldb/test/Shell/Driver/TestProcessAttach.test +++ lldb/test/Shell/Driver/TestProcessAttach.test @@ -1,2 +1,2 @@ -# RUN: %lldb -x -b -S %S/Inputs/process_attach_pid.in 2>&1 | FileCheck %s +# RUN: not %lldb -x -b -S %S/Inputs/process_attach_pid.in 2>&1 | FileCheck %s # CHECK: last option requires an argument Index: lldb/test/Shell/Host/TestCustomShell.test =================================================================== --- lldb/test/Shell/Host/TestCustomShell.test +++ lldb/test/Shell/Host/TestCustomShell.test @@ -8,7 +8,7 @@ # XFAIL: system-openbsd # RUN: %clang_host %S/Inputs/simple.c -g -o %t.out -# RUN: SHELL=bogus %lldb %t.out -b -o 'run' 2>&1 | FileCheck %s --check-prefix ERROR +# RUN: SHELL=bogus not %lldb %t.out -b -o 'run' 2>&1 | FileCheck %s --check-prefix ERROR # RUN: env -i %lldb %t.out -b -o 'run' 2>&1 | FileCheck %s # ERROR: error: shell expansion failed Index: lldb/test/Shell/Quit/TestQuitExitCodeNonInt.test =================================================================== --- lldb/test/Shell/Quit/TestQuitExitCodeNonInt.test +++ lldb/test/Shell/Quit/TestQuitExitCodeNonInt.test @@ -1,4 +1,4 @@ # UNSUPPORTED: system-windows -# RUN: %lldb -b -s %s 2>&1 | FileCheck %s +# RUN: not %lldb -b -s %s 2>&1 | FileCheck %s q str // CHECK: Couldn't parse 'str' Index: lldb/test/Shell/Quit/TestQuitExitCodeTooManyArgs.test =================================================================== --- lldb/test/Shell/Quit/TestQuitExitCodeTooManyArgs.test +++ lldb/test/Shell/Quit/TestQuitExitCodeTooManyArgs.test @@ -1,4 +1,4 @@ # UNSUPPORTED: system-windows -# RUN: %lldb -b -s %s 2>&1 | FileCheck %s +# RUN: not %lldb -b -s %s 2>&1 | FileCheck %s q 1 2 // CHECK: Too many arguments for 'quit' Index: lldb/test/Shell/Reproducer/TestDiscard.test =================================================================== --- lldb/test/Shell/Reproducer/TestDiscard.test +++ lldb/test/Shell/Reproducer/TestDiscard.test @@ -6,7 +6,7 @@ # RUN: %clang_host %S/Inputs/simple.c -g -o %t/reproducer.out # Capture but don't generate the reproducer. -# RUN: %lldb -x -b -s %S/Inputs/Discard.in --capture --capture-path %t.repro %t/reproducer.out +# RUN: not %lldb -x -b -s %S/Inputs/Discard.in --capture --capture-path %t.repro %t/reproducer.out # Make sure the directory doesn't exist. # RUN: mkdir %t.repro Index: lldb/test/Shell/Reproducer/TestDump.test =================================================================== --- lldb/test/Shell/Reproducer/TestDump.test +++ lldb/test/Shell/Reproducer/TestDump.test @@ -25,9 +25,9 @@ # RUN: %lldb --replay %t.repro | FileCheck %s --check-prefix FILES # RUN: rm %t.repro/gdb-remote.yaml -# RUN: %lldb -b -o 'reproducer dump -p gdb -f %t.repro' 2>&1 | FileCheck %s --check-prefix GDB-ERROR +# RUN: not %lldb -b -o 'reproducer dump -p gdb -f %t.repro' 2>&1 | FileCheck %s --check-prefix GDB-ERROR # GDB-ERROR: error: Unable to create GDB loader. # RUN: rm %t.repro/command-interpreter.yaml -# RUN: %lldb -b -o 'reproducer dump -p commands -f %t.repro' 2>&1 | FileCheck %s --check-prefix COMMANDS-ERROR +# RUN: not %lldb -b -o 'reproducer dump -p commands -f %t.repro' 2>&1 | FileCheck %s --check-prefix COMMANDS-ERROR # COMMANDS-ERROR: error: Unable to create command loader. Index: lldb/test/Shell/Settings/TestSettingsSet.test =================================================================== --- lldb/test/Shell/Settings/TestSettingsSet.test +++ lldb/test/Shell/Settings/TestSettingsSet.test @@ -1,7 +1,7 @@ # This tests setting setting values. # Check that setting an empty value with -f(orce) clears the value. -# RUN: %lldb -b -s %s 2>&1 | FileCheck %s +# RUN: not %lldb -b -s %s 2>&1 | FileCheck %s settings set tab-size 16 settings show tab-size Index: lldb/test/Shell/Settings/TestStopCommandSourceOnError.test =================================================================== --- lldb/test/Shell/Settings/TestStopCommandSourceOnError.test +++ lldb/test/Shell/Settings/TestStopCommandSourceOnError.test @@ -12,13 +12,13 @@ # RUN: %lldb -b -o 'settings set interpreter.stop-command-source-on-error false' -s %S/Inputs/StopCommandSource.in | FileCheck %s --check-prefix CONTINUE # FIXME: Should continue -# RUN: %lldb -b -s %S/Inputs/DontStopCommandSource.in -o 'bogus' -o 'print 111100000 + 11111' | FileCheck %s --check-prefix STOP +# RUN: not %lldb -b -s %S/Inputs/DontStopCommandSource.in -o 'bogus' -o 'print 111100000 + 11111' | FileCheck %s --check-prefix STOP # FIXME: Should continue -# RUN: %lldb -b -o 'settings set interpreter.stop-command-source-on-error false' -o 'bogus' -o 'print 123400000 + 56789' | FileCheck %s --check-prefix STOP +# RUN: not %lldb -b -o 'settings set interpreter.stop-command-source-on-error false' -o 'bogus' -o 'print 123400000 + 56789' | FileCheck %s --check-prefix STOP # FIXME: Should continue -# RUN: %lldb -b -s %S/Inputs/DontStopCommandSource.in | FileCheck %s --check-prefix STOP +# RUN: not %lldb -b -s %S/Inputs/DontStopCommandSource.in | FileCheck %s --check-prefix STOP # FIXME: Should continue -# RUN: %lldb -b -o 'settings set interpreter.stop-command-source-on-error true' -s %S/Inputs/DontStopCommandSource.in | FileCheck %s --check-prefix STOP +# RUN: not %lldb -b -o 'settings set interpreter.stop-command-source-on-error true' -s %S/Inputs/DontStopCommandSource.in | FileCheck %s --check-prefix STOP Index: lldb/test/Shell/SymbolFile/DWARF/debug-types-missing-signature.test =================================================================== --- lldb/test/Shell/SymbolFile/DWARF/debug-types-missing-signature.test +++ lldb/test/Shell/SymbolFile/DWARF/debug-types-missing-signature.test @@ -14,10 +14,10 @@ RUN: %lldb %t -b -o "type lookup EC" | FileCheck --check-prefix=LOOKUPEC %s LOOKUPEC: no type was found matching 'EC' -RUN: %lldb %t -b -o "print (E) 1" 2>&1 | FileCheck --check-prefix=PRINTE %s +RUN: not %lldb %t -b -o "print (E) 1" 2>&1 | FileCheck --check-prefix=PRINTE %s PRINTE: use of undeclared identifier 'E' -RUN: %lldb %t -b -o "print (EC) 1" 2>&1 | FileCheck --check-prefix=PRINTEC %s +RUN: not %lldb %t -b -o "print (EC) 1" 2>&1 | FileCheck --check-prefix=PRINTEC %s PRINTEC: use of undeclared identifier 'EC' RUN: %lldb %t -b -o "target variable a e ec" | FileCheck --check-prefix=VARS %s Index: lldb/test/Shell/Unwind/thread-step-out-ret-addr-check.test =================================================================== --- lldb/test/Shell/Unwind/thread-step-out-ret-addr-check.test +++ lldb/test/Shell/Unwind/thread-step-out-ret-addr-check.test @@ -5,7 +5,7 @@ # UNSUPPORTED: system-windows # RUN: %clang_host %p/Inputs/call-asm.c -x assembler-with-cpp %p/Inputs/thread-step-out-ret-addr-check.s -o %t -# RUN: %lldb %t -s %s -b 2>&1 | FileCheck %s +# RUN: not %lldb %t -s %s -b 2>&1 | FileCheck %s breakpoint set -n nonstandard_stub # CHECK: Breakpoint 1: where = {{.*}}`nonstandard_stub Index: lldb/tools/driver/Driver.cpp =================================================================== --- lldb/tools/driver/Driver.cpp +++ lldb/tools/driver/Driver.cpp @@ -591,8 +591,8 @@ // track that. bool quit_requested = false; bool stopped_for_crash = false; + bool stopped_for_error = false; if ((commands_data != nullptr) && (commands_size != 0u)) { - bool success = true; FILE *commands_file = PrepareCommandsForSourcing(commands_data, commands_size); if (commands_file != nullptr) { @@ -612,7 +612,7 @@ m_debugger.RunCommandInterpreter(handle_events, spawn_thread, options, num_errors, quit_requested, - stopped_for_crash); + stopped_for_crash, stopped_for_error); if (m_option_data.m_batch && stopped_for_crash && !m_option_data.m_after_crash_commands.empty()) { @@ -626,21 +626,31 @@ if (commands_file != nullptr) { bool local_quit_requested; bool local_stopped_for_crash; + bool local_stopped_for_error; m_debugger.SetInputFileHandle(commands_file, true); m_debugger.RunCommandInterpreter(handle_events, spawn_thread, options, num_errors, local_quit_requested, - local_stopped_for_crash); + local_stopped_for_crash, + local_stopped_for_error); if (local_quit_requested) quit_requested = true; + + // When running in batch mode and an error occurred while sourcing + // the crash commands, exit with a non-zero exit status. + if (m_option_data.m_batch && local_stopped_for_error) + exit(1); } } - m_debugger.SetAsync(old_async); - } else - success = false; - // Something went wrong with command pipe - if (!success) { + // When running in batch mode and stopped because of an error, exit with + // a non-zero exit status. + if (m_option_data.m_batch && stopped_for_error) + exit(1); + + m_debugger.SetAsync(old_async); + } else { + // Something went wrong with command pipe. exit(1); } }