From 399f1cafa64b9dc15be5b8b48bfd12d5449e5b6e Mon Sep 17 00:00:00 2001 From: Jim Ingham Date: Fri, 5 Nov 2010 19:25:48 +0000 Subject: [PATCH] Added the equivalent of gdb's "unwind-on-signal" to the expression command, and a parameter to control it in ClangUserExpression, and on down to ClangFunction. llvm-svn: 118290 --- lldb/include/lldb/Expression/ClangFunction.h | 13 +++-- .../lldb/Expression/ClangUserExpression.h | 7 +++ lldb/include/lldb/Target/Thread.h | 10 ++++ lldb/lldb.xcodeproj/project.pbxproj | 5 +- lldb/source/API/SBFrame.cpp | 3 +- .../Commands/CommandObjectExpression.cpp | 13 ++++- .../source/Commands/CommandObjectExpression.h | 1 + lldb/source/Expression/ClangFunction.cpp | 32 ++++++++++--- .../source/Expression/ClangUserExpression.cpp | 12 +++-- .../AppleObjCRuntime/AppleObjCRuntime.cpp | 6 ++- .../AppleObjCRuntime/AppleObjCRuntimeV1.cpp | 6 ++- .../AppleObjCRuntime/AppleObjCRuntimeV2.cpp | 7 ++- lldb/source/Target/Process.cpp | 8 ++-- lldb/source/Target/Thread.cpp | 47 ++++++++++++++++--- 14 files changed, 136 insertions(+), 34 deletions(-) diff --git a/lldb/include/lldb/Expression/ClangFunction.h b/lldb/include/lldb/Expression/ClangFunction.h index df7ccbffdd87..357607ce7f5a 100644 --- a/lldb/include/lldb/Expression/ClangFunction.h +++ b/lldb/include/lldb/Expression/ClangFunction.h @@ -256,6 +256,11 @@ public: /// 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 + /// 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] single_thread_timeout_usec /// If stop_others is true, the length of time to wait before /// concluding that the system is deadlocked. @@ -274,7 +279,8 @@ public: lldb::addr_t function_address, lldb::addr_t &void_arg, bool stop_others, - bool try_all_threads, + bool try_all_threads, + bool discard_on_error, uint32_t single_thread_timeout_usec, Stream &errors, lldb::addr_t* this_arg = 0); @@ -396,7 +402,8 @@ public: Stream &errors, bool stop_others, uint32_t single_thread_timeout_usec, - bool try_all_threads, + bool try_all_threads, + bool discard_on_error, Value &results); //------------------------------------------------------------------ @@ -434,7 +441,7 @@ public: lldb::addr_t &args_addr_ref, Stream &errors, bool stop_others, - bool discard_on_error = true, + bool discard_on_error, lldb::addr_t *this_arg = 0); //------------------------------------------------------------------ diff --git a/lldb/include/lldb/Expression/ClangUserExpression.h b/lldb/include/lldb/Expression/ClangUserExpression.h index 35871bcdf889..6135a245ad94 100644 --- a/lldb/include/lldb/Expression/ClangUserExpression.h +++ b/lldb/include/lldb/Expression/ClangUserExpression.h @@ -89,6 +89,11 @@ public: /// The execution context to use when looking up entities that /// are needed for parsing (locations of variables, etc.) /// + /// @param[in] discard_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] result /// A pointer to direct at the persistent variable in which the /// expression's result is stored. @@ -99,6 +104,7 @@ public: bool Execute (Stream &error_stream, ExecutionContext &exe_ctx, + bool discard_on_error, ClangExpressionVariable *&result); ThreadPlan * @@ -212,6 +218,7 @@ public: //------------------------------------------------------------------ static lldb::ValueObjectSP Evaluate (ExecutionContext &exe_ctx, + bool discard_on_error, const char *expr_cstr, const char *expr_prefix); diff --git a/lldb/include/lldb/Target/Thread.h b/lldb/include/lldb/Target/Thread.h index 00ef2075e7ee..6369b5bc32a2 100644 --- a/lldb/include/lldb/Target/Thread.h +++ b/lldb/include/lldb/Target/Thread.h @@ -570,6 +570,16 @@ public: void DiscardThreadPlans (bool force); + //------------------------------------------------------------------ + /// Discards the plans queued on the plan stack of the current thread up to and + /// including up_to_plan_sp. + // + // @param[in] up_to_plan_sp + // Discard all plans up to and including this one. + //------------------------------------------------------------------ + void + DiscardThreadPlansUpToPlan (lldb::ThreadPlanSP &up_to_plan_sp); + //------------------------------------------------------------------ /// Prints the current plan stack. /// diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj index 6e0396bb59de..c2b903c7f4e3 100644 --- a/lldb/lldb.xcodeproj/project.pbxproj +++ b/lldb/lldb.xcodeproj/project.pbxproj @@ -2911,10 +2911,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = ( - x86_64, - i386, - ); + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( diff --git a/lldb/source/API/SBFrame.cpp b/lldb/source/API/SBFrame.cpp index 1d9080825d14..c0f2f558c67f 100644 --- a/lldb/source/API/SBFrame.cpp +++ b/lldb/source/API/SBFrame.cpp @@ -560,11 +560,12 @@ SBFrame::EvaluateExpression (const char *expr) m_opaque_sp->CalculateExecutionContext (exe_ctx); const char *prefix = NULL; + const bool discard_on_error = true; if (exe_ctx.target) prefix = exe_ctx.target->GetExpressionPrefixContentsAsCString(); - *expr_result = ClangUserExpression::Evaluate (exe_ctx, expr, prefix); + *expr_result = ClangUserExpression::Evaluate (exe_ctx, discard_on_error, expr, prefix); } if (log) diff --git a/lldb/source/Commands/CommandObjectExpression.cpp b/lldb/source/Commands/CommandObjectExpression.cpp index 2045c59d058c..436b2e7540c6 100644 --- a/lldb/source/Commands/CommandObjectExpression.cpp +++ b/lldb/source/Commands/CommandObjectExpression.cpp @@ -75,6 +75,13 @@ CommandObjectExpression::CommandOptions::SetOptionValue (int option_idx, const c case 'o': print_object = true; break; + + case 'u': + bool success; + unwind_on_error = Args::StringToBoolean(option_arg, true, &success); + if (!success) + error.SetErrorStringWithFormat("Could not convert \"%s\" to a boolean value.", option_arg); + break; default: error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option); @@ -92,6 +99,7 @@ CommandObjectExpression::CommandOptions::ResetOptionValues () debug = false; format = eFormatDefault; print_object = false; + unwind_on_error = true; show_types = true; show_summary = true; } @@ -223,7 +231,7 @@ CommandObjectExpression::EvaluateExpression if (m_exe_ctx.target) prefix = m_exe_ctx.target->GetExpressionPrefixContentsAsCString(); - lldb::ValueObjectSP result_valobj_sp (ClangUserExpression::Evaluate (m_exe_ctx, expr, prefix)); + lldb::ValueObjectSP result_valobj_sp (ClangUserExpression::Evaluate (m_exe_ctx, m_options.unwind_on_error, expr, prefix)); assert (result_valobj_sp.get()); if (result_valobj_sp->GetError().Success()) { @@ -347,7 +355,8 @@ CommandObjectExpression::CommandOptions::g_option_table[] = //{ LLDB_OPT_SET_ALL, false, "language", 'l', required_argument, NULL, 0, "[c|c++|objc|objc++]", "Sets the language to use when parsing the expression."}, //{ LLDB_OPT_SET_1, false, "format", 'f', required_argument, NULL, 0, "[ [bool|b] | [bin] | [char|c] | [oct|o] | [dec|i|d|u] | [hex|x] | [float|f] | [cstr|s] ]", "Specify the format that the expression output should use."}, { LLDB_OPT_SET_1, false, "format", 'f', required_argument, NULL, 0, eArgTypeExprFormat, "Specify the format that the expression output should use."}, -{ LLDB_OPT_SET_2, false, "object-description", 'o', no_argument, NULL, 0, eArgTypeNone, "Print the object description of the value resulting from the expression"}, +{ LLDB_OPT_SET_2, false, "object-description", 'o', no_argument, NULL, 0, eArgTypeNone, "Print the object description of the value resulting from the expression."}, +{ LLDB_OPT_SET_ALL, false, "unwind-on-error", 'u', required_argument, NULL, 0, eArgTypeBoolean, "Clean up program state if the expression causes a crash, breakpoint hit or signal."}, { LLDB_OPT_SET_ALL, false, "debug", 'g', no_argument, NULL, 0, eArgTypeNone, "Enable verbose debug logging of the expression parsing and evaluation."}, { LLDB_OPT_SET_ALL, false, "use-ir", 'i', no_argument, NULL, 0, eArgTypeNone, "[Temporary] Instructs the expression evaluator to use IR instead of ASTs."}, { 0, false, NULL, 0, 0, NULL, NULL, eArgTypeNone, NULL } diff --git a/lldb/source/Commands/CommandObjectExpression.h b/lldb/source/Commands/CommandObjectExpression.h index a15454934db4..9cbdf34f570c 100644 --- a/lldb/source/Commands/CommandObjectExpression.h +++ b/lldb/source/Commands/CommandObjectExpression.h @@ -51,6 +51,7 @@ public: lldb::Format format; bool debug; bool print_object; + bool unwind_on_error; bool show_types; bool show_summary; }; diff --git a/lldb/source/Expression/ClangFunction.cpp b/lldb/source/Expression/ClangFunction.cpp index 0ded1909bbc1..52cfab090a83 100644 --- a/lldb/source/Expression/ClangFunction.cpp +++ b/lldb/source/Expression/ClangFunction.cpp @@ -365,7 +365,13 @@ ClangFunction::InsertFunction (ExecutionContext &exe_ctx, lldb::addr_t &args_add } ThreadPlan * -ClangFunction::GetThreadPlanToCallFunction (ExecutionContext &exe_ctx, lldb::addr_t func_addr, lldb::addr_t &args_addr, Stream &errors, bool stop_others, bool discard_on_error, lldb::addr_t *this_arg) +ClangFunction::GetThreadPlanToCallFunction (ExecutionContext &exe_ctx, + lldb::addr_t func_addr, + lldb::addr_t &args_addr, + Stream &errors, + bool stop_others, + bool discard_on_error, + lldb::addr_t *this_arg) { // FIXME: Use the errors Stream for better error reporting. @@ -441,7 +447,9 @@ ClangFunction::ExecuteFunction(ExecutionContext &exe_ctx, Stream &errors, Value ClangFunction::ExecutionResults ClangFunction::ExecuteFunction(ExecutionContext &exe_ctx, Stream &errors, bool stop_others, Value &results) { - return ExecuteFunction (exe_ctx, NULL, errors, stop_others, NULL, false, results); + const bool try_all_threads = false; + const bool discard_on_error = true; + return ExecuteFunction (exe_ctx, NULL, errors, stop_others, NULL, try_all_threads, discard_on_error, results); } ClangFunction::ExecutionResults @@ -452,7 +460,10 @@ ClangFunction::ExecuteFunction( bool try_all_threads, Value &results) { - return ExecuteFunction (exe_ctx, NULL, errors, true, single_thread_timeout_usec, try_all_threads, results); + const bool stop_others = true; + const bool discard_on_error = true; + return ExecuteFunction (exe_ctx, NULL, errors, stop_others, single_thread_timeout_usec, + try_all_threads, discard_on_error, results); } // This is the static function @@ -463,6 +474,7 @@ ClangFunction::ExecuteFunction ( lldb::addr_t &void_arg, bool stop_others, bool try_all_threads, + bool discard_on_error, uint32_t single_thread_timeout_usec, Stream &errors, lldb::addr_t *this_arg) @@ -488,8 +500,9 @@ ClangFunction::ExecuteFunction ( } ClangFunction::ExecutionResults return_value = eExecutionSetupError; - - lldb::ThreadPlanSP call_plan_sp(ClangFunction::GetThreadPlanToCallFunction(exe_ctx, function_address, void_arg, errors, stop_others, false, this_arg)); + lldb::ThreadPlanSP call_plan_sp(ClangFunction::GetThreadPlanToCallFunction(exe_ctx, function_address, void_arg, + errors, stop_others, discard_on_error, + this_arg)); ThreadPlanCallFunction *call_plan_ptr = static_cast (call_plan_sp.get()); @@ -682,6 +695,10 @@ ClangFunction::ExecuteFunction ( log->Printf("Execution interrupted: %s %s", s.GetData(), event_explanation); } + if (discard_on_error && call_plan_sp) + { + exe_ctx.thread->DiscardThreadPlansUpToPlan (call_plan_sp); + } return_value = eExecutionInterrupted; break; } @@ -718,7 +735,8 @@ ClangFunction::ExecuteFunction( Stream &errors, bool stop_others, uint32_t single_thread_timeout_usec, - bool try_all_threads, + bool try_all_threads, + bool discard_on_error, Value &results) { using namespace clang; @@ -741,7 +759,7 @@ ClangFunction::ExecuteFunction( } return_value = ClangFunction::ExecuteFunction(exe_ctx, m_wrapper_function_addr, args_addr, stop_others, - try_all_threads, single_thread_timeout_usec, errors); + try_all_threads, discard_on_error, single_thread_timeout_usec, errors); if (args_addr_ptr != NULL) *args_addr_ptr = args_addr; diff --git a/lldb/source/Expression/ClangUserExpression.cpp b/lldb/source/Expression/ClangUserExpression.cpp index e75c323912ce..87bf733605eb 100644 --- a/lldb/source/Expression/ClangUserExpression.cpp +++ b/lldb/source/Expression/ClangUserExpression.cpp @@ -357,6 +357,7 @@ ClangUserExpression::FinalizeJITExecution (Stream &error_stream, bool ClangUserExpression::Execute (Stream &error_stream, ExecutionContext &exe_ctx, + bool discard_on_error, ClangExpressionVariable *&result) { if (m_dwarf_opcodes.get()) @@ -375,12 +376,15 @@ ClangUserExpression::Execute (Stream &error_stream, PrepareToExecuteJITExpression (error_stream, exe_ctx, struct_address, object_ptr); + const bool stop_others = true; + const bool try_all_threads = true; ClangFunction::ExecutionResults execution_result = ClangFunction::ExecuteFunction (exe_ctx, m_jit_addr, struct_address, - true, - true, + stop_others, + try_all_threads, + discard_on_error, 10000000, error_stream, (m_needs_object_ptr ? &object_ptr : NULL)); @@ -430,9 +434,9 @@ ClangUserExpression::DwarfOpcodeStream () return *m_dwarf_opcodes.get(); } - lldb::ValueObjectSP ClangUserExpression::Evaluate (ExecutionContext &exe_ctx, + bool discard_on_error, const char *expr_cstr, const char *expr_prefix) { @@ -479,7 +483,7 @@ ClangUserExpression::Evaluate (ExecutionContext &exe_ctx, error_stream.GetString().clear(); - if (!user_expression.Execute (error_stream, exe_ctx, expr_result)) + if (!user_expression.Execute (error_stream, exe_ctx, discard_on_error, expr_result)) { if (error_stream.GetString().empty()) error.SetErrorString ("expression failed to execute, unknown error"); diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp index 0556f10c4fcd..863bb1b885e9 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp @@ -118,8 +118,12 @@ AppleObjCRuntime::GetObjectDescription (Stream &str, Value &value, ExecutionCont 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; + ClangFunction::ExecutionResults results - = func.ExecuteFunction(exe_ctx, &wrapper_struct_addr, error_stream, true, 1000, true, ret); + = func.ExecuteFunction(exe_ctx, &wrapper_struct_addr, error_stream, stop_others, 1000, try_all_threads, unwind_on_error, ret); if (results != ClangFunction::eExecutionCompleted) { str.Printf("Error evaluating Print Object function: %d.\n", results); diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp index e786da9e1456..4a91a28513cc 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp @@ -120,8 +120,12 @@ AppleObjCRuntimeV1::GetObjectDescription (Stream &str, Value &value, ExecutionCo 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; + ClangFunction::ExecutionResults results - = func.ExecuteFunction(exe_ctx, &wrapper_struct_addr, error_stream, true, 1000, true, ret); + = func.ExecuteFunction(exe_ctx, &wrapper_struct_addr, error_stream, stop_others, 1000, try_all_threads, unwind_on_error, ret); if (results != ClangFunction::eExecutionCompleted) { str.Printf("Error evaluating Print Object function: %d.\n", results); diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp index 17280090bff4..247e42edc687 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp @@ -126,8 +126,13 @@ AppleObjCRuntimeV2::GetObjectDescription (Stream &str, Value &value, ExecutionCo lldb::addr_t wrapper_struct_addr = LLDB_INVALID_ADDRESS; func.InsertFunction(exe_ctx, wrapper_struct_addr, error_stream); + const bool stop_others = true; + const bool try_all_threads = true; + const bool discard_on_error = true; + ClangFunction::ExecutionResults results - = func.ExecuteFunction(exe_ctx, &wrapper_struct_addr, error_stream, true, 1000, true, ret); + = func.ExecuteFunction(exe_ctx, &wrapper_struct_addr, error_stream, stop_others, 1000, + try_all_threads, discard_on_error, ret); if (results != ClangFunction::eExecutionCompleted) { str.Printf("Error evaluating Print Object function: %d.\n", results); diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index fa7ac71c89e0..d544a4f61ba7 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -505,13 +505,13 @@ Process::LoadImage (const FileSpec &image_spec, Error &error) { ExecutionContext exe_ctx; frame_sp->CalculateExecutionContext (exe_ctx); - + bool unwind_on_error = true; StreamString expr; char path[PATH_MAX]; image_spec.GetPath(path, sizeof(path)); expr.Printf("dlopen (\"%s\", 2)", path); const char *prefix = "extern \"C\" void* dlopen (const char *path, int mode);\n"; - lldb::ValueObjectSP result_valobj_sp (ClangUserExpression::Evaluate (exe_ctx, expr.GetData(), prefix)); + lldb::ValueObjectSP result_valobj_sp (ClangUserExpression::Evaluate (exe_ctx, unwind_on_error, expr.GetData(), prefix)); if (result_valobj_sp->GetError().Success()) { Scalar scalar; @@ -571,11 +571,11 @@ Process::UnloadImage (uint32_t image_token) { ExecutionContext exe_ctx; frame_sp->CalculateExecutionContext (exe_ctx); - + bool unwind_on_error = true; StreamString expr; expr.Printf("dlclose ((void *)0x%llx)", image_addr); const char *prefix = "extern \"C\" int dlclose(void* handle);\n"; - lldb::ValueObjectSP result_valobj_sp (ClangUserExpression::Evaluate (exe_ctx, expr.GetData(), prefix)); + lldb::ValueObjectSP result_valobj_sp (ClangUserExpression::Evaluate (exe_ctx, unwind_on_error, expr.GetData(), prefix)); if (result_valobj_sp->GetError().Success()) { Scalar scalar; diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp index 9bd7e76b8e03..231dc0332101 100644 --- a/lldb/source/Target/Thread.cpp +++ b/lldb/source/Target/Thread.cpp @@ -489,15 +489,50 @@ Thread::QueueThreadPlan (ThreadPlanSP &thread_plan_sp, bool abort_other_plans) PushPlan (thread_plan_sp); } +void +Thread::DiscardThreadPlansUpToPlan (lldb::ThreadPlanSP &up_to_plan_sp) +{ + Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP); + if (log) + { + log->Printf("Discarding thread plans for thread tid = 0x%4.4x, up to %p", GetID(), up_to_plan_sp.get()); + } + + int stack_size = m_plan_stack.size(); + + // If the input plan is NULL, discard all plans. Otherwise make sure this plan is in the + // stack, and if so discard up to and including it. + + if (up_to_plan_sp.get() == NULL) + { + for (int i = stack_size - 1; i > 0; i--) + DiscardPlan(); + } + else + { + bool found_it = false; + for (int i = stack_size - 1; i > 0; i--) + { + if (m_plan_stack[i] == up_to_plan_sp) + found_it = true; + } + if (found_it) + { + bool last_one = false; + for (int i = stack_size - 1; i > 0 && !last_one ; i--) + { + if (GetCurrentPlan() == up_to_plan_sp.get()) + last_one = true; + DiscardPlan(); + } + } + } + return; +} + void Thread::DiscardThreadPlans(bool force) { - // FIXME: It is not always safe to just discard plans. Some, like the step over - // breakpoint trap can't be discarded in general (though you can if you plan to - // force a return from a function, for instance. - // For now I'm just not clearing immediate plans, but I need a way for plans to - // say they really need to be kept on, and then a way to override that. Humm... - Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP); if (log) {