diff options
Diffstat (limited to 'lldb/source')
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. |