This patch does a couple of things.

It completes the job of using EvaluateExpressionOptions consistently throughout
the inferior function calling mechanism in lldb begun in Greg's patch r194009. 

It removes a handful of alternate calls into the ClangUserExpression/ClangFunction/ThreadPlanCallFunction which
were there for convenience.  Using the EvaluateExpressionOptions removes the need for them.

Using that it gets the --debug option from Greg's patch to work cleanly.

It also adds another EvaluateExpressionOption to not trap exceptions when running expressions.  You shouldn't
use this option unless you KNOW your expression can't throw beyond itself.  This is:

<rdar://problem/15374885>

At present this is only available through the SB API's or python.

It fixes a bug where function calls would unset the ObjC & C++ exception breakpoints without checking whether
they were set by somebody else already.

llvm-svn: 194182
This commit is contained in:
Jim Ingham 2013-11-07 00:11:47 +00:00
parent bed356a9ea
commit 6fbc48bc42
36 changed files with 425 additions and 710 deletions

View File

@ -65,6 +65,12 @@ public:
void void
SetTryAllThreads (bool run_others = true); SetTryAllThreads (bool run_others = true);
bool
GetTrapExceptions () const;
void
SetTrapExceptions (bool trap_exceptions = true);
protected: protected:
SBExpressionOptions (lldb_private::EvaluateExpressionOptions &expression_options); SBExpressionOptions (lldb_private::EvaluateExpressionOptions &expression_options);

View File

@ -226,143 +226,6 @@ public:
ValueList &arg_values, ValueList &arg_values,
Stream &errors); Stream &errors);
//------------------------------------------------------------------
/// [Static] Execute a function, passing it a single void* parameter.
/// ClangFunction uses this to call the wrapper function.
///
/// @param[in] exe_ctx
/// The execution context to insert the function and its arguments
/// into.
///
/// @param[in] function_address
/// The address of the function in the target process.
///
/// @param[in] void_arg
/// The value of the void* parameter.
///
/// @param[in] stop_others
/// True if other threads should pause during execution.
///
/// @param[in] try_all_threads
/// If the timeout expires, true if other threads should run. If
/// the function may try to take locks, this is useful.
///
/// @param[in] unwind_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] timeout_usec
/// Timeout value (0 for no timeout). If try_all_threads is true, then we
/// will try on one thread for the lesser of .25 sec and half the total timeout.
/// then switch to running all threads, otherwise this will be the total timeout.
///
/// @param[in] errors
/// The stream to write errors to.
///
/// @param[in] this_arg
/// If non-NULL, the function is invoked like a C++ method, with the
/// value pointed to by the pointer as its 'this' argument.
///
/// @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 unwind_on_error,
bool ignore_breakpoints,
uint32_t timeout_usec,
Stream &errors,
lldb::addr_t* this_arg = 0);
//------------------------------------------------------------------
/// Run the function this ClangFunction was created with.
///
/// This simple version will run the function stopping other threads
/// for a fixed timeout period (1000 usec) and if it does not complete,
/// we halt the process and try with all threads running.
///
/// @param[in] exe_ctx
/// The thread & process in which this function will run.
///
/// @param[in] errors
/// Errors will be written here if there are any.
///
/// @param[out] results
/// The result value will be put here after running the function.
///
/// @return
/// Returns one of the ExecutionResults enum indicating function call status.
//------------------------------------------------------------------
ExecutionResults
ExecuteFunction(ExecutionContext &exe_ctx,
Stream &errors,
Value &results);
//------------------------------------------------------------------
/// Run the function this ClangFunction was created with.
///
/// This simple version will run the function obeying the stop_others
/// argument. There is no timeout.
///
/// @param[in] exe_ctx
/// The thread & process in which this function will run.
///
/// @param[in] errors
/// Errors will be written here if there are any.
///
/// @param[in] stop_others
/// If \b true, run only this thread, if \b false let all threads run.
///
/// @param[out] results
/// The result value will be put here after running the function.
///
/// @return
/// Returns one of the ExecutionResults enum indicating function call status.
//------------------------------------------------------------------
ExecutionResults
ExecuteFunction(ExecutionContext &exe_ctx,
Stream &errors, bool stop_others,
Value &results);
//------------------------------------------------------------------
/// Run the function this ClangFunction was created with.
///
/// This simple version will run the function on one thread. If \a timeout_usec
/// is not zero, we time out after that timeout. If \a try_all_threads is true, then we will
/// resume with all threads on, otherwise we halt the process, and eExecutionInterrupted will be returned.
///
/// @param[in] exe_ctx
/// The thread & process in which this function will run.
///
/// @param[in] errors
/// Errors will be written here if there are any.
///
/// @param[in] timeout_usec
/// Timeout value (0 for no timeout). If try_all_threads is true, then we
/// will try on one thread for the lesser of .25 sec and half the total timeout.
/// then switch to running all threads, otherwise this will be the total timeout.
///
/// @param[in] try_all_threads
/// If \b true, run only this thread, if \b false let all threads run.
///
/// @param[out] results
/// The result value will be put here after running the function.
///
/// @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);
//------------------------------------------------------------------ //------------------------------------------------------------------
/// Run the function this ClangFunction was created with. /// Run the function this ClangFunction was created with.
/// ///
@ -381,17 +244,8 @@ public:
/// @param[in] errors /// @param[in] errors
/// Errors will be written here if there are any. /// Errors will be written here if there are any.
/// ///
/// @param[in] stop_others /// @param[in] options
/// If \b true, run only this thread, if \b false let all threads run. /// The options for this expression execution.
///
/// @param[in] timeout_usec
/// Timeout value (0 for no timeout). If try_all_threads is true, then we
/// will try on one thread for the lesser of .25 sec and half the total timeout.
/// then switch to running all threads, otherwise this will be the total timeout.
///
///
/// @param[in] try_all_threads
/// If \b true, run only this thread, if \b false let all threads run.
/// ///
/// @param[out] results /// @param[out] results
/// The result value will be put here after running the function. /// The result value will be put here after running the function.
@ -402,62 +256,10 @@ public:
ExecutionResults ExecutionResults
ExecuteFunction(ExecutionContext &exe_ctx, ExecuteFunction(ExecutionContext &exe_ctx,
lldb::addr_t *args_addr_ptr, lldb::addr_t *args_addr_ptr,
Stream &errors, const EvaluateExpressionOptions &options,
bool stop_others, Stream &errors,
uint32_t timeout_usec,
bool try_all_threads,
bool unwind_on_error,
bool ignore_breakpoints,
Value &results); Value &results);
//------------------------------------------------------------------
/// [static] Get a thread plan to run a function.
///
/// @param[in] exe_ctx
/// The execution context to insert the function and its arguments
/// into.
///
/// @param[in] func_addr
/// The address of the function in the target process.
///
/// @param[in] args_addr_ref
/// The value of the void* parameter.
///
/// @param[in] errors
/// The stream to write errors to.
///
/// @param[in] stop_others
/// True if other threads should pause during execution.
///
/// @param[in] unwind_on_error
/// True if the thread plan may simply be discarded if an error occurs.
///
/// @param[in] ignore_breakpoints
/// True if the expression execution will ignore breakpoint hits and continue executing.
///
/// @param[in] this_arg
/// If non-NULL (and cmd_arg is NULL), the function is invoked like a C++
/// method, with the value pointed to by the pointer as its 'this'
/// argument.
///
/// @param[in] cmd_arg
/// If non-NULL, the function is invoked like an Objective-C method, with
/// this_arg in the 'self' slot and cmd_arg in the '_cmd' slot
///
/// @return
/// A ThreadPlan for executing the function.
//------------------------------------------------------------------
static ThreadPlan *
GetThreadPlanToCallFunction (ExecutionContext &exe_ctx,
lldb::addr_t func_addr,
lldb::addr_t &args_addr_ref,
Stream &errors,
bool stop_others,
bool unwind_on_error,
bool ignore_breakpoints,
lldb::addr_t *this_arg = 0,
lldb::addr_t *cmd_arg = 0);
//------------------------------------------------------------------ //------------------------------------------------------------------
/// Get a thread plan to run the function this ClangFunction was created with. /// Get a thread plan to run the function this ClangFunction was created with.
/// ///
@ -485,20 +287,9 @@ public:
//------------------------------------------------------------------ //------------------------------------------------------------------
ThreadPlan * ThreadPlan *
GetThreadPlanToCallFunction (ExecutionContext &exe_ctx, GetThreadPlanToCallFunction (ExecutionContext &exe_ctx,
lldb::addr_t &args_addr_ref, lldb::addr_t &args_addr_ref,
Stream &errors, const EvaluateExpressionOptions &options,
bool stop_others, Stream &errors);
bool unwind_on_error = true,
bool ignore_breakpoints = true)
{
return ClangFunction::GetThreadPlanToCallFunction (exe_ctx,
m_jit_start_addr,
args_addr_ref,
errors,
stop_others,
unwind_on_error,
ignore_breakpoints);
}
//------------------------------------------------------------------ //------------------------------------------------------------------
/// Get the result of the function from its struct /// Get the result of the function from its struct

View File

@ -150,10 +150,6 @@ public:
ClangUserExpressionSP &shared_ptr_to_me, ClangUserExpressionSP &shared_ptr_to_me,
lldb::ClangExpressionVariableSP &result); lldb::ClangExpressionVariableSP &result);
ThreadPlan *
GetThreadPlanToExecuteJITExpression (Stream &error_stream,
ExecutionContext &exe_ctx);
//------------------------------------------------------------------ //------------------------------------------------------------------
/// Apply the side effects of the function to program state. /// Apply the side effects of the function to program state.
/// ///

View File

