diff options
-rw-r--r-- | lldb/include/lldb/Expression/ClangFunction.h | 74 | ||||
-rw-r--r-- | lldb/include/lldb/Expression/ClangUserExpression.h | 25 | ||||
-rw-r--r-- | lldb/include/lldb/Target/Process.h | 31 | ||||
-rw-r--r-- | lldb/include/lldb/Target/ThreadPlan.h | 9 | ||||
-rw-r--r-- | lldb/include/lldb/Target/ThreadPlanCallUserExpression.h | 59 | ||||
-rw-r--r-- | lldb/lldb.xcodeproj/project.pbxproj | 9 | ||||
-rw-r--r-- | lldb/source/API/SBFrame.cpp | 2 | ||||
-rw-r--r-- | lldb/source/Commands/CommandObjectCall.cpp | 6 | ||||
-rw-r--r-- | lldb/source/Commands/CommandObjectExpression.cpp | 14 | ||||
-rw-r--r-- | lldb/source/Expression/ClangFunction.cpp | 268 | ||||
-rw-r--r-- | lldb/source/Expression/ClangUserExpression.cpp | 111 | ||||
-rw-r--r-- | lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp | 4 | ||||
-rw-r--r-- | lldb/source/Target/Process.cpp | 287 | ||||
-rw-r--r-- | lldb/source/Target/ThreadPlan.cpp | 7 | ||||
-rw-r--r-- | lldb/source/Target/ThreadPlanCallUserExpression.cpp | 59 | ||||
-rw-r--r-- | lldb/source/Target/ThreadPlanRunToAddress.cpp | 9 | ||||
-rw-r--r-- | lldb/source/Target/ThreadPlanTestCondition.cpp | 5 |
17 files changed, 615 insertions, 364 deletions
diff --git a/lldb/include/lldb/Expression/ClangFunction.h b/lldb/include/lldb/Expression/ClangFunction.h index 357607ce7f5..2e1dabe71d0 100644 --- a/lldb/include/lldb/Expression/ClangFunction.h +++ b/lldb/include/lldb/Expression/ClangFunction.h @@ -21,9 +21,7 @@ #include "lldb/Core/Value.h" #include "lldb/Core/ValueObjectList.h" #include "lldb/Expression/ClangExpression.h" - -// Right now, this is just a toy. It calls a set function, with fixed -// values. +#include "lldb/Target/Process.h" namespace lldb_private { @@ -68,15 +66,6 @@ class ClangFunction : public ClangExpression { friend class ASTStructExtractor; public: - enum ExecutionResults - { - eExecutionSetupError, - eExecutionCompleted, - eExecutionDiscarded, - eExecutionInterrupted, - eExecutionTimedOut - }; - //------------------------------------------------------------------ /// Constructor /// @@ -275,15 +264,16 @@ public: /// @return /// Returns one of the ExecutionResults enum indicating function call status. //------------------------------------------------------------------ - static ExecutionResults ExecuteFunction (ExecutionContext &exe_ctx, - lldb::addr_t function_address, - 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 = 0); + static Process::ExecutionResults + ExecuteFunction (ExecutionContext &exe_ctx, + lldb::addr_t function_address, + 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 = 0); //------------------------------------------------------------------ /// Run the function this ClangFunction was created with. @@ -304,9 +294,10 @@ public: /// @return /// Returns one of the ExecutionResults enum indicating function call status. //------------------------------------------------------------------ - ExecutionResults ExecuteFunction(ExecutionContext &exe_ctx, - Stream &errors, - Value &results); + Process::ExecutionResults + ExecuteFunction(ExecutionContext &exe_ctx, + Stream &errors, + Value &results); //------------------------------------------------------------------ /// Run the function this ClangFunction was created with. @@ -329,9 +320,10 @@ public: /// @return /// Returns one of the ExecutionResults enum indicating function call status. //------------------------------------------------------------------ - ExecutionResults ExecuteFunction(ExecutionContext &exe_ctx, - Stream &errors, bool stop_others, - Value &results); + Process::ExecutionResults + ExecuteFunction(ExecutionContext &exe_ctx, + Stream &errors, bool stop_others, + Value &results); //------------------------------------------------------------------ /// Run the function this ClangFunction was created with. @@ -358,11 +350,12 @@ public: /// @return /// Returns one of the ExecutionResults enum indicating function call status. //------------------------------------------------------------------ - ExecutionResults ExecuteFunction(ExecutionContext &exe_ctx, - Stream &errors, - uint32_t single_thread_timeout_usec, - bool try_all_threads, - Value &results); + Process::ExecutionResults + ExecuteFunction(ExecutionContext &exe_ctx, + Stream &errors, + uint32_t single_thread_timeout_usec, + bool try_all_threads, + Value &results); //------------------------------------------------------------------ /// Run the function this ClangFunction was created with. @@ -397,14 +390,15 @@ public: /// @return /// Returns one of the ExecutionResults enum indicating function call status. //------------------------------------------------------------------ - ExecutionResults ExecuteFunction(ExecutionContext &exe_ctx, - lldb::addr_t *args_addr_ptr, - Stream &errors, - bool stop_others, - uint32_t single_thread_timeout_usec, - bool try_all_threads, - bool discard_on_error, - Value &results); + Process::ExecutionResults + ExecuteFunction(ExecutionContext &exe_ctx, + lldb::addr_t *args_addr_ptr, + Stream &errors, + bool stop_others, + uint32_t single_thread_timeout_usec, + bool try_all_threads, + bool discard_on_error, + Value &results); //------------------------------------------------------------------ /// [static] Get a thread plan to run a function. diff --git a/lldb/include/lldb/Expression/ClangUserExpression.h b/lldb/include/lldb/Expression/ClangUserExpression.h index 6ff92c45149..be4b5b093fd 100644 --- a/lldb/include/lldb/Expression/ClangUserExpression.h +++ b/lldb/include/lldb/Expression/ClangUserExpression.h @@ -26,6 +26,7 @@ #include "lldb/Expression/ClangExpression.h" #include "lldb/Expression/ClangExpressionVariable.h" #include "lldb/Symbol/TaggedASTType.h" +#include "lldb/Target/Process.h" #include "llvm/ExecutionEngine/JITMemoryManager.h" @@ -44,6 +45,8 @@ namespace lldb_private class ClangUserExpression : public ClangExpression { public: + typedef lldb::SharedPtr<ClangUserExpression>::Type ClangUserExpressionSP; + //------------------------------------------------------------------ /// Constructor /// @@ -100,18 +103,25 @@ public: /// 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] shared_ptr_to_me + /// This is a shared pointer to this ClangUserExpression. This is + /// needed because Execute can push a thread plan that will hold onto + /// the ClangUserExpression for an unbounded period of time. So you + /// need to give the thread plan a reference to this object that can + /// keep it alive. /// /// @param[in] result /// A pointer to direct at the persistent variable in which the /// expression's result is stored. /// /// @return - /// True on success; false otherwise. + /// A Process::Execution results value. //------------------------------------------------------------------ - bool + Process::ExecutionResults Execute (Stream &error_stream, ExecutionContext &exe_ctx, bool discard_on_error, + ClangUserExpressionSP &shared_ptr_to_me, ClangExpressionVariable *&result); ThreadPlan * @@ -222,12 +232,19 @@ public: /// @param[in] expr_prefix /// If non-NULL, a C string containing translation-unit level /// definitions to be included when the expression is parsed. + /// + /// @param[in/out] result_valobj_sp + /// If execution is successful, the result valobj is placed here. + /// + /// @result + /// A Process::ExecutionResults value. eExecutionCompleted for success. //------------------------------------------------------------------ - static lldb::ValueObjectSP + static Process::ExecutionResults Evaluate (ExecutionContext &exe_ctx, bool discard_on_error, const char *expr_cstr, - const char *expr_prefix); + const char *expr_prefix, + lldb::ValueObjectSP &result_valobj_sp); private: //------------------------------------------------------------------ diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index d318ca1f651..dd4950d07ad 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -255,6 +255,17 @@ public: eBroadcastInternalStateControlResume = (1<<2) }; + // We can execute Thread Plans on one thread with various fall-back modes (try other threads after timeout, etc.) + // This enum gives the result of thread plan executions. + typedef enum ExecutionResults + { + eExecutionSetupError, + eExecutionCompleted, + eExecutionDiscarded, + eExecutionInterrupted, + eExecutionTimedOut + } ExecutionResults; + //------------------------------------------------------------------ /// A notification structure that can be used by clients to listen /// for changes in a process's lifetime. @@ -1019,8 +1030,12 @@ public: //------------------------------------------------------------------ /// Halts a running process. /// - /// DoHalt should consume any process events that were delivered in - /// the process of implementing the halt. + /// DoHalt must produce one and only one stop StateChanged event if it actually + /// stops the process. If the stop happens through some natural event (for + /// instance a SIGSTOP), then forwarding that event will do. Otherwise, you must + /// generate the event manually. Note also, the private event thread is stopped when + /// DoHalt is run to prevent the events generated while halting to trigger + /// other state changes before the halt is complete. /// /// @param[out] caused_stop /// If true, then this Halt caused the stop, otherwise, the @@ -1167,6 +1182,18 @@ public: //------------------------------------------------------------------ lldb::StateType GetState (); + + ExecutionResults + RunThreadPlan (ExecutionContext &exe_ctx, + lldb::ThreadPlanSP &thread_plan_sp, + bool stop_others, + bool try_all_threads, + bool discard_on_error, + uint32_t single_thread_timeout_usec, + Stream &errors); + + static const char * + ExecutionResultAsCString (ExecutionResults result); protected: friend class CommandObjectProcessLaunch; diff --git a/lldb/include/lldb/Target/ThreadPlan.h b/lldb/include/lldb/Target/ThreadPlan.h index a0ae0e605e7..0cc6ec4405c 100644 --- a/lldb/include/lldb/Target/ThreadPlan.h +++ b/lldb/include/lldb/Target/ThreadPlan.h @@ -82,6 +82,11 @@ namespace lldb_private { // Next the "StopOthers" method of all the threads are polled, and if one thread's Current plan // returns "true" then only that thread gets to run. If more than one returns "true" the threads that want to run solo // get run one by one round robin fashion. Otherwise all are let to run. +// +// Note, the way StopOthers is implemented, the base class implementation just asks the previous plan. So if your plan +// has no opinion about whether it should run stopping others or not, just don't implement StopOthers, and the parent +// will be asked. +// // Finally, for each thread that is running, it run state is set to the return of RunState from the // thread's Current plan. // @@ -240,6 +245,7 @@ public: /// /// @param[in] error /// A stream to which to print some reason why the plan could not be created. + /// Can be NULL. /// /// @return /// \b true if the plan should be queued, \b false otherwise. @@ -281,6 +287,9 @@ public: virtual lldb::Vote ShouldReportRun (Event *event_ptr); + virtual void + SetStopOthers (bool new_value); + virtual bool StopOthers (); diff --git a/lldb/include/lldb/Target/ThreadPlanCallUserExpression.h b/lldb/include/lldb/Target/ThreadPlanCallUserExpression.h new file mode 100644 index 00000000000..5a0f7407f97 --- /dev/null +++ b/lldb/include/lldb/Target/ThreadPlanCallUserExpression.h @@ -0,0 +1,59 @@ +//===-- ThreadPlanCallUserExpression.h --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ThreadPlanCallUserExpression_h_ +#define liblldb_ThreadPlanCallUserExpression_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-private.h" +#include "lldb/Expression/ClangUserExpression.h" +#include "lldb/Target/Thread.h" +#include "lldb/Target/ThreadPlan.h" +#include "lldb/Target/ThreadPlanCallFunction.h" + +namespace lldb_private { + +class ThreadPlanCallUserExpression : public ThreadPlanCallFunction +{ +public: + ThreadPlanCallUserExpression (Thread &thread, + Address &function, + lldb::addr_t arg, + bool stop_other_threads, + bool discard_on_error, + lldb::addr_t *this_arg, + ClangUserExpression::ClangUserExpressionSP &user_expression_sp); + + virtual + ~ThreadPlanCallUserExpression (); + + virtual void + GetDescription (Stream *s, lldb::DescriptionLevel level); + + virtual void + WillPop () + { + if (m_user_expression_sp) + m_user_expression_sp.reset(); + } + +protected: +private: + ClangUserExpression::ClangUserExpressionSP m_user_expression_sp; // This is currently just used to ensure the + // User expression the initiated this ThreadPlan + // lives as long as the thread plan does. + DISALLOW_COPY_AND_ASSIGN (ThreadPlanCallUserExpression); +}; + +} // namespace lldb_private + +#endif // liblldb_ThreadPlanCallUserExpression_h_ diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj index 8c0f59080df..b4a3afe138f 100644 --- a/lldb/lldb.xcodeproj/project.pbxproj +++ b/lldb/lldb.xcodeproj/project.pbxproj @@ -341,6 +341,8 @@ 4C61978E12823D4300FAFFCC /* AppleObjCRuntimeV1.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C61978A12823D4300FAFFCC /* AppleObjCRuntimeV1.cpp */; }; 4C61978F12823D4300FAFFCC /* AppleObjCRuntimeV1.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C61978B12823D4300FAFFCC /* AppleObjCRuntimeV1.h */; }; 4C74CB6312288704006A8171 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C74CB6212288704006A8171 /* Carbon.framework */; }; + 4C7CF7E41295E10E00B4FBB5 /* ThreadPlanCallUserExpression.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C7CF7E31295E10E00B4FBB5 /* ThreadPlanCallUserExpression.h */; }; + 4C7CF7E61295E12B00B4FBB5 /* ThreadPlanCallUserExpression.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C7CF7E51295E12B00B4FBB5 /* ThreadPlanCallUserExpression.cpp */; }; 4CA9637B11B6E99A00780E28 /* CommandObjectApropos.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CA9637911B6E99A00780E28 /* CommandObjectApropos.cpp */; }; 4CB4430C12491DDA00C13DC2 /* LanguageRuntime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CB4430A12491DDA00C13DC2 /* LanguageRuntime.cpp */; }; 4CB4436C124944B000C13DC2 /* ItaniumABILanguageRuntime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CB4436A124944B000C13DC2 /* ItaniumABILanguageRuntime.cpp */; }; @@ -981,6 +983,8 @@ 4C61978A12823D4300FAFFCC /* AppleObjCRuntimeV1.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AppleObjCRuntimeV1.cpp; path = LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp; sourceTree = "<group>"; }; 4C61978B12823D4300FAFFCC /* AppleObjCRuntimeV1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppleObjCRuntimeV1.h; path = LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h; sourceTree = "<group>"; }; 4C74CB6212288704006A8171 /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = /System/Library/Frameworks/Carbon.framework; sourceTree = "<absolute>"; }; + 4C7CF7E31295E10E00B4FBB5 /* ThreadPlanCallUserExpression.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanCallUserExpression.h; path = include/lldb/Target/ThreadPlanCallUserExpression.h; sourceTree = "<group>"; }; + 4C7CF7E51295E12B00B4FBB5 /* ThreadPlanCallUserExpression.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadPlanCallUserExpression.cpp; path = source/Target/ThreadPlanCallUserExpression.cpp; sourceTree = "<group>"; }; 4C98D3DA118FB96F00E575D0 /* ClangFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClangFunction.cpp; path = source/Expression/ClangFunction.cpp; sourceTree = "<group>"; }; 4C98D3DB118FB96F00E575D0 /* RecordingMemoryManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RecordingMemoryManager.cpp; path = source/Expression/RecordingMemoryManager.cpp; sourceTree = "<group>"; }; 4C98D3E0118FB98F00E575D0 /* ClangFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangFunction.h; path = include/lldb/Expression/ClangFunction.h; sourceTree = "<group>"; }; @@ -2061,6 +2065,8 @@ 260C847110F50EFC00BB2B04 /* ThreadPlanBase.cpp */, 49EC3E9C118F90D400B1265E /* ThreadPlanCallFunction.h */, 49EC3E98118F90AC00B1265E /* ThreadPlanCallFunction.cpp */, + 4C7CF7E31295E10E00B4FBB5 /* ThreadPlanCallUserExpression.h */, + 4C7CF7E51295E12B00B4FBB5 /* ThreadPlanCallUserExpression.cpp */, 4C43DEF9110641F300E55CBF /* ThreadPlanShouldStopHere.h */, 4C43DEFA110641F300E55CBF /* ThreadPlanShouldStopHere.cpp */, 260C848010F50F0A00BB2B04 /* ThreadPlanStepInstruction.h */, @@ -2381,6 +2387,7 @@ 4C61978F12823D4300FAFFCC /* AppleObjCRuntimeV1.h in Headers */, 4CC2A14D128C7409001531C4 /* ThreadPlanTracer.h in Headers */, 266A42D8128E40040090CF7C /* ClangNamespaceDecl.h in Headers */, + 4C7CF7E41295E10E00B4FBB5 /* ThreadPlanCallUserExpression.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2452,7 +2459,6 @@ isa = PBXProject; buildConfigurationList = 1DEB91EF08733DB70010E9CD /* Build configuration list for PBXProject "lldb" */; compatibilityVersion = "Xcode 3.1"; - developmentRegion = English; hasScannedForEncodings = 1; knownRegions = ( en, @@ -2885,6 +2891,7 @@ 4C61978E12823D4300FAFFCC /* AppleObjCRuntimeV1.cpp in Sources */, 4CC2A149128C73ED001531C4 /* ThreadPlanTracer.cpp in Sources */, 266A42D6128E3FFB0090CF7C /* ClangNamespaceDecl.cpp in Sources */, + 4C7CF7E61295E12B00B4FBB5 /* ThreadPlanCallUserExpression.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/lldb/source/API/SBFrame.cpp b/lldb/source/API/SBFrame.cpp index 58faed6eea6..ed514fd1221 100644 --- a/lldb/source/API/SBFrame.cpp +++ b/lldb/source/API/SBFrame.cpp @@ -577,7 +577,7 @@ SBFrame::EvaluateExpression (const char *expr) if (exe_ctx.target) prefix = exe_ctx.target->GetExpressionPrefixContentsAsCString(); - *expr_result = ClangUserExpression::Evaluate (exe_ctx, discard_on_error, expr, prefix); + ClangUserExpression::Evaluate (exe_ctx, discard_on_error, expr, prefix, *expr_result); } if (log) diff --git a/lldb/source/Commands/CommandObjectCall.cpp b/lldb/source/Commands/CommandObjectCall.cpp index 9a1a7977d78..11dab9b710f 100644 --- a/lldb/source/Commands/CommandObjectCall.cpp +++ b/lldb/source/Commands/CommandObjectCall.cpp @@ -292,20 +292,20 @@ CommandObjectCall::Execute } } - ClangFunction::ExecutionResults return_status; + Process::ExecutionResults return_status; Value return_value; bool stop_others = true; return_status = clang_fun.ExecuteFunction(exe_ctx, errors, stop_others, NULL, return_value); // Now figure out what to do with the return value. - if (return_status == ClangFunction::eExecutionSetupError) + if (return_status == Process::eExecutionSetupError) { result.AppendErrorWithFormat("Error setting up function execution: '%s'.\n", errors.GetData()); result.SetStatus (eReturnStatusFailed); return false; } - else if (return_status != ClangFunction::eExecutionCompleted) + else if (return_status != Process::eExecutionCompleted) { result.AppendWarningWithFormat("Interrupted while calling function: '%s'.\n", errors.GetData()); result.SetStatus(eReturnStatusSuccessFinishNoResult); diff --git a/lldb/source/Commands/CommandObjectExpression.cpp b/lldb/source/Commands/CommandObjectExpression.cpp index 32236f8c917..c58f3f529c8 100644 --- a/lldb/source/Commands/CommandObjectExpression.cpp +++ b/lldb/source/Commands/CommandObjectExpression.cpp @@ -13,6 +13,7 @@ // C++ Includes // Other libraries and framework includes // Project includes +#include "CommandObjectThread.h" // For DisplayThreadInfo. #include "lldb/Interpreter/Args.h" #include "lldb/Core/Value.h" #include "lldb/Core/InputReader.h" @@ -242,7 +243,8 @@ CommandObjectExpression::EvaluateExpression if (m_exe_ctx.target) prefix = m_exe_ctx.target->GetExpressionPrefixContentsAsCString(); - lldb::ValueObjectSP result_valobj_sp (ClangUserExpression::Evaluate (m_exe_ctx, m_options.unwind_on_error, expr, prefix)); + lldb::ValueObjectSP result_valobj_sp; + Process::ExecutionResults execution_results = ClangUserExpression::Evaluate (m_exe_ctx, m_options.unwind_on_error, expr, prefix, result_valobj_sp); assert (result_valobj_sp.get()); if (result_valobj_sp->GetError().Success()) { @@ -267,6 +269,16 @@ CommandObjectExpression::EvaluateExpression else { error_stream.PutCString(result_valobj_sp->GetError().AsCString()); + // If we've been interrupted, display state information. + if (execution_results == Process::eExecutionInterrupted && !m_options.unwind_on_error) + { + if (m_exe_ctx.thread) + lldb_private::DisplayThreadInfo (m_interpreter, result->GetOutputStream(), m_exe_ctx.thread, false, true); + else + { + lldb_private::DisplayThreadsInfo (m_interpreter, &m_exe_ctx, *result, true, true); + } + } if (result) result->SetStatus (eReturnStatusFailed); } diff --git a/lldb/source/Expression/ClangFunction.cpp b/lldb/source/Expression/ClangFunction.cpp index 1eeeb006291..3dc31ec0b09 100644 --- a/lldb/source/Expression/ClangFunction.cpp +++ b/lldb/source/Expression/ClangFunction.cpp @@ -275,7 +275,7 @@ ClangFunction::WriteFunctionArguments (ExecutionContext &exe_ctx, Error error; using namespace clang; - ExecutionResults return_value = eExecutionSetupError; + Process::ExecutionResults return_value = Process::eExecutionSetupError; Process *process = exe_ctx.process; @@ -439,13 +439,13 @@ ClangFunction::DeallocateFunctionResults (ExecutionContext &exe_ctx, lldb::addr_ exe_ctx.process->DeallocateMemory(args_addr); } -ClangFunction::ExecutionResults +Process::ExecutionResults ClangFunction::ExecuteFunction(ExecutionContext &exe_ctx, Stream &errors, Value &results) { return ExecuteFunction (exe_ctx, errors, 1000, true, results); } -ClangFunction::ExecutionResults +Process::ExecutionResults ClangFunction::ExecuteFunction(ExecutionContext &exe_ctx, Stream &errors, bool stop_others, Value &results) { const bool try_all_threads = false; @@ -453,7 +453,7 @@ ClangFunction::ExecuteFunction(ExecutionContext &exe_ctx, Stream &errors, bool s return ExecuteFunction (exe_ctx, NULL, errors, stop_others, NULL, try_all_threads, discard_on_error, results); } -ClangFunction::ExecutionResults +Process::ExecutionResults ClangFunction::ExecuteFunction( ExecutionContext &exe_ctx, Stream &errors, @@ -468,7 +468,7 @@ ClangFunction::ExecuteFunction( } // This is the static function -ClangFunction::ExecutionResults +Process::ExecutionResults ClangFunction::ExecuteFunction ( ExecutionContext &exe_ctx, lldb::addr_t function_address, @@ -480,259 +480,19 @@ ClangFunction::ExecuteFunction ( Stream &errors, lldb::addr_t *this_arg) { - // Save this value for restoration of the execution context after we run - uint32_t tid = exe_ctx.thread->GetIndexID(); - - // N.B. Running the target may unset the currently selected thread and frame. We don't want to do that either, - // so we should arrange to reset them as well. - - lldb::ThreadSP selected_thread_sp = exe_ctx.process->GetThreadList().GetSelectedThread(); - lldb::StackFrameSP selected_frame_sp; - - uint32_t selected_tid; - if (selected_thread_sp != NULL) - { - selected_tid = selected_thread_sp->GetIndexID(); - selected_frame_sp = selected_thread_sp->GetSelectedFrame(); - } - else - { - selected_tid = LLDB_INVALID_THREAD_ID; - } - - ClangFunction::ExecutionResults return_value = eExecutionSetupError; 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<ThreadPlanCallFunction *> (call_plan_sp.get()); - if (call_plan_sp == NULL) - return eExecutionSetupError; + return Process::eExecutionSetupError; call_plan_sp->SetPrivate(true); - exe_ctx.thread->QueueThreadPlan(call_plan_sp, true); - - Listener listener("ClangFunction temporary listener"); - exe_ctx.process->HijackProcessEvents(&listener); - - Error resume_error = exe_ctx.process->Resume (); - if (!resume_error.Success()) - { - errors.Printf("Error resuming inferior: \"%s\".\n", resume_error.AsCString()); - exe_ctx.process->RestoreProcessEvents(); - return eExecutionSetupError; - } - - // We need to call the function synchronously, so spin waiting for it to return. - // If we get interrupted while executing, we're going to lose our context, and - // won't be able to gather the result at this point. - // We set the timeout AFTER the resume, since the resume takes some time and we - // don't want to charge that to the timeout. - - TimeValue* timeout_ptr = NULL; - TimeValue real_timeout; - - if (single_thread_timeout_usec != 0) - { - real_timeout = TimeValue::Now(); - real_timeout.OffsetWithMicroSeconds(single_thread_timeout_usec); - timeout_ptr = &real_timeout; - } - - lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - while (1) - { - lldb::EventSP event_sp; - lldb::StateType stop_state = lldb::eStateInvalid; - // Now wait for the process to stop again: - bool got_event = listener.WaitForEvent (timeout_ptr, event_sp); - - if (!got_event) - { - // Right now this is the only way to tell we've timed out... - // We should interrupt the process here... - // Not really sure what to do if Halt fails here... - if (log) - if (try_all_threads) - log->Printf ("Running function with timeout: %d timed out, trying with all threads enabled.", - single_thread_timeout_usec); - else - log->Printf ("Running function with timeout: %d timed out, abandoning execution.", - single_thread_timeout_usec); - - if (exe_ctx.process->Halt().Success()) - { - timeout_ptr = NULL; - if (log) - log->Printf ("Halt succeeded."); - - // Between the time that we got the timeout and the time we halted, but target - // might have actually completed the plan. If so, we're done. Note, I call WFE here with a short - // timeout to - got_event = listener.WaitForEvent(NULL, event_sp); - - if (got_event) - { - stop_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get()); - if (log) - { - log->Printf ("Stopped with event: %s", StateAsCString(stop_state)); - if (stop_state == lldb::eStateStopped && Process::ProcessEventData::GetInterruptedFromEvent(event_sp.get())) - log->Printf (" Event was the Halt interruption event."); - } - - if (exe_ctx.thread->IsThreadPlanDone (call_plan_sp.get())) - { - if (log) - log->Printf ("Even though we timed out, the call plan was done. Exiting wait loop."); - return_value = eExecutionCompleted; - break; - } - - if (try_all_threads - && (stop_state == lldb::eStateStopped && Process::ProcessEventData::GetInterruptedFromEvent (event_sp.get()))) - { - - call_plan_ptr->SetStopOthers (false); - if (log) - log->Printf ("About to resume."); - - exe_ctx.process->Resume(); - continue; - } - else - { - exe_ctx.process->RestoreProcessEvents (); - return eExecutionInterrupted; - } - } - } - } - - stop_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get()); - if (log) - log->Printf("Got event: %s.", StateAsCString(stop_state)); - - if (stop_state == lldb::eStateRunning || stop_state == lldb::eStateStepping) - continue; - - if (exe_ctx.thread->IsThreadPlanDone (call_plan_sp.get())) - { - return_value = eExecutionCompleted; - break; - } - else if (exe_ctx.thread->WasThreadPlanDiscarded (call_plan_sp.get())) - { - return_value = eExecutionDiscarded; - break; - } - else - { - if (log) - { - StreamString s; - event_sp->Dump (&s); - StreamString ts; - - const char *event_explanation; - - do - { - const Process::ProcessEventData *event_data = Process::ProcessEventData::GetEventDataFromEvent (event_sp.get()); - - if (!event_data) - { - event_explanation = "<no event data>"; - break; - } - - Process *process = event_data->GetProcessSP().get(); - - if (!process) - { - event_explanation = "<no process>"; - break; - } - - ThreadList &thread_list = process->GetThreadList(); - - uint32_t num_threads = thread_list.GetSize(); - uint32_t thread_index; - - ts.Printf("<%u threads> ", num_threads); - - for (thread_index = 0; - thread_index < num_threads; - ++thread_index) - { - Thread *thread = thread_list.GetThreadAtIndex(thread_index).get(); - - if (!thread) - { - ts.Printf("<?> "); - continue; - } - - ts.Printf("<"); - RegisterContext *register_context = thread->GetRegisterContext(); - - if (register_context) - ts.Printf("[ip 0x%llx] ", register_context->GetPC()); - else - ts.Printf("[ip unknown] "); - - lldb::StopInfoSP stop_info_sp = thread->GetStopInfo(); - if (stop_info_sp) - { - const char *stop_desc = stop_info_sp->GetDescription(); - if (stop_desc) - ts.PutCString (stop_desc); - } - ts.Printf(">"); - } - - event_explanation = ts.GetData(); - } while (0); - - if (log) - 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; - } - } - - if (exe_ctx.process) - exe_ctx.process->RestoreProcessEvents (); - - // Thread we ran the function in may have gone away because we ran the target - // Check that it's still there. - exe_ctx.thread = exe_ctx.process->GetThreadList().FindThreadByIndexID(tid, true).get(); - if (exe_ctx.thread) - exe_ctx.frame = exe_ctx.thread->GetStackFrameAtIndex(0).get(); - - // Also restore the current process'es selected frame & thread, since this function calling may - // be done behind the user's back. - - if (selected_tid != LLDB_INVALID_THREAD_ID) - { - if (exe_ctx.process->GetThreadList().SetSelectedThreadByIndexID (selected_tid)) - { - // We were able to restore the selected thread, now restore the frame: - exe_ctx.process->GetThreadList().GetSelectedThread()->SetSelectedFrame(selected_frame_sp.get()); - } - } - return return_value; + return exe_ctx.process->RunThreadPlan (exe_ctx, call_plan_sp, stop_others, try_all_threads, discard_on_error, + single_thread_timeout_usec, errors); } -ClangFunction::ExecutionResults +Process::ExecutionResults ClangFunction::ExecuteFunction( ExecutionContext &exe_ctx, lldb::addr_t *args_addr_ptr, @@ -744,7 +504,7 @@ ClangFunction::ExecuteFunction( Value &results) { using namespace clang; - ExecutionResults return_value = eExecutionSetupError; + Process::ExecutionResults return_value = Process::eExecutionSetupError; lldb::addr_t args_addr; @@ -754,12 +514,12 @@ ClangFunction::ExecuteFunction( args_addr = LLDB_INVALID_ADDRESS; if (CompileFunction(errors) != 0) - return eExecutionSetupError; + return Process::eExecutionSetupError; if (args_addr == LLDB_INVALID_ADDRESS) { if (!InsertFunction(exe_ctx, args_addr, errors)) - return eExecutionSetupError; + return Process::eExecutionSetupError; } return_value = ClangFunction::ExecuteFunction(exe_ctx, m_wrapper_function_addr, args_addr, stop_others, @@ -768,7 +528,7 @@ ClangFunction::ExecuteFunction( if (args_addr_ptr != NULL) *args_addr_ptr = args_addr; - if (return_value != eExecutionCompleted) + if (return_value != Process::eExecutionCompleted) return return_value; FetchFunctionResults(exe_ctx, args_addr, results); @@ -776,7 +536,7 @@ ClangFunction::ExecuteFunction( if (args_addr_ptr == NULL) DeallocateFunctionResults(exe_ctx, args_addr); - return eExecutionCompleted; + return Process::eExecutionCompleted; } clang::ASTConsumer * diff --git a/lldb/source/Expression/ClangUserExpression.cpp b/lldb/source/Expression/ClangUserExpression.cpp index 3e4827b9f0f..993b7805c41 100644 --- a/lldb/source/Expression/ClangUserExpression.cpp +++ b/lldb/source/Expression/ClangUserExpression.cpp @@ -33,6 +33,8 @@ #include "lldb/Target/Process.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/Target.h" +#include "lldb/Target/ThreadPlan.h" +#include "lldb/Target/ThreadPlanCallUserExpression.h" using namespace lldb_private; @@ -318,6 +320,9 @@ ClangUserExpression::GetThreadPlanToExecuteJITExpression (Stream &error_stream, PrepareToExecuteJITExpression (error_stream, exe_ctx, struct_address, object_ptr); + // FIXME: This should really return a ThreadPlanCallUserExpression, in order to make sure that we don't release the + // 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. return ClangFunction::GetThreadPlanToCallFunction (exe_ctx, m_jit_addr, struct_address, @@ -342,10 +347,11 @@ ClangUserExpression::FinalizeJITExecution (Stream &error_stream, return true; } -bool +Process::ExecutionResults ClangUserExpression::Execute (Stream &error_stream, ExecutionContext &exe_ctx, bool discard_on_error, + ClangUserExpression::ClangUserExpressionSP &shared_ptr_to_me, ClangExpressionVariable *&result) { if (m_dwarf_opcodes.get()) @@ -354,7 +360,7 @@ ClangUserExpression::Execute (Stream &error_stream, error_stream.Printf("We don't currently support executing DWARF expressions"); - return false; + return Process::eExecutionSetupError; } else if (m_jit_addr != LLDB_INVALID_ADDRESS) { @@ -366,50 +372,46 @@ ClangUserExpression::Execute (Stream &error_stream, const bool stop_others = true; const bool try_all_threads = true; - ClangFunction::ExecutionResults execution_result = - ClangFunction::ExecuteFunction (exe_ctx, - m_jit_addr, - struct_address, - stop_others, - try_all_threads, - discard_on_error, - 10000000, - error_stream, - (m_needs_object_ptr ? &object_ptr : NULL)); - if (execution_result != ClangFunction::eExecutionCompleted) + Address wrapper_address (NULL, m_jit_addr); + lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallUserExpression (*(exe_ctx.thread), wrapper_address, struct_address, + stop_others, discard_on_error, + (m_needs_object_ptr ? &object_ptr : NULL), + shared_ptr_to_me)); + if (call_plan_sp == NULL || !call_plan_sp->ValidatePlan (NULL)) + return Process::eExecutionSetupError; + + call_plan_sp->SetPrivate(true); + + uint32_t single_thread_timeout_usec = 10000000; + Process::ExecutionResults execution_result = + exe_ctx.process->RunThreadPlan (exe_ctx, call_plan_sp, stop_others, try_all_threads, discard_on_error, + single_thread_timeout_usec, error_stream); + + if (execution_result == Process::eExecutionInterrupted) { - const char *result_name; - - switch (execution_result) - { - case ClangFunction::eExecutionCompleted: - result_name = "eExecutionCompleted"; - break; - case ClangFunction::eExecutionDiscarded: - result_name = "eExecutionDiscarded"; - break; - case ClangFunction::eExecutionInterrupted: - result_name = "eExecutionInterrupted"; - break; - case ClangFunction::eExecutionSetupError: - result_name = "eExecutionSetupError"; - break; - case ClangFunction::eExecutionTimedOut: - result_name = "eExecutionTimedOut"; - break; - } - - error_stream.Printf ("Couldn't execute function; result was %s\n", result_name); - return false; + if (discard_on_error) + error_stream.Printf ("Expression execution was interrupted. The process has been returned to the state before execution."); + else + error_stream.Printf ("Expression execution was interrupted. The process has been left at the point where it was interrupted."); + + return execution_result; + } + else if (execution_result != Process::eExecutionCompleted) + { + error_stream.Printf ("Couldn't execute function; result was %s\n", Process::ExecutionResultAsCString (execution_result)); + return execution_result; } - return FinalizeJITExecution (error_stream, exe_ctx, result); + if (FinalizeJITExecution (error_stream, exe_ctx, result)) + return Process::eExecutionCompleted; + else + return Process::eExecutionSetupError; } else { error_stream.Printf("Expression can't be run; neither DWARF nor a JIT compiled function is present"); - return false; + return Process::eExecutionSetupError; } } @@ -422,18 +424,24 @@ ClangUserExpression::DwarfOpcodeStream () return *m_dwarf_opcodes.get(); } -lldb::ValueObjectSP +Process::ExecutionResults ClangUserExpression::Evaluate (ExecutionContext &exe_ctx, bool discard_on_error, const char *expr_cstr, - const char *expr_prefix) + const char *expr_prefix, + lldb::ValueObjectSP &result_valobj_sp) { Error error; - lldb::ValueObjectSP result_valobj_sp; + Process::ExecutionResults execution_results = Process::eExecutionSetupError; if (exe_ctx.process == NULL) - return result_valobj_sp; - + { + error.SetErrorString ("Must have a process to evaluate expressions."); + + result_valobj_sp.reset (new ValueObjectConstResult (error)); + return Process::eExecutionSetupError; + } + if (!exe_ctx.process->GetDynamicCheckers()) { DynamicCheckerFunctions *dynamic_checkers = new DynamicCheckerFunctions(); @@ -448,17 +456,17 @@ ClangUserExpression::Evaluate (ExecutionContext &exe_ctx, error.SetErrorString (install_errors.GetString().c_str()); result_valobj_sp.reset (new ValueObjectConstResult (error)); - return result_valobj_sp; + return Process::eExecutionSetupError; } exe_ctx.process->SetDynamicCheckers(dynamic_checkers); } - ClangUserExpression user_expression (expr_cstr, expr_prefix); - + ClangUserExpressionSP user_expression_sp (new ClangUserExpression (expr_cstr, expr_prefix)); + StreamString error_stream; - if (!user_expression.Parse (error_stream, exe_ctx, TypeFromUser(NULL, NULL))) + if (!user_expression_sp->Parse (error_stream, exe_ctx, TypeFromUser(NULL, NULL))) { if (error_stream.GetString().empty()) error.SetErrorString ("expression failed to parse, unknown error"); @@ -471,7 +479,12 @@ ClangUserExpression::Evaluate (ExecutionContext &exe_ctx, error_stream.GetString().clear(); - if (!user_expression.Execute (error_stream, exe_ctx, discard_on_error, expr_result)) + execution_results = user_expression_sp->Execute (error_stream, + exe_ctx, + discard_on_error, + user_expression_sp, + expr_result); + if (execution_results != Process::eExecutionCompleted) { if (error_stream.GetString().empty()) error.SetErrorString ("expression failed to execute, unknown error"); @@ -499,5 +512,5 @@ ClangUserExpression::Evaluate (ExecutionContext &exe_ctx, if (result_valobj_sp.get() == NULL) result_valobj_sp.reset (new ValueObjectConstResult (error)); - return result_valobj_sp; + return execution_results; } diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp index 6e4fdb71c5b..6c8302dbd5a 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp @@ -122,9 +122,9 @@ AppleObjCRuntime::GetObjectDescription (Stream &str, Value &value, ExecutionCont bool try_all_threads = true; bool stop_others = true; - ClangFunction::ExecutionResults results + Process::ExecutionResults results = func.ExecuteFunction(exe_ctx, &wrapper_struct_addr, error_stream, stop_others, 1000000, try_all_threads, unwind_on_error, ret); - if (results != ClangFunction::eExecutionCompleted) + if (results != Process::eExecutionCompleted) { str.Printf("Error evaluating Print Object function: %d.\n", results); return false; diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index cebec5bbd31..b025970a477 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -524,7 +524,8 @@ Process::LoadImage (const FileSpec &image_spec, Error &error) 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, unwind_on_error, expr.GetData(), prefix)); + lldb::ValueObjectSP result_valobj_sp; + ClangUserExpression::Evaluate (exe_ctx, unwind_on_error, expr.GetData(), prefix, result_valobj_sp); if (result_valobj_sp->GetError().Success()) { Scalar scalar; @@ -588,7 +589,8 @@ Process::UnloadImage (uint32_t image_token) 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, unwind_on_error, expr.GetData(), prefix)); + lldb::ValueObjectSP result_valobj_sp; + ClangUserExpression::Evaluate (exe_ctx, unwind_on_error, expr.GetData(), prefix, result_valobj_sp); if (result_valobj_sp->GetError().Success()) { Scalar scalar; @@ -1502,7 +1504,8 @@ Process::Halt () // Post any event we might have consumed. If all goes well, we will have // stopped the process, intercepted the event and set the interrupted - // bool in the event. + // bool in the event. Post it to the private event queue and that will end up + // correctly setting the state. if (event_sp) m_private_state_broadcaster.BroadcastEvent(event_sp); @@ -2281,6 +2284,284 @@ Process::UpdateInstanceName () } } +Process::ExecutionResults +Process::RunThreadPlan (ExecutionContext &exe_ctx, + lldb::ThreadPlanSP &thread_plan_sp, + bool stop_others, + bool try_all_threads, + bool discard_on_error, + uint32_t single_thread_timeout_usec, + Stream &errors) +{ + ExecutionResults return_value = eExecutionSetupError; + + // Save this value for restoration of the execution context after we run + uint32_t tid = exe_ctx.thread->GetIndexID(); + + // N.B. Running the target may unset the currently selected thread and frame. We don't want to do that either, + // so we should arrange to reset them as well. + + lldb::ThreadSP selected_thread_sp = exe_ctx.process->GetThreadList().GetSelectedThread(); + lldb::StackFrameSP selected_frame_sp; + + uint32_t selected_tid; + if (selected_thread_sp != NULL) + { + selected_tid = selected_thread_sp->GetIndexID(); + selected_frame_sp = selected_thread_sp->GetSelectedFrame(); + } + else + { + selected_tid = LLDB_INVALID_THREAD_ID; + } + + exe_ctx.thread->QueueThreadPlan(thread_plan_sp, true); + + Listener listener("ClangFunction temporary listener"); + exe_ctx.process->HijackProcessEvents(&listener); + + Error resume_error = exe_ctx.process->Resume (); + if (!resume_error.Success()) + { + errors.Printf("Error resuming inferior: \"%s\".\n", resume_error.AsCString()); + exe_ctx.process->RestoreProcessEvents(); + return Process::eExecutionSetupError; + } + + // We need to call the function synchronously, so spin waiting for it to return. + // If we get interrupted while executing, we're going to lose our context, and + // won't be able to gather the result at this point. + // We set the timeout AFTER the resume, since the resume takes some time and we + // don't want to charge that to the timeout. + + TimeValue* timeout_ptr = NULL; + TimeValue real_timeout; + + if (single_thread_timeout_usec != 0) + { + real_timeout = TimeValue::Now(); + real_timeout.OffsetWithMicroSeconds(single_thread_timeout_usec); + timeout_ptr = &real_timeout; + } + + lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); + while (1) + { + lldb::EventSP event_sp; + lldb::StateType stop_state = lldb::eStateInvalid; + // Now wait for the process to stop again: + bool got_event = listener.WaitForEvent (timeout_ptr, event_sp); + + if (!got_event) + { + // Right now this is the only way to tell we've timed out... + // We should interrupt the process here... + // Not really sure what to do if Halt fails here... + if (log) + if (try_all_threads) + log->Printf ("Running function with timeout: %d timed out, trying with all threads enabled.", + single_thread_timeout_usec); + else + log->Printf ("Running function with timeout: %d timed out, abandoning execution.", + single_thread_timeout_usec); + + if (exe_ctx.process->Halt().Success()) + { + timeout_ptr = NULL; + if (log) + log->Printf ("Halt succeeded."); + + // Between the time that we got the timeout and the time we halted, but target + // might have actually completed the plan. If so, we're done. Note, I call WFE here with a short + // timeout to + got_event = listener.WaitForEvent(NULL, event_sp); + + if (got_event) + { + stop_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get()); + if (log) + { + log->Printf ("Stopped with event: %s", StateAsCString(stop_state)); + if (stop_state == lldb::eStateStopped && Process::ProcessEventData::GetInterruptedFromEvent(event_sp.get())) + log->Printf (" Event was the Halt interruption event."); + } + + if (exe_ctx.thread->IsThreadPlanDone (thread_plan_sp.get())) + { + if (log) + log->Printf ("Even though we timed out, the call plan was done. Exiting wait loop."); + return_value = Process::eExecutionCompleted; + break; + } + + if (try_all_threads + && (stop_state == lldb::eStateStopped && Process::ProcessEventData::GetInterruptedFromEvent (event_sp.get()))) + { + + thread_plan_sp->SetStopOthers (false); + if (log) + log->Printf ("About to resume."); + + exe_ctx.process->Resume(); + continue; + } + else + { + exe_ctx.process->RestoreProcessEvents (); + return Process::eExecutionInterrupted; + } + } + } + } + + stop_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get()); + if (log) + log->Printf("Got event: %s.", StateAsCString(stop_state)); + + if (stop_state == lldb::eStateRunning || stop_state == lldb::eStateStepping) + continue; + + if (exe_ctx.thread->IsThreadPlanDone (thread_plan_sp.get())) + { + return_value = Process::eExecutionCompleted; + break; + } + else if (exe_ctx.thread->WasThreadPlanDiscarded (thread_plan_sp.get())) + { + return_value = Process::eExecutionDiscarded; + break; + } + else + { + if (log) + { + StreamString s; + event_sp->Dump (&s); + StreamString ts; + + const char *event_explanation; + + do + { + const Process::ProcessEventData *event_data = Process::ProcessEventData::GetEventDataFromEvent (event_sp.get()); + + if (!event_data) + { + event_explanation = "<no event data>"; + break; + } + + Process *process = event_data->GetProcessSP().get(); + + if (!process) + { + event_explanation = "<no process>"; + break; + } + + ThreadList &thread_list = process->GetThreadList(); + + uint32_t num_threads = thread_list.GetSize(); + uint32_t thread_index; + + ts.Printf("<%u threads> ", num_threads); + + for (thread_index = 0; + thread_index < num_threads; + ++thread_index) + { + Thread *thread = thread_list.GetThreadAtIndex(thread_index).get(); + + if (!thread) + { + ts.Printf("<?> "); + continue; + } + + ts.Printf("<"); + RegisterContext *register_context = thread->GetRegisterContext(); + + if (register_context) + ts.Printf("[ip 0x%llx] ", register_context->GetPC()); + else + ts.Printf("[ip unknown] "); + + lldb::StopInfoSP stop_info_sp = thread->GetStopInfo(); + if (stop_info_sp) + { + const char *stop_desc = stop_info_sp->GetDescription(); + if (stop_desc) + ts.PutCString (stop_desc); + } + ts.Printf(">"); + } + + event_explanation = ts.GetData(); + } while (0); + + if (log) + log->Printf("Execution interrupted: %s %s", s.GetData(), event_explanation); + } + + if (discard_on_error && thread_plan_sp) + { + exe_ctx.thread->DiscardThreadPlansUpToPlan (thread_plan_sp); + } + return_value = Process::eExecutionInterrupted; + break; + } + } + + if (exe_ctx.process) + exe_ctx.process->RestoreProcessEvents (); + + // Thread we ran the function in may have gone away because we ran the target + // Check that it's still there. + exe_ctx.thread = exe_ctx.process->GetThreadList().FindThreadByIndexID(tid, true).get(); + if (exe_ctx.thread) + exe_ctx.frame = exe_ctx.thread->GetStackFrameAtIndex(0).get(); + + // Also restore the current process'es selected frame & thread, since this function calling may + // be done behind the user's back. + + if (selected_tid != LLDB_INVALID_THREAD_ID) + { + if (exe_ctx.process->GetThreadList().SetSelectedThreadByIndexID (selected_tid)) + { + // We were able to restore the selected thread, now restore the frame: + exe_ctx.process->GetThreadList().GetSelectedThread()->SetSelectedFrame(selected_frame_sp.get()); + } + } + + return return_value; +} + +const char * +Process::ExecutionResultAsCString (ExecutionResults result) +{ + const char *result_name; + + switch (result) + { + case Process::eExecutionCompleted: + result_name = "eExecutionCompleted"; + break; + case Process::eExecutionDiscarded: + result_name = "eExecutionDiscarded"; + break; + case Process::eExecutionInterrupted: + result_name = "eExecutionInterrupted"; + break; + case Process::eExecutionSetupError: + result_name = "eExecutionSetupError"; + break; + case Process::eExecutionTimedOut: + result_name = "eExecutionTimedOut"; + break; + } + return result_name; +} + //-------------------------------------------------------------- // class Process::SettingsController //-------------------------------------------------------------- diff --git a/lldb/source/Target/ThreadPlan.cpp b/lldb/source/Target/ThreadPlan.cpp index 4d2d54b6137..8b6aedd839f 100644 --- a/lldb/source/Target/ThreadPlan.cpp +++ b/lldb/source/Target/ThreadPlan.cpp @@ -133,6 +133,13 @@ ThreadPlan::StopOthers () return prev_plan->StopOthers(); } +void +ThreadPlan::SetStopOthers (bool new_value) +{ + // SetStopOthers doesn't work up the hierarchy. You have to set the + // explicit ThreadPlan you want to affect. +} + bool ThreadPlan::WillResume (StateType resume_state, bool current_plan) { diff --git a/lldb/source/Target/ThreadPlanCallUserExpression.cpp b/lldb/source/Target/ThreadPlanCallUserExpression.cpp new file mode 100644 index 00000000000..fd022a26d55 --- /dev/null +++ b/lldb/source/Target/ThreadPlanCallUserExpression.cpp @@ -0,0 +1,59 @@ +//===-- ThreadPlanCallUserExpression.cpp ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Target/ThreadPlanCallUserExpression.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +#include "llvm/Support/MachO.h" +// Project includes +#include "lldb/lldb-private-log.h" +#include "lldb/Breakpoint/Breakpoint.h" +#include "lldb/Breakpoint/BreakpointLocation.h" +#include "lldb/Core/Address.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Stream.h" +#include "lldb/Expression/ClangUserExpression.h" +#include "lldb/Target/LanguageRuntime.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/StopInfo.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Target/ThreadPlanRunToAddress.h" + +using namespace lldb; +using namespace lldb_private; + +//---------------------------------------------------------------------- +// ThreadPlanCallUserExpression: Plan to call a single function +//---------------------------------------------------------------------- + +ThreadPlanCallUserExpression::ThreadPlanCallUserExpression (Thread &thread, + Address &function, + lldb::addr_t arg, + bool stop_other_threads, + bool discard_on_error, + lldb::addr_t *this_arg, + ClangUserExpression::ClangUserExpressionSP &user_expression_sp) : + ThreadPlanCallFunction (thread, function, arg, stop_other_threads, discard_on_error, this_arg), + m_user_expression_sp (user_expression_sp) +{ +} + +ThreadPlanCallUserExpression::~ThreadPlanCallUserExpression () +{ +} + +void +ThreadPlanCallUserExpression::GetDescription (Stream *s, lldb::DescriptionLevel level) +{ + ThreadPlanCallFunction::GetDescription (s, level); +} diff --git a/lldb/source/Target/ThreadPlanRunToAddress.cpp b/lldb/source/Target/ThreadPlanRunToAddress.cpp index f8df04e20b9..2dc9daa2e65 100644 --- a/lldb/source/Target/ThreadPlanRunToAddress.cpp +++ b/lldb/source/Target/ThreadPlanRunToAddress.cpp @@ -168,9 +168,12 @@ ThreadPlanRunToAddress::ValidatePlan (Stream *error) if (m_break_ids[i] == LLDB_INVALID_BREAK_ID) { all_bps_good = false; - error->Printf ("Could not set breakpoint for address: "); - error->Address (m_addresses[i], sizeof (addr_t)); - error->Printf ("\n"); + if (error) + { + error->Printf ("Could not set breakpoint for address: "); + error->Address (m_addresses[i], sizeof (addr_t)); + error->Printf ("\n"); + } } } return all_bps_good; diff --git a/lldb/source/Target/ThreadPlanTestCondition.cpp b/lldb/source/Target/ThreadPlanTestCondition.cpp index 0087dfc920f..b5f7db87f8d 100644 --- a/lldb/source/Target/ThreadPlanTestCondition.cpp +++ b/lldb/source/Target/ThreadPlanTestCondition.cpp @@ -64,7 +64,10 @@ ThreadPlanTestCondition::ValidatePlan (Stream *error) void ThreadPlanTestCondition::GetDescription (Stream *s, lldb::DescriptionLevel level) { - + if (m_expression) + s->Printf("Thread plan to test condition: \"%s\".", m_expression->GetUserText()); + else + s->Printf("Thread plan to test unspecified condition."); } bool |