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
This commit is contained in:
Jim Ingham 2010-11-05 19:25:48 +00:00
parent 2bab7570f5
commit 399f1cafa6
14 changed files with 136 additions and 34 deletions

View File

@ -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.
@ -275,6 +280,7 @@ public:
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);
@ -397,6 +403,7 @@ public:
bool stop_others,
uint32_t single_thread_timeout_usec,
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);
//------------------------------------------------------------------

View File

@ -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);

View File

@ -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.
///

View File

@ -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 = (

View File

@ -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)

View File

@ -76,6 +76,13 @@ CommandObjectExpression::CommandOptions::SetOptionValue (int option_idx, const c
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);
break;
@ -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 }

View File

@ -51,6 +51,7 @@ public:
lldb::Format format;
bool debug;
bool print_object;
bool unwind_on_error;
bool show_types;
bool show_summary;
};

View File

@ -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<ThreadPlanCallFunction *> (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;
}
@ -719,6 +736,7 @@ ClangFunction::ExecuteFunction(
bool stop_others,
uint32_t single_thread_timeout_usec,
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;

View File

@ -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");

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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)
{