Index: include/lldb/Core/Debugger.h =================================================================== --- include/lldb/Core/Debugger.h +++ include/lldb/Core/Debugger.h @@ -192,7 +192,8 @@ lldb::StreamFileSP &out, lldb::StreamFileSP &err); - void PushIOHandler(const lldb::IOHandlerSP &reader_sp); + void PushIOHandler(const lldb::IOHandlerSP &reader_sp, + bool cancel_top_handler = true); bool PopIOHandler(const lldb::IOHandlerSP &reader_sp); Index: include/lldb/Target/Process.h =================================================================== --- include/lldb/Target/Process.h +++ include/lldb/Target/Process.h @@ -402,7 +402,8 @@ public: ProcessModID() : m_stop_id(0), m_last_natural_stop_id(0), m_resume_id(0), m_memory_id(0), - m_last_user_expression_resume(0), m_running_user_expression(false) {} + m_last_user_expression_resume(0), m_running_user_expression(false), + m_running_utility_function(0) {} ProcessModID(const ProcessModID &rhs) : m_stop_id(rhs.m_stop_id), m_memory_id(rhs.m_memory_id) {} @@ -431,6 +432,10 @@ m_last_user_expression_resume = m_resume_id; } + bool IsRunningUtilityFunction() const { + return m_running_utility_function > 0; + } + uint32_t GetStopID() const { return m_stop_id; } uint32_t GetLastNaturalStopID() const { return m_last_natural_stop_id; } uint32_t GetMemoryID() const { return m_memory_id; } @@ -467,6 +472,17 @@ m_running_user_expression--; } + void SetRunningUtilityFunction(bool on) { + if (on) + m_running_utility_function++; + else { + assert(m_running_utility_function > 0 && + "Called SetRunningUtilityFunction(false) without calling " + "SetRunningUtilityFunction(true) before?"); + m_running_utility_function--; + } + } + void SetStopEventForLastNaturalStopID(lldb::EventSP event_sp) { m_last_natural_stop_event = event_sp; } @@ -484,6 +500,7 @@ uint32_t m_memory_id; uint32_t m_last_user_expression_resume; uint32_t m_running_user_expression; + uint32_t m_running_utility_function; lldb::EventSP m_last_natural_stop_event; }; @@ -2554,6 +2571,7 @@ virtual bool StopNoticingNewThreads() { return true; } void SetRunningUserExpression(bool on); + void SetRunningUtilityFunction(bool on); //------------------------------------------------------------------ // lldb::ExecutionContextScope pure virtual functions @@ -3225,6 +3243,24 @@ DISALLOW_COPY_AND_ASSIGN(Process); }; +//------------------------------------------------------------------ +/// RAII guard that should be aquired when an utility function is called within +/// a given process. +//------------------------------------------------------------------ +class UtilityFunctionScope { + Process *m_process; + +public: + UtilityFunctionScope(Process *p) : m_process(p) { + if (m_process) + m_process->SetRunningUtilityFunction(true); + } + ~UtilityFunctionScope() { + if (m_process) + m_process->SetRunningUtilityFunction(false); + } +}; + } // namespace lldb_private #endif // liblldb_Process_h_ Index: include/lldb/Target/Target.h =================================================================== --- include/lldb/Target/Target.h +++ include/lldb/Target/Target.h @@ -375,6 +375,10 @@ bool GetAutoApplyFixIts() const { return m_auto_apply_fixits; } + bool IsForUtilityExpr() const { return m_running_utility_expression; } + + void SetIsForUtilityExpr(bool b) { m_running_utility_expression = b; } + private: ExecutionPolicy m_execution_policy = default_execution_policy; lldb::LanguageType m_language = lldb::eLanguageTypeUnknown; @@ -392,6 +396,10 @@ bool m_ansi_color_errors = false; bool m_result_is_internal = false; bool m_auto_apply_fixits = true; + /// True if the executed code should be treated as utility code that is only + /// used by LLDB internally. + bool m_running_utility_expression = false; + lldb::DynamicValueType m_use_dynamic = lldb::eNoDynamicValues; Timeout m_timeout = default_timeout; Timeout m_one_thread_timeout = llvm::None; Index: source/Core/Debugger.cpp =================================================================== --- source/Core/Debugger.cpp +++ source/Core/Debugger.cpp @@ -1080,7 +1080,8 @@ } } -void Debugger::PushIOHandler(const IOHandlerSP &reader_sp) { +void Debugger::PushIOHandler(const IOHandlerSP &reader_sp, + bool cancel_top_handler) { if (!reader_sp) return; @@ -1101,7 +1102,8 @@ // this new input reader take over if (top_reader_sp) { top_reader_sp->Deactivate(); - top_reader_sp->Cancel(); + if (cancel_top_handler) + top_reader_sp->Cancel(); } } Index: source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp =================================================================== --- source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp +++ source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp @@ -167,6 +167,7 @@ options.SetStopOthers(true); options.SetIgnoreBreakpoints(true); options.SetTimeout(g_po_function_timeout); + options.SetIsForUtilityExpr(true); ExpressionResults results = m_print_object_caller_up->ExecuteFunction( exe_ctx, &wrapper_struct_addr, options, diagnostics, ret); Index: source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp =================================================================== --- source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp +++ source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp @@ -1409,6 +1409,7 @@ options.SetStopOthers(true); options.SetIgnoreBreakpoints(true); options.SetTimeout(g_utility_function_timeout); + options.SetIsForUtilityExpr(true); Value return_value; return_value.SetValueType(Value::eValueTypeScalar); @@ -1659,6 +1660,7 @@ options.SetStopOthers(true); options.SetIgnoreBreakpoints(true); options.SetTimeout(g_utility_function_timeout); + options.SetIsForUtilityExpr(true); Value return_value; return_value.SetValueType(Value::eValueTypeScalar); Index: source/Plugins/Platform/POSIX/PlatformPOSIX.cpp =================================================================== --- source/Plugins/Platform/POSIX/PlatformPOSIX.cpp +++ source/Plugins/Platform/POSIX/PlatformPOSIX.cpp @@ -1244,7 +1244,8 @@ options.SetTrapExceptions(false); // dlopen can't throw exceptions, so // don't do the work to trap them. options.SetTimeout(std::chrono::seconds(2)); - + options.SetIsForUtilityExpr(true); + Value return_value; // Fetch the clang types we will need: ClangASTContext *ast = process->GetTarget().GetScratchClangASTContext(); Index: source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp =================================================================== --- source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp +++ source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp @@ -340,6 +340,7 @@ options.SetStopOthers(true); options.SetTimeout(std::chrono::milliseconds(500)); options.SetTryAllThreads(false); + options.SetIsForUtilityExpr(true); thread.CalculateExecutionContext(exe_ctx); if (!m_get_item_info_impl_code) { Index: source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp =================================================================== --- source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp +++ source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp @@ -349,6 +349,7 @@ options.SetStopOthers(true); options.SetTimeout(std::chrono::milliseconds(500)); options.SetTryAllThreads(false); + options.SetIsForUtilityExpr(true); thread.CalculateExecutionContext(exe_ctx); if (get_pending_items_caller == NULL) { Index: source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp =================================================================== --- source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp +++ source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp @@ -354,6 +354,7 @@ options.SetStopOthers(true); options.SetTimeout(std::chrono::milliseconds(500)); options.SetTryAllThreads(false); + options.SetIsForUtilityExpr(true); thread.CalculateExecutionContext(exe_ctx); ExpressionResults func_call_ret; Index: source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp =================================================================== --- source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp +++ source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp @@ -351,6 +351,7 @@ options.SetStopOthers(true); options.SetTimeout(std::chrono::milliseconds(500)); options.SetTryAllThreads(false); + options.SetIsForUtilityExpr(true); thread.CalculateExecutionContext(exe_ctx); if (!m_get_thread_item_info_impl_code) { Index: source/Target/Process.cpp =================================================================== --- source/Target/Process.cpp +++ source/Target/Process.cpp @@ -1729,6 +1729,10 @@ m_mod_id.SetRunningUserExpression(on); } +void Process::SetRunningUtilityFunction(bool on) { + m_mod_id.SetRunningUtilityFunction(on); +} + addr_t Process::GetImageInfoAddress() { return LLDB_INVALID_ADDRESS; } const lldb::ABISP &Process::GetABI() { @@ -4685,7 +4689,12 @@ log->Printf("Process::%s pushing IO handler", __FUNCTION__); io_handler_sp->SetIsDone(false); - GetTarget().GetDebugger().PushIOHandler(io_handler_sp); + // If we evaluate an utility function, then we don't cancel the current + // IOHandler. Our IOHandler is non-interactive and shouldn't disturb the + // existing IOHandler that potentially provides the user interface (e.g. + // the IOHandler for Editline). + bool cancel_top_handler = !m_mod_id.IsRunningUtilityFunction(); + GetTarget().GetDebugger().PushIOHandler(io_handler_sp, cancel_top_handler); return true; } return false; @@ -4875,6 +4884,11 @@ thread_plan_sp->SetIsMasterPlan(true); thread_plan_sp->SetOkayToDiscard(false); + // If we are running some utility expression for LLDB, we now have to mark + // this in the ProcesModID of this process. This RAII takes care of marking + // and reverting the mark it once we are done running the expression. + UtilityFunctionScope util_scope(options.IsForUtilityExpr() ? this : nullptr); + if (m_private_state.GetValue() != eStateStopped) { diagnostic_manager.PutString( eDiagnosticSeverityError,