Move the handling of breakpoint conditions from the Private event loop to the StopInfoBreakpoint::DoActions, which happens as the
event is removed. Also use the return value of asynchronous breakpoint callbacks, they get checked before, and override the
breakpoint conditions.
Added ProcessModInfo class, to unify "stop_id generation" and "memory modification generation", and use where needed.
git-svn-id: https://llvm.org/svn/llvm-project/llvdb/trunk@137102 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Target/StopInfo.cpp b/source/Target/StopInfo.cpp
index a958710..79cdab4 100644
--- a/source/Target/StopInfo.cpp
+++ b/source/Target/StopInfo.cpp
@@ -19,7 +19,10 @@
#include "lldb/Breakpoint/Breakpoint.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/Debugger.h"
#include "lldb/Core/StreamString.h"
+#include "lldb/Expression/ClangUserExpression.h"
+#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlan.h"
#include "lldb/Target/Process.h"
@@ -47,10 +50,18 @@
m_stop_id = m_thread.GetProcess().GetStopID();
}
+lldb::StateType
+StopInfo::GetPrivateState ()
+{
+ return m_thread.GetProcess().GetPrivateState();
+}
+
//----------------------------------------------------------------------
// StopInfoBreakpoint
//----------------------------------------------------------------------
+namespace lldb_private
+{
class StopInfoBreakpoint : public StopInfo
{
public:
@@ -121,21 +132,122 @@
return;
m_should_perform_action = false;
+ LogSP log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
+ // We're going to calculate whether we should stop or not in some way during the course of
+ // this code. So set the valid flag here. Also by default we're going to stop, so
+ // set that here too.
+ // m_should_stop_is_valid = true;
+ m_should_stop = true;
+
BreakpointSiteSP bp_site_sp (m_thread.GetProcess().GetBreakpointSiteList().FindByID (m_value));
if (bp_site_sp)
{
size_t num_owners = bp_site_sp->GetNumberOfOwners();
+
+ // We only continue from the callbacks if ALL the callbacks want us to continue.
+ // However we want to run all the callbacks, except of course if one of them actually
+ // resumes the target.
+ // So we use stop_requested to track what we're were asked to do.
+ bool stop_requested = true;
for (size_t j = 0; j < num_owners; j++)
{
- // The breakpoint action is an asynchronous breakpoint callback. If we ever need to have both
- // callbacks and actions on the same breakpoint, we'll have to split this into two.
lldb::BreakpointLocationSP bp_loc_sp = bp_site_sp->GetOwnerAtIndex(j);
StoppointCallbackContext context (event_ptr,
&m_thread.GetProcess(),
&m_thread,
m_thread.GetStackFrameAtIndex(0).get(),
false);
- bp_loc_sp->InvokeCallback (&context);
+ stop_requested = bp_loc_sp->InvokeCallback (&context);
+ // Also make sure that the callback hasn't continued the target.
+ // If it did, when we'll set m_should_start to false and get out of here.
+ if (GetPrivateState() == eStateRunning)
+ m_should_stop = false;
+ }
+
+ if (m_should_stop && !stop_requested)
+ {
+ m_should_stop_is_valid = true;
+ m_should_stop = false;
+ }
+
+ // Okay, so now if all the callbacks say we should stop, let's try the Conditions:
+ if (m_should_stop)
+ {
+ size_t num_owners = bp_site_sp->GetNumberOfOwners();
+ for (size_t j = 0; j < num_owners; j++)
+ {
+ lldb::BreakpointLocationSP bp_loc_sp = bp_site_sp->GetOwnerAtIndex(j);
+ if (bp_loc_sp->GetConditionText() != NULL)
+ {
+ // We need to make sure the user sees any parse errors in their condition, so we'll hook the
+ // constructor errors up to the debugger's Async I/O.
+
+ StoppointCallbackContext context (event_ptr,
+ &m_thread.GetProcess(),
+ &m_thread,
+ m_thread.GetStackFrameAtIndex(0).get(),
+ false);
+ ValueObjectSP result_valobj_sp;
+
+ ExecutionResults result_code;
+ ValueObjectSP result_value_sp;
+ const bool discard_on_error = true;
+ Error error;
+ result_code = ClangUserExpression::EvaluateWithError (context.exe_ctx,
+ discard_on_error,
+ bp_loc_sp->GetConditionText(),
+ NULL,
+ result_value_sp,
+ error);
+ if (result_code == eExecutionCompleted)
+ {
+ if (result_value_sp)
+ {
+ Scalar scalar_value;
+ if (result_value_sp->ResolveValue (scalar_value))
+ {
+ if (scalar_value.ULongLong(1) == 0)
+ m_should_stop = false;
+ else
+ m_should_stop = true;
+ if (log)
+ log->Printf("Condition successfully evaluated, result is %s.\n",
+ m_should_stop ? "true" : "false");
+ }
+ else
+ {
+ m_should_stop = true;
+ if (log)
+ log->Printf("Failed to get an integer result from the expression.");
+ }
+ }
+ }
+ else
+ {
+ Debugger &debugger = context.exe_ctx.target->GetDebugger();
+ StreamSP error_sp = debugger.GetAsyncErrorStream ();
+ error_sp->Printf ("Stopped due to an error evaluating condition of breakpoint ");
+ bp_loc_sp->GetDescription (error_sp.get(), eDescriptionLevelBrief);
+ error_sp->Printf (": \"%s\"",
+ bp_loc_sp->GetConditionText());
+ error_sp->EOL();
+ const char *err_str = error.AsCString("<Unknown Error>");
+ if (log)
+ log->Printf("Error evaluating condition: \"%s\"\n", err_str);
+
+ error_sp->PutCString (err_str);
+ error_sp->EOL();
+ error_sp->Flush();
+ // If the condition fails to be parsed or run, we should stop.
+ m_should_stop = true;
+ }
+ }
+
+ // If any condition says we should stop, then we're going to stop, so we don't need
+ // to evaluate the others.
+ if (m_should_stop)
+ break;
+ }
}
}
else
@@ -145,6 +257,8 @@
if (log)
log->Printf ("Process::%s could not find breakpoint site id: %lld...", __FUNCTION__, m_value);
}
+ if (log)
+ log->Printf ("Process::%s returning from action with m_should_stop: %d.", __FUNCTION__, m_should_stop);
}
virtual bool
@@ -417,6 +531,7 @@
private:
ThreadPlanSP m_plan_sp;
};
+} // namespace lldb_private
StopInfoSP
StopInfo::CreateStopReasonWithBreakpointSiteID (Thread &thread, break_id_t break_id)