forked from OSchip/llvm-project
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:
parent
2bab7570f5
commit
399f1cafa6
|
@ -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);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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.
|
||||
///
|
||||
|
|
|
@ -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 = (
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -51,6 +51,7 @@ public:
|
|||
lldb::Format format;
|
||||
bool debug;
|
||||
bool print_object;
|
||||
bool unwind_on_error;
|
||||
bool show_types;
|
||||
bool show_summary;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue