Moved the code in ClangUserExpression that set up & ran the thread plan with timeouts, and restarting with all threads into a utility function in Process. This required a bunch of renaming.
Added a ThreadPlanCallUserExpression that differs from ThreadPlanCallFunction in that it holds onto a shared pointer to its ClangUserExpression so that can't go away before the thread plan is done using it.
Fixed the stop message when you hit a breakpoint while running a user expression so it is more obvious what has happened.
git-svn-id: https://llvm.org/svn/llvm-project/llvdb/trunk@120386 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Expression/ClangUserExpression.cpp b/source/Expression/ClangUserExpression.cpp
index 3e4827b..993b780 100644
--- a/source/Expression/ClangUserExpression.cpp
+++ b/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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
if (result_valobj_sp.get() == NULL)
result_valobj_sp.reset (new ValueObjectConstResult (error));
- return result_valobj_sp;
+ return execution_results;
}