@ -66,6 +66,12 @@ public:
{ {
} }
virtual bool
ExceptionBreakpointsAreSet ()
{
return false;
}
virtual bool virtual bool
ExceptionBreakpointsExplainStop (lldb::StopInfoSP stop_reason) ExceptionBreakpointsExplainStop (lldb::StopInfoSP stop_reason)
{ {

View File

@ -2502,11 +2502,7 @@ public:
ExecutionResults ExecutionResults
RunThreadPlan (ExecutionContext &exe_ctx, RunThreadPlan (ExecutionContext &exe_ctx,
lldb::ThreadPlanSP &thread_plan_sp, lldb::ThreadPlanSP &thread_plan_sp,
bool stop_others, const EvaluateExpressionOptions &options,
bool run_others,
bool unwind_on_error,
bool ignore_breakpoints,
uint32_t timeout_usec,
Stream &errors); Stream &errors);
static const char * static const char *

View File

@ -189,8 +189,10 @@ public:
m_unwind_on_error(true), m_unwind_on_error(true),
m_ignore_breakpoints (false), m_ignore_breakpoints (false),
m_keep_in_memory(false), m_keep_in_memory(false),
m_run_others(true), m_try_others(true),
m_stop_others(true),
m_debug(false), m_debug(false),
m_trap_exceptions(true),
m_use_dynamic(lldb::eNoDynamicValues), m_use_dynamic(lldb::eNoDynamicValues),
m_timeout_usec(default_timeout) m_timeout_usec(default_timeout)
{} {}
@ -201,11 +203,10 @@ public:
return m_execution_policy; return m_execution_policy;
} }
EvaluateExpressionOptions& void
SetExecutionPolicy (ExecutionPolicy policy = eExecutionPolicyAlways) SetExecutionPolicy (ExecutionPolicy policy = eExecutionPolicyAlways)
{ {
m_execution_policy = policy; m_execution_policy = policy;
return *this;
} }
lldb::LanguageType lldb::LanguageType
@ -214,11 +215,10 @@ public:
return m_language; return m_language;
} }
EvaluateExpressionOptions& void
SetLanguage(lldb::LanguageType language) SetLanguage(lldb::LanguageType language)
{ {
m_language = language; m_language = language;
return *this;
} }
bool bool
@ -227,11 +227,10 @@ public:
return m_coerce_to_id; return m_coerce_to_id;
} }
EvaluateExpressionOptions& void
SetCoerceToId (bool coerce = true) SetCoerceToId (bool coerce = true)
{ {
m_coerce_to_id = coerce; m_coerce_to_id = coerce;
return *this;
} }
bool bool
@ -240,11 +239,10 @@ public:
return m_unwind_on_error; return m_unwind_on_error;
} }
EvaluateExpressionOptions& void
SetUnwindOnError (bool unwind = false) SetUnwindOnError (bool unwind = false)
{ {
m_unwind_on_error = unwind; m_unwind_on_error = unwind;
return *this;
} }
bool bool
@ -253,11 +251,10 @@ public:
return m_ignore_breakpoints; return m_ignore_breakpoints;
} }
EvaluateExpressionOptions& void
SetIgnoreBreakpoints (bool ignore = false) SetIgnoreBreakpoints (bool ignore = false)
{ {
m_ignore_breakpoints = ignore; m_ignore_breakpoints = ignore;
return *this;
} }
bool bool
@ -266,11 +263,10 @@ public:
return m_keep_in_memory; return m_keep_in_memory;
} }
EvaluateExpressionOptions& void
SetKeepInMemory (bool keep = true) SetKeepInMemory (bool keep = true)
{ {
m_keep_in_memory = keep; m_keep_in_memory = keep;
return *this;
} }
lldb::DynamicValueType lldb::DynamicValueType
@ -279,11 +275,10 @@ public:
return m_use_dynamic; return m_use_dynamic;
} }
EvaluateExpressionOptions& void
SetUseDynamic (lldb::DynamicValueType dynamic = lldb::eDynamicCanRunTarget) SetUseDynamic (lldb::DynamicValueType dynamic = lldb::eDynamicCanRunTarget)
{ {
m_use_dynamic = dynamic; m_use_dynamic = dynamic;
return *this;
} }
uint32_t uint32_t
@ -292,24 +287,34 @@ public:
return m_timeout_usec; return m_timeout_usec;
} }
EvaluateExpressionOptions& void
SetTimeoutUsec (uint32_t timeout = 0) SetTimeoutUsec (uint32_t timeout = 0)
{ {
m_timeout_usec = timeout; m_timeout_usec = timeout;
return *this;
} }
bool bool
GetRunOthers () const GetTryAllThreads () const
{ {
return m_run_others; return m_try_others;
} }
EvaluateExpressionOptions& void
SetRunOthers (bool run_others = true) SetTryAllThreads (bool try_others = true)
{ {
m_run_others = run_others; m_try_others = try_others;
return *this; }
bool
GetStopOthers () const
{
return m_stop_others;
}
void
SetStopOthers (bool stop_others = true)
{
m_stop_others = stop_others;
} }
bool bool
@ -318,11 +323,22 @@ public:
return m_debug; return m_debug;
} }
EvaluateExpressionOptions& void
SetDebug(bool b) SetDebug(bool b)
{ {
m_debug = b; m_debug = b;
return *this; }
bool
GetTrapExceptions() const
{
return m_trap_exceptions;
}
void
SetTrapExceptions (bool b)
{
m_trap_exceptions = b;
} }
private: private:
@ -332,8 +348,10 @@ private:
bool m_unwind_on_error; bool m_unwind_on_error;
bool m_ignore_breakpoints; bool m_ignore_breakpoints;
bool m_keep_in_memory; bool m_keep_in_memory;
bool m_run_others; bool m_try_others;
bool m_stop_others;
bool m_debug; bool m_debug;
bool m_trap_exceptions;
lldb::DynamicValueType m_use_dynamic; lldb::DynamicValueType m_use_dynamic;
uint32_t m_timeout_usec; uint32_t m_timeout_usec;
}; };

View File

@ -528,21 +528,6 @@ public:
virtual lldb::ThreadPlanSP virtual lldb::ThreadPlanSP
QueueFundamentalPlan (bool abort_other_plans); QueueFundamentalPlan (bool abort_other_plans);
//------------------------------------------------------------------
/// Queues the plan used to step over a breakpoint at the current PC of \a thread.
/// The default version returned by Process handles trap based breakpoints, and
/// will disable the breakpoint, single step over it, then re-enable it.
///
/// @param[in] abort_other_plans
/// \b true if we discard the currently queued plans and replace them with this one.
/// Otherwise this plan will go on the end of the plan stack.
///
/// @return
/// A shared pointer to the newly queued thread plan, or NULL if the plan could not be queued.
//------------------------------------------------------------------
virtual lldb::ThreadPlanSP
QueueThreadPlanForStepOverBreakpointPlan (bool abort_other_plans);
//------------------------------------------------------------------ //------------------------------------------------------------------
/// Queues the plan used to step one instruction from the current PC of \a thread. /// Queues the plan used to step one instruction from the current PC of \a thread.
/// ///
@ -728,14 +713,6 @@ public:
bool stop_others, bool stop_others,
uint32_t frame_idx); uint32_t frame_idx);
virtual lldb::ThreadPlanSP
QueueThreadPlanForCallFunction (bool abort_other_plans,
Address& function,
lldb::addr_t arg,
bool stop_other_threads,
bool unwind_on_error = false,
bool ignore_breakpoints = true);
//------------------------------------------------------------------ //------------------------------------------------------------------
// Thread Plan accessors: // Thread Plan accessors:
//------------------------------------------------------------------ //------------------------------------------------------------------

View File

@ -30,18 +30,14 @@ public:
const Address &function, const Address &function,
const ClangASTType &return_type, const ClangASTType &return_type,
lldb::addr_t arg, lldb::addr_t arg,
bool stop_other_threads, const EvaluateExpressionOptions &options,
bool unwind_on_error = true,
bool ignore_breakpoints = false,
lldb::addr_t *this_arg = 0, lldb::addr_t *this_arg = 0,
lldb::addr_t *cmd_arg = 0); lldb::addr_t *cmd_arg = 0);
ThreadPlanCallFunction (Thread &thread, ThreadPlanCallFunction (Thread &thread,
const Address &function, const Address &function,
const ClangASTType &return_type, const ClangASTType &return_type,
bool stop_other_threads, const EvaluateExpressionOptions &options,
bool unwind_on_error,
bool ignore_breakpoints,
lldb::addr_t *arg1_ptr = NULL, lldb::addr_t *arg1_ptr = NULL,
lldb::addr_t *arg2_ptr = NULL, lldb::addr_t *arg2_ptr = NULL,
lldb::addr_t *arg3_ptr = NULL, lldb::addr_t *arg3_ptr = NULL,
@ -171,6 +167,10 @@ private:
bool m_valid; bool m_valid;
bool m_stop_other_threads; bool m_stop_other_threads;
bool m_unwind_on_error;
bool m_ignore_breakpoints;
bool m_debug_execution;
bool m_trap_exceptions;
Address m_function_addr; Address m_function_addr;
Address m_start_addr; Address m_start_addr;
lldb::addr_t m_function_sp; lldb::addr_t m_function_sp;
@ -187,9 +187,9 @@ private:
ClangASTType m_return_type; ClangASTType m_return_type;
lldb::ValueObjectSP m_return_valobj_sp; // If this contains a valid pointer, use the ABI to extract values when complete lldb::ValueObjectSP m_return_valobj_sp; // If this contains a valid pointer, use the ABI to extract values when complete
bool m_takedown_done; // We want to ensure we only do the takedown once. This ensures that. bool m_takedown_done; // We want to ensure we only do the takedown once. This ensures that.
bool m_should_clear_objc_exception_bp;
bool m_should_clear_cxx_exception_bp;
lldb::addr_t m_stop_address; // This is the address we stopped at. Also set in DoTakedown; lldb::addr_t m_stop_address; // This is the address we stopped at. Also set in DoTakedown;
bool m_unwind_on_error;
bool m_ignore_breakpoints;
DISALLOW_COPY_AND_ASSIGN (ThreadPlanCallFunction); DISALLOW_COPY_AND_ASSIGN (ThreadPlanCallFunction);
}; };

View File

@ -28,9 +28,7 @@ public:
ThreadPlanCallUserExpression (Thread &thread, ThreadPlanCallUserExpression (Thread &thread,
Address &function, Address &function,
lldb::addr_t arg, lldb::addr_t arg,
bool stop_other_threads, const EvaluateExpressionOptions &options,
bool unwind_on_error,
bool ignore_breakpoints,
lldb::addr_t *this_arg, lldb::addr_t *this_arg,
lldb::addr_t *cmd_arg, lldb::addr_t *cmd_arg,
ClangUserExpression::ClangUserExpressionSP &user_expression_sp); ClangUserExpression::ClangUserExpressionSP &user_expression_sp);

View File

@ -133,7 +133,8 @@ typedef enum ExecutionResults
eExecutionDiscarded, eExecutionDiscarded,
eExecutionInterrupted, eExecutionInterrupted,
eExecutionHitBreakpoint, eExecutionHitBreakpoint,
eExecutionTimedOut eExecutionTimedOut,
eExecutionStoppedForDebug
} ExecutionResults; } ExecutionResults;
typedef enum ObjCRuntimeVersions { typedef enum ObjCRuntimeVersions {

View File

@ -71,6 +71,13 @@ public:
void void
SetTryAllThreads (bool run_others = true); SetTryAllThreads (bool run_others = true);
bool
GetTrapExceptions () const;
%feature("docstring", "Sets whether to abort expression evaluation if an exception is thrown while executing. Don't set this to false unless you know the function you are calling traps all exceptions itself.") SetTryAllThreads;
void
SetTrapExceptions (bool trap_exceptions = true);
protected: protected:
SBExpressionOptions (lldb_private::EvaluateExpressionOptions &expression_options); SBExpressionOptions (lldb_private::EvaluateExpressionOptions &expression_options);

View File

@ -104,13 +104,25 @@ SBExpressionOptions::SetTimeoutInMicroSeconds (uint32_t timeout)
bool bool
SBExpressionOptions::GetTryAllThreads () const SBExpressionOptions::GetTryAllThreads () const
{ {
return m_opaque_ap->GetRunOthers (); return m_opaque_ap->GetTryAllThreads ();
} }
void void
SBExpressionOptions::SetTryAllThreads (bool run_others) SBExpressionOptions::SetTryAllThreads (bool run_others)
{ {
m_opaque_ap->SetRunOthers (run_others); m_opaque_ap->SetTryAllThreads (run_others);
}
bool
SBExpressionOptions::GetTrapExceptions () const
{
return m_opaque_ap->GetTrapExceptions ();
}
void
SBExpressionOptions::SetTrapExceptions (bool trap_exceptions)
{
m_opaque_ap->SetTrapExceptions (trap_exceptions);
} }
EvaluateExpressionOptions * EvaluateExpressionOptions *

View File

@ -295,7 +295,7 @@ BreakpointLocation::ConditionSaysStop (ExecutionContext &exe_ctx, Error &error)
EvaluateExpressionOptions options; EvaluateExpressionOptions options;
options.SetUnwindOnError(true); options.SetUnwindOnError(true);
options.SetIgnoreBreakpoints(true); options.SetIgnoreBreakpoints(true);
options.SetRunOthers(true); options.SetTryAllThreads(true);
Error expr_error; Error expr_error;

View File

@ -363,13 +363,13 @@ CommandObjectExpression::EvaluateExpression
bool keep_in_memory = true; bool keep_in_memory = true;
EvaluateExpressionOptions options; EvaluateExpressionOptions options;
options.SetCoerceToId(m_varobj_options.use_objc) options.SetCoerceToId(m_varobj_options.use_objc);
.SetUnwindOnError(m_command_options.unwind_on_error) options.SetUnwindOnError(m_command_options.unwind_on_error);
.SetIgnoreBreakpoints (m_command_options.ignore_breakpoints) options.SetIgnoreBreakpoints (m_command_options.ignore_breakpoints);
.SetKeepInMemory(keep_in_memory) options.SetKeepInMemory(keep_in_memory);
.SetUseDynamic(m_varobj_options.use_dynamic) options.SetUseDynamic(m_varobj_options.use_dynamic);
.SetRunOthers(m_command_options.try_all_threads) options.SetTryAllThreads(m_command_options.try_all_threads);
.SetDebug(m_command_options.debug); options.SetDebug(m_command_options.debug);
if (m_command_options.timeout > 0) if (m_command_options.timeout > 0)
options.SetTimeoutUsec(m_command_options.timeout); options.SetTimeoutUsec(m_command_options.timeout);

View File

@ -1256,11 +1256,11 @@ protected:
// Use expression evaluation to arrive at the address to watch. // Use expression evaluation to arrive at the address to watch.
EvaluateExpressionOptions options; EvaluateExpressionOptions options;
options.SetCoerceToId(false) options.SetCoerceToId(false);
.SetUnwindOnError(true) options.SetUnwindOnError(true);
.SetKeepInMemory(false) options.SetKeepInMemory(false);
.SetRunOthers(true) options.SetTryAllThreads(true);
.SetTimeoutUsec(0); options.SetTimeoutUsec(0);
ExecutionResults expr_result = target->EvaluateExpression (expr, ExecutionResults expr_result = target->EvaluateExpression (expr,
frame, frame,

View File

@ -49,9 +49,9 @@ lldb_private::formatters::ExtractValueFromObjCExpression (ValueObject &valobj,
return false; return false;
EvaluateExpressionOptions options; EvaluateExpressionOptions options;
options.SetCoerceToId(false) options.SetCoerceToId(false);
.SetUnwindOnError(true) options.SetUnwindOnError(true);
.SetKeepInMemory(true); options.SetKeepInMemory(true);
target->EvaluateExpression(expr.GetData(), target->EvaluateExpression(expr.GetData(),
stack_frame, stack_frame,
@ -83,10 +83,10 @@ lldb_private::formatters::ExtractSummaryFromObjCExpression (ValueObject &valobj,
return false; return false;
EvaluateExpressionOptions options; EvaluateExpressionOptions options;
options.SetCoerceToId(false) options.SetCoerceToId(false);
.SetUnwindOnError(true) options.SetUnwindOnError(true);
.SetKeepInMemory(true) options.SetKeepInMemory(true);
.SetUseDynamic(lldb::eDynamicCanRunTarget); options.SetUseDynamic(lldb::eDynamicCanRunTarget);
target->EvaluateExpression(expr.GetData(), target->EvaluateExpression(expr.GetData(),
stack_frame, stack_frame,
@ -121,10 +121,10 @@ lldb_private::formatters::CallSelectorOnObject (ValueObject &valobj,
return valobj_sp; return valobj_sp;
EvaluateExpressionOptions options; EvaluateExpressionOptions options;
options.SetCoerceToId(false) options.SetCoerceToId(false);
.SetUnwindOnError(true) options.SetUnwindOnError(true);
.SetKeepInMemory(true) options.SetKeepInMemory(true);
.SetUseDynamic(lldb::eDynamicCanRunTarget); options.SetUseDynamic(lldb::eDynamicCanRunTarget);
target->EvaluateExpression(expr.GetData(), target->EvaluateExpression(expr.GetData(),
stack_frame, stack_frame,
@ -158,10 +158,10 @@ lldb_private::formatters::CallSelectorOnObject (ValueObject &valobj,
return valobj_sp; return valobj_sp;
EvaluateExpressionOptions options; EvaluateExpressionOptions options;
options.SetCoerceToId(false) options.SetCoerceToId(false);
.SetUnwindOnError(true) options.SetUnwindOnError(true);
.SetKeepInMemory(true) options.SetKeepInMemory(true);
.SetUseDynamic(lldb::eDynamicCanRunTarget); options.SetUseDynamic(lldb::eDynamicCanRunTarget);
target->EvaluateExpression(expr.GetData(), target->EvaluateExpression(expr.GetData(),
stack_frame, stack_frame,

View File

@ -35,10 +35,10 @@ m_options()
{ {
if (valobj_sp) if (valobj_sp)
Update(); Update();
m_options.SetCoerceToId(false) m_options.SetCoerceToId(false);
.SetUnwindOnError(true) m_options.SetUnwindOnError(true);
.SetKeepInMemory(true) m_options.SetKeepInMemory(true);
.SetUseDynamic(lldb::eDynamicCanRunTarget); m_options.SetUseDynamic(lldb::eDynamicCanRunTarget);
} }
size_t size_t

View File

@ -34,10 +34,10 @@ m_options()
{ {
if (valobj_sp) if (valobj_sp)
Update(); Update();
m_options.SetCoerceToId(false) m_options.SetCoerceToId(false);
.SetUnwindOnError(true) m_options.SetUnwindOnError(true);
.SetKeepInMemory(true) m_options.SetKeepInMemory(true);
.SetUseDynamic(lldb::eDynamicCanRunTarget); m_options.SetUseDynamic(lldb::eDynamicCanRunTarget);
} }
size_t size_t
@ -215,10 +215,10 @@ lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEnd::LibstdcppMapIte
{ {
if (valobj_sp) if (valobj_sp)
Update(); Update();
m_options.SetCoerceToId(false) m_options.SetCoerceToId(false);
.SetUnwindOnError(true) m_options.SetUnwindOnError(true);
.SetKeepInMemory(true) m_options.SetKeepInMemory(true);
.SetUseDynamic(lldb::eDynamicCanRunTarget); m_options.SetUseDynamic(lldb::eDynamicCanRunTarget);
} }
bool bool

View File

@ -218,8 +218,10 @@ lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::GetChildAtIn
StreamString object_fetcher_expr; StreamString object_fetcher_expr;
object_fetcher_expr.Printf("struct __lldb_autogen_nspair { id key; id value; } _lldb_valgen_item; _lldb_valgen_item.key = %s; _lldb_valgen_item.value = %s; _lldb_valgen_item;",key_fetcher_expr.GetData(),value_fetcher_expr.GetData()); object_fetcher_expr.Printf("struct __lldb_autogen_nspair { id key; id value; } _lldb_valgen_item; _lldb_valgen_item.key = %s; _lldb_valgen_item.value = %s; _lldb_valgen_item;",key_fetcher_expr.GetData(),value_fetcher_expr.GetData());
lldb::ValueObjectSP child_sp; lldb::ValueObjectSP child_sp;
EvaluateExpressionOptions options;
options.SetKeepInMemory(true);
m_backend.GetTargetSP()->EvaluateExpression(object_fetcher_expr.GetData(), m_backend.GetFrameSP().get(), child_sp, m_backend.GetTargetSP()->EvaluateExpression(object_fetcher_expr.GetData(), m_backend.GetFrameSP().get(), child_sp,
EvaluateExpressionOptions().SetKeepInMemory(true)); options);
if (child_sp) if (child_sp)
child_sp->SetName(ConstString(idx_name.GetData())); child_sp->SetName(ConstString(idx_name.GetData()));
return child_sp; return child_sp;

View File

@ -394,14 +394,9 @@ ClangFunction::InsertFunction (ExecutionContext &exe_ctx, lldb::addr_t &args_add
ThreadPlan * ThreadPlan *
ClangFunction::GetThreadPlanToCallFunction (ExecutionContext &exe_ctx, ClangFunction::GetThreadPlanToCallFunction (ExecutionContext &exe_ctx,
lldb::addr_t func_addr, lldb::addr_t &args_addr,
lldb::addr_t &args_addr, const EvaluateExpressionOptions &options,
Stream &errors, Stream &errors)
bool stop_others,
bool unwind_on_error,
bool ignore_breakpoints,
lldb::addr_t *this_arg,
lldb::addr_t *cmd_arg)
{ {
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP)); Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP));
@ -418,16 +413,14 @@ ClangFunction::GetThreadPlanToCallFunction (ExecutionContext &exe_ctx,
// Okay, now run the function: // Okay, now run the function:
Address wrapper_address (func_addr); Address wrapper_address (m_jit_start_addr);
ThreadPlan *new_plan = new ThreadPlanCallFunction (*thread, ThreadPlan *new_plan = new ThreadPlanCallFunction (*thread,
wrapper_address, wrapper_address,
ClangASTType(), ClangASTType(),
args_addr, args_addr,
stop_others, options,
unwind_on_error, 0,
ignore_breakpoints, 0);
this_arg,
cmd_arg);
new_plan->SetIsMasterPlan(true); new_plan->SetIsMasterPlan(true);
new_plan->SetOkayToDiscard (false); new_plan->SetOkayToDiscard (false);
return new_plan; return new_plan;
@ -478,113 +471,24 @@ ClangFunction::DeallocateFunctionResults (ExecutionContext &exe_ctx, lldb::addr_
exe_ctx.GetProcessRef().DeallocateMemory(args_addr); exe_ctx.GetProcessRef().DeallocateMemory(args_addr);
} }
ExecutionResults
ClangFunction::ExecuteFunction(ExecutionContext &exe_ctx, Stream &errors, Value &results)
{
return ExecuteFunction (exe_ctx, errors, 1000, true, results);
}
ExecutionResults
ClangFunction::ExecuteFunction(ExecutionContext &exe_ctx, Stream &errors, bool stop_others, Value &results)
{
const bool try_all_threads = false;
const bool unwind_on_error = true;
const bool ignore_breakpoints = true;
return ExecuteFunction (exe_ctx, NULL, errors, stop_others, 0UL, try_all_threads,
unwind_on_error, ignore_breakpoints, results);
}
ExecutionResults ExecutionResults
ClangFunction::ExecuteFunction( ClangFunction::ExecuteFunction(
ExecutionContext &exe_ctx, ExecutionContext &exe_ctx,
lldb::addr_t *args_addr_ptr,
const EvaluateExpressionOptions &options,
Stream &errors, Stream &errors,
uint32_t timeout_usec,
bool try_all_threads,
Value &results)
{
const bool stop_others = true;
const bool unwind_on_error = true;
const bool ignore_breakpoints = true;
return ExecuteFunction (exe_ctx, NULL, errors, stop_others, timeout_usec,
try_all_threads, unwind_on_error, ignore_breakpoints, results);
}
// This is the static function
ExecutionResults
ClangFunction::ExecuteFunction (
ExecutionContext &exe_ctx,
lldb::addr_t function_address,
lldb::addr_t &void_arg,
bool stop_others,
bool try_all_threads,
bool unwind_on_error,
bool ignore_breakpoints,
uint32_t timeout_usec,
Stream &errors,
lldb::addr_t *this_arg)
{
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP));
if (log)
log->Printf("== [ClangFunction::ExecuteFunction] Executing function ==");
lldb::ThreadPlanSP call_plan_sp (ClangFunction::GetThreadPlanToCallFunction (exe_ctx,
function_address,
void_arg,
errors,
stop_others,
unwind_on_error,
ignore_breakpoints,
this_arg));
if (!call_plan_sp)
return eExecutionSetupError;
// <rdar://problem/12027563> we need to make sure we record the fact that we are running an expression here
// otherwise this fact will fail to be recorded when fetching an Objective-C object description
if (exe_ctx.GetProcessPtr())
exe_ctx.GetProcessPtr()->SetRunningUserExpression(true);
ExecutionResults results = exe_ctx.GetProcessRef().RunThreadPlan (exe_ctx, call_plan_sp,
stop_others,
try_all_threads,
unwind_on_error,
ignore_breakpoints,
timeout_usec,
errors);
if (log)
{
if (results != eExecutionCompleted)
{
log->Printf("== [ClangFunction::ExecuteFunction] Execution completed abnormally ==");
}
else
{
log->Printf("== [ClangFunction::ExecuteFunction] Execution completed normally ==");
}
}
if (exe_ctx.GetProcessPtr())
exe_ctx.GetProcessPtr()->SetRunningUserExpression(false);
return results;
}
ExecutionResults
ClangFunction::ExecuteFunction(
ExecutionContext &exe_ctx,
lldb::addr_t *args_addr_ptr,
Stream &errors,
bool stop_others,
uint32_t timeout_usec,
bool try_all_threads,
bool unwind_on_error,
bool ignore_breakpoints,
Value &results) Value &results)
{ {
using namespace clang; using namespace clang;
ExecutionResults return_value = eExecutionSetupError; ExecutionResults return_value = eExecutionSetupError;
// ClangFunction::ExecuteFunction execution is always just to get the result. Do make sure we ignore
// breakpoints, unwind on error, and don't try to debug it.
EvaluateExpressionOptions real_options = options;
real_options.SetDebug(false);
real_options.SetUnwindOnError(true);
real_options.SetIgnoreBreakpoints(true);
lldb::addr_t args_addr; lldb::addr_t args_addr;
if (args_addr_ptr != NULL) if (args_addr_ptr != NULL)
@ -600,17 +504,44 @@ ClangFunction::ExecuteFunction(
if (!InsertFunction(exe_ctx, args_addr, errors)) if (!InsertFunction(exe_ctx, args_addr, errors))
return eExecutionSetupError; return eExecutionSetupError;
} }
return_value = ClangFunction::ExecuteFunction (exe_ctx,
m_jit_start_addr,
args_addr,
stop_others,
try_all_threads,
unwind_on_error,
ignore_breakpoints,
timeout_usec,
errors);
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP));
if (log)
log->Printf("== [ClangFunction::ExecuteFunction] Executing function ==");
lldb::ThreadPlanSP call_plan_sp (GetThreadPlanToCallFunction (exe_ctx,
args_addr,
real_options,
errors));
if (!call_plan_sp)
return eExecutionSetupError;
// <rdar://problem/12027563> we need to make sure we record the fact that we are running an expression here
// otherwise this fact will fail to be recorded when fetching an Objective-C object description
if (exe_ctx.GetProcessPtr())
exe_ctx.GetProcessPtr()->SetRunningUserExpression(true);
return_value = exe_ctx.GetProcessRef().RunThreadPlan (exe_ctx,
call_plan_sp,
real_options,
errors);
if (log)
{
if (return_value != eExecutionCompleted)
{
log->Printf("== [ClangFunction::ExecuteFunction] Execution completed abnormally ==");
}
else
{
log->Printf("== [ClangFunction::ExecuteFunction] Execution completed normally ==");
}
}
if (exe_ctx.GetProcessPtr())
exe_ctx.GetProcessPtr()->SetRunningUserExpression(false);
if (args_addr_ptr != NULL) if (args_addr_ptr != NULL)
*args_addr_ptr = args_addr; *args_addr_ptr = args_addr;

View File

@ -716,35 +716,6 @@ ClangUserExpression::PrepareToExecuteJITExpression (Stream &error_stream,
return true; return true;
} }
ThreadPlan *
ClangUserExpression::GetThreadPlanToExecuteJITExpression (Stream &error_stream,
ExecutionContext &exe_ctx)
{
lldb::addr_t struct_address;
lldb::addr_t object_ptr = 0;
lldb::addr_t cmd_ptr = 0;
PrepareToExecuteJITExpression (error_stream, exe_ctx, struct_address, object_ptr, cmd_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.
const bool stop_others = true;
const bool unwind_on_error = true;
const bool ignore_breakpoints = false;
return ClangFunction::GetThreadPlanToCallFunction (exe_ctx,
m_jit_start_addr,
struct_address,
error_stream,
stop_others,
unwind_on_error,
ignore_breakpoints,
(m_needs_object_ptr ? &object_ptr : NULL),
(m_needs_object_ptr && m_objectivec) ? &cmd_ptr : NULL);
}
bool bool
ClangUserExpression::FinalizeJITExecution (Stream &error_stream, ClangUserExpression::FinalizeJITExecution (Stream &error_stream,
ExecutionContext &exe_ctx, ExecutionContext &exe_ctx,
@ -852,25 +823,11 @@ ClangUserExpression::Execute (Stream &error_stream,
} }
else else
{ {
const uint32_t timeout_usec = options.GetTimeoutUsec();
const bool debug = options.GetDebug();
const bool unwind_on_error = debug ? false : options.DoesUnwindOnError();
const bool ignore_breakpoints = debug ? false : options.DoesIgnoreBreakpoints();
const bool stop_others = true;
const bool try_all_threads = options.GetRunOthers();
lldb::BreakpointSP debug_bkpt_sp;
if (debug)
{
// TODO: push this down into the thread plan and let the plan manage it
debug_bkpt_sp = exe_ctx.GetTargetRef().CreateBreakpoint(m_jit_start_addr, false, false);
}
Address wrapper_address (m_jit_start_addr); Address wrapper_address (m_jit_start_addr);
lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallUserExpression (exe_ctx.GetThreadRef(), lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallUserExpression (exe_ctx.GetThreadRef(),
wrapper_address, wrapper_address,
struct_address, struct_address,
stop_others, options,
unwind_on_error,
ignore_breakpoints,
(m_needs_object_ptr ? &object_ptr : NULL), (m_needs_object_ptr ? &object_ptr : NULL),
((m_needs_object_ptr && m_objectivec) ? &cmd_ptr : NULL), ((m_needs_object_ptr && m_objectivec) ? &cmd_ptr : NULL),
shared_ptr_to_me)); shared_ptr_to_me));
@ -890,19 +847,10 @@ ClangUserExpression::Execute (Stream &error_stream,
exe_ctx.GetProcessPtr()->SetRunningUserExpression(true); exe_ctx.GetProcessPtr()->SetRunningUserExpression(true);
ExecutionResults execution_result = exe_ctx.GetProcessRef().RunThreadPlan (exe_ctx, ExecutionResults execution_result = exe_ctx.GetProcessRef().RunThreadPlan (exe_ctx,
call_plan_sp, call_plan_sp,
stop_others, options,
try_all_threads,
unwind_on_error,
ignore_breakpoints,
timeout_usec,
error_stream); error_stream);
if (debug_bkpt_sp)
{
exe_ctx.GetTargetRef().RemoveBreakpointByID(debug_bkpt_sp->GetID());
}
if (exe_ctx.GetProcessPtr()) if (exe_ctx.GetProcessPtr())
exe_ctx.GetProcessPtr()->SetRunningUserExpression(false); exe_ctx.GetProcessPtr()->SetRunningUserExpression(false);
@ -922,16 +870,22 @@ ClangUserExpression::Execute (Stream &error_stream,
if (error_desc) if (error_desc)
error_stream.Printf ("Execution was interrupted, reason: %s.", error_desc); error_stream.Printf ("Execution was interrupted, reason: %s.", error_desc);
else else
error_stream.Printf ("Execution was interrupted."); error_stream.PutCString ("Execution was interrupted.");
if ((execution_result == eExecutionInterrupted && unwind_on_error) if ((execution_result == eExecutionInterrupted && options.DoesUnwindOnError())
|| (execution_result == eExecutionHitBreakpoint && ignore_breakpoints)) || (execution_result == eExecutionHitBreakpoint && options.DoesIgnoreBreakpoints()))
error_stream.Printf ("\nThe process has been returned to the state before expression evaluation."); error_stream.PutCString ("\nThe process has been returned to the state before expression evaluation.");
else else
error_stream.Printf ("\nThe process has been left at the point where it was interrupted, use \"thread return -x\" to return to the state before expression evaluation."); error_stream.PutCString ("\nThe process has been left at the point where it was interrupted, use \"thread return -x\" to return to the state before expression evaluation.");
return execution_result; return execution_result;
} }
else if (execution_result == eExecutionStoppedForDebug)
{
error_stream.PutCString ("Execution was halted at the first instruction of the expression function because \"debug\" was requested.\n"
"Use \"thread return -x\" to return to the state before expression evaluation.");
return execution_result;
}
else if (execution_result != eExecutionCompleted) else if (execution_result != eExecutionCompleted)
{ {
error_stream.Printf ("Couldn't execute function; result was %s\n", Process::ExecutionResultAsCString (execution_result)); error_stream.Printf ("Couldn't execute function; result was %s\n", Process::ExecutionResultAsCString (execution_result));

View File

@ -815,7 +815,7 @@ Args::StringToAddress (const ExecutionContext *exe_ctx, const char *s, lldb::add
options.SetCoerceToId(false); options.SetCoerceToId(false);
options.SetUnwindOnError(true); options.SetUnwindOnError(true);
options.SetKeepInMemory(false); options.SetKeepInMemory(false);
options.SetRunOthers(true); options.SetTryAllThreads(true);
ExecutionResults expr_result = target->EvaluateExpression(s, ExecutionResults expr_result = target->EvaluateExpression(s,
exe_ctx->GetFramePtr(), exe_ctx->GetFramePtr(),

View File

@ -1434,12 +1434,12 @@ CommandInterpreter::PreprocessCommand (std::string &command)
ValueObjectSP expr_result_valobj_sp; ValueObjectSP expr_result_valobj_sp;
EvaluateExpressionOptions options; EvaluateExpressionOptions options;
options.SetCoerceToId(false) options.SetCoerceToId(false);
.SetUnwindOnError(true) options.SetUnwindOnError(true);
.SetIgnoreBreakpoints(true) options.SetIgnoreBreakpoints(true);
.SetKeepInMemory(false) options.SetKeepInMemory(false);
.SetRunOthers(true) options.SetTryAllThreads(true);
.SetTimeoutUsec(0); options.SetTimeoutUsec(0);
ExecutionResults expr_result = target->EvaluateExpression (expr_str.c_str(), ExecutionResults expr_result = target->EvaluateExpression (expr_str.c_str(),
exe_ctx.GetFramePtr(), exe_ctx.GetFramePtr(),

View File

@ -444,6 +444,12 @@ ItaniumABILanguageRuntime::ClearExceptionBreakpoints ()
} }
} }
bool
ItaniumABILanguageRuntime::ExceptionBreakpointsAreSet ()
{
return m_cxx_exception_bp_sp && m_cxx_exception_bp_sp->IsEnabled();
}
bool bool
ItaniumABILanguageRuntime::ExceptionBreakpointsExplainStop (lldb::StopInfoSP stop_reason) ItaniumABILanguageRuntime::ExceptionBreakpointsExplainStop (lldb::StopInfoSP stop_reason)
{ {

View File

@ -70,6 +70,9 @@ namespace lldb_private {
virtual void virtual void
ClearExceptionBreakpoints (); ClearExceptionBreakpoints ();
virtual bool
ExceptionBreakpointsAreSet ();
virtual bool virtual bool
ExceptionBreakpointsExplainStop (lldb::StopInfoSP stop_reason); ExceptionBreakpointsExplainStop (lldb::StopInfoSP stop_reason);

View File

@ -137,19 +137,17 @@ AppleObjCRuntime::GetObjectDescription (Stream &strm, Value &value, ExecutionCon
lldb::addr_t wrapper_struct_addr = LLDB_INVALID_ADDRESS; lldb::addr_t wrapper_struct_addr = LLDB_INVALID_ADDRESS;
func.InsertFunction(exe_ctx, wrapper_struct_addr, error_stream); func.InsertFunction(exe_ctx, wrapper_struct_addr, error_stream);
const bool unwind_on_error = true; EvaluateExpressionOptions options;
const bool try_all_threads = true; options.SetUnwindOnError(true);
const bool stop_others = true; options.SetTryAllThreads(true);
const bool ignore_breakpoints = true; options.SetStopOthers(true);
options.SetIgnoreBreakpoints(true);
options.SetTimeoutUsec(PO_FUNCTION_TIMEOUT_USEC);
ExecutionResults results = func.ExecuteFunction (exe_ctx, ExecutionResults results = func.ExecuteFunction (exe_ctx,
&wrapper_struct_addr, &wrapper_struct_addr,
options,
error_stream, error_stream,
stop_others,
PO_FUNCTION_TIMEOUT_USEC /* 15 secs timeout */,
try_all_threads,
unwind_on_error,
ignore_breakpoints,
ret); ret);
if (results != eExecutionCompleted) if (results != eExecutionCompleted)
{ {
@ -361,6 +359,12 @@ AppleObjCRuntime::ClearExceptionBreakpoints ()
} }
} }
bool
AppleObjCRuntime::ExceptionBreakpointsAreSet ()
{
return m_objc_exception_bp_sp && m_objc_exception_bp_sp->IsEnabled();
}
bool bool
AppleObjCRuntime::ExceptionBreakpointsExplainStop (lldb::StopInfoSP stop_reason) AppleObjCRuntime::ExceptionBreakpointsExplainStop (lldb::StopInfoSP stop_reason)
{ {

View File

@ -94,6 +94,9 @@ public:
virtual void virtual void
ClearExceptionBreakpoints (); ClearExceptionBreakpoints ();
virtual bool
ExceptionBreakpointsAreSet ();
virtual bool virtual bool
ExceptionBreakpointsExplainStop (lldb::StopInfoSP stop_reason); ExceptionBreakpointsExplainStop (lldb::StopInfoSP stop_reason);

View File

@ -1829,10 +1829,12 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapDynamic(RemoteNXMapTable &hash_table
arguments, arguments,
errors)) errors))
{ {
bool stop_others = true; EvaluateExpressionOptions options;
bool try_all_threads = false; options.SetUnwindOnError(true);
bool unwind_on_error = true; options.SetTryAllThreads(false);
bool ignore_breakpoints = true; options.SetStopOthers(true);
options.SetIgnoreBreakpoints(true);
options.SetTimeoutUsec(UTILITY_FUNCTION_TIMEOUT_USEC);
Value return_value; Value return_value;
return_value.SetValueType (Value::eValueTypeScalar); return_value.SetValueType (Value::eValueTypeScalar);
@ -1845,12 +1847,8 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapDynamic(RemoteNXMapTable &hash_table
// Run the function // Run the function
ExecutionResults results = m_get_class_info_function->ExecuteFunction (exe_ctx, ExecutionResults results = m_get_class_info_function->ExecuteFunction (exe_ctx,
&m_get_class_info_args, &m_get_class_info_args,
options,
errors, errors,
stop_others,
UTILITY_FUNCTION_TIMEOUT_USEC,
try_all_threads,
unwind_on_error,
ignore_breakpoints,
return_value); return_value);
if (results == eExecutionCompleted) if (results == eExecutionCompleted)
@ -2080,10 +2078,12 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache()
arguments, arguments,
errors)) errors))
{ {
bool stop_others = true; EvaluateExpressionOptions options;
bool try_all_threads = false; options.SetUnwindOnError(true);
bool unwind_on_error = true; options.SetTryAllThreads(false);
bool ignore_breakpoints = true; options.SetStopOthers(true);
options.SetIgnoreBreakpoints(true);
options.SetTimeoutUsec(UTILITY_FUNCTION_TIMEOUT_USEC);
Value return_value; Value return_value;
return_value.SetValueType (Value::eValueTypeScalar); return_value.SetValueType (Value::eValueTypeScalar);
@ -2096,12 +2096,8 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache()
// Run the function // Run the function
ExecutionResults results = m_get_shared_cache_class_info_function->ExecuteFunction (exe_ctx, ExecutionResults results = m_get_shared_cache_class_info_function->ExecuteFunction (exe_ctx,
&m_get_shared_cache_class_info_args, &m_get_shared_cache_class_info_args,
options,
errors, errors,
stop_others,
UTILITY_FUNCTION_TIMEOUT_USEC,
try_all_threads,
unwind_on_error,
ignore_breakpoints,
return_value); return_value);
if (results == eExecutionCompleted) if (results == eExecutionCompleted)

View File

@ -84,15 +84,15 @@ AppleThreadPlanStepThroughObjCTrampoline::InitializeClangFunction ()
} }
m_impl_function = m_trampoline_handler->GetLookupImplementationWrapperFunction(); m_impl_function = m_trampoline_handler->GetLookupImplementationWrapperFunction();
ExecutionContext exc_ctx; ExecutionContext exc_ctx;
const bool unwind_on_error = true; EvaluateExpressionOptions options;
const bool ignore_breakpoints = true; options.SetUnwindOnError(true);
options.SetIgnoreBreakpoints(true);
options.SetStopOthers(m_stop_others);
m_thread.CalculateExecutionContext(exc_ctx); m_thread.CalculateExecutionContext(exc_ctx);
m_func_sp.reset(m_impl_function->GetThreadPlanToCallFunction (exc_ctx, m_func_sp.reset(m_impl_function->GetThreadPlanToCallFunction (exc_ctx,
m_args_addr, m_args_addr,
errors, options,
m_stop_others, errors));
unwind_on_error,
ignore_breakpoints));
m_func_sp->SetOkayToDiscard(true); m_func_sp->SetOkayToDiscard(true);
m_thread.QueueThreadPlan (m_func_sp, false); m_thread.QueueThreadPlan (m_func_sp, false);
} }

View File

@ -59,11 +59,13 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr,
{ {
const uint32_t range_scope = eSymbolContextFunction | eSymbolContextSymbol; const uint32_t range_scope = eSymbolContextFunction | eSymbolContextSymbol;
const bool use_inline_block_range = false; const bool use_inline_block_range = false;
const bool stop_other_threads = true; EvaluateExpressionOptions options;
const bool unwind_on_error = true; options.SetStopOthers(true);
const bool ignore_breakpoints = true; options.SetUnwindOnError(true);
const bool try_all_threads = true; options.SetIgnoreBreakpoints(true);
const uint32_t timeout_usec = 500000; options.SetTryAllThreads(true);
options.SetDebug (false);
options.SetTimeoutUsec(500000);
addr_t prot_arg, flags_arg = 0; addr_t prot_arg, flags_arg = 0;
if (prot == eMmapProtNone) if (prot == eMmapProtNone)
@ -92,9 +94,7 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr,
= new ThreadPlanCallFunction (*thread, = new ThreadPlanCallFunction (*thread,
mmap_range.GetBaseAddress(), mmap_range.GetBaseAddress(),
clang_void_ptr_type, clang_void_ptr_type,
stop_other_threads, options,
unwind_on_error,
ignore_breakpoints,
&addr, &addr,
&length, &length,
&prot_arg, &prot_arg,
@ -115,12 +115,8 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr,
ExecutionContext exe_ctx; ExecutionContext exe_ctx;
frame->CalculateExecutionContext (exe_ctx); frame->CalculateExecutionContext (exe_ctx);
ExecutionResults result = process->RunThreadPlan (exe_ctx, ExecutionResults result = process->RunThreadPlan (exe_ctx,
call_plan_sp, call_plan_sp,
stop_other_threads, options,
try_all_threads,
unwind_on_error,
ignore_breakpoints,
timeout_usec,
error_strm); error_strm);
if (result == eExecutionCompleted) if (result == eExecutionCompleted)
{ {
@ -169,56 +165,52 @@ bool lldb_private::InferiorCallMunmap(Process *process, addr_t addr,
SymbolContext sc; SymbolContext sc;
if (sc_list.GetContextAtIndex(0, sc)) if (sc_list.GetContextAtIndex(0, sc))
{ {
const uint32_t range_scope = eSymbolContextFunction | eSymbolContextSymbol; const uint32_t range_scope = eSymbolContextFunction | eSymbolContextSymbol;
const bool use_inline_block_range = false; const bool use_inline_block_range = false;
const bool stop_other_threads = true; EvaluateExpressionOptions options;
const bool unwind_on_error = true; options.SetStopOthers(true);
const bool ignore_breakpoints = true; options.SetUnwindOnError(true);
const bool try_all_threads = true; options.SetIgnoreBreakpoints(true);
const uint32_t timeout_usec = 500000; options.SetTryAllThreads(true);
options.SetDebug (false);
options.SetTimeoutUsec(500000);
AddressRange munmap_range; AddressRange munmap_range;
if (sc.GetAddressRange(range_scope, 0, use_inline_block_range, munmap_range)) if (sc.GetAddressRange(range_scope, 0, use_inline_block_range, munmap_range))
{ {
lldb::ThreadPlanSP call_plan_sp (new ThreadPlanCallFunction (*thread, lldb::ThreadPlanSP call_plan_sp (new ThreadPlanCallFunction (*thread,
munmap_range.GetBaseAddress(), munmap_range.GetBaseAddress(),
ClangASTType(), ClangASTType(),
stop_other_threads, options,
unwind_on_error,
ignore_breakpoints,
&addr, &addr,
&length)); &length));
if (call_plan_sp) if (call_plan_sp)
{ {
StreamFile error_strm; StreamFile error_strm;
// This plan is a utility plan, so set it to discard itself when done. // This plan is a utility plan, so set it to discard itself when done.
call_plan_sp->SetIsMasterPlan (true); call_plan_sp->SetIsMasterPlan (true);
call_plan_sp->SetOkayToDiscard(true); call_plan_sp->SetOkayToDiscard(true);
StackFrame *frame = thread->GetStackFrameAtIndex (0).get(); StackFrame *frame = thread->GetStackFrameAtIndex (0).get();
if (frame) if (frame)
{ {
ExecutionContext exe_ctx; ExecutionContext exe_ctx;
frame->CalculateExecutionContext (exe_ctx); frame->CalculateExecutionContext (exe_ctx);
ExecutionResults result = process->RunThreadPlan (exe_ctx, ExecutionResults result = process->RunThreadPlan (exe_ctx,
call_plan_sp, call_plan_sp,
stop_other_threads, options,
try_all_threads, error_strm);
unwind_on_error, if (result == eExecutionCompleted)
ignore_breakpoints, {
timeout_usec, return true;
error_strm); }
if (result == eExecutionCompleted) }
{ }
return true; }
} }
} }
}
}
}
}
return false; return false;
} }
bool lldb_private::InferiorCall(Process *process, const Address *address, addr_t &returned_func) { bool lldb_private::InferiorCall(Process *process, const Address *address, addr_t &returned_func) {
@ -226,11 +218,13 @@ bool lldb_private::InferiorCall(Process *process, const Address *address, addr_t
if (thread == NULL || address == NULL) if (thread == NULL || address == NULL)
return false; return false;
const bool stop_other_threads = true; EvaluateExpressionOptions options;
const bool unwind_on_error = true; options.SetStopOthers(true);
const bool ignore_breakpoints = true; options.SetUnwindOnError(true);
const bool try_all_threads = true; options.SetIgnoreBreakpoints(true);
const uint32_t timeout_usec = 500000; options.SetTryAllThreads(true);
options.SetDebug (false);
options.SetTimeoutUsec(500000);
ClangASTContext *clang_ast_context = process->GetTarget().GetScratchClangASTContext(); ClangASTContext *clang_ast_context = process->GetTarget().GetScratchClangASTContext();
ClangASTType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); ClangASTType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
@ -238,9 +232,7 @@ bool lldb_private::InferiorCall(Process *process, const Address *address, addr_t
= new ThreadPlanCallFunction (*thread, = new ThreadPlanCallFunction (*thread,
*address, *address,
clang_void_ptr_type, clang_void_ptr_type,
stop_other_threads, options);
unwind_on_error,
ignore_breakpoints);
lldb::ThreadPlanSP call_plan_sp (call_function_thread_plan); lldb::ThreadPlanSP call_plan_sp (call_function_thread_plan);
if (call_plan_sp) if (call_plan_sp)
{ {
@ -256,11 +248,7 @@ bool lldb_private::InferiorCall(Process *process, const Address *address, addr_t
frame->CalculateExecutionContext (exe_ctx); frame->CalculateExecutionContext (exe_ctx);
ExecutionResults result = process->RunThreadPlan (exe_ctx, ExecutionResults result = process->RunThreadPlan (exe_ctx,
call_plan_sp, call_plan_sp,
stop_other_threads, options,
try_all_threads,
unwind_on_error,
ignore_breakpoints,
timeout_usec,
error_strm); error_strm);
if (result == eExecutionCompleted) if (result == eExecutionCompleted)
{ {

View File

@ -4697,11 +4697,7 @@ Process::SettingsTerminate ()
ExecutionResults ExecutionResults
Process::RunThreadPlan (ExecutionContext &exe_ctx, Process::RunThreadPlan (ExecutionContext &exe_ctx,
lldb::ThreadPlanSP &thread_plan_sp, lldb::ThreadPlanSP &thread_plan_sp,
bool stop_others, const EvaluateExpressionOptions &options,
bool run_others,
bool unwind_on_error,
bool ignore_breakpoints,
uint32_t timeout_usec,
Stream &errors) Stream &errors)
{ {
ExecutionResults return_value = eExecutionSetupError; ExecutionResults return_value = eExecutionSetupError;
@ -4812,6 +4808,17 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
thread->QueueThreadPlan(thread_plan_sp, false); // This used to pass "true" does that make sense? thread->QueueThreadPlan(thread_plan_sp, false); // This used to pass "true" does that make sense?
if (options.GetDebug())
{
// In this case, we aren't actually going to run, we just want to stop right away.
// Flush this thread so we will refetch the stacks and show the correct backtrace.
// FIXME: To make this prettier we should invent some stop reason for this, but that
// is only cosmetic, and this functionality is only of use to lldb developers who can
// live with not pretty...
thread->Flush();
return eExecutionStoppedForDebug;
}
Listener listener("lldb.process.listener.run-thread-plan"); Listener listener("lldb.process.listener.run-thread-plan");
lldb::EventSP event_to_broadcast_sp; lldb::EventSP event_to_broadcast_sp;
@ -4853,11 +4860,12 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
TimeValue one_thread_timeout = TimeValue::Now(); TimeValue one_thread_timeout = TimeValue::Now();
TimeValue final_timeout = one_thread_timeout; TimeValue final_timeout = one_thread_timeout;
if (run_others) uint32_t timeout_usec = options.GetTimeoutUsec();
if (options.GetTryAllThreads())
{ {
// If we are running all threads then we take half the time to run all threads, bounded by // If we are running all threads then we take half the time to run all threads, bounded by
// .25 sec. // .25 sec.
if (timeout_usec == 0) if (options.GetTimeoutUsec() == 0)
one_thread_timeout.OffsetWithMicroSeconds(default_one_thread_timeout_usec); one_thread_timeout.OffsetWithMicroSeconds(default_one_thread_timeout_usec);
else else
{ {
@ -4969,7 +4977,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
if (before_first_timeout) if (before_first_timeout)
{ {
if (run_others) if (options.GetTryAllThreads())
timeout_ptr = &one_thread_timeout; timeout_ptr = &one_thread_timeout;
else else
{ {
@ -5085,7 +5093,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
if (log) if (log)
log->Printf ("Process::RunThreadPlan() stopped for breakpoint: %s.", stop_info_sp->GetDescription()); log->Printf ("Process::RunThreadPlan() stopped for breakpoint: %s.", stop_info_sp->GetDescription());
return_value = eExecutionHitBreakpoint; return_value = eExecutionHitBreakpoint;
if (!ignore_breakpoints) if (!options.DoesIgnoreBreakpoints())
{ {
event_to_broadcast_sp = event_sp; event_to_broadcast_sp = event_sp;
} }
@ -5094,7 +5102,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
{ {
if (log) if (log)
log->PutCString ("Process::RunThreadPlan(): thread plan didn't successfully complete."); log->PutCString ("Process::RunThreadPlan(): thread plan didn't successfully complete.");
if (!unwind_on_error) if (!options.DoesUnwindOnError())
event_to_broadcast_sp = event_sp; event_to_broadcast_sp = event_sp;
return_value = eExecutionInterrupted; return_value = eExecutionInterrupted;
} }
@ -5145,7 +5153,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
// either exit, or try with all threads running for the same timeout. // either exit, or try with all threads running for the same timeout.
if (log) { if (log) {
if (run_others) if (options.GetTryAllThreads())
{ {
uint64_t remaining_time = final_timeout - TimeValue::Now(); uint64_t remaining_time = final_timeout - TimeValue::Now();
if (before_first_timeout) if (before_first_timeout)
@ -5228,7 +5236,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
continue; continue;
} }
if (!run_others) if (!options.GetTryAllThreads())
{ {
if (log) if (log)
log->PutCString ("Process::RunThreadPlan(): try_all_threads was false, we stopped so now we're quitting."); log->PutCString ("Process::RunThreadPlan(): try_all_threads was false, we stopped so now we're quitting.");
@ -5301,8 +5309,8 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
// 1) The execution successfully completed // 1) The execution successfully completed
// 2) We hit a breakpoint, and ignore_breakpoints was true // 2) We hit a breakpoint, and ignore_breakpoints was true
// 3) We got some other error, and discard_on_error was true // 3) We got some other error, and discard_on_error was true
bool should_unwind = (return_value == eExecutionInterrupted && unwind_on_error) bool should_unwind = (return_value == eExecutionInterrupted && options.DoesUnwindOnError())
|| (return_value == eExecutionHitBreakpoint && ignore_breakpoints); || (return_value == eExecutionHitBreakpoint && options.DoesIgnoreBreakpoints());
if (return_value == eExecutionCompleted if (return_value == eExecutionCompleted
|| should_unwind) || should_unwind)
@ -5422,7 +5430,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
if (log) if (log)
log->PutCString("Process::RunThreadPlan(): execution set up error."); log->PutCString("Process::RunThreadPlan(): execution set up error.");
if (unwind_on_error) if (options.DoesUnwindOnError())
{ {
thread->DiscardThreadPlansUpToPlan (thread_plan_sp); thread->DiscardThreadPlansUpToPlan (thread_plan_sp);
thread_plan_sp->SetPrivate (orig_plan_private); thread_plan_sp->SetPrivate (orig_plan_private);
@ -5446,7 +5454,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
{ {
if (log) if (log)
log->PutCString("Process::RunThreadPlan(): thread plan stopped in mid course"); log->PutCString("Process::RunThreadPlan(): thread plan stopped in mid course");
if (unwind_on_error && thread_plan_sp) if (options.DoesUnwindOnError() && thread_plan_sp)
{ {
if (log) if (log)
log->PutCString("Process::RunThreadPlan(): discarding thread plan 'cause unwind_on_error is set."); log->PutCString("Process::RunThreadPlan(): discarding thread plan 'cause unwind_on_error is set.");
@ -5518,6 +5526,9 @@ Process::ExecutionResultAsCString (ExecutionResults result)
case eExecutionTimedOut: case eExecutionTimedOut:
result_name = "eExecutionTimedOut"; result_name = "eExecutionTimedOut";
break; break;
case eExecutionStoppedForDebug:
result_name = "eExecutionStoppedForDebug";
break;
} }
return result_name; return result_name;
} }

View File

@ -1419,14 +1419,6 @@ Thread::QueueThreadPlanForStepInRange
} }
ThreadPlanSP
Thread::QueueThreadPlanForStepOverBreakpointPlan (bool abort_other_plans)
{
ThreadPlanSP thread_plan_sp (new ThreadPlanStepOverBreakpoint (*this));
QueueThreadPlan (thread_plan_sp, abort_other_plans);
return thread_plan_sp;
}
ThreadPlanSP ThreadPlanSP
Thread::QueueThreadPlanForStepOut Thread::QueueThreadPlanForStepOut
( (
@ -1469,25 +1461,6 @@ Thread::QueueThreadPlanForStepThrough (StackID &return_stack_id, bool abort_othe
return thread_plan_sp; return thread_plan_sp;
} }
ThreadPlanSP
Thread::QueueThreadPlanForCallFunction (bool abort_other_plans,
Address& function,
lldb::addr_t arg,
bool stop_other_threads,
bool unwind_on_error,
bool ignore_breakpoints)
{
ThreadPlanSP thread_plan_sp (new ThreadPlanCallFunction (*this,
function,
ClangASTType(),
arg,
stop_other_threads,
unwind_on_error,
ignore_breakpoints));
QueueThreadPlan (thread_plan_sp, abort_other_plans);
return thread_plan_sp;
}
ThreadPlanSP ThreadPlanSP
Thread::QueueThreadPlanForRunToAddress (bool abort_other_plans, Thread::QueueThreadPlanForRunToAddress (bool abort_other_plans,
Address &target_addr, Address &target_addr,

View File

@ -55,8 +55,6 @@ ThreadPlanCallFunction::ConstructorSetup (Thread &thread,
if (!abi) if (!abi)
return false; return false;
TargetSP target_sp (thread.CalculateTarget());
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP)); Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP));
SetBreakpoints(); SetBreakpoints();
@ -74,7 +72,7 @@ ThreadPlanCallFunction::ConstructorSetup (Thread &thread,
return false; return false;
} }
Module *exe_module = target_sp->GetExecutableModulePointer(); Module *exe_module = GetTarget().GetExecutableModulePointer();
if (exe_module == NULL) if (exe_module == NULL)
{ {
@ -107,7 +105,7 @@ ThreadPlanCallFunction::ConstructorSetup (Thread &thread,
} }
} }
start_load_addr = m_start_addr.GetLoadAddress (target_sp.get()); start_load_addr = m_start_addr.GetLoadAddress (&GetTarget());
// Checkpoint the thread state so we can restore it later. // Checkpoint the thread state so we can restore it later.
if (log && log->GetVerbose()) if (log && log->GetVerbose())
@ -120,7 +118,7 @@ ThreadPlanCallFunction::ConstructorSetup (Thread &thread,
log->Printf ("ThreadPlanCallFunction(%p): %s.", this, m_constructor_errors.GetData()); log->Printf ("ThreadPlanCallFunction(%p): %s.", this, m_constructor_errors.GetData());
return false; return false;
} }
function_load_addr = m_function_addr.GetLoadAddress (target_sp.get()); function_load_addr = m_function_addr.GetLoadAddress (&GetTarget());
return true; return true;
} }
@ -129,28 +127,30 @@ ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
const Address &function, const Address &function,
const ClangASTType &return_type, const ClangASTType &return_type,
addr_t arg, addr_t arg,
bool stop_other_threads, const EvaluateExpressionOptions &options,
bool unwind_on_error,
bool ignore_breakpoints,
addr_t *this_arg, addr_t *this_arg,
addr_t *cmd_arg) : addr_t *cmd_arg) :
ThreadPlan (ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion), ThreadPlan (ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion),
m_valid (false), m_valid (false),
m_stop_other_threads (stop_other_threads), m_stop_other_threads (options.GetStopOthers()),
m_unwind_on_error (options.DoesUnwindOnError()),
m_ignore_breakpoints (options.DoesIgnoreBreakpoints()),
m_debug_execution (options.GetDebug()),
m_trap_exceptions (options.GetTrapExceptions()),
m_function_addr (function), m_function_addr (function),
m_function_sp (0), m_function_sp (0),
m_return_type (return_type), m_return_type (return_type),
m_takedown_done (false), m_takedown_done (false),
m_stop_address (LLDB_INVALID_ADDRESS), m_should_clear_objc_exception_bp(false),
m_unwind_on_error (unwind_on_error), m_should_clear_cxx_exception_bp (false),
m_ignore_breakpoints (ignore_breakpoints) m_stop_address (LLDB_INVALID_ADDRESS)
{ {
lldb::addr_t start_load_addr; lldb::addr_t start_load_addr;
ABI *abi; ABI *abi;
lldb::addr_t function_load_addr; lldb::addr_t function_load_addr;
if (!ConstructorSetup (thread, abi, start_load_addr, function_load_addr)) if (!ConstructorSetup (thread, abi, start_load_addr, function_load_addr))
return; return;
if (this_arg && cmd_arg) if (this_arg && cmd_arg)
{ {
if (!abi->PrepareTrivialCall (thread, if (!abi->PrepareTrivialCall (thread,
@ -191,9 +191,7 @@ ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread, ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
const Address &function, const Address &function,
const ClangASTType &return_type, const ClangASTType &return_type,
bool stop_other_threads, const EvaluateExpressionOptions &options,
bool unwind_on_error,
bool ignore_breakpoints,
addr_t *arg1_ptr, addr_t *arg1_ptr,
addr_t *arg2_ptr, addr_t *arg2_ptr,
addr_t *arg3_ptr, addr_t *arg3_ptr,
@ -202,14 +200,16 @@ ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
addr_t *arg6_ptr) : addr_t *arg6_ptr) :
ThreadPlan (ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion), ThreadPlan (ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion),
m_valid (false), m_valid (false),
m_stop_other_threads (stop_other_threads), m_stop_other_threads (options.GetStopOthers()),
m_unwind_on_error (options.DoesUnwindOnError()),
m_ignore_breakpoints (options.DoesIgnoreBreakpoints()),
m_debug_execution (options.GetDebug()),
m_trap_exceptions (options.GetTrapExceptions()),
m_function_addr (function), m_function_addr (function),
m_function_sp (0), m_function_sp (0),
m_return_type (return_type), m_return_type (return_type),
m_takedown_done (false), m_takedown_done (false),
m_stop_address (LLDB_INVALID_ADDRESS), m_stop_address (LLDB_INVALID_ADDRESS)
m_unwind_on_error (unwind_on_error),
m_ignore_breakpoints (ignore_breakpoints)
{ {
lldb::addr_t start_load_addr; lldb::addr_t start_load_addr;
ABI *abi; ABI *abi;
@ -560,25 +560,34 @@ void
ThreadPlanCallFunction::SetBreakpoints () ThreadPlanCallFunction::SetBreakpoints ()
{ {
ProcessSP process_sp (m_thread.CalculateProcess()); ProcessSP process_sp (m_thread.CalculateProcess());
if (process_sp) if (m_trap_exceptions && process_sp)
{ {
m_cxx_language_runtime = process_sp->GetLanguageRuntime(eLanguageTypeC_plus_plus); m_cxx_language_runtime = process_sp->GetLanguageRuntime(eLanguageTypeC_plus_plus);
m_objc_language_runtime = process_sp->GetLanguageRuntime(eLanguageTypeObjC); m_objc_language_runtime = process_sp->GetLanguageRuntime(eLanguageTypeObjC);
if (m_cxx_language_runtime) if (m_cxx_language_runtime)
{
m_should_clear_cxx_exception_bp = !m_cxx_language_runtime->ExceptionBreakpointsAreSet();
m_cxx_language_runtime->SetExceptionBreakpoints(); m_cxx_language_runtime->SetExceptionBreakpoints();
}
if (m_objc_language_runtime) if (m_objc_language_runtime)
{
m_should_clear_objc_exception_bp = !m_objc_language_runtime->ExceptionBreakpointsAreSet();
m_objc_language_runtime->SetExceptionBreakpoints(); m_objc_language_runtime->SetExceptionBreakpoints();
}
} }
} }
void void
ThreadPlanCallFunction::ClearBreakpoints () ThreadPlanCallFunction::ClearBreakpoints ()
{ {
if (m_cxx_language_runtime) if (m_trap_exceptions)
m_cxx_language_runtime->ClearExceptionBreakpoints(); {
if (m_objc_language_runtime) if (m_cxx_language_runtime && m_should_clear_cxx_exception_bp)
m_objc_language_runtime->ClearExceptionBreakpoints(); m_cxx_language_runtime->ClearExceptionBreakpoints();
if (m_objc_language_runtime && m_should_clear_objc_exception_bp)
m_objc_language_runtime->ClearExceptionBreakpoints();
}
} }
bool bool
@ -586,21 +595,24 @@ ThreadPlanCallFunction::BreakpointsExplainStop()
{ {
StopInfoSP stop_info_sp = GetPrivateStopInfo (); StopInfoSP stop_info_sp = GetPrivateStopInfo ();
if ((m_cxx_language_runtime && if (m_trap_exceptions)
m_cxx_language_runtime->ExceptionBreakpointsExplainStop(stop_info_sp))
||(m_objc_language_runtime &&
m_objc_language_runtime->ExceptionBreakpointsExplainStop(stop_info_sp)))
{ {
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP)); if ((m_cxx_language_runtime &&
if (log) m_cxx_language_runtime->ExceptionBreakpointsExplainStop(stop_info_sp))
log->Printf ("ThreadPlanCallFunction::BreakpointsExplainStop - Hit an exception breakpoint, setting plan complete."); ||(m_objc_language_runtime &&
m_objc_language_runtime->ExceptionBreakpointsExplainStop(stop_info_sp)))
SetPlanComplete(false); {
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP));
// If the user has set the ObjC language breakpoint, it would normally get priority over our internal if (log)
// catcher breakpoint, but in this case we can't let that happen, so force the ShouldStop here. log->Printf ("ThreadPlanCallFunction::BreakpointsExplainStop - Hit an exception breakpoint, setting plan complete.");
stop_info_sp->OverrideShouldStop (true);
return true; SetPlanComplete(false);
// If the user has set the ObjC language breakpoint, it would normally get priority over our internal
// catcher breakpoint, but in this case we can't let that happen, so force the ShouldStop here.
stop_info_sp->OverrideShouldStop (true);
return true;
}
} }
return false; return false;

View File

@ -39,13 +39,11 @@ using namespace lldb_private;
ThreadPlanCallUserExpression::ThreadPlanCallUserExpression (Thread &thread, ThreadPlanCallUserExpression::ThreadPlanCallUserExpression (Thread &thread,
Address &function, Address &function,
lldb::addr_t arg, lldb::addr_t arg,
bool stop_other_threads, const EvaluateExpressionOptions &options,
bool unwind_on_error,
bool ignore_breakpoints,
lldb::addr_t *this_arg, lldb::addr_t *this_arg,
lldb::addr_t *cmd_arg, lldb::addr_t *cmd_arg,
ClangUserExpression::ClangUserExpressionSP &user_expression_sp) : ClangUserExpression::ClangUserExpressionSP &user_expression_sp) :
ThreadPlanCallFunction (thread, function, ClangASTType(), arg, stop_other_threads, unwind_on_error, ignore_breakpoints, this_arg, cmd_arg), ThreadPlanCallFunction (thread, function, ClangASTType(), arg, options, this_arg, cmd_arg),
m_user_expression_sp (user_expression_sp) m_user_expression_sp (user_expression_sp)
{ {
// User expressions are generally "User generated" so we should set them up to stop when done. // User expressions are generally "User generated" so we should set them up to stop when done.

View File

@ -98,6 +98,17 @@ class ExprCommandWithThrowTestCase(TestBase):
self.assertTrue (value.IsValid() and value.GetError().Success() == False) self.assertTrue (value.IsValid() and value.GetError().Success() == False)
self.check_after_call() self.check_after_call()
# Now turn off exception trapping, and call a function that catches the exceptions,
# and make sure the function actually completes, and we get the right value:
options.SetTrapExceptions(False)
value = frame.EvaluateExpression ("[my_class iCatchMyself]", options)
self.assertTrue (value.IsValid())
self.assertTrue (value.GetError().Success() == True)
self.assertTrue (value.GetValueAsUnsigned() == 57)
self.check_after_call()
options.SetTrapExceptions(True)
# Now set this unwind on error to false, and make sure that we stop where the exception was thrown # Now set this unwind on error to false, and make sure that we stop where the exception was thrown
options.SetUnwindOnError(False) options.SetUnwindOnError(False)
value = frame.EvaluateExpression ("[my_class callMeIThrow]", options) value = frame.EvaluateExpression ("[my_class callMeIThrow]", options)

View File

@ -4,6 +4,7 @@
{ {
} }
- (int) callMeIThrow; - (int) callMeIThrow;
- (int) iCatchMyself;
@end @end
@implementation MyClass @implementation MyClass
@ -16,6 +17,20 @@
@throw e; @throw e;
return 56; return 56;
} }
- (int) iCatchMyself
{
int return_value = 55;
@try
{
return_value = [self callMeIThrow];
}
@catch (NSException *e)
{
return_value = 57;
}
return return_value;
}
@end @end
int int
@ -26,7 +41,7 @@ main ()
NSLog (@"I am about to throw."); NSLog (@"I am about to throw.");
return_value = [my_class callMeIThrow]; return_value = [my_class iCatchMyself];
return return_value; return return_value;
} }