void
SetUnwindOnError (bool unwind = false);
+ bool
+ GetIgnoreBreakpoints () const;
+
+ void
+ SetIgnoreBreakpoints (bool ignore = false);
+
lldb::DynamicValueType
GetFetchDynamicValue () const;
/// If the timeout expires, true if other threads should run. If
/// the function may try to take locks, this is useful.
///
- /// @param[in] discard_on_error
+ /// @param[in] unwind_on_error
/// If true, and the execution stops before completion, we unwind the
/// function call, and return the program state to what it was before the
/// execution. If false, we leave the program in the stopped state.
lldb::addr_t &void_arg,
bool stop_others,
bool try_all_threads,
- bool discard_on_error,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
uint32_t timeout_usec,
Stream &errors,
lldb::addr_t* this_arg = 0);
bool stop_others,
uint32_t timeout_usec,
bool try_all_threads,
- bool discard_on_error,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
Value &results);
//------------------------------------------------------------------
/// @param[in] stop_others
/// True if other threads should pause during execution.
///
- /// @param[in] discard_on_error
+ /// @param[in] unwind_on_error
/// True if the thread plan may simply be discarded if an error occurs.
///
+ /// @param[in] ignore_breakpoints
+ /// True if the expression execution will ignore breakpoint hits and continue executing.
+ ///
/// @param[in] this_arg
/// If non-NULL (and cmd_arg is NULL), the function is invoked like a C++
/// method, with the value pointed to by the pointer as its 'this'
lldb::addr_t &args_addr_ref,
Stream &errors,
bool stop_others,
- bool discard_on_error,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
lldb::addr_t *this_arg = 0,
lldb::addr_t *cmd_arg = 0);
/// @param[in] stop_others
/// True if other threads should pause during execution.
///
- /// @param[in] discard_on_error
+ /// @param[in] unwind_on_error
/// True if the thread plan may simply be discarded if an error occurs.
///
/// @return
lldb::addr_t &args_addr_ref,
Stream &errors,
bool stop_others,
- bool discard_on_error = true)
+ bool unwind_on_error = true,
+ bool ignore_breakpoints = true)
{
return ClangFunction::GetThreadPlanToCallFunction (exe_ctx,
m_jit_start_addr,
args_addr_ref,
errors,
stop_others,
- discard_on_error);
+ unwind_on_error,
+ ignore_breakpoints);
}
//------------------------------------------------------------------
/// The execution context to use when looking up entities that
/// are needed for parsing (locations of variables, etc.)
///
- /// @param[in] discard_on_error
+ /// @param[in] unwind_on_error
/// If true, and the execution stops before completion, we unwind the
/// function call, and return the program state to what it was before the
/// execution. If false, we leave the program in the stopped state.
///
+ /// @param[in] ignore_breakpoints
+ /// If true, ignore breakpoints while executing the expression.
+ ///
/// @param[in] shared_ptr_to_me
/// This is a shared pointer to this ClangUserExpression. This is
/// needed because Execute can push a thread plan that will hold onto
ExecutionResults
Execute (Stream &error_stream,
ExecutionContext &exe_ctx,
- bool discard_on_error,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
ClangUserExpressionSP &shared_ptr_to_me,
lldb::ClangExpressionVariableSP &result,
bool try_all_threads,
/// the expression. Currently restricted to those languages
/// supported by Clang.
///
- /// @param[in] discard_on_error
+ /// @param[in] unwind_on_error
/// True if the thread's state should be restored in the case
/// of an error.
///
+ /// @param[in] ignore_breakpoints
+ /// If true, ignore breakpoints while executing the expression.
+ ///
/// @param[in] result_type
/// If not eResultTypeAny, the type of the desired result. Will
/// result in parse errors if impossible.
lldb_private::ExecutionPolicy execution_policy,
lldb::LanguageType language,
ResultType desired_type,
- bool discard_on_error,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
const char *expr_cstr,
const char *expr_prefix,
lldb::ValueObjectSP &result_valobj_sp,
lldb_private::ExecutionPolicy execution_policy,
lldb::LanguageType language,
ResultType desired_type,
- bool discard_on_error,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
const char *expr_cstr,
const char *expr_prefix,
lldb::ValueObjectSP &result_valobj_sp,
void
SetPythonOSPluginPath (const FileSpec &file);
+
+ bool
+ GetIgnoreBreakpointsInExpressions () const;
+
+ void
+ SetIgnoreBreakpointsInExpressions (bool ignore);
+
+ bool
+ GetUnwindOnErrorInExpressions () const;
+
+ void
+ SetUnwindOnErrorInExpressions (bool ignore);
};
typedef STD_SHARED_PTR(ProcessProperties) ProcessPropertiesSP;
lldb::ThreadPlanSP &thread_plan_sp,
bool stop_others,
bool run_others,
- bool discard_on_error,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
uint32_t timeout_usec,
Stream &errors);
m_execution_policy(eExecutionPolicyOnlyWhenNeeded),
m_coerce_to_id(false),
m_unwind_on_error(true),
+ m_ignore_breakpoints (false),
m_keep_in_memory(false),
m_run_others(true),
m_use_dynamic(lldb::eNoDynamicValues),
}
bool
+ DoesIgnoreBreakpoints () const
+ {
+ return m_ignore_breakpoints;
+ }
+
+ EvaluateExpressionOptions&
+ SetIgnoreBreakpoints (bool ignore = false)
+ {
+ m_ignore_breakpoints = ignore;
+ return *this;
+ }
+
+ bool
DoesKeepInMemory () const
{
return m_keep_in_memory;
ExecutionPolicy m_execution_policy;
bool m_coerce_to_id;
bool m_unwind_on_error;
+ bool m_ignore_breakpoints;
bool m_keep_in_memory;
bool m_run_others;
lldb::DynamicValueType m_use_dynamic;
Address& function,
lldb::addr_t arg,
bool stop_other_threads,
- bool discard_on_error = false);
+ bool unwind_on_error = false,
+ bool ignore_breakpoints = true);
//------------------------------------------------------------------
// Thread Plan accessors:
const ClangASTType &return_type,
lldb::addr_t arg,
bool stop_other_threads,
- bool discard_on_error = true,
+ bool unwind_on_error = true,
+ bool ignore_breakpoints = false,
lldb::addr_t *this_arg = 0,
lldb::addr_t *cmd_arg = 0);
Address &function,
const ClangASTType &return_type,
bool stop_other_threads,
- bool discard_on_error,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
lldb::addr_t *arg1_ptr = NULL,
lldb::addr_t *arg2_ptr = NULL,
lldb::addr_t *arg3_ptr = NULL,
lldb::ValueObjectSP m_return_valobj_sp; // If this contains a valid pointer, use the ABI to extract values when complete
bool m_takedown_done; // We want to ensure we only do the takedown once. This ensures that.
lldb::addr_t m_stop_address; // This is the address we stopped at. Also set in DoTakedown;
- bool m_discard_on_error;
+ bool m_unwind_on_error;
+ bool m_ignore_breakpoints;
DISALLOW_COPY_AND_ASSIGN (ThreadPlanCallFunction);
};
Address &function,
lldb::addr_t arg,
bool stop_other_threads,
- bool discard_on_error,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
lldb::addr_t *this_arg,
lldb::addr_t *cmd_arg,
ClangUserExpression::ClangUserExpressionSP &user_expression_sp);
eExecutionCompleted,
eExecutionDiscarded,
eExecutionInterrupted,
+ eExecutionHitBreakpoint,
eExecutionTimedOut
} ExecutionResults;
void
SetUnwindOnError (bool unwind = false);
+ bool
+ GetIgnoreBreakpoints () const;
+
+ %feature("docstring", "Sets whether to ignore breakpoint hits while running expressions.") SetUnwindOnError;
+
+ void
+ SetIgnoreBreakpoints (bool ignore = false);
+
lldb::DynamicValueType
GetFetchDynamicValue () const;
m_opaque_ap->SetUnwindOnError (unwind);
}
+bool
+SBExpressionOptions::GetIgnoreBreakpoints () const
+{
+ return m_opaque_ap->DoesIgnoreBreakpoints ();
+}
+
+void
+SBExpressionOptions::SetIgnoreBreakpoints (bool ignore)
+{
+ m_opaque_ap->SetIgnoreBreakpoints (ignore);
+}
+
lldb::DynamicValueType
SBExpressionOptions::GetFetchDynamicValue () const
{
CommandObjectExpression::CommandOptions::g_option_table[] =
{
{ LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "all-threads", 'a', required_argument, NULL, 0, eArgTypeBoolean, "Should we run all threads if the execution doesn't complete on one thread."},
+ { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "ignore-breakpoints", 'i', required_argument, NULL, 0, eArgTypeBoolean, "Ignore breakpoint hits while running expressions"},
{ LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "timeout", 't', required_argument, NULL, 0, eArgTypeUnsignedInteger, "Timeout value for running the expression."},
{ LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "unwind-on-error", 'u', required_argument, NULL, 0, eArgTypeBoolean, "Clean up program state if the expression causes a crash, breakpoint hit or signal."},
};
}
break;
+ case 'i':
+ {
+ bool success;
+ bool tmp_value = Args::StringToBoolean(option_arg, true, &success);
+ if (success)
+ ignore_breakpoints = tmp_value;
+ else
+ error.SetErrorStringWithFormat("could not convert \"%s\" to a boolean value.", option_arg);
+ break;
+ }
case 't':
{
bool success;
case 'u':
{
bool success;
- unwind_on_error = Args::StringToBoolean(option_arg, true, &success);
- if (!success)
+ bool tmp_value = Args::StringToBoolean(option_arg, true, &success);
+ if (success)
+ unwind_on_error = tmp_value;
+ else
error.SetErrorStringWithFormat("could not convert \"%s\" to a boolean value.", option_arg);
break;
}
void
CommandObjectExpression::CommandOptions::OptionParsingStarting (CommandInterpreter &interpreter)
{
- unwind_on_error = true;
+ Process *process = interpreter.GetExecutionContext().GetProcessPtr();
+ if (process != NULL)
+ {
+ ignore_breakpoints = process->GetIgnoreBreakpointsInExpressions();
+ unwind_on_error = process->GetUnwindOnErrorInExpressions();
+ }
+ else
+ {
+ ignore_breakpoints = false;
+ unwind_on_error = true;
+ }
+
show_summary = true;
try_all_threads = true;
timeout = 0;
EvaluateExpressionOptions options;
options.SetCoerceToId(m_varobj_options.use_objc)
.SetUnwindOnError(m_command_options.unwind_on_error)
+ .SetIgnoreBreakpoints (m_command_options.ignore_breakpoints)
.SetKeepInMemory(keep_in_memory)
.SetUseDynamic(m_varobj_options.use_dynamic)
.SetRunOthers(m_command_options.try_all_threads)
result_valobj_sp,
options);
- if (exe_results == eExecutionInterrupted && !m_command_options.unwind_on_error)
+ if ((exe_results == eExecutionInterrupted && !m_command_options.unwind_on_error)
+ ||(exe_results == eExecutionHitBreakpoint && !m_command_options.ignore_breakpoints))
{
uint32_t start_frame = 0;
uint32_t num_frames = 1;
static OptionDefinition g_option_table[];
bool unwind_on_error;
+ bool ignore_breakpoints;
bool show_types;
bool show_summary;
uint32_t timeout;
lldb::addr_t &args_addr,
Stream &errors,
bool stop_others,
- bool discard_on_error,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
lldb::addr_t *this_arg,
lldb::addr_t *cmd_arg)
{
ClangASTType(),
args_addr,
stop_others,
- discard_on_error,
+ unwind_on_error,
+ ignore_breakpoints,
this_arg,
cmd_arg);
new_plan->SetIsMasterPlan(true);
ClangFunction::ExecuteFunction(ExecutionContext &exe_ctx, Stream &errors, bool stop_others, Value &results)
{
const bool try_all_threads = false;
- const bool discard_on_error = true;
- return ExecuteFunction (exe_ctx, NULL, errors, stop_others, 0UL, try_all_threads, discard_on_error, results);
+ const bool unwind_on_error = true;
+ const bool ignore_breakpoints = true;
+ return ExecuteFunction (exe_ctx, NULL, errors, stop_others, 0UL, try_all_threads,
+ unwind_on_error, ignore_breakpoints, results);
}
ExecutionResults
Value &results)
{
const bool stop_others = true;
- const bool discard_on_error = true;
+ const bool unwind_on_error = true;
+ const bool ignore_breakpoints = true;
return ExecuteFunction (exe_ctx, NULL, errors, stop_others, timeout_usec,
- try_all_threads, discard_on_error, results);
+ try_all_threads, unwind_on_error, ignore_breakpoints, results);
}
// This is the static function
lldb::addr_t &void_arg,
bool stop_others,
bool try_all_threads,
- bool discard_on_error,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
uint32_t timeout_usec,
Stream &errors,
lldb::addr_t *this_arg)
void_arg,
errors,
stop_others,
- discard_on_error,
+ unwind_on_error,
+ ignore_breakpoints,
this_arg));
if (!call_plan_sp)
return eExecutionSetupError;
ExecutionResults results = exe_ctx.GetProcessRef().RunThreadPlan (exe_ctx, call_plan_sp,
stop_others,
try_all_threads,
- discard_on_error,
+ unwind_on_error,
+ ignore_breakpoints,
timeout_usec,
errors);
bool stop_others,
uint32_t timeout_usec,
bool try_all_threads,
- bool discard_on_error,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
Value &results)
{
using namespace clang;
args_addr,
stop_others,
try_all_threads,
- discard_on_error,
+ unwind_on_error,
+ ignore_breakpoints,
timeout_usec,
errors);
// ClangUserExpression resources before the thread plan finishes execution in the target. But because we are
// forcing unwind_on_error to be true here, in practical terms that can't happen.
+ const bool stop_others = true;
+ const bool unwind_on_error = true;
+ const bool ignore_breakpoints = false;
return ClangFunction::GetThreadPlanToCallFunction (exe_ctx,
m_jit_start_addr,
struct_address,
error_stream,
- true,
- true,
+ stop_others,
+ unwind_on_error,
+ ignore_breakpoints,
(m_needs_object_ptr ? &object_ptr : NULL),
(m_needs_object_ptr && m_objectivec) ? &cmd_ptr : NULL);
}
ExecutionResults
ClangUserExpression::Execute (Stream &error_stream,
ExecutionContext &exe_ctx,
- bool discard_on_error,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
ClangUserExpression::ClangUserExpressionSP &shared_ptr_to_me,
lldb::ClangExpressionVariableSP &result,
bool run_others,
wrapper_address,
struct_address,
stop_others,
- discard_on_error,
+ unwind_on_error,
+ ignore_breakpoints,
(m_needs_object_ptr ? &object_ptr : NULL),
((m_needs_object_ptr && m_objectivec) ? &cmd_ptr : NULL),
shared_ptr_to_me));
call_plan_sp,
stop_others,
try_all_threads,
- discard_on_error,
+ unwind_on_error,
+ ignore_breakpoints,
timeout_usec,
error_stream);
if (log)
log->Printf("-- [ClangUserExpression::Execute] Execution of expression completed --");
- if (execution_result == eExecutionInterrupted)
+ if (execution_result == eExecutionInterrupted || execution_result == eExecutionHitBreakpoint)
{
const char *error_desc = NULL;
else
error_stream.Printf ("Execution was interrupted.");
- if (discard_on_error)
+ if ((execution_result == eExecutionInterrupted && unwind_on_error)
+ || (execution_result == eExecutionHitBreakpoint && ignore_breakpoints))
error_stream.Printf ("\nThe process has been returned to the state before execution.");
else
error_stream.Printf ("\nThe process has been left at the point where it was interrupted.");
lldb_private::ExecutionPolicy execution_policy,
lldb::LanguageType language,
ResultType desired_type,
- bool discard_on_error,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
const char *expr_cstr,
const char *expr_prefix,
lldb::ValueObjectSP &result_valobj_sp,
execution_policy,
language,
desired_type,
- discard_on_error,
+ unwind_on_error,
+ ignore_breakpoints,
expr_cstr,
expr_prefix,
result_valobj_sp,
lldb_private::ExecutionPolicy execution_policy,
lldb::LanguageType language,
ResultType desired_type,
- bool discard_on_error,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
const char *expr_cstr,
const char *expr_prefix,
lldb::ValueObjectSP &result_valobj_sp,
execution_results = user_expression_sp->Execute (error_stream,
exe_ctx,
- discard_on_error,
+ unwind_on_error,
+ ignore_breakpoints,
user_expression_sp,
expr_result,
run_others,
EvaluateExpressionOptions options;
options.SetCoerceToId(false)
.SetUnwindOnError(true)
+ .SetIgnoreBreakpoints(true)
.SetKeepInMemory(false)
.SetRunOthers(true)
.SetTimeoutUsec(0);
case eExecutionInterrupted:
error.SetErrorStringWithFormat("expression interrupted for the expression '%s'", expr_str.c_str());
break;
+ case eExecutionHitBreakpoint:
+ error.SetErrorStringWithFormat("expression hit breakpoint for the expression '%s'", expr_str.c_str());
+ break;
case eExecutionTimedOut:
error.SetErrorStringWithFormat("expression timed out for the expression '%s'", expr_str.c_str());
break;
lldb::addr_t wrapper_struct_addr = LLDB_INVALID_ADDRESS;
func.InsertFunction(exe_ctx, wrapper_struct_addr, error_stream);
- bool unwind_on_error = true;
- bool try_all_threads = true;
- bool stop_others = true;
+ const bool unwind_on_error = true;
+ const bool try_all_threads = true;
+ const bool stop_others = true;
+ const bool ignore_breakpoints = true;
ExecutionResults results = func.ExecuteFunction (exe_ctx,
&wrapper_struct_addr,
stop_others,
0 /* no timeout */,
try_all_threads,
- unwind_on_error,
+ unwind_on_error,
+ ignore_breakpoints,
ret);
if (results != eExecutionCompleted)
{
if (!m_get_class_name_function->WriteFunctionArguments (exe_ctx, m_get_class_name_args, find_class_name_address, dispatch_values, errors))
return false;
- bool stop_others = true;
- bool try_all_threads = true;
- bool unwind_on_error = true;
+ const bool stop_others = true;
+ const bool try_all_threads = true;
+ const bool unwind_on_error = true;
+ const bool ignore_breakpoints = true;
ExecutionResults results = m_get_class_name_function->ExecuteFunction (exe_ctx,
&m_get_class_name_args,
stop_others,
100000,
try_all_threads,
- unwind_on_error,
+ unwind_on_error,
+ ignore_breakpoints,
void_ptr_value);
if (results != eExecutionCompleted)
}
m_impl_function = m_trampoline_handler->GetLookupImplementationWrapperFunction();
ExecutionContext exc_ctx;
+ const bool unwind_on_error = true;
+ const bool ignore_breakpoints = true;
m_thread.CalculateExecutionContext(exc_ctx);
- m_func_sp.reset(m_impl_function->GetThreadPlanToCallFunction (exc_ctx, m_args_addr, errors, m_stop_others));
+ m_func_sp.reset(m_impl_function->GetThreadPlanToCallFunction (exc_ctx,
+ m_args_addr,
+ errors,
+ m_stop_others,
+ unwind_on_error,
+ ignore_breakpoints));
m_func_sp->SetOkayToDiscard(true);
m_thread.QueueThreadPlan (m_func_sp, false);
}
const uint32_t range_scope = eSymbolContextFunction | eSymbolContextSymbol;
const bool use_inline_block_range = false;
const bool stop_other_threads = true;
- const bool discard_on_error = true;
+ const bool unwind_on_error = true;
+ const bool ignore_breakpoints = true;
const bool try_all_threads = true;
const uint32_t timeout_usec = 500000;
mmap_range.GetBaseAddress(),
ClangASTType (clang_ast_context->getASTContext(), clang_void_ptr_type),
stop_other_threads,
- discard_on_error,
+ unwind_on_error,
+ ignore_breakpoints,
&addr,
&length,
&prot_arg,
call_plan_sp,
stop_other_threads,
try_all_threads,
- discard_on_error,
+ unwind_on_error,
+ ignore_breakpoints,
timeout_usec,
error_strm);
if (result == eExecutionCompleted)
const uint32_t range_scope = eSymbolContextFunction | eSymbolContextSymbol;
const bool use_inline_block_range = false;
const bool stop_other_threads = true;
- const bool discard_on_error = true;
+ const bool unwind_on_error = true;
+ const bool ignore_breakpoints = true;
const bool try_all_threads = true;
const uint32_t timeout_usec = 500000;
munmap_range.GetBaseAddress(),
ClangASTType(),
stop_other_threads,
- discard_on_error,
+ unwind_on_error,
+ ignore_breakpoints,
&addr,
&length));
if (call_plan_sp)
call_plan_sp,
stop_other_threads,
try_all_threads,
- discard_on_error,
+ unwind_on_error,
+ ignore_breakpoints,
timeout_usec,
error_strm);
if (result == eExecutionCompleted)
{ "disable-memory-cache" , OptionValue::eTypeBoolean, false, DISABLE_MEM_CACHE_DEFAULT, NULL, NULL, "Disable reading and caching of memory in fixed-size units." },
{ "extra-startup-command", OptionValue::eTypeArray , false, OptionValue::eTypeString, NULL, NULL, "A list containing extra commands understood by the particular process plugin used. "
"For instance, to turn on debugserver logging set this to \"QSetLogging:bitmask=LOG_DEFAULT;\"" },
+ { "ignore-breakpoints-in-expressions", OptionValue::eTypeBoolean, true, false, NULL, NULL, "If true, breakpoints will be ignored during expression evaluation." },
+ { "unwind-on-error-in-expressions", OptionValue::eTypeBoolean, true, false, NULL, NULL, "If true, errors in expression evaluation will unwind the stack back to the state before the call." },
{ "python-os-plugin-path", OptionValue::eTypeFileSpec, false, true, NULL, NULL, "A path to a python OS plug-in module file that contains a OperatingSystemPlugIn class." },
{ NULL , OptionValue::eTypeInvalid, false, 0, NULL, NULL, NULL }
};
enum {
ePropertyDisableMemCache,
ePropertyExtraStartCommand,
+ ePropertyIgnoreBreakpointsInExpressions,
+ ePropertyUnwindOnErrorInExpressions,
ePropertyPythonOSPluginPath
};
m_collection_sp->SetPropertyAtIndexAsFileSpec(NULL, idx, file);
}
+
+bool
+ProcessProperties::GetIgnoreBreakpointsInExpressions () const
+{
+ const uint32_t idx = ePropertyIgnoreBreakpointsInExpressions;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean(NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
+void
+ProcessProperties::SetIgnoreBreakpointsInExpressions (bool ignore)
+{
+ const uint32_t idx = ePropertyIgnoreBreakpointsInExpressions;
+ m_collection_sp->SetPropertyAtIndexAsBoolean(NULL, idx, ignore);
+}
+
+bool
+ProcessProperties::GetUnwindOnErrorInExpressions () const
+{
+ const uint32_t idx = ePropertyUnwindOnErrorInExpressions;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean(NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
+void
+ProcessProperties::SetUnwindOnErrorInExpressions (bool ignore)
+{
+ const uint32_t idx = ePropertyUnwindOnErrorInExpressions;
+ m_collection_sp->SetPropertyAtIndexAsBoolean(NULL, idx, ignore);
+}
+
void
ProcessInstanceInfo::Dump (Stream &s, Platform *platform) const
{
{
ExecutionContext exe_ctx;
frame_sp->CalculateExecutionContext (exe_ctx);
- bool unwind_on_error = true;
+ const bool unwind_on_error = true;
+ const bool ignore_breakpoints = true;
StreamString expr;
expr.Printf("dlopen (\"%s\", 2)", path);
const char *prefix = "extern \"C\" void* dlopen (const char *path, int mode);\n";
lldb::eLanguageTypeUnknown,
ClangUserExpression::eResultTypeAny,
unwind_on_error,
+ ignore_breakpoints,
expr.GetData(),
prefix,
result_valobj_sp,
{
ExecutionContext exe_ctx;
frame_sp->CalculateExecutionContext (exe_ctx);
- bool unwind_on_error = true;
+ const bool unwind_on_error = true;
+ const bool ignore_breakpoints = true;
StreamString expr;
expr.Printf("dlclose ((void *)0x%" PRIx64 ")", image_addr);
const char *prefix = "extern \"C\" int dlclose(void* handle);\n";
lldb::eLanguageTypeUnknown,
ClangUserExpression::eResultTypeAny,
unwind_on_error,
+ ignore_breakpoints,
expr.GetData(),
prefix,
result_valobj_sp,
lldb::ThreadPlanSP &thread_plan_sp,
bool stop_others,
bool run_others,
- bool discard_on_error,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
uint32_t timeout_usec,
Stream &errors)
{
bool first_timeout = true;
bool do_resume = true;
+ bool handle_running_event = true;
const uint64_t default_one_thread_timeout_usec = 250000;
uint64_t computed_timeout = 0;
+ bool stopped_by_breakpoint = false;
// This while loop must exit out the bottom, there's cleanup that we need to do when we are done.
// So don't call return anywhere within it.
// The only exception is if we get two running events with no intervening
// stop, which can happen, we will just wait for then next stop event.
- if (do_resume)
+ if (do_resume || handle_running_event)
{
// Do the initial resume and wait for the running event before going further.
- Error resume_error = PrivateResume ();
- if (!resume_error.Success())
+ if (do_resume)
{
- errors.Printf("Error resuming inferior: \"%s\".\n", resume_error.AsCString());
- return_value = eExecutionSetupError;
- break;
+ Error resume_error = PrivateResume ();
+ if (!resume_error.Success())
+ {
+ errors.Printf("Error resuming inferior: \"%s\".\n", resume_error.AsCString());
+ return_value = eExecutionSetupError;
+ break;
+ }
}
real_timeout = TimeValue::Now();
if (log)
log->PutCString ("Process::RunThreadPlan(): handled an extra running event.");
do_resume = true;
+ handle_running_event = true;
}
// Now wait for the process to stop again:
}
else
{
- if (log)
- log->PutCString ("Process::RunThreadPlan(): thread plan didn't successfully complete.");
-
- return_value = eExecutionInterrupted;
+ // Something restarted the target, so just wait for it to stop for real.
+ if (Process::ProcessEventData::GetRestartedFromEvent(event_sp.get()))
+ {
+ if (log)
+ log->PutCString ("Process::RunThreadPlan(): Somebody stopped and then restarted, we'll continue waiting.");
+ keep_going = true;
+ do_resume = false;
+ handle_running_event = true;
+ }
+ else
+ {
+ if (log)
+ log->PutCString ("Process::RunThreadPlan(): thread plan didn't successfully complete.");
+ if (stop_reason == eStopReasonBreakpoint)
+ return_value = eExecutionHitBreakpoint;
+ else
+ return_value = eExecutionInterrupted;
+ }
}
}
}
case lldb::eStateRunning:
do_resume = false;
keep_going = true;
+ handle_running_event = false;
break;
default:
}
}
-
} // END WAIT LOOP
// If we had to start up a temporary private state thread to run this thread plan, shut it down now.
}
- // Restore the thread state if we are going to discard the plan execution.
+ // Restore the thread state if we are going to discard the plan execution. There are three cases where this
+ // could happen:
+ // 1) The execution successfully completed
+ // 2) We hit a breakpoint, and ignore_breakpoints was true
+ // 3) We got some other error, and discard_on_error was true
+ bool should_unwind = (return_value == eExecutionInterrupted && unwind_on_error)
+ || (return_value == eExecutionHitBreakpoint && ignore_breakpoints);
- if (return_value == eExecutionCompleted || discard_on_error)
+ if (return_value == eExecutionCompleted
+ || should_unwind)
{
thread_plan_sp->RestoreThreadState();
}
// Now do some processing on the results of the run:
- if (return_value == eExecutionInterrupted)
+ if (return_value == eExecutionInterrupted || return_value == eExecutionHitBreakpoint)
{
if (log)
{
log->Printf("Process::RunThreadPlan(): execution interrupted: %s", s.GetData());
}
- if (discard_on_error && thread_plan_sp)
+ if (should_unwind && thread_plan_sp)
{
if (log)
log->Printf ("Process::RunThreadPlan: ExecutionInterrupted - discarding thread plans up to %p.", thread_plan_sp.get());
if (log)
log->PutCString("Process::RunThreadPlan(): execution set up error.");
- if (discard_on_error && thread_plan_sp)
+ if (unwind_on_error && thread_plan_sp)
{
thread->DiscardThreadPlansUpToPlan (thread_plan_sp);
thread_plan_sp->SetPrivate (orig_plan_private);
{
if (log)
log->PutCString("Process::RunThreadPlan(): thread plan stopped in mid course");
- if (discard_on_error && thread_plan_sp)
+ if (unwind_on_error && thread_plan_sp)
{
if (log)
- log->PutCString("Process::RunThreadPlan(): discarding thread plan 'cause discard_on_error is set.");
+ log->PutCString("Process::RunThreadPlan(): discarding thread plan 'cause unwind_on_error is set.");
thread->DiscardThreadPlansUpToPlan (thread_plan_sp);
thread_plan_sp->SetPrivate (orig_plan_private);
}
case eExecutionInterrupted:
result_name = "eExecutionInterrupted";
break;
+ case eExecutionHitBreakpoint:
+ result_name = "eExecutionHitBreakpoint";
+ break;
case eExecutionSetupError:
result_name = "eExecutionSetupError";
break;
m_should_stop = false;
ExecutionContext exe_ctx (m_thread.GetStackFrameAtIndex(0));
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process->GetModIDRef().IsLastResumeForUserExpression())
+ {
+ // If we are in the middle of evaluating an expression, don't run asynchronous breakpoint commands or
+ // expressions. That could lead to infinite recursion if the command or condition re-calls the function
+ // with this breakpoint.
+ // TODO: We can keep a list of the breakpoints we've seen while running expressions in the nested
+ // PerformAction calls that can arise when the action runs a function that hits another breakpoint,
+ // and only stop running commands when we see the same breakpoint hit a second time.
+
+ m_should_stop_is_valid = true;
+ if (log)
+ log->Printf ("StopInfoBreakpoint::PerformAction - Hit a breakpoint while running an expression,"
+ " not running commands to avoid recursion.");
+ bool ignoring_breakpoints = process->GetIgnoreBreakpointsInExpressions();
+ if (ignoring_breakpoints)
+ {
+ m_should_stop = false;
+ // Internal breakpoints will always stop.
+ for (size_t j = 0; j < num_owners; j++)
+ {
+ lldb::BreakpointLocationSP bp_loc_sp = bp_site_sp->GetOwnerAtIndex(j);
+ if (bp_loc_sp->GetBreakpoint().IsInternal())
+ {
+ m_should_stop = true;
+ break;
+ }
+ }
+ }
+ else
+ {
+ m_should_stop = true;
+ }
+ if (log)
+ log->Printf ("StopInfoBreakpoint::PerformAction - in expression, continuing: %s.",
+ m_should_stop ? "true" : "false");
+ process->GetTarget().GetDebugger().GetAsyncOutputStream()->Printf("Warning: hit breakpoint while "
+ "running function, skipping commands and conditions to prevent recursion.");
+ return;
+ }
+
StoppointCallbackContext context (event_ptr, exe_ctx, false);
for (size_t j = 0; j < num_owners; j++)
ExecutionResults result_code;
ValueObjectSP result_value_sp;
- const bool discard_on_error = true;
+ const bool unwind_on_error = true;
+ const bool ignore_breakpoints = true;
Error error;
result_code = ClangUserExpression::EvaluateWithError (exe_ctx,
eExecutionPolicyOnlyWhenNeeded,
lldb::eLanguageTypeUnknown,
ClangUserExpression::eResultTypeAny,
- discard_on_error,
+ unwind_on_error,
+ ignore_breakpoints,
bp_loc_sp->GetConditionText(),
NULL,
result_value_sp,
// constructor errors up to the debugger's Async I/O.
ExecutionResults result_code;
ValueObjectSP result_value_sp;
- const bool discard_on_error = true;
+ const bool unwind_on_error = true;
+ const bool ignore_breakpoints = true;
Error error;
result_code = ClangUserExpression::EvaluateWithError (exe_ctx,
eExecutionPolicyOnlyWhenNeeded,
lldb::eLanguageTypeUnknown,
ClangUserExpression::eResultTypeAny,
- discard_on_error,
+ unwind_on_error,
+ ignore_breakpoints,
wp_sp->GetConditionText(),
NULL,
result_value_sp,
lldb::eLanguageTypeUnknown,
options.DoesCoerceToId() ? ClangUserExpression::eResultTypeId : ClangUserExpression::eResultTypeAny,
options.DoesUnwindOnError(),
+ options.DoesIgnoreBreakpoints(),
expr_cstr,
prefix,
result_valobj_sp,
Address& function,
lldb::addr_t arg,
bool stop_other_threads,
- bool discard_on_error)
-{
- ThreadPlanSP thread_plan_sp (new ThreadPlanCallFunction (*this, function, ClangASTType(), arg, stop_other_threads, discard_on_error));
+ bool unwind_on_error,
+ bool ignore_breakpoints)
+{
+ ThreadPlanSP thread_plan_sp (new ThreadPlanCallFunction (*this,
+ function,
+ ClangASTType(),
+ arg,
+ stop_other_threads,
+ unwind_on_error,
+ ignore_breakpoints));
QueueThreadPlan (thread_plan_sp, abort_other_plans);
return thread_plan_sp.get();
}
const ClangASTType &return_type,
addr_t arg,
bool stop_other_threads,
- bool discard_on_error,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
addr_t *this_arg,
addr_t *cmd_arg) :
ThreadPlan (ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion),
m_return_type (return_type),
m_takedown_done (false),
m_stop_address (LLDB_INVALID_ADDRESS),
- m_discard_on_error (discard_on_error)
+ m_unwind_on_error (unwind_on_error),
+ m_ignore_breakpoints (ignore_breakpoints)
{
lldb::addr_t start_load_addr;
ABI *abi;
Address &function,
const ClangASTType &return_type,
bool stop_other_threads,
- bool discard_on_error,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
addr_t *arg1_ptr,
addr_t *arg2_ptr,
addr_t *arg3_ptr,
m_return_type (return_type),
m_takedown_done (false),
m_stop_address (LLDB_INVALID_ADDRESS),
- m_discard_on_error (discard_on_error)
+ m_unwind_on_error (unwind_on_error),
+ m_ignore_breakpoints (ignore_breakpoints)
{
lldb::addr_t start_load_addr;
ABI *abi;
// If our subplan knows why we stopped, even if it's done (which would forward the question to us)
// we answer yes.
if (m_subplan_sp.get() != NULL && m_subplan_sp->PlanExplainsStop())
+ {
+ SetPlanComplete();
return true;
+ }
// Check if the breakpoint is one of ours.
return true;
// If we don't want to discard this plan, than any stop we don't understand should be propagated up the stack.
- if (!m_discard_on_error)
+ if (!m_unwind_on_error)
return false;
// Otherwise, check the case where we stopped for an internal breakpoint, in that case, continue on.
return false;
}
- if (m_discard_on_error)
+ if (m_ignore_breakpoints)
{
DoTakedown(false);
return true;
// If we want to discard the plan, then we say we explain the stop
// but if we are going to be discarded, let whoever is above us
// explain the stop.
+ SetPlanComplete(false);
if (m_subplan_sp)
{
- if (m_discard_on_error)
+ if (m_unwind_on_error)
{
DoTakedown(false);
return true;
bool
ThreadPlanCallFunction::ShouldStop (Event *event_ptr)
{
- if (IsPlanComplete() || PlanExplainsStop())
+ // We do some computation in PlanExplainsStop that may or may not set the plan as complete.
+ // We need to do that here to make sure our state is correct.
+ PlanExplainsStop();
+
+ if (IsPlanComplete())
{
ReportRegisterState ("Function completed. Register state was:");
bool
ThreadPlanCallFunction::MischiefManaged ()
{
+ LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+
+ if (PlanExplainsStop() && !IsPlanComplete())
+ {
+ if (log)
+ log->Printf ("ThreadPlanCallFunction: Got into MischiefManaged, explained stop but was not complete.");
+ }
+
if (IsPlanComplete())
{
- LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
-
if (log)
log->Printf("ThreadPlanCallFunction(%p): Completed call function plan.", this);
{
StopInfoSP stop_info_sp = GetPrivateStopReason();
- if (m_cxx_language_runtime &&
- m_cxx_language_runtime->ExceptionBreakpointsExplainStop(stop_info_sp))
+ if ((m_cxx_language_runtime &&
+ m_cxx_language_runtime->ExceptionBreakpointsExplainStop(stop_info_sp))
+ ||(m_objc_language_runtime &&
+ m_objc_language_runtime->ExceptionBreakpointsExplainStop(stop_info_sp)))
+ {
+ SetPlanComplete(false);
return true;
+ }
+
+ // Finally, if the process is set to ignore breakpoints in function calls,
+ // then we explain all breakpoint stops.
- if (m_objc_language_runtime &&
- m_objc_language_runtime->ExceptionBreakpointsExplainStop(stop_info_sp))
+ if (m_ignore_breakpoints)
return true;
return false;
Address &function,
lldb::addr_t arg,
bool stop_other_threads,
- bool discard_on_error,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
lldb::addr_t *this_arg,
lldb::addr_t *cmd_arg,
ClangUserExpression::ClangUserExpressionSP &user_expression_sp) :
- ThreadPlanCallFunction (thread, function, ClangASTType(), arg, stop_other_threads, discard_on_error, this_arg, cmd_arg),
+ ThreadPlanCallFunction (thread, function, ClangASTType(), arg, stop_other_threads, unwind_on_error, ignore_breakpoints, this_arg, cmd_arg),
m_user_expression_sp (user_expression_sp)
{
// User expressions are generally "User generated" so we should set them up to stop when done.
startstr = "'Z'")
self.DebugSBValue(val)
+ callee_break = target.BreakpointCreateByName ("a_function_to_call", None)
+ self.assertTrue(callee_break.GetNumLocations() > 0)
+
+ # Make sure ignoring breakpoints works from the command line:
+ self.expect("expression -i true -- a_function_to_call()",
+ substrs = ['(int) $', ' 1'])
+ self.assertTrue (callee_break.GetHitCount() == 1)
+
+ # Now try ignoring breakpoints using the SB API's:
+ options = lldb.SBExpressionOptions()
+ options.SetIgnoreBreakpoints(True)
+ value = frame.EvaluateExpression('a_function_to_call()', options)
+ self.assertTrue (value.IsValid())
+ self.assertTrue (value.GetValueAsSigned(0) == 2)
+ self.assertTrue (callee_break.GetHitCount() == 2)
+
# rdar://problem/8686536
# CommandInterpreter::HandleCommand is stripping \'s from input for WantsRawCommand commands
def test_expr_commands_can_handle_quotes(self):
substrs = ['(int) $',
'6'])
-
if __name__ == '__main__':
import atexit
lldb.SBDebugger.Initialize()
#include <stdio.h>
+static int static_value = 0;
+
+int
+a_function_to_call()
+{
+ static_value++;
+ return static_value;
+}
+
int main (int argc, char const *argv[])
{
printf ("Hello world!\n");
expression printf ("two: %llu, one: %i\n", 2ull, 1)
expression random() % 255l
#endif
+
+ a_function_to_call();
return 0;
}