after all the commands have been executed except if one of the commands was an execution control
command that stopped because of a signal or exception.
Also adds a variant of SBCommandInterpreter::HandleCommand that takes an SBExecutionContext. That
way you can run an lldb command targeted at a particular target, thread or process w/o having to
select same before running the command.
Also exposes CommandInterpreter::HandleCommandsFromFile to the SBCommandInterpreter API, since that
seemed generally useful.
llvm-svn: 219654
class SBCommandInterpreterRunOptions
{
friend class SBDebugger;
+friend class SBCommandInterpreter;
+
public:
SBCommandInterpreterRunOptions();
~SBCommandInterpreterRunOptions();
lldb::ReturnStatus
HandleCommand (const char *command_line, lldb::SBCommandReturnObject &result, bool add_to_history = false);
+ lldb::ReturnStatus
+ HandleCommand (const char *command_line, SBExecutionContext &exe_ctx, SBCommandReturnObject &result, bool add_to_history = false);
+
+ void
+ HandleCommandsFromFile (lldb::SBFileSpec &file,
+ lldb::SBExecutionContext &override_context,
+ lldb::SBCommandInterpreterRunOptions &options,
+ lldb::SBCommandReturnObject result);
+
// The pointer based interface is not useful in SWIG, since the cursor & last_char arguments are string pointers INTO current_line
// and you can't do that in a scripting language interface in general...
bool spawn_thread,
SBCommandInterpreterRunOptions &options,
int &num_errors,
- bool &quit_requested);
+ bool &quit_requested,
+ bool &stopped_for_crash);
private:
friend class SBCommandInterpreter;
class SBExecutionContext
{
+friend class SBCommandInterpreter;
+
public:
SBExecutionContext();
private:
friend class SBAttachInfo;
friend class SBBlock;
+ friend class SBCommandInterpreter;
friend class SBCompileUnit;
friend class SBDeclaration;
friend class SBFileSpecList;
{
return m_quit_requested;
}
+
+ bool
+ GetStoppedForCrash () const
+ {
+ return m_stopped_for_crash;
+ }
protected:
friend class Debugger;
std::vector<uint32_t> m_command_source_flags;
uint32_t m_num_errors;
bool m_quit_requested;
+ bool m_stopped_for_crash;
};
<LaunchAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- launchStyle = "0"
+ launchStyle = "1"
useCustomWorkingDirectory = "NO"
customWorkingDirectory = "/Volumes/work/gclayton/Documents/devb/attach"
buildConfiguration = "Debug"
lldb::ReturnStatus
HandleCommand (const char *command_line, lldb::SBCommandReturnObject &result, bool add_to_history = false);
+ lldb::ReturnStatus
+ HandleCommand (const char *command_line, SBExecutionContext &exe_ctx, SBCommandReturnObject &result, bool add_to_history = false);
+
+ void
+ HandleCommandsFromFile (lldb::SBFileSpec &file,
+ lldb::SBExecutionContext &override_context,
+ lldb::SBCommandInterpreterRunOptions &options,
+ lldb::SBCommandReturnObject result);
+
int
HandleCompletion (const char *current_line,
uint32_t cursor_pos,
bool spawn_thread,
SBCommandInterpreterRunOptions &options,
int &num_errors,
- bool &quit_requested);
+ bool &quit_requested,
+ bool &stopped_for_crash);
}; // class SBDebugger
} // namespace lldb
#include "lldb/API/SBBroadcaster.h"
#include "lldb/API/SBCommandReturnObject.h"
#include "lldb/API/SBCommandInterpreter.h"
+#include "lldb/API/SBExecutionContext.h"
#include "lldb/API/SBProcess.h"
#include "lldb/API/SBTarget.h"
#include "lldb/API/SBListener.h"
lldb::ReturnStatus
SBCommandInterpreter::HandleCommand (const char *command_line, SBCommandReturnObject &result, bool add_to_history)
{
+ SBExecutionContext sb_exe_ctx;
+ return HandleCommand (command_line, sb_exe_ctx, result, add_to_history);
+}
+
+lldb::ReturnStatus
+SBCommandInterpreter::HandleCommand (const char *command_line, SBExecutionContext &override_context, SBCommandReturnObject &result, bool add_to_history)
+{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
static_cast<void*>(m_opaque_ptr), command_line,
static_cast<void*>(result.get()), add_to_history);
+ ExecutionContext ctx, *ctx_ptr;
+ if (override_context.get())
+ {
+ ctx = override_context.get()->Lock(true);
+ ctx_ptr = &ctx;
+ }
+ else
+ ctx_ptr = nullptr;
+
+
result.Clear();
if (command_line && m_opaque_ptr)
{
result.ref().SetInteractive(false);
- m_opaque_ptr->HandleCommand (command_line, add_to_history ? eLazyBoolYes : eLazyBoolNo, result.ref());
+ m_opaque_ptr->HandleCommand (command_line, add_to_history ? eLazyBoolYes : eLazyBoolNo, result.ref(), ctx_ptr);
}
else
{
return result.GetStatus();
}
+void
+SBCommandInterpreter::HandleCommandsFromFile (lldb::SBFileSpec &file,
+ lldb::SBExecutionContext &override_context,
+ lldb::SBCommandInterpreterRunOptions &options,
+ lldb::SBCommandReturnObject result)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ {
+ SBStream s;
+ file.GetDescription (s);
+ log->Printf ("SBCommandInterpreter(%p)::HandleCommandsFromFile (file=\"%s\", SBCommandReturnObject(%p))",
+ static_cast<void*>(m_opaque_ptr), s.GetData(),
+ static_cast<void*>(result.get()));
+ }
+
+ if (!m_opaque_ptr)
+ {
+ result->AppendError ("SBCommandInterpreter is not valid.");
+ result->SetStatus (eReturnStatusFailed);
+ return;
+ }
+
+ if (!file.IsValid())
+ {
+ SBStream s;
+ file.GetDescription (s);
+ result->AppendErrorWithFormat ("File is not valid: %s.", s.GetData());
+ result->SetStatus (eReturnStatusFailed);
+ }
+
+ FileSpec tmp_spec = file.ref();
+ ExecutionContext ctx, *ctx_ptr;
+ if (override_context.get())
+ {
+ ctx = override_context.get()->Lock(true);
+ ctx_ptr = &ctx;
+ }
+ else
+ ctx_ptr = nullptr;
+
+
+ m_opaque_ptr->HandleCommandsFromFile (tmp_spec, ctx_ptr, options.ref(), result.ref());
+
+}
+
+
int
SBCommandInterpreter::HandleCompletion (const char *current_line,
const char *cursor,
bool spawn_thread,
SBCommandInterpreterRunOptions &options,
int &num_errors,
- bool &quit_requested)
+ bool &quit_requested,
+ bool &stopped_for_crash)
{
if (m_opaque_sp)
interp.RunCommandInterpreter(auto_handle_events, spawn_thread, options.ref());
num_errors = interp.GetNumErrors();
quit_requested = interp.GetQuitRequested();
+ stopped_for_crash = interp.GetStoppedForCrash();
}
}
return *this;
}
+ExecutionContextRef *
+SBExecutionContext::get () const
+{
+ return m_exe_ctx_sp.get();
+}
+
SBTarget
SBExecutionContext::GetTarget () const
{
m_truncation_warning(eNoTruncation),
m_command_source_depth (0),
m_num_errors(0),
- m_quit_requested(false)
+ m_quit_requested(false),
+ m_stopped_for_crash(false)
{
debugger.SetScriptLanguage (script_language);
return;
}
}
+
+ // Also check for "stop on crash here:
+ bool should_stop = false;
+ if (tmp_result.GetDidChangeProcessState() && options.GetStopOnCrash())
+ {
+ TargetSP target_sp (m_debugger.GetTargetList().GetSelectedTarget());
+ if (target_sp)
+ {
+ ProcessSP process_sp (target_sp->GetProcessSP());
+ if (process_sp)
+ {
+ for (ThreadSP thread_sp : process_sp->GetThreadList().Threads())
+ {
+ StopReason reason = thread_sp->GetStopReason();
+ if (reason == eStopReasonSignal || reason == eStopReasonException || reason == eStopReasonInstrumentation)
+ {
+ should_stop = true;
+ break;
+ }
+ }
+ }
+ }
+ if (should_stop)
+ {
+ if (idx != num_lines - 1)
+ result.AppendErrorWithFormat("Aborting reading of commands after command #%" PRIu64 ": '%s' stopped with a signal or exception.\n",
+ (uint64_t)idx + 1, cmd);
+ else
+ result.AppendMessageWithFormat("Command #%" PRIu64 " '%s' stopped with a signal or exception.\n", (uint64_t)idx + 1, cmd);
+
+ result.SetStatus(tmp_result.GetStatus());
+ m_debugger.SetAsyncExecution (old_async_execution);
+
+ return;
+ }
+ }
}
flags |= eHandleCommandFlagStopOnError;
}
+ if (options.GetStopOnCrash())
+ {
+ if (m_command_source_flags.empty())
+ {
+ // Echo command by default
+ flags |= eHandleCommandFlagStopOnCrash;
+ }
+ else if (m_command_source_flags.back() & eHandleCommandFlagStopOnCrash)
+ {
+ flags |= eHandleCommandFlagStopOnCrash;
+ }
+ }
+
if (options.m_echo_commands == eLazyBoolCalculate)
{
if (m_command_source_flags.empty())
*this));
const bool old_async_execution = debugger.GetAsyncExecution();
- // Set synchronous execution if we not stopping when we continue
+ // Set synchronous execution if we are not stopping on continue
if ((flags & eHandleCommandFlagStopOnContinue) == 0)
debugger.SetAsyncExecution (false);
io_handler.SetIsDone(true);
break;
}
+
+ // Finally, if we're going to stop on crash, check that here:
+ if (!m_quit_requested
+ && result.GetDidChangeProcessState()
+ && io_handler.GetFlags().Test(eHandleCommandFlagStopOnCrash))
+ {
+ bool should_stop = false;
+ TargetSP target_sp (m_debugger.GetTargetList().GetSelectedTarget());
+ if (target_sp)
+ {
+ ProcessSP process_sp (target_sp->GetProcessSP());
+ if (process_sp)
+ {
+ for (ThreadSP thread_sp : process_sp->GetThreadList().Threads())
+ {
+ StopReason reason = thread_sp->GetStopReason();
+ if (reason == eStopReasonSignal || reason == eStopReasonException || reason == eStopReasonInstrumentation)
+ {
+ // If we are printing results, we ought to show the resaon why we are stopping here:
+ if (io_handler.GetFlags().Test(eHandleCommandFlagPrintResult))
+ {
+ if (!result.GetImmediateOutputStream())
+ {
+ const uint32_t start_frame = 0;
+ const uint32_t num_frames = 1;
+ const uint32_t num_frames_with_source = 1;
+ thread_sp->GetStatus (*io_handler.GetOutputStreamFile().get(),
+ start_frame,
+ num_frames,
+ num_frames_with_source);
+ }
+ }
+ should_stop = true;
+ break;
+ }
+ }
+ }
+ }
+ if (should_stop)
+ {
+ io_handler.SetIsDone(true);
+ m_stopped_for_crash = true;
+ }
+ }
}
bool
const bool multiple_lines = false;
m_num_errors = 0;
m_quit_requested = false;
+ m_stopped_for_crash = false;
// Always re-create the IOHandlerEditline in case the input
// changed. The old instance might have had a non-interactive
{ LLDB_3_TO_5, false, "one-line-before-file" , 'O', required_argument, 0, eArgTypeNone,
"Tells the debugger to execute this one-line lldb command before any file provided on the command line has been loaded." },
{ LLDB_3_TO_5, false, "source-quietly" , 'Q', no_argument , 0, eArgTypeNone,
- "Tells the debugger suppress output from commands provided in the -s, -S, -O and -o commands." },
+ "Tells the debugger to execute this one-line lldb command before any file provided on the command line has been loaded." },
+ { LLDB_3_TO_5, false, "batch" , 'b', no_argument , 0, eArgTypeNone,
+ "Tells the debugger to running the commands from -s, -S, -o & -O, and then quit. However if any run command stopped due to a signal or crash, "
+ "the debugger will return to the interactive prompt at the place of the crash." },
{ LLDB_3_TO_5, false, "editor" , 'e', no_argument , 0, eArgTypeNone,
"Tells the debugger to open source files using the host's \"external editor\" mechanism." },
{ LLDB_3_TO_5, false, "no-lldbinit" , 'x', no_argument , 0, eArgTypeNone,
m_process_name(),
m_process_pid(LLDB_INVALID_PROCESS_ID),
m_use_external_editor(false),
+ m_batch(false),
m_seen_options()
{
}
m_use_external_editor = false;
m_wait_for = false;
m_process_name.erase();
+ m_batch = false;
m_process_pid = LLDB_INVALID_PROCESS_ID;
}
m_option_data.m_print_python_path = true;
break;
+ case 'b':
+ m_option_data.m_batch = true;
+ break;
+
case 'c':
{
SBFileSpec file(optarg);
// The command file might have requested that we quit, this variable will track that.
bool quit_requested = false;
+ bool stopped_for_crash = false;
if (commands_data && commands_size)
{
enum PIPES { READ, WRITE }; // Constants 0 and 1 for READ and WRITE
SBCommandInterpreterRunOptions options;
options.SetStopOnError (true);
-
- m_debugger.RunCommandInterpreter(handle_events, spawn_thread, options, num_errors, quit_requested);
+ if (m_option_data.m_batch)
+ options.SetStopOnCrash (true);
+
+ m_debugger.RunCommandInterpreter(handle_events,
+ spawn_thread,
+ options,
+ num_errors,
+ quit_requested,
+ stopped_for_crash);
m_debugger.SetAsync(old_async);
}
else
// interpreter again in interactive mode and let the debugger
// take ownership of stdin
- if (!quit_requested)
+ bool go_interactive = true;
+ if (quit_requested)
+ go_interactive = false;
+ else if (m_option_data.m_batch && !stopped_for_crash)
+ go_interactive = false;
+
+ if (go_interactive)
{
m_debugger.SetInputFileHandle (stdin, true);
m_debugger.RunCommandInterpreter(handle_events, spawn_thread);
std::string m_process_name;
lldb::pid_t m_process_pid;
bool m_use_external_editor; // FIXME: When we have set/show variables we can remove this from here.
+ bool m_batch;
typedef std::set<char> OptionSet;
OptionSet m_seen_options;
};