[Lldb-commits] [lldb] r142227 - in /lldb/trunk: include/lldb/API/SBWatchpoint.h include/lldb/Breakpoint/Watchpoint.h scripts/Python/interface/SBWatchpoint.i source/API/SBWatchpoint.cpp source/Breakpoint/Watchpoint.cpp source/Commands/CommandObjectWatchpoint.cpp source/Commands/CommandObjectWatchpoint.h source/Target/StopInfo.cpp test/functionalities/watchpoint/multiple_threads/main.cpp test/functionalities/watchpoint/watchpoint_commands/condition/
Johnny Chen
johnny.chen at apple.com
Mon Oct 17 11:58:01 PDT 2011
Author: johnny
Date: Mon Oct 17 13:58:00 2011
New Revision: 142227
URL: http://llvm.org/viewvc/llvm-project?rev=142227&view=rev
Log:
Add a commnad to set a condition for a watchpoint. Example:
watchpoint modify -c 'global==5'
modifies the last created watchpoint so that the condition expression
is evaluated at the stop point to decide whether we should proceed with
the stopping.
Also add SBWatchpont::SetCondition(const char *condition) to set condition
programmatically.
Test cases to come later.
Added:
lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/condition/
Modified:
lldb/trunk/include/lldb/API/SBWatchpoint.h
lldb/trunk/include/lldb/Breakpoint/Watchpoint.h
lldb/trunk/scripts/Python/interface/SBWatchpoint.i
lldb/trunk/source/API/SBWatchpoint.cpp
lldb/trunk/source/Breakpoint/Watchpoint.cpp
lldb/trunk/source/Commands/CommandObjectWatchpoint.cpp
lldb/trunk/source/Commands/CommandObjectWatchpoint.h
lldb/trunk/source/Target/StopInfo.cpp
lldb/trunk/test/functionalities/watchpoint/multiple_threads/main.cpp
Modified: lldb/trunk/include/lldb/API/SBWatchpoint.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/API/SBWatchpoint.h?rev=142227&r1=142226&r2=142227&view=diff
==============================================================================
--- lldb/trunk/include/lldb/API/SBWatchpoint.h (original)
+++ lldb/trunk/include/lldb/API/SBWatchpoint.h Mon Oct 17 13:58:00 2011
@@ -63,6 +63,12 @@
void
SetIgnoreCount (uint32_t n);
+ const char *
+ GetCondition ();
+
+ void
+ SetCondition (const char *condition);
+
bool
GetDescription (lldb::SBStream &description, DescriptionLevel level);
Modified: lldb/trunk/include/lldb/Breakpoint/Watchpoint.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Breakpoint/Watchpoint.h?rev=142227&r1=142226&r2=142227&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Breakpoint/Watchpoint.h (original)
+++ lldb/trunk/include/lldb/Breakpoint/Watchpoint.h Mon Oct 17 13:58:00 2011
@@ -53,6 +53,7 @@
void SetIgnoreCount (uint32_t n);
void SetWatchpointType (uint32_t type);
bool SetCallback (WatchpointHitCallback callback, void *callback_baton);
+ void ClearCallback();
void SetDeclInfo (std::string &str);
void GetDescription (Stream *s, lldb::DescriptionLevel level);
void Dump (Stream *s) const;
@@ -60,6 +61,39 @@
Target &GetTarget() { return *m_target; }
const Error &GetError() { return m_error; }
+ //------------------------------------------------------------------
+ /// Invoke the callback action when the watchpoint is hit.
+ ///
+ /// @param[in] context
+ /// Described the watchpoint event.
+ ///
+ /// @return
+ /// \b true if the target should stop at this watchpoint and \b false not.
+ //------------------------------------------------------------------
+ bool
+ InvokeCallback (StoppointCallbackContext *context);
+
+ //------------------------------------------------------------------
+ // Condition
+ //------------------------------------------------------------------
+ //------------------------------------------------------------------
+ /// Set the breakpoint's condition.
+ ///
+ /// @param[in] condition
+ /// The condition expression to evaluate when the breakpoint is hit.
+ /// Pass in NULL to clear the condition.
+ //------------------------------------------------------------------
+ void SetCondition (const char *condition);
+
+ //------------------------------------------------------------------
+ /// Return a pointer to the text of the condition expression.
+ ///
+ /// @return
+ /// A pointer to the condition expression text, or NULL if no
+ // condition has been set.
+ //------------------------------------------------------------------
+ const char *GetConditionText () const;
+
private:
friend class Target;
@@ -78,6 +112,7 @@
std::string m_decl_str; // Declaration information, if any.
Error m_error; // An error object describing errors creating watchpoint.
+ std::auto_ptr<ClangUserExpression> m_condition_ap; // The condition to test.
static lldb::break_id_t
GetNextID();
Modified: lldb/trunk/scripts/Python/interface/SBWatchpoint.i
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/scripts/Python/interface/SBWatchpoint.i?rev=142227&r1=142226&r2=142227&view=diff
==============================================================================
--- lldb/trunk/scripts/Python/interface/SBWatchpoint.i (original)
+++ lldb/trunk/scripts/Python/interface/SBWatchpoint.i Mon Oct 17 13:58:00 2011
@@ -66,6 +66,12 @@
void
SetIgnoreCount (uint32_t n);
+ const char *
+ GetCondition ();
+
+ void
+ SetCondition (const char *condition);
+
bool
GetDescription (lldb::SBStream &description, DescriptionLevel level);
};
Modified: lldb/trunk/source/API/SBWatchpoint.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/API/SBWatchpoint.cpp?rev=142227&r1=142226&r2=142227&view=diff
==============================================================================
--- lldb/trunk/source/API/SBWatchpoint.cpp (original)
+++ lldb/trunk/source/API/SBWatchpoint.cpp Mon Oct 17 13:58:00 2011
@@ -205,6 +205,27 @@
}
}
+const char *
+SBWatchpoint::GetCondition ()
+{
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
+ return m_opaque_sp->GetConditionText ();
+ }
+ return NULL;
+}
+
+void
+SBWatchpoint::SetCondition (const char *condition)
+{
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
+ m_opaque_sp->SetCondition (condition);
+ }
+}
+
bool
SBWatchpoint::GetDescription (SBStream &description, DescriptionLevel level)
{
Modified: lldb/trunk/source/Breakpoint/Watchpoint.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Breakpoint/Watchpoint.cpp?rev=142227&r1=142226&r2=142227&view=diff
==============================================================================
--- lldb/trunk/source/Breakpoint/Watchpoint.cpp (original)
+++ lldb/trunk/source/Breakpoint/Watchpoint.cpp Mon Oct 17 13:58:00 2011
@@ -13,7 +13,12 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
#include "lldb/Core/Stream.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadSpec.h"
+#include "lldb/Target/ThreadPlanTestCondition.h"
using namespace lldb;
using namespace lldb_private;
@@ -82,16 +87,7 @@
if (m_hit_count <= GetIgnoreCount())
return false;
- uint32_t access = 0;
- if (m_watch_was_read)
- access |= LLDB_WATCH_TYPE_READ;
- if (m_watch_was_written)
- access |= LLDB_WATCH_TYPE_WRITE;
-
- if (m_callback)
- return m_callback(m_callback_baton, context, GetID(), access);
- else
- return true;
+ return true;
}
void
@@ -124,8 +120,12 @@
m_watch_read ? "r" : "",
m_watch_write ? "w" : "");
- if (description_level >= lldb::eDescriptionLevelFull)
- s->Printf("\n declare @ '%s'", m_decl_str.c_str());
+ if (description_level >= lldb::eDescriptionLevelFull) {
+ if (m_decl_str.c_str())
+ s->Printf("\n declare @ '%s'", m_decl_str.c_str());
+ if (GetConditionText())
+ s->Printf("\n condition = '%s'", GetConditionText());
+ }
if (description_level >= lldb::eDescriptionLevelVerbose)
if (m_callback)
@@ -184,3 +184,44 @@
{
m_ignore_count = n;
}
+
+bool
+Watchpoint::InvokeCallback (StoppointCallbackContext *context)
+{
+ if (m_callback && context->is_synchronous)
+ {
+ uint32_t access = 0;
+ if (m_watch_was_read)
+ access |= LLDB_WATCH_TYPE_READ;
+ if (m_watch_was_written)
+ access |= LLDB_WATCH_TYPE_WRITE;
+ return m_callback(m_callback_baton, context, GetID(), access);
+ }
+ else
+ return true;
+}
+
+void
+Watchpoint::SetCondition (const char *condition)
+{
+ if (condition == NULL || condition[0] == '\0')
+ {
+ if (m_condition_ap.get())
+ m_condition_ap.reset();
+ }
+ else
+ {
+ // Pass NULL for expr_prefix (no translation-unit level definitions).
+ m_condition_ap.reset(new ClangUserExpression (condition, NULL));
+ }
+}
+
+const char *
+Watchpoint::GetConditionText () const
+{
+ if (m_condition_ap.get())
+ return m_condition_ap->GetUserText();
+ else
+ return NULL;
+}
+
Modified: lldb/trunk/source/Commands/CommandObjectWatchpoint.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectWatchpoint.cpp?rev=142227&r1=142226&r2=142227&view=diff
==============================================================================
--- lldb/trunk/source/Commands/CommandObjectWatchpoint.cpp (original)
+++ lldb/trunk/source/Commands/CommandObjectWatchpoint.cpp Mon Oct 17 13:58:00 2011
@@ -156,18 +156,21 @@
CommandObjectSP disable_command_object (new CommandObjectWatchpointDisable (interpreter));
CommandObjectSP delete_command_object (new CommandObjectWatchpointDelete (interpreter));
CommandObjectSP ignore_command_object (new CommandObjectWatchpointIgnore (interpreter));
+ CommandObjectSP modify_command_object (new CommandObjectWatchpointModify (interpreter));
list_command_object->SetCommandName ("watchpoint list");
enable_command_object->SetCommandName("watchpoint enable");
disable_command_object->SetCommandName("watchpoint disable");
delete_command_object->SetCommandName("watchpoint delete");
ignore_command_object->SetCommandName("watchpoint ignore");
+ modify_command_object->SetCommandName("watchpoint modify");
status = LoadSubCommand ("list", list_command_object);
status = LoadSubCommand ("enable", enable_command_object);
status = LoadSubCommand ("disable", disable_command_object);
status = LoadSubCommand ("delete", delete_command_object);
status = LoadSubCommand ("ignore", ignore_command_object);
+ status = LoadSubCommand ("modify", modify_command_object);
}
CommandObjectMultiwordWatchpoint::~CommandObjectMultiwordWatchpoint()
@@ -693,3 +696,151 @@
return result.Succeeded();
}
+//-------------------------------------------------------------------------
+// CommandObjectWatchpointModify::CommandOptions
+//-------------------------------------------------------------------------
+#pragma mark Modify::CommandOptions
+
+CommandObjectWatchpointModify::CommandOptions::CommandOptions(CommandInterpreter &interpreter) :
+ Options (interpreter),
+ m_condition (),
+ m_condition_passed (false)
+{
+}
+
+CommandObjectWatchpointModify::CommandOptions::~CommandOptions ()
+{
+}
+
+OptionDefinition
+CommandObjectWatchpointModify::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_ALL, false, "condition", 'c', required_argument, NULL, NULL, eArgTypeExpression, "The watchpoint stops only if this condition expression evaluates to true."},
+{ 0, false, NULL, 0 , 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+const OptionDefinition*
+CommandObjectWatchpointModify::CommandOptions::GetDefinitions ()
+{
+ return g_option_table;
+}
+
+Error
+CommandObjectWatchpointModify::CommandOptions::SetOptionValue (uint32_t option_idx, const char *option_arg)
+{
+ Error error;
+ char short_option = (char) m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'c':
+ if (option_arg != NULL)
+ m_condition.assign (option_arg);
+ else
+ m_condition.clear();
+ m_condition_passed = true;
+ break;
+ default:
+ error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option);
+ break;
+ }
+
+ return error;
+}
+
+void
+CommandObjectWatchpointModify::CommandOptions::OptionParsingStarting ()
+{
+ m_condition.clear();
+ m_condition_passed = false;
+}
+
+//-------------------------------------------------------------------------
+// CommandObjectWatchpointModify
+//-------------------------------------------------------------------------
+#pragma mark Modify
+
+CommandObjectWatchpointModify::CommandObjectWatchpointModify (CommandInterpreter &interpreter) :
+ CommandObject (interpreter,
+ "watchpoint modify",
+ "Modify the options on a watchpoint or set of watchpoints in the executable. "
+ "If no watchpoint is specified, act on the last created watchpoint. "
+ "Passing an empty argument clears the modification.",
+ NULL),
+ m_options (interpreter)
+{
+ CommandArgumentEntry arg;
+ CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, eArgTypeWatchpointIDRange);
+ // Add the entry for the first argument for this command to the object's arguments vector.
+ m_arguments.push_back (arg);
+}
+
+CommandObjectWatchpointModify::~CommandObjectWatchpointModify ()
+{
+}
+
+Options *
+CommandObjectWatchpointModify::GetOptions ()
+{
+ return &m_options;
+}
+
+bool
+CommandObjectWatchpointModify::Execute
+(
+ Args& args,
+ CommandReturnObject &result
+)
+{
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (!CheckTargetForWatchpointOperations(target, result))
+ return false;
+
+ Mutex::Locker locker;
+ target->GetWatchpointList().GetListMutex(locker);
+
+ const WatchpointList &watchpoints = target->GetWatchpointList();
+
+ size_t num_watchpoints = watchpoints.GetSize();
+
+ if (num_watchpoints == 0)
+ {
+ result.AppendError("No watchpoints exist to be modified.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (args.GetArgumentCount() == 0)
+ {
+ WatchpointSP wp_sp = target->GetLastCreatedWatchpoint();
+ wp_sp->SetCondition(m_options.m_condition.c_str());
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ // Particular watchpoints selected; set condition on them.
+ std::vector<uint32_t> wp_ids;
+ if (!VerifyWatchpointIDs(args, wp_ids))
+ {
+ result.AppendError("Invalid watchpoints specification.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ int count = 0;
+ const size_t size = wp_ids.size();
+ for (size_t i = 0; i < size; ++i)
+ {
+ WatchpointSP wp_sp = watchpoints.FindByID(wp_ids[i]);
+ if (wp_sp)
+ {
+ wp_sp->SetCondition(m_options.m_condition.c_str());
+ ++count;
+ }
+ }
+ result.AppendMessageWithFormat("%d watchpoints modified.\n",count);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+
+ return result.Succeeded();
+}
Modified: lldb/trunk/source/Commands/CommandObjectWatchpoint.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectWatchpoint.h?rev=142227&r1=142226&r2=142227&view=diff
==============================================================================
--- lldb/trunk/source/Commands/CommandObjectWatchpoint.h (original)
+++ lldb/trunk/source/Commands/CommandObjectWatchpoint.h Mon Oct 17 13:58:00 2011
@@ -190,6 +190,58 @@
CommandOptions m_options;
};
+//-------------------------------------------------------------------------
+// CommandObjectWatchpointModify
+//-------------------------------------------------------------------------
+
+class CommandObjectWatchpointModify : public CommandObject
+{
+public:
+
+ CommandObjectWatchpointModify (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectWatchpointModify ();
+
+ virtual bool
+ Execute (Args& command,
+ CommandReturnObject &result);
+
+ virtual Options *
+ GetOptions ();
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandOptions ();
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg);
+
+ void
+ OptionParsingStarting ();
+
+ const OptionDefinition*
+ GetDefinitions ();
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ std::string m_condition;
+ bool m_condition_passed;
+ };
+
+private:
+ CommandOptions m_options;
+};
+
} // namespace lldb_private
#endif // liblldb_CommandObjectWatchpoint_h_
Modified: lldb/trunk/source/Target/StopInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/StopInfo.cpp?rev=142227&r1=142226&r2=142227&view=diff
==============================================================================
--- lldb/trunk/source/Target/StopInfo.cpp (original)
+++ lldb/trunk/source/Target/StopInfo.cpp Mon Oct 17 13:58:00 2011
@@ -346,6 +346,12 @@
ShouldStop (Event *event_ptr)
{
// ShouldStop() method is idempotent and should not affect hit count.
+ // See Process::RunPrivateStateThread()->Process()->HandlePrivateEvent()
+ // -->Process()::ShouldBroadcastEvent()->ThreadList::ShouldStop()->
+ // Thread::ShouldStop()->ThreadPlanBase::ShouldStop()->
+ // StopInfoWatchpoint::ShouldStop() and
+ // Event::DoOnRemoval()->Process::ProcessEventData::DoOnRemoval()->
+ // StopInfoWatchpoint::PerformAction().
if (m_should_stop_is_valid)
return m_should_stop;
@@ -376,6 +382,118 @@
return m_should_stop;
}
+ // Perform any action that is associated with this stop. This is done as the
+ // Event is removed from the event queue.
+ virtual void
+ PerformAction (Event *event_ptr)
+ {
+ LogSP log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
+ // We're going to calculate if we should stop or not in some way during the course of
+ // this code. Also by default we're going to stop, so set that here.
+ m_should_stop = true;
+
+ WatchpointSP wp_sp =
+ m_thread.GetProcess().GetTarget().GetWatchpointList().FindByID(GetValue());
+ if (wp_sp)
+ {
+ StoppointCallbackContext context (event_ptr,
+ &m_thread.GetProcess(),
+ &m_thread,
+ m_thread.GetStackFrameAtIndex(0).get(),
+ false);
+ bool stop_requested = wp_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)
+ {
+ // We have been vetoed.
+ m_should_stop = false;
+ }
+
+ if (m_should_stop && wp_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);
+ ExecutionResults result_code;
+ ValueObjectSP result_value_sp;
+ const bool discard_on_error = true;
+ Error error;
+ result_code = ClangUserExpression::EvaluateWithError (context.exe_ctx,
+ eExecutionPolicyAlways,
+ discard_on_error,
+ wp_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)
+ {
+ // We have been vetoed. This takes precedence over querying
+ // the watchpoint whether it should stop (aka ignore count and
+ // friends). See also StopInfoWatchpoint::ShouldStop() as well
+ // as Process::ProcessEventData::DoOnRemoval().
+ 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.GetTargetRef().GetDebugger();
+ StreamSP error_sp = debugger.GetAsyncErrorStream ();
+ error_sp->Printf ("Stopped due to an error evaluating condition of breakpoint ");
+ wp_sp->GetDescription (error_sp.get(), eDescriptionLevelBrief);
+ error_sp->Printf (": \"%s\"",
+ wp_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;
+ }
+ }
+ }
+ else
+ {
+ LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ if (log)
+ log->Printf ("Process::%s could not find watchpoint id: %lld...", __FUNCTION__, m_value);
+ }
+ if (log)
+ log->Printf ("Process::%s returning from action with m_should_stop: %d.", __FUNCTION__, m_should_stop);
+ }
+
virtual const char *
GetDescription ()
{
Modified: lldb/trunk/test/functionalities/watchpoint/multiple_threads/main.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/watchpoint/multiple_threads/main.cpp?rev=142227&r1=142226&r2=142227&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/watchpoint/multiple_threads/main.cpp (original)
+++ lldb/trunk/test/functionalities/watchpoint/multiple_threads/main.cpp Mon Oct 17 13:58:00 2011
@@ -30,8 +30,10 @@
::pthread_mutex_lock (&g_access_mutex);
uint32_t old_val = g_val;
- if (flag != 0)
+ if (flag != 0) {
+ printf("changing g_val to %d...\n", (old_val + 1));
g_val = old_val + 1;
+ }
if (flag == 0)
::pthread_mutex_unlock (&g_access_mutex);
More information about the lldb-commits
mailing list