summaryrefslogtreecommitdiffstats
path: root/lldb/source
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source')
-rw-r--r--lldb/source/API/SBExpressionOptions.cpp12
-rw-r--r--lldb/source/Commands/CommandObjectExpression.cpp34
-rw-r--r--lldb/source/Commands/CommandObjectExpression.h1
-rw-r--r--lldb/source/Expression/ClangFunction.cpp32
-rw-r--r--lldb/source/Expression/ClangUserExpression.cpp34
-rw-r--r--lldb/source/Interpreter/CommandInterpreter.cpp4
-rw-r--r--lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp10
-rw-r--r--lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp10
-rw-r--r--lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp9
-rw-r--r--lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp18
-rw-r--r--lldb/source/Target/Process.cpp110
-rw-r--r--lldb/source/Target/StopInfo.cpp53
-rw-r--r--lldb/source/Target/Target.cpp1
-rw-r--r--lldb/source/Target/Thread.cpp13
-rw-r--r--lldb/source/Target/ThreadPlanCallFunction.cpp53
-rw-r--r--lldb/source/Target/ThreadPlanCallUserExpression.cpp5
16 files changed, 314 insertions, 85 deletions
diff --git a/lldb/source/API/SBExpressionOptions.cpp b/lldb/source/API/SBExpressionOptions.cpp
index 9733d25b5e4..127b0cf13cd 100644
--- a/lldb/source/API/SBExpressionOptions.cpp
+++ b/lldb/source/API/SBExpressionOptions.cpp
@@ -65,6 +65,18 @@ SBExpressionOptions::SetUnwindOnError (bool unwind)
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
{
diff --git a/lldb/source/Commands/CommandObjectExpression.cpp b/lldb/source/Commands/CommandObjectExpression.cpp
index 9689b401fb5..abaf4c67891 100644
--- a/lldb/source/Commands/CommandObjectExpression.cpp
+++ b/lldb/source/Commands/CommandObjectExpression.cpp
@@ -53,6 +53,7 @@ OptionDefinition
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."},
};
@@ -94,6 +95,16 @@ CommandObjectExpression::CommandOptions::SetOptionValue (CommandInterpreter &int
}
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;
@@ -109,8 +120,10 @@ CommandObjectExpression::CommandOptions::SetOptionValue (CommandInterpreter &int
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;
}
@@ -125,7 +138,18 @@ CommandObjectExpression::CommandOptions::SetOptionValue (CommandInterpreter &int
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;
@@ -306,6 +330,7 @@ CommandObjectExpression::EvaluateExpression
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)
@@ -316,7 +341,8 @@ CommandObjectExpression::EvaluateExpression
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;
diff --git a/lldb/source/Commands/CommandObjectExpression.h b/lldb/source/Commands/CommandObjectExpression.h
index b10e20889ee..3964f2d423e 100644
--- a/lldb/source/Commands/CommandObjectExpression.h
+++ b/lldb/source/Commands/CommandObjectExpression.h
@@ -52,6 +52,7 @@ public:
static OptionDefinition g_option_table[];
bool unwind_on_error;
+ bool ignore_breakpoints;
bool show_types;
bool show_summary;
uint32_t timeout;
diff --git a/lldb/source/Expression/ClangFunction.cpp b/lldb/source/Expression/ClangFunction.cpp
index 49e09c4e7d2..2d69941a010 100644
--- a/lldb/source/Expression/ClangFunction.cpp
+++ b/lldb/source/Expression/ClangFunction.cpp
@@ -402,7 +402,8 @@ ClangFunction::GetThreadPlanToCallFunction (ExecutionContext &exe_ctx,
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)
{
@@ -422,7 +423,8 @@ ClangFunction::GetThreadPlanToCallFunction (ExecutionContext &exe_ctx,
ClangASTType(),
args_addr,
stop_others,
- discard_on_error,
+ unwind_on_error,
+ ignore_breakpoints,
this_arg,
cmd_arg);
new_plan->SetIsMasterPlan(true);
@@ -479,8 +481,10 @@ ExecutionResults
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
@@ -492,9 +496,10 @@ ClangFunction::ExecuteFunction(
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
@@ -505,7 +510,8 @@ ClangFunction::ExecuteFunction (
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)
@@ -515,7 +521,8 @@ ClangFunction::ExecuteFunction (
void_arg,
errors,
stop_others,
- discard_on_error,
+ unwind_on_error,
+ ignore_breakpoints,
this_arg));
if (!call_plan_sp)
return eExecutionSetupError;
@@ -528,7 +535,8 @@ ClangFunction::ExecuteFunction (
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);
@@ -546,7 +554,8 @@ ClangFunction::ExecuteFunction(
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;
@@ -573,7 +582,8 @@ ClangFunction::ExecuteFunction(
args_addr,
stop_others,
try_all_threads,
- discard_on_error,
+ unwind_on_error,
+ ignore_breakpoints,
timeout_usec,
errors);
diff --git a/lldb/source/Expression/ClangUserExpression.cpp b/lldb/source/Expression/ClangUserExpression.cpp
index 81db3288277..d228569fa1c 100644
--- a/lldb/source/Expression/ClangUserExpression.cpp
+++ b/lldb/source/Expression/ClangUserExpression.cpp
@@ -537,12 +537,16 @@ ClangUserExpression::GetThreadPlanToExecuteJITExpression (Stream &error_stream,
// 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);
}
@@ -593,7 +597,8 @@ ClangUserExpression::FinalizeJITExecution (Stream &error_stream,
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,
@@ -624,7 +629,8 @@ ClangUserExpression::Execute (Stream &error_stream,
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));
@@ -644,7 +650,8 @@ ClangUserExpression::Execute (Stream &error_stream,
call_plan_sp,
stop_others,
try_all_threads,
- discard_on_error,
+ unwind_on_error,
+ ignore_breakpoints,
timeout_usec,
error_stream);
@@ -654,7 +661,7 @@ ClangUserExpression::Execute (Stream &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;
@@ -669,7 +676,8 @@ ClangUserExpression::Execute (Stream &error_stream,
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.");
@@ -702,7 +710,8 @@ ClangUserExpression::Evaluate (ExecutionContext &exe_ctx,
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,
@@ -714,7 +723,8 @@ ClangUserExpression::Evaluate (ExecutionContext &exe_ctx,
execution_policy,
language,
desired_type,
- discard_on_error,
+ unwind_on_error,
+ ignore_breakpoints,
expr_cstr,
expr_prefix,
result_valobj_sp,
@@ -728,7 +738,8 @@ ClangUserExpression::EvaluateWithError (ExecutionContext &exe_ctx,
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,
@@ -807,7 +818,8 @@ ClangUserExpression::EvaluateWithError (ExecutionContext &exe_ctx,
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,
diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp
index 9f1c6cc7f50..f248fdf1d88 100644
--- a/lldb/source/Interpreter/CommandInterpreter.cpp
+++ b/lldb/source/Interpreter/CommandInterpreter.cpp
@@ -1320,6 +1320,7 @@ CommandInterpreter::PreprocessCommand (std::string &command)
EvaluateExpressionOptions options;
options.SetCoerceToId(false)
.SetUnwindOnError(true)
+ .SetIgnoreBreakpoints(true)
.SetKeepInMemory(false)
.SetRunOthers(true)
.SetTimeoutUsec(0);
@@ -1375,6 +1376,9 @@ CommandInterpreter::PreprocessCommand (std::string &command)
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;
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp
index a49b2137f1d..cacdfdb181e 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp
@@ -134,9 +134,10 @@ AppleObjCRuntime::GetObjectDescription (Stream &strm, Value &value, ExecutionCon
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,
@@ -144,7 +145,8 @@ AppleObjCRuntime::GetObjectDescription (Stream &strm, Value &value, ExecutionCon
stop_others,
0 /* no timeout */,
try_all_threads,
- unwind_on_error,
+ unwind_on_error,
+ ignore_breakpoints,
ret);
if (results != eExecutionCompleted)
{
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
index b7edba8b600..b81182915ca 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
@@ -220,9 +220,10 @@ AppleObjCRuntimeV2::RunFunctionToFindClassName(addr_t object_addr, Thread *threa
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,
@@ -230,7 +231,8 @@ AppleObjCRuntimeV2::RunFunctionToFindClassName(addr_t object_addr, Thread *threa
stop_others,
100000,
try_all_threads,
- unwind_on_error,
+ unwind_on_error,
+ ignore_breakpoints,
void_ptr_value);
if (results != eExecutionCompleted)
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp
index 18667d694e4..956b0fc0876 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp
@@ -84,8 +84,15 @@ AppleThreadPlanStepThroughObjCTrampoline::InitializeClangFunction ()
}
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);
}
diff --git a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
index 040058b952f..905ab251446 100644
--- a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
+++ b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
@@ -48,7 +48,8 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr,
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;
@@ -80,7 +81,8 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr,
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,
@@ -104,7 +106,8 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr,
call_plan_sp,
stop_other_threads,
try_all_threads,
- discard_on_error,
+ unwind_on_error,
+ ignore_breakpoints,
timeout_usec,
error_strm);
if (result == eExecutionCompleted)
@@ -152,7 +155,8 @@ bool lldb_private::InferiorCallMunmap(Process *process, addr_t addr,
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;
@@ -163,7 +167,8 @@ bool lldb_private::InferiorCallMunmap(Process *process, addr_t addr,
munmap_range.GetBaseAddress(),
ClangASTType(),
stop_other_threads,
- discard_on_error,
+ unwind_on_error,
+ ignore_breakpoints,
&addr,
&length));
if (call_plan_sp)
@@ -182,7 +187,8 @@ bool lldb_private::InferiorCallMunmap(Process *process, addr_t addr,
call_plan_sp,
stop_other_threads,
try_all_threads,
- discard_on_error,
+ unwind_on_error,
+ ignore_breakpoints,
timeout_usec,
error_strm);
if (result == eExecutionCompleted)
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index e95fbf89755..18493de1e63 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -97,6 +97,8 @@ g_properties[] =
{ "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 }
};
@@ -104,6 +106,8 @@ g_properties[] =
enum {
ePropertyDisableMemCache,
ePropertyExtraStartCommand,
+ ePropertyIgnoreBreakpointsInExpressions,
+ ePropertyUnwindOnErrorInExpressions,
ePropertyPythonOSPluginPath
};
@@ -164,6 +168,35 @@ ProcessProperties::SetPythonOSPluginPath (const FileSpec &file)
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
{
@@ -1668,7 +1701,8 @@ Process::LoadImage (const FileSpec &image_spec, Error &error)
{
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";
@@ -1678,6 +1712,7 @@ Process::LoadImage (const FileSpec &image_spec, Error &error)
lldb::eLanguageTypeUnknown,
ClangUserExpression::eResultTypeAny,
unwind_on_error,
+ ignore_breakpoints,
expr.GetData(),
prefix,
result_valobj_sp,
@@ -1743,7 +1778,8 @@ Process::UnloadImage (uint32_t image_token)
{
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";
@@ -1753,6 +1789,7 @@ Process::UnloadImage (uint32_t image_token)
lldb::eLanguageTypeUnknown,
ClangUserExpression::eResultTypeAny,
unwind_on_error,
+ ignore_breakpoints,
expr.GetData(),
prefix,
result_valobj_sp,
@@ -4293,7 +4330,8 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
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)
{
@@ -4419,8 +4457,10 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
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.
@@ -4431,16 +4471,19 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
// 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();
@@ -4526,6 +4569,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
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:
@@ -4601,10 +4645,24 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
}
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;
+ }
}
}
}
@@ -4619,6 +4677,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
case lldb::eStateRunning:
do_resume = false;
keep_going = true;
+ handle_running_event = false;
break;
default:
@@ -4815,7 +4874,6 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
}
}
-
} // END WAIT LOOP
// If we had to start up a temporary private state thread to run this thread plan, shut it down now.
@@ -4832,15 +4890,22 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
}
- // 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)
{
@@ -4933,7 +4998,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
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());
@@ -4951,7 +5016,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
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);
@@ -4975,10 +5040,10 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
{
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);
}
@@ -5037,6 +5102,9 @@ Process::ExecutionResultAsCString (ExecutionResults result)
case eExecutionInterrupted:
result_name = "eExecutionInterrupted";
break;
+ case eExecutionHitBreakpoint:
+ result_name = "eExecutionHitBreakpoint";
+ break;
case eExecutionSetupError:
result_name = "eExecutionSetupError";
break;
diff --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp
index 77a960a260a..3774c510eea 100644
--- a/lldb/source/Target/StopInfo.cpp
+++ b/lldb/source/Target/StopInfo.cpp
@@ -275,6 +275,47 @@ protected:
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++)
@@ -294,13 +335,15 @@ protected:
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,
@@ -575,13 +618,15 @@ protected:
// 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,
diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp
index 219453b21fc..6238d2e337f 100644
--- a/lldb/source/Target/Target.cpp
+++ b/lldb/source/Target/Target.cpp
@@ -1757,6 +1757,7 @@ Target::EvaluateExpression
lldb::eLanguageTypeUnknown,
options.DoesCoerceToId() ? ClangUserExpression::eResultTypeId : ClangUserExpression::eResultTypeAny,
options.DoesUnwindOnError(),
+ options.DoesIgnoreBreakpoints(),
expr_cstr,
prefix,
result_valobj_sp,
diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp
index 3137cf56413..88760d529c8 100644
--- a/lldb/source/Target/Thread.cpp
+++ b/lldb/source/Target/Thread.cpp
@@ -1283,9 +1283,16 @@ Thread::QueueThreadPlanForCallFunction (bool abort_other_plans,
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();
}
diff --git a/lldb/source/Target/ThreadPlanCallFunction.cpp b/lldb/source/Target/ThreadPlanCallFunction.cpp
index 9e768641f05..1f4edb406e9 100644
--- a/lldb/source/Target/ThreadPlanCallFunction.cpp
+++ b/lldb/source/Target/ThreadPlanCallFunction.cpp
@@ -123,7 +123,8 @@ ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
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),
@@ -134,7 +135,8 @@ ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
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;
@@ -183,7 +185,8 @@ ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
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,
@@ -198,7 +201,8 @@ ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
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;
@@ -339,7 +343,10 @@ ThreadPlanCallFunction::PlanExplainsStop ()
// 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.
@@ -353,7 +360,7 @@ ThreadPlanCallFunction::PlanExplainsStop ()
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.
@@ -385,7 +392,7 @@ ThreadPlanCallFunction::PlanExplainsStop ()
return false;
}
- if (m_discard_on_error)
+ if (m_ignore_breakpoints)
{
DoTakedown(false);
return true;
@@ -399,9 +406,10 @@ ThreadPlanCallFunction::PlanExplainsStop ()
// 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;
@@ -417,7 +425,11 @@ ThreadPlanCallFunction::PlanExplainsStop ()
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:");
@@ -481,10 +493,16 @@ ThreadPlanCallFunction::WillStop ()
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);
@@ -527,12 +545,19 @@ ThreadPlanCallFunction::BreakpointsExplainStop()
{
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;
diff --git a/lldb/source/Target/ThreadPlanCallUserExpression.cpp b/lldb/source/Target/ThreadPlanCallUserExpression.cpp
index f739d2aef2c..6e478089db7 100644
--- a/lldb/source/Target/ThreadPlanCallUserExpression.cpp
+++ b/lldb/source/Target/ThreadPlanCallUserExpression.cpp
@@ -40,11 +40,12 @@ ThreadPlanCallUserExpression::ThreadPlanCallUserExpression (Thread &thread,
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.
OpenPOWER on IntegriCloud