summaryrefslogtreecommitdiff
path: root/source/Breakpoint
diff options
context:
space:
mode:
authorEd Maste <emaste@FreeBSD.org>2013-08-23 17:46:38 +0000
committerEd Maste <emaste@FreeBSD.org>2013-08-23 17:46:38 +0000
commitf034231a6a1fd5d6395206c1651de8cd9402cca3 (patch)
treef561dabc721ad515599172c16da3a4400b7f4aec /source/Breakpoint
Notes
Diffstat (limited to 'source/Breakpoint')
-rw-r--r--source/Breakpoint/Breakpoint.cpp794
-rw-r--r--source/Breakpoint/BreakpointID.cpp123
-rw-r--r--source/Breakpoint/BreakpointIDList.cpp397
-rw-r--r--source/Breakpoint/BreakpointList.cpp243
-rw-r--r--source/Breakpoint/BreakpointLocation.cpp677
-rw-r--r--source/Breakpoint/BreakpointLocationCollection.cpp198
-rw-r--r--source/Breakpoint/BreakpointLocationList.cpp305
-rw-r--r--source/Breakpoint/BreakpointOptions.cpp298
-rw-r--r--source/Breakpoint/BreakpointResolver.cpp61
-rw-r--r--source/Breakpoint/BreakpointResolverAddress.cpp111
-rw-r--r--source/Breakpoint/BreakpointResolverFileLine.cpp246
-rw-r--r--source/Breakpoint/BreakpointResolverFileRegex.cpp134
-rw-r--r--source/Breakpoint/BreakpointResolverName.cpp357
-rw-r--r--source/Breakpoint/BreakpointSite.cpp234
-rw-r--r--source/Breakpoint/BreakpointSiteList.cpp240
-rw-r--r--source/Breakpoint/Stoppoint.cpp46
-rw-r--r--source/Breakpoint/StoppointCallbackContext.cpp39
-rw-r--r--source/Breakpoint/StoppointLocation.cpp48
-rw-r--r--source/Breakpoint/Watchpoint.cpp489
-rw-r--r--source/Breakpoint/WatchpointList.cpp306
-rw-r--r--source/Breakpoint/WatchpointOptions.cpp241
21 files changed, 5587 insertions, 0 deletions
diff --git a/source/Breakpoint/Breakpoint.cpp b/source/Breakpoint/Breakpoint.cpp
new file mode 100644
index 000000000000..9bc43814b48a
--- /dev/null
+++ b/source/Breakpoint/Breakpoint.cpp
@@ -0,0 +1,794 @@
+//===-- Breakpoint.cpp ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/Core/Address.h"
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Breakpoint/BreakpointLocationCollection.h"
+#include "lldb/Breakpoint/BreakpointResolver.h"
+#include "lldb/Breakpoint/BreakpointResolverFileLine.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/SearchFilter.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadSpec.h"
+#include "lldb/lldb-private-log.h"
+#include "llvm/Support/Casting.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace llvm;
+
+const ConstString &
+Breakpoint::GetEventIdentifier ()
+{
+ static ConstString g_identifier("event-identifier.breakpoint.changed");
+ return g_identifier;
+}
+
+//----------------------------------------------------------------------
+// Breakpoint constructor
+//----------------------------------------------------------------------
+Breakpoint::Breakpoint(Target &target, SearchFilterSP &filter_sp, BreakpointResolverSP &resolver_sp) :
+ m_being_created(true),
+ m_target (target),
+ m_filter_sp (filter_sp),
+ m_resolver_sp (resolver_sp),
+ m_options (),
+ m_locations (*this)
+{
+ m_being_created = false;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+Breakpoint::~Breakpoint()
+{
+}
+
+bool
+Breakpoint::IsInternal () const
+{
+ return LLDB_BREAK_ID_IS_INTERNAL(m_bid);
+}
+
+
+
+Target&
+Breakpoint::GetTarget ()
+{
+ return m_target;
+}
+
+const Target&
+Breakpoint::GetTarget () const
+{
+ return m_target;
+}
+
+BreakpointLocationSP
+Breakpoint::AddLocation (const Address &addr, bool *new_location)
+{
+ return m_locations.AddLocation (addr, new_location);
+}
+
+BreakpointLocationSP
+Breakpoint::FindLocationByAddress (const Address &addr)
+{
+ return m_locations.FindByAddress(addr);
+}
+
+break_id_t
+Breakpoint::FindLocationIDByAddress (const Address &addr)
+{
+ return m_locations.FindIDByAddress(addr);
+}
+
+BreakpointLocationSP
+Breakpoint::FindLocationByID (break_id_t bp_loc_id)
+{
+ return m_locations.FindByID(bp_loc_id);
+}
+
+BreakpointLocationSP
+Breakpoint::GetLocationAtIndex (size_t index)
+{
+ return m_locations.GetByIndex(index);
+}
+
+// For each of the overall options we need to decide how they propagate to
+// the location options. This will determine the precedence of options on
+// the breakpoint vs. its locations.
+
+// Disable at the breakpoint level should override the location settings.
+// That way you can conveniently turn off a whole breakpoint without messing
+// up the individual settings.
+
+void
+Breakpoint::SetEnabled (bool enable)
+{
+ if (enable == m_options.IsEnabled())
+ return;
+
+ m_options.SetEnabled(enable);
+ if (enable)
+ m_locations.ResolveAllBreakpointSites();
+ else
+ m_locations.ClearAllBreakpointSites();
+
+ SendBreakpointChangedEvent (enable ? eBreakpointEventTypeEnabled : eBreakpointEventTypeDisabled);
+
+}
+
+bool
+Breakpoint::IsEnabled ()
+{
+ return m_options.IsEnabled();
+}
+
+void
+Breakpoint::SetIgnoreCount (uint32_t n)
+{
+ if (m_options.GetIgnoreCount() == n)
+ return;
+
+ m_options.SetIgnoreCount(n);
+ SendBreakpointChangedEvent (eBreakpointEventTypeIgnoreChanged);
+}
+
+void
+Breakpoint::DecrementIgnoreCount ()
+{
+ uint32_t ignore = m_options.GetIgnoreCount();
+ if (ignore != 0)
+ m_options.SetIgnoreCount(ignore - 1);
+}
+
+uint32_t
+Breakpoint::GetIgnoreCount () const
+{
+ return m_options.GetIgnoreCount();
+}
+
+bool
+Breakpoint::IgnoreCountShouldStop ()
+{
+ uint32_t ignore = GetIgnoreCount();
+ if (ignore != 0)
+ {
+ // When we get here we know the location that caused the stop doesn't have an ignore count,
+ // since by contract we call it first... So we don't have to find & decrement it, we only have
+ // to decrement our own ignore count.
+ DecrementIgnoreCount();
+ return false;
+ }
+ else
+ return true;
+}
+
+uint32_t
+Breakpoint::GetHitCount () const
+{
+ return m_locations.GetHitCount();
+}
+
+bool
+Breakpoint::IsOneShot () const
+{
+ return m_options.IsOneShot();
+}
+
+void
+Breakpoint::SetOneShot (bool one_shot)
+{
+ m_options.SetOneShot (one_shot);
+}
+
+void
+Breakpoint::SetThreadID (lldb::tid_t thread_id)
+{
+ if (m_options.GetThreadSpec()->GetTID() == thread_id)
+ return;
+
+ m_options.GetThreadSpec()->SetTID(thread_id);
+ SendBreakpointChangedEvent (eBreakpointEventTypeThreadChanged);
+}
+
+lldb::tid_t
+Breakpoint::GetThreadID () const
+{
+ if (m_options.GetThreadSpecNoCreate() == NULL)
+ return LLDB_INVALID_THREAD_ID;
+ else
+ return m_options.GetThreadSpecNoCreate()->GetTID();
+}
+
+void
+Breakpoint::SetThreadIndex (uint32_t index)
+{
+ if (m_options.GetThreadSpec()->GetIndex() == index)
+ return;
+
+ m_options.GetThreadSpec()->SetIndex(index);
+ SendBreakpointChangedEvent (eBreakpointEventTypeThreadChanged);
+}
+
+uint32_t
+Breakpoint::GetThreadIndex() const
+{
+ if (m_options.GetThreadSpecNoCreate() == NULL)
+ return 0;
+ else
+ return m_options.GetThreadSpecNoCreate()->GetIndex();
+}
+
+void
+Breakpoint::SetThreadName (const char *thread_name)
+{
+ if (m_options.GetThreadSpec()->GetName() != NULL
+ && ::strcmp (m_options.GetThreadSpec()->GetName(), thread_name) == 0)
+ return;
+
+ m_options.GetThreadSpec()->SetName (thread_name);
+ SendBreakpointChangedEvent (eBreakpointEventTypeThreadChanged);
+}
+
+const char *
+Breakpoint::GetThreadName () const
+{
+ if (m_options.GetThreadSpecNoCreate() == NULL)
+ return NULL;
+ else
+ return m_options.GetThreadSpecNoCreate()->GetName();
+}
+
+void
+Breakpoint::SetQueueName (const char *queue_name)
+{
+ if (m_options.GetThreadSpec()->GetQueueName() != NULL
+ && ::strcmp (m_options.GetThreadSpec()->GetQueueName(), queue_name) == 0)
+ return;
+
+ m_options.GetThreadSpec()->SetQueueName (queue_name);
+ SendBreakpointChangedEvent (eBreakpointEventTypeThreadChanged);
+}
+
+const char *
+Breakpoint::GetQueueName () const
+{
+ if (m_options.GetThreadSpecNoCreate() == NULL)
+ return NULL;
+ else
+ return m_options.GetThreadSpecNoCreate()->GetQueueName();
+}
+
+void
+Breakpoint::SetCondition (const char *condition)
+{
+ m_options.SetCondition (condition);
+ SendBreakpointChangedEvent (eBreakpointEventTypeConditionChanged);
+}
+
+const char *
+Breakpoint::GetConditionText () const
+{
+ return m_options.GetConditionText();
+}
+
+// This function is used when "baton" doesn't need to be freed
+void
+Breakpoint::SetCallback (BreakpointHitCallback callback, void *baton, bool is_synchronous)
+{
+ // The default "Baton" class will keep a copy of "baton" and won't free
+ // or delete it when it goes goes out of scope.
+ m_options.SetCallback(callback, BatonSP (new Baton(baton)), is_synchronous);
+
+ SendBreakpointChangedEvent (eBreakpointEventTypeCommandChanged);
+}
+
+// This function is used when a baton needs to be freed and therefore is
+// contained in a "Baton" subclass.
+void
+Breakpoint::SetCallback (BreakpointHitCallback callback, const BatonSP &callback_baton_sp, bool is_synchronous)
+{
+ m_options.SetCallback(callback, callback_baton_sp, is_synchronous);
+}
+
+void
+Breakpoint::ClearCallback ()
+{
+ m_options.ClearCallback ();
+}
+
+bool
+Breakpoint::InvokeCallback (StoppointCallbackContext *context, break_id_t bp_loc_id)
+{
+ return m_options.InvokeCallback (context, GetID(), bp_loc_id);
+}
+
+BreakpointOptions *
+Breakpoint::GetOptions ()
+{
+ return &m_options;
+}
+
+void
+Breakpoint::ResolveBreakpoint ()
+{
+ if (m_resolver_sp)
+ m_resolver_sp->ResolveBreakpoint(*m_filter_sp);
+}
+
+void
+Breakpoint::ResolveBreakpointInModules (ModuleList &module_list)
+{
+ if (m_resolver_sp)
+ m_resolver_sp->ResolveBreakpointInModules(*m_filter_sp, module_list);
+}
+
+void
+Breakpoint::ClearAllBreakpointSites ()
+{
+ m_locations.ClearAllBreakpointSites();
+}
+
+//----------------------------------------------------------------------
+// ModulesChanged: Pass in a list of new modules, and
+//----------------------------------------------------------------------
+
+void
+Breakpoint::ModulesChanged (ModuleList &module_list, bool load, bool delete_locations)
+{
+ Mutex::Locker modules_mutex(module_list.GetMutex());
+ if (load)
+ {
+ // The logic for handling new modules is:
+ // 1) If the filter rejects this module, then skip it.
+ // 2) Run through the current location list and if there are any locations
+ // for that module, we mark the module as "seen" and we don't try to re-resolve
+ // breakpoint locations for that module.
+ // However, we do add breakpoint sites to these locations if needed.
+ // 3) If we don't see this module in our breakpoint location list, call ResolveInModules.
+
+ ModuleList new_modules; // We'll stuff the "unseen" modules in this list, and then resolve
+ // them after the locations pass. Have to do it this way because
+ // resolving breakpoints will add new locations potentially.
+
+ const size_t num_locs = m_locations.GetSize();
+ size_t num_modules = module_list.GetSize();
+ for (size_t i = 0; i < num_modules; i++)
+ {
+ bool seen = false;
+ ModuleSP module_sp (module_list.GetModuleAtIndexUnlocked (i));
+ if (!m_filter_sp->ModulePasses (module_sp))
+ continue;
+
+ for (size_t loc_idx = 0; loc_idx < num_locs; loc_idx++)
+ {
+ BreakpointLocationSP break_loc = m_locations.GetByIndex(loc_idx);
+ if (!break_loc->IsEnabled())
+ continue;
+ SectionSP section_sp (break_loc->GetAddress().GetSection());
+ if (!section_sp || section_sp->GetModule() == module_sp)
+ {
+ if (!seen)
+ seen = true;
+
+ if (!break_loc->ResolveBreakpointSite())
+ {
+ Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("Warning: could not set breakpoint site for breakpoint location %d of breakpoint %d.\n",
+ break_loc->GetID(), GetID());
+ }
+ }
+ }
+
+ if (!seen)
+ new_modules.AppendIfNeeded (module_sp);
+
+ }
+
+ if (new_modules.GetSize() > 0)
+ {
+ // If this is not an internal breakpoint, set up to record the new locations, then dispatch
+ // an event with the new locations.
+ if (!IsInternal())
+ {
+ BreakpointEventData *new_locations_event = new BreakpointEventData (eBreakpointEventTypeLocationsAdded,
+ shared_from_this());
+
+ m_locations.StartRecordingNewLocations(new_locations_event->GetBreakpointLocationCollection());
+
+ ResolveBreakpointInModules(new_modules);
+
+ m_locations.StopRecordingNewLocations();
+ if (new_locations_event->GetBreakpointLocationCollection().GetSize() != 0)
+ {
+ SendBreakpointChangedEvent (new_locations_event);
+ }
+ else
+ delete new_locations_event;
+ }
+ else
+ ResolveBreakpointInModules(new_modules);
+
+ }
+ }
+ else
+ {
+ // Go through the currently set locations and if any have breakpoints in
+ // the module list, then remove their breakpoint sites, and their locations if asked to.
+
+ BreakpointEventData *removed_locations_event;
+ if (!IsInternal())
+ removed_locations_event = new BreakpointEventData (eBreakpointEventTypeLocationsRemoved,
+ shared_from_this());
+ else
+ removed_locations_event = NULL;
+
+ size_t num_modules = module_list.GetSize();
+ for (size_t i = 0; i < num_modules; i++)
+ {
+ ModuleSP module_sp (module_list.GetModuleAtIndexUnlocked (i));
+ if (m_filter_sp->ModulePasses (module_sp))
+ {
+ size_t loc_idx = 0;
+ size_t num_locations = m_locations.GetSize();
+ BreakpointLocationCollection locations_to_remove;
+ for (loc_idx = 0; loc_idx < num_locations; loc_idx++)
+ {
+ BreakpointLocationSP break_loc_sp (m_locations.GetByIndex(loc_idx));
+ SectionSP section_sp (break_loc_sp->GetAddress().GetSection());
+ if (section_sp && section_sp->GetModule() == module_sp)
+ {
+ // Remove this breakpoint since the shared library is
+ // unloaded, but keep the breakpoint location around
+ // so we always get complete hit count and breakpoint
+ // lifetime info
+ break_loc_sp->ClearBreakpointSite();
+ if (removed_locations_event)
+ {
+ removed_locations_event->GetBreakpointLocationCollection().Add(break_loc_sp);
+ }
+ if (delete_locations)
+ locations_to_remove.Add (break_loc_sp);
+
+ }
+ }
+
+ if (delete_locations)
+ {
+ size_t num_locations_to_remove = locations_to_remove.GetSize();
+ for (loc_idx = 0; loc_idx < num_locations_to_remove; loc_idx++)
+ m_locations.RemoveLocation (locations_to_remove.GetByIndex(loc_idx));
+ }
+ }
+ }
+ SendBreakpointChangedEvent (removed_locations_event);
+ }
+}
+
+void
+Breakpoint::ModuleReplaced (ModuleSP old_module_sp, ModuleSP new_module_sp)
+{
+ ModuleList temp_list;
+ temp_list.Append (new_module_sp);
+ ModulesChanged (temp_list, true);
+
+ // TO DO: For now I'm just adding locations for the new module and removing the
+ // breakpoint locations that were in the old module.
+ // We should really go find the ones that are in the new module & if we can determine that they are "equivalent"
+ // carry over the options from the old location to the new.
+
+ temp_list.Clear();
+ temp_list.Append (old_module_sp);
+ ModulesChanged (temp_list, false, true);
+}
+
+void
+Breakpoint::Dump (Stream *)
+{
+}
+
+size_t
+Breakpoint::GetNumResolvedLocations() const
+{
+ // Return the number of breakpoints that are actually resolved and set
+ // down in the inferior process.
+ return m_locations.GetNumResolvedLocations();
+}
+
+size_t
+Breakpoint::GetNumLocations() const
+{
+ return m_locations.GetSize();
+}
+
+void
+Breakpoint::GetDescription (Stream *s, lldb::DescriptionLevel level, bool show_locations)
+{
+ assert (s != NULL);
+
+ if (!m_kind_description.empty())
+ {
+ if (eDescriptionLevelBrief)
+ {
+ s->PutCString (GetBreakpointKind());
+ return;
+ }
+ else
+ s->Printf("Kind: %s\n", GetBreakpointKind ());
+ }
+
+ const size_t num_locations = GetNumLocations ();
+ const size_t num_resolved_locations = GetNumResolvedLocations ();
+
+ // They just made the breakpoint, they don't need to be told HOW they made it...
+ // Also, we'll print the breakpoint number differently depending on whether there is 1 or more locations.
+ if (level != eDescriptionLevelInitial)
+ {
+ s->Printf("%i: ", GetID());
+ GetResolverDescription (s);
+ GetFilterDescription (s);
+ }
+
+ switch (level)
+ {
+ case lldb::eDescriptionLevelBrief:
+ case lldb::eDescriptionLevelFull:
+ if (num_locations > 0)
+ {
+ s->Printf(", locations = %" PRIu64, (uint64_t)num_locations);
+ if (num_resolved_locations > 0)
+ s->Printf(", resolved = %" PRIu64, (uint64_t)num_resolved_locations);
+ }
+ else
+ {
+ // Don't print the pending notification for exception resolvers since we don't generally
+ // know how to set them until the target is run.
+ if (m_resolver_sp->getResolverID() != BreakpointResolver::ExceptionResolver)
+ s->Printf(", locations = 0 (pending)");
+ }
+
+ GetOptions()->GetDescription(s, level);
+
+ if (level == lldb::eDescriptionLevelFull)
+ {
+ s->IndentLess();
+ s->EOL();
+ }
+ break;
+
+ case lldb::eDescriptionLevelInitial:
+ s->Printf ("Breakpoint %i: ", GetID());
+ if (num_locations == 0)
+ {
+ s->Printf ("no locations (pending).");
+ }
+ else if (num_locations == 1)
+ {
+ // If there is one location only, we'll just print that location information. But don't do this if
+ // show locations is true, then that will be handled below.
+ if (show_locations == false)
+ {
+ GetLocationAtIndex(0)->GetDescription(s, level);
+ }
+ else
+ {
+ s->Printf ("%zd locations.", num_locations);
+ }
+ }
+ else
+ {
+ s->Printf ("%zd locations.", num_locations);
+ }
+ s->EOL();
+ break;
+ case lldb::eDescriptionLevelVerbose:
+ // Verbose mode does a debug dump of the breakpoint
+ Dump (s);
+ s->EOL ();
+ //s->Indent();
+ GetOptions()->GetDescription(s, level);
+ break;
+
+ default:
+ break;
+ }
+
+ // The brief description is just the location name (1.2 or whatever). That's pointless to
+ // show in the breakpoint's description, so suppress it.
+ if (show_locations && level != lldb::eDescriptionLevelBrief)
+ {
+ s->IndentMore();
+ for (size_t i = 0; i < num_locations; ++i)
+ {
+ BreakpointLocation *loc = GetLocationAtIndex(i).get();
+ loc->GetDescription(s, level);
+ s->EOL();
+ }
+ s->IndentLess();
+ }
+}
+
+void
+Breakpoint::GetResolverDescription (Stream *s)
+{
+ if (m_resolver_sp)
+ m_resolver_sp->GetDescription (s);
+}
+
+
+bool
+Breakpoint::GetMatchingFileLine (const ConstString &filename, uint32_t line_number, BreakpointLocationCollection &loc_coll)
+{
+ // TODO: To be correct, this method needs to fill the breakpoint location collection
+ // with the location IDs which match the filename and line_number.
+ //
+
+ if (m_resolver_sp)
+ {
+ BreakpointResolverFileLine *resolverFileLine = dyn_cast<BreakpointResolverFileLine>(m_resolver_sp.get());
+ if (resolverFileLine &&
+ resolverFileLine->m_file_spec.GetFilename() == filename &&
+ resolverFileLine->m_line_number == line_number)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+Breakpoint::GetFilterDescription (Stream *s)
+{
+ m_filter_sp->GetDescription (s);
+}
+
+void
+Breakpoint::SendBreakpointChangedEvent (lldb::BreakpointEventType eventKind)
+{
+ if (!m_being_created
+ && !IsInternal()
+ && GetTarget().EventTypeHasListeners(Target::eBroadcastBitBreakpointChanged))
+ {
+ BreakpointEventData *data = new Breakpoint::BreakpointEventData (eventKind, shared_from_this());
+
+ GetTarget().BroadcastEvent (Target::eBroadcastBitBreakpointChanged, data);
+ }
+}
+
+void
+Breakpoint::SendBreakpointChangedEvent (BreakpointEventData *data)
+{
+
+ if (data == NULL)
+ return;
+
+ if (!m_being_created
+ && !IsInternal()
+ && GetTarget().EventTypeHasListeners(Target::eBroadcastBitBreakpointChanged))
+ GetTarget().BroadcastEvent (Target::eBroadcastBitBreakpointChanged, data);
+ else
+ delete data;
+}
+
+Breakpoint::BreakpointEventData::BreakpointEventData (BreakpointEventType sub_type,
+ const BreakpointSP &new_breakpoint_sp) :
+ EventData (),
+ m_breakpoint_event (sub_type),
+ m_new_breakpoint_sp (new_breakpoint_sp)
+{
+}
+
+Breakpoint::BreakpointEventData::~BreakpointEventData ()
+{
+}
+
+const ConstString &
+Breakpoint::BreakpointEventData::GetFlavorString ()
+{
+ static ConstString g_flavor ("Breakpoint::BreakpointEventData");
+ return g_flavor;
+}
+
+const ConstString &
+Breakpoint::BreakpointEventData::GetFlavor () const
+{
+ return BreakpointEventData::GetFlavorString ();
+}
+
+
+BreakpointSP &
+Breakpoint::BreakpointEventData::GetBreakpoint ()
+{
+ return m_new_breakpoint_sp;
+}
+
+BreakpointEventType
+Breakpoint::BreakpointEventData::GetBreakpointEventType () const
+{
+ return m_breakpoint_event;
+}
+
+void
+Breakpoint::BreakpointEventData::Dump (Stream *s) const
+{
+}
+
+const Breakpoint::BreakpointEventData *
+Breakpoint::BreakpointEventData::GetEventDataFromEvent (const Event *event)
+{
+ if (event)
+ {
+ const EventData *event_data = event->GetData();
+ if (event_data && event_data->GetFlavor() == BreakpointEventData::GetFlavorString())
+ return static_cast <const BreakpointEventData *> (event->GetData());
+ }
+ return NULL;
+}
+
+BreakpointEventType
+Breakpoint::BreakpointEventData::GetBreakpointEventTypeFromEvent (const EventSP &event_sp)
+{
+ const BreakpointEventData *data = GetEventDataFromEvent (event_sp.get());
+
+ if (data == NULL)
+ return eBreakpointEventTypeInvalidType;
+ else
+ return data->GetBreakpointEventType();
+}
+
+BreakpointSP
+Breakpoint::BreakpointEventData::GetBreakpointFromEvent (const EventSP &event_sp)
+{
+ BreakpointSP bp_sp;
+
+ const BreakpointEventData *data = GetEventDataFromEvent (event_sp.get());
+ if (data)
+ bp_sp = data->m_new_breakpoint_sp;
+
+ return bp_sp;
+}
+
+size_t
+Breakpoint::BreakpointEventData::GetNumBreakpointLocationsFromEvent (const EventSP &event_sp)
+{
+ const BreakpointEventData *data = GetEventDataFromEvent (event_sp.get());
+ if (data)
+ return data->m_locations.GetSize();
+
+ return 0;
+}
+
+lldb::BreakpointLocationSP
+Breakpoint::BreakpointEventData::GetBreakpointLocationAtIndexFromEvent (const lldb::EventSP &event_sp, uint32_t bp_loc_idx)
+{
+ lldb::BreakpointLocationSP bp_loc_sp;
+
+ const BreakpointEventData *data = GetEventDataFromEvent (event_sp.get());
+ if (data)
+ {
+ bp_loc_sp = data->m_locations.GetByIndex(bp_loc_idx);
+ }
+
+ return bp_loc_sp;
+}
diff --git a/source/Breakpoint/BreakpointID.cpp b/source/Breakpoint/BreakpointID.cpp
new file mode 100644
index 000000000000..9a59e29d007d
--- /dev/null
+++ b/source/Breakpoint/BreakpointID.cpp
@@ -0,0 +1,123 @@
+//===-- BreakpointID.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+// C Includes
+#include <stdio.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/Breakpoint/BreakpointID.h"
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Core/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+BreakpointID::BreakpointID (break_id_t bp_id, break_id_t loc_id) :
+ m_break_id (bp_id),
+ m_location_id (loc_id)
+{
+}
+
+BreakpointID::~BreakpointID ()
+{
+}
+
+const char *BreakpointID::g_range_specifiers[] = { "-", "to", "To", "TO", NULL };
+
+// Tells whether or not STR is valid to use between two strings representing breakpoint IDs, to
+// indicate a range of breakpoint IDs. This is broken out into a separate function so that we can
+// easily change or add to the format for specifying ID ranges at a later date.
+
+bool
+BreakpointID::IsRangeIdentifier (const char *str)
+{
+ int specifier_count = 0;
+ for (int i = 0; g_range_specifiers[i] != NULL; ++i)
+ ++specifier_count;
+
+ for (int i = 0; i < specifier_count; ++i)
+ {
+ if (strcmp (g_range_specifiers[i], str) == 0)
+ return true;
+ }
+
+ return false;
+}
+
+bool
+BreakpointID::IsValidIDExpression (const char *str)
+{
+ break_id_t bp_id;
+ break_id_t loc_id;
+ BreakpointID::ParseCanonicalReference (str, &bp_id, &loc_id);
+
+ if (bp_id == LLDB_INVALID_BREAK_ID)
+ return false;
+ else
+ return true;
+}
+
+void
+BreakpointID::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ if (level == eDescriptionLevelVerbose)
+ s->Printf("%p BreakpointID:", this);
+
+ if (m_break_id == LLDB_INVALID_BREAK_ID)
+ s->PutCString ("<invalid>");
+ else if (m_location_id == LLDB_INVALID_BREAK_ID)
+ s->Printf("%i", m_break_id);
+ else
+ s->Printf("%i.%i", m_break_id, m_location_id);
+}
+
+void
+BreakpointID::GetCanonicalReference (Stream *s, break_id_t bp_id, break_id_t loc_id)
+{
+ if (bp_id == LLDB_INVALID_BREAK_ID)
+ s->PutCString ("<invalid>");
+ else if (loc_id == LLDB_INVALID_BREAK_ID)
+ s->Printf("%i", bp_id);
+ else
+ s->Printf("%i.%i", bp_id, loc_id);
+}
+
+bool
+BreakpointID::ParseCanonicalReference (const char *input, break_id_t *break_id_ptr, break_id_t *break_loc_id_ptr)
+{
+ *break_id_ptr = LLDB_INVALID_BREAK_ID;
+ *break_loc_id_ptr = LLDB_INVALID_BREAK_ID;
+
+ if (input == NULL || *input == '\0')
+ return false;
+
+ const char *format = "%i%n.%i%n";
+ int chars_consumed_1 = 0;
+ int chars_consumed_2 = 0;
+ int n_items_parsed = ::sscanf (input,
+ format,
+ break_id_ptr, // %i parse the breakpoint ID
+ &chars_consumed_1, // %n gets the number of characters parsed so far
+ break_loc_id_ptr, // %i parse the breakpoint location ID
+ &chars_consumed_2); // %n gets the number of characters parsed so far
+
+ if ((n_items_parsed == 1 && input[chars_consumed_1] == '\0') ||
+ (n_items_parsed == 2 && input[chars_consumed_2] == '\0'))
+ return true;
+
+ // Badly formatted canonical reference.
+ *break_id_ptr = LLDB_INVALID_BREAK_ID;
+ *break_loc_id_ptr = LLDB_INVALID_BREAK_ID;
+ return false;
+}
+
diff --git a/source/Breakpoint/BreakpointIDList.cpp b/source/Breakpoint/BreakpointIDList.cpp
new file mode 100644
index 000000000000..24101b1442fb
--- /dev/null
+++ b/source/Breakpoint/BreakpointIDList.cpp
@@ -0,0 +1,397 @@
+//===-- BreakpointIDList.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/BreakpointIDList.h"
+
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// class BreakpointIDList
+//----------------------------------------------------------------------
+
+BreakpointIDList::BreakpointIDList () :
+m_invalid_id (LLDB_INVALID_BREAK_ID, LLDB_INVALID_BREAK_ID)
+{
+}
+
+BreakpointIDList::~BreakpointIDList ()
+{
+}
+
+size_t
+BreakpointIDList::GetSize()
+{
+ return m_breakpoint_ids.size();
+}
+
+BreakpointID &
+BreakpointIDList::GetBreakpointIDAtIndex (size_t index)
+{
+ if (index < m_breakpoint_ids.size())
+ return m_breakpoint_ids[index];
+ else
+ return m_invalid_id;
+}
+
+bool
+BreakpointIDList::RemoveBreakpointIDAtIndex (size_t index)
+{
+ if (index >= m_breakpoint_ids.size())
+ return false;
+
+ m_breakpoint_ids.erase (m_breakpoint_ids.begin() + index);
+ return true;
+}
+
+void
+BreakpointIDList::Clear()
+{
+ m_breakpoint_ids.clear ();
+}
+
+bool
+BreakpointIDList::AddBreakpointID (BreakpointID bp_id)
+{
+ m_breakpoint_ids.push_back (bp_id);
+
+ return true; // We don't do any verification in this function, so always return true.
+}
+
+bool
+BreakpointIDList::AddBreakpointID (const char *bp_id_str)
+{
+ BreakpointID temp_bp_id;
+ break_id_t bp_id;
+ break_id_t loc_id;
+
+ bool success = BreakpointID::ParseCanonicalReference (bp_id_str, &bp_id, &loc_id);
+
+ if (success)
+ {
+ temp_bp_id.SetID (bp_id, loc_id);
+ m_breakpoint_ids.push_back (temp_bp_id);
+ }
+
+ return success;
+}
+
+bool
+BreakpointIDList::FindBreakpointID (BreakpointID &bp_id, size_t *position)
+{
+ for (size_t i = 0; i < m_breakpoint_ids.size(); ++i)
+ {
+ BreakpointID tmp_id = m_breakpoint_ids[i];
+ if (tmp_id.GetBreakpointID() == bp_id.GetBreakpointID()
+ && tmp_id.GetLocationID() == bp_id.GetLocationID())
+ {
+ *position = i;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool
+BreakpointIDList::FindBreakpointID (const char *bp_id_str, size_t *position)
+{
+ BreakpointID temp_bp_id;
+ break_id_t bp_id;
+ break_id_t loc_id;
+
+ if (BreakpointID::ParseCanonicalReference (bp_id_str, &bp_id, &loc_id))
+ {
+ temp_bp_id.SetID (bp_id, loc_id);
+ return FindBreakpointID (temp_bp_id, position);
+ }
+ else
+ return false;
+}
+
+void
+BreakpointIDList::InsertStringArray (const char **string_array, size_t array_size, CommandReturnObject &result)
+{
+ if (string_array == NULL)
+ return;
+
+ for (uint32_t i = 0; i < array_size; ++i)
+ {
+ break_id_t bp_id;
+ break_id_t loc_id;
+
+ if (BreakpointID::ParseCanonicalReference (string_array[i], &bp_id, &loc_id))
+ {
+ if (bp_id != LLDB_INVALID_BREAK_ID)
+ {
+ BreakpointID temp_bp_id(bp_id, loc_id);
+ m_breakpoint_ids.push_back (temp_bp_id);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("'%s' is not a valid breakpoint ID.\n", string_array[i]);
+ result.SetStatus (eReturnStatusFailed);
+ return;
+ }
+ }
+ }
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+}
+
+
+// This function takes OLD_ARGS, which is usually the result of breaking the command string arguments into
+// an array of space-separated strings, and searches through the arguments for any breakpoint ID range specifiers.
+// Any string in the array that is not part of an ID range specifier is copied directly into NEW_ARGS. If any
+// ID range specifiers are found, the range is interpreted and a list of canonical breakpoint IDs corresponding to
+// all the current breakpoints and locations in the range are added to NEW_ARGS. When this function is done,
+// NEW_ARGS should be a copy of OLD_ARGS, with and ID range specifiers replaced by the members of the range.
+
+void
+BreakpointIDList::FindAndReplaceIDRanges (Args &old_args, Target *target, CommandReturnObject &result,
+ Args &new_args)
+{
+ std::string range_start;
+ const char *range_end;
+ const char *current_arg;
+ const size_t num_old_args = old_args.GetArgumentCount();
+
+ for (size_t i = 0; i < num_old_args; ++i)
+ {
+ bool is_range = false;
+ current_arg = old_args.GetArgumentAtIndex (i);
+
+ size_t range_start_len = 0;
+ size_t range_end_pos = 0;
+ if (BreakpointIDList::StringContainsIDRangeExpression (current_arg, &range_start_len, &range_end_pos))
+ {
+ is_range = true;
+ range_start.assign (current_arg, range_start_len);
+ range_end = current_arg + range_end_pos;
+ }
+ else if ((i + 2 < num_old_args)
+ && BreakpointID::IsRangeIdentifier (old_args.GetArgumentAtIndex (i+1))
+ && BreakpointID::IsValidIDExpression (current_arg)
+ && BreakpointID::IsValidIDExpression (old_args.GetArgumentAtIndex (i+2)))
+ {
+ range_start.assign (current_arg);
+ range_end = old_args.GetArgumentAtIndex (i+2);
+ is_range = true;
+ i = i+2;
+ }
+ else
+ {
+ // See if user has specified id.*
+ std::string tmp_str = old_args.GetArgumentAtIndex (i);
+ size_t pos = tmp_str.find ('.');
+ if (pos != std::string::npos)
+ {
+ std::string bp_id_str = tmp_str.substr (0, pos);
+ if (BreakpointID::IsValidIDExpression (bp_id_str.c_str())
+ && tmp_str[pos+1] == '*'
+ && tmp_str.length() == (pos + 2))
+ {
+ break_id_t bp_id;
+ break_id_t bp_loc_id;
+
+ BreakpointID::ParseCanonicalReference (bp_id_str.c_str(), &bp_id, &bp_loc_id);
+ BreakpointSP breakpoint_sp = target->GetBreakpointByID (bp_id);
+ if (! breakpoint_sp)
+ {
+ new_args.Clear();
+ result.AppendErrorWithFormat ("'%d' is not a valid breakpoint ID.\n", bp_id);
+ result.SetStatus (eReturnStatusFailed);
+ return;
+ }
+ const size_t num_locations = breakpoint_sp->GetNumLocations();
+ for (size_t j = 0; j < num_locations; ++j)
+ {
+ BreakpointLocation *bp_loc = breakpoint_sp->GetLocationAtIndex(j).get();
+ StreamString canonical_id_str;
+ BreakpointID::GetCanonicalReference (&canonical_id_str, bp_id, bp_loc->GetID());
+ new_args.AppendArgument (canonical_id_str.GetData());
+ }
+ }
+
+ }
+ }
+
+ if (is_range)
+ {
+ break_id_t start_bp_id;
+ break_id_t end_bp_id;
+ break_id_t start_loc_id;
+ break_id_t end_loc_id;
+
+ BreakpointID::ParseCanonicalReference (range_start.c_str(), &start_bp_id, &start_loc_id);
+ BreakpointID::ParseCanonicalReference (range_end, &end_bp_id, &end_loc_id);
+
+ if ((start_bp_id == LLDB_INVALID_BREAK_ID)
+ || (! target->GetBreakpointByID (start_bp_id)))
+ {
+ new_args.Clear();
+ result.AppendErrorWithFormat ("'%s' is not a valid breakpoint ID.\n", range_start.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return;
+ }
+
+ if ((end_bp_id == LLDB_INVALID_BREAK_ID)
+ || (! target->GetBreakpointByID (end_bp_id)))
+ {
+ new_args.Clear();
+ result.AppendErrorWithFormat ("'%s' is not a valid breakpoint ID.\n", range_end);
+ result.SetStatus (eReturnStatusFailed);
+ return;
+ }
+
+
+ if (((start_loc_id == LLDB_INVALID_BREAK_ID)
+ && (end_loc_id != LLDB_INVALID_BREAK_ID))
+ || ((start_loc_id != LLDB_INVALID_BREAK_ID)
+ && (end_loc_id == LLDB_INVALID_BREAK_ID)))
+ {
+ new_args.Clear ();
+ result.AppendErrorWithFormat ("Invalid breakpoint id range: Either both ends of range must specify"
+ " a breakpoint location, or neither can specify a breakpoint location.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return;
+ }
+
+ // We have valid range starting & ending breakpoint IDs. Go through all the breakpoints in the
+ // target and find all the breakpoints that fit into this range, and add them to new_args.
+
+ // Next check to see if we have location id's. If so, make sure the start_bp_id and end_bp_id are
+ // for the same breakpoint; otherwise we have an illegal range: breakpoint id ranges that specify
+ // bp locations are NOT allowed to cross major bp id numbers.
+
+ if ((start_loc_id != LLDB_INVALID_BREAK_ID)
+ || (end_loc_id != LLDB_INVALID_BREAK_ID))
+ {
+ if (start_bp_id != end_bp_id)
+ {
+ new_args.Clear();
+ result.AppendErrorWithFormat ("Invalid range: Ranges that specify particular breakpoint locations"
+ " must be within the same major breakpoint; you specified two"
+ " different major breakpoints, %d and %d.\n",
+ start_bp_id, end_bp_id);
+ result.SetStatus (eReturnStatusFailed);
+ return;
+ }
+ }
+
+ const BreakpointList& breakpoints = target->GetBreakpointList();
+ const size_t num_breakpoints = breakpoints.GetSize();
+ for (size_t j = 0; j < num_breakpoints; ++j)
+ {
+ Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex (j).get();
+ break_id_t cur_bp_id = breakpoint->GetID();
+
+ if ((cur_bp_id < start_bp_id) || (cur_bp_id > end_bp_id))
+ continue;
+
+ const size_t num_locations = breakpoint->GetNumLocations();
+
+ if ((cur_bp_id == start_bp_id) && (start_loc_id != LLDB_INVALID_BREAK_ID))
+ {
+ for (size_t k = 0; k < num_locations; ++k)
+ {
+ BreakpointLocation * bp_loc = breakpoint->GetLocationAtIndex(k).get();
+ if ((bp_loc->GetID() >= start_loc_id) && (bp_loc->GetID() <= end_loc_id))
+ {
+ StreamString canonical_id_str;
+ BreakpointID::GetCanonicalReference (&canonical_id_str, cur_bp_id, bp_loc->GetID());
+ new_args.AppendArgument (canonical_id_str.GetData());
+ }
+ }
+ }
+ else if ((cur_bp_id == end_bp_id) && (end_loc_id != LLDB_INVALID_BREAK_ID))
+ {
+ for (size_t k = 0; k < num_locations; ++k)
+ {
+ BreakpointLocation * bp_loc = breakpoint->GetLocationAtIndex(k).get();
+ if (bp_loc->GetID() <= end_loc_id)
+ {
+ StreamString canonical_id_str;
+ BreakpointID::GetCanonicalReference (&canonical_id_str, cur_bp_id, bp_loc->GetID());
+ new_args.AppendArgument (canonical_id_str.GetData());
+ }
+ }
+ }
+ else
+ {
+ StreamString canonical_id_str;
+ BreakpointID::GetCanonicalReference (&canonical_id_str, cur_bp_id, LLDB_INVALID_BREAK_ID);
+ new_args.AppendArgument (canonical_id_str.GetData());
+ }
+ }
+ }
+ else // else is_range was false
+ {
+ new_args.AppendArgument (current_arg);
+ }
+ }
+
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ return;
+}
+
+bool
+BreakpointIDList::StringContainsIDRangeExpression (const char *in_string,
+ size_t *range_start_len,
+ size_t *range_end_pos)
+{
+ bool is_range_expression = false;
+ std::string arg_str = in_string;
+ std::string::size_type idx;
+ std::string::size_type start_pos = 0;
+
+ *range_start_len = 0;
+ *range_end_pos = 0;
+
+ int specifiers_size = 0;
+ for (int i = 0; BreakpointID::g_range_specifiers[i] != NULL; ++i)
+ ++specifiers_size;
+
+ for (int i = 0; i < specifiers_size && !is_range_expression; ++i)
+ {
+ const char *specifier_str = BreakpointID::g_range_specifiers[i];
+ size_t len = strlen (specifier_str);
+ idx = arg_str.find (BreakpointID::g_range_specifiers[i]);
+ if (idx != std::string::npos)
+ {
+ *range_start_len = idx - start_pos;
+ std::string start_str = arg_str.substr (start_pos, *range_start_len);
+ if (idx + len < arg_str.length())
+ {
+ *range_end_pos = idx + len;
+ std::string end_str = arg_str.substr (*range_end_pos);
+ if (BreakpointID::IsValidIDExpression (start_str.c_str())
+ && BreakpointID::IsValidIDExpression (end_str.c_str()))
+ {
+ is_range_expression = true;
+ //*range_start = start_str;
+ //*range_end = end_str;
+ }
+ }
+ }
+ }
+
+ if (!is_range_expression)
+ {
+ *range_start_len = 0;
+ *range_end_pos = 0;
+ }
+
+ return is_range_expression;
+}
diff --git a/source/Breakpoint/BreakpointList.cpp b/source/Breakpoint/BreakpointList.cpp
new file mode 100644
index 000000000000..5926663af7b1
--- /dev/null
+++ b/source/Breakpoint/BreakpointList.cpp
@@ -0,0 +1,243 @@
+//===-- BreakpointList.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/BreakpointList.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+BreakpointList::BreakpointList (bool is_internal) :
+ m_mutex (Mutex::eMutexTypeRecursive),
+ m_breakpoints(),
+ m_next_break_id (0),
+ m_is_internal (is_internal)
+{
+}
+
+BreakpointList::~BreakpointList()
+{
+}
+
+
+break_id_t
+BreakpointList::Add (BreakpointSP &bp_sp, bool notify)
+{
+ Mutex::Locker locker(m_mutex);
+ // Internal breakpoint IDs are negative, normal ones are positive
+ bp_sp->SetID (m_is_internal ? --m_next_break_id : ++m_next_break_id);
+
+ m_breakpoints.push_back(bp_sp);
+ if (notify)
+ {
+ if (bp_sp->GetTarget().EventTypeHasListeners(Target::eBroadcastBitBreakpointChanged))
+ bp_sp->GetTarget().BroadcastEvent (Target::eBroadcastBitBreakpointChanged,
+ new Breakpoint::BreakpointEventData (eBreakpointEventTypeAdded, bp_sp));
+ }
+ return bp_sp->GetID();
+}
+
+bool
+BreakpointList::Remove (break_id_t break_id, bool notify)
+{
+ Mutex::Locker locker(m_mutex);
+ bp_collection::iterator pos = GetBreakpointIDIterator(break_id); // Predicate
+ if (pos != m_breakpoints.end())
+ {
+ BreakpointSP bp_sp (*pos);
+ m_breakpoints.erase(pos);
+ if (notify)
+ {
+ if (bp_sp->GetTarget().EventTypeHasListeners(Target::eBroadcastBitBreakpointChanged))
+ bp_sp->GetTarget().BroadcastEvent (Target::eBroadcastBitBreakpointChanged,
+ new Breakpoint::BreakpointEventData (eBreakpointEventTypeRemoved, bp_sp));
+ }
+ return true;
+ }
+ return false;
+}
+
+void
+BreakpointList::SetEnabledAll (bool enabled)
+{
+ Mutex::Locker locker(m_mutex);
+ bp_collection::iterator pos, end = m_breakpoints.end();
+ for (pos = m_breakpoints.begin(); pos != end; ++pos)
+ (*pos)->SetEnabled (enabled);
+}
+
+
+void
+BreakpointList::RemoveAll (bool notify)
+{
+ Mutex::Locker locker(m_mutex);
+ ClearAllBreakpointSites ();
+
+ if (notify)
+ {
+ bp_collection::iterator pos, end = m_breakpoints.end();
+ for (pos = m_breakpoints.begin(); pos != end; ++pos)
+ {
+ if ((*pos)->GetTarget().EventTypeHasListeners(Target::eBroadcastBitBreakpointChanged))
+ {
+ (*pos)->GetTarget().BroadcastEvent (Target::eBroadcastBitBreakpointChanged,
+ new Breakpoint::BreakpointEventData (eBreakpointEventTypeRemoved,
+ *pos));
+ }
+ }
+ }
+ m_breakpoints.erase (m_breakpoints.begin(), m_breakpoints.end());
+}
+
+class BreakpointIDMatches
+{
+public:
+ BreakpointIDMatches (break_id_t break_id) :
+ m_break_id(break_id)
+ {
+ }
+
+ bool operator() (const BreakpointSP &bp) const
+ {
+ return m_break_id == bp->GetID();
+ }
+
+private:
+ const break_id_t m_break_id;
+};
+
+BreakpointList::bp_collection::iterator
+BreakpointList::GetBreakpointIDIterator (break_id_t break_id)
+{
+ return std::find_if(m_breakpoints.begin(), m_breakpoints.end(), // Search full range
+ BreakpointIDMatches(break_id)); // Predicate
+}
+
+BreakpointList::bp_collection::const_iterator
+BreakpointList::GetBreakpointIDConstIterator (break_id_t break_id) const
+{
+ return std::find_if(m_breakpoints.begin(), m_breakpoints.end(), // Search full range
+ BreakpointIDMatches(break_id)); // Predicate
+}
+
+BreakpointSP
+BreakpointList::FindBreakpointByID (break_id_t break_id)
+{
+ Mutex::Locker locker(m_mutex);
+ BreakpointSP stop_sp;
+ bp_collection::iterator pos = GetBreakpointIDIterator(break_id);
+ if (pos != m_breakpoints.end())
+ stop_sp = *pos;
+
+ return stop_sp;
+}
+
+const BreakpointSP
+BreakpointList::FindBreakpointByID (break_id_t break_id) const
+{
+ Mutex::Locker locker(m_mutex);
+ BreakpointSP stop_sp;
+ bp_collection::const_iterator pos = GetBreakpointIDConstIterator(break_id);
+ if (pos != m_breakpoints.end())
+ stop_sp = *pos;
+
+ return stop_sp;
+}
+
+void
+BreakpointList::Dump (Stream *s) const
+{
+ Mutex::Locker locker(m_mutex);
+ s->Printf("%p: ", this);
+ s->Indent();
+ s->Printf("BreakpointList with %u Breakpoints:\n", (uint32_t)m_breakpoints.size());
+ s->IndentMore();
+ bp_collection::const_iterator pos;
+ bp_collection::const_iterator end = m_breakpoints.end();
+ for (pos = m_breakpoints.begin(); pos != end; ++pos)
+ (*pos)->Dump(s);
+ s->IndentLess();
+}
+
+
+BreakpointSP
+BreakpointList::GetBreakpointAtIndex (size_t i)
+{
+ Mutex::Locker locker(m_mutex);
+ BreakpointSP stop_sp;
+ bp_collection::iterator end = m_breakpoints.end();
+ bp_collection::iterator pos;
+ size_t curr_i = 0;
+ for (pos = m_breakpoints.begin(), curr_i = 0; pos != end; ++pos, ++curr_i)
+ {
+ if (curr_i == i)
+ stop_sp = *pos;
+ }
+ return stop_sp;
+}
+
+const BreakpointSP
+BreakpointList::GetBreakpointAtIndex (size_t i) const
+{
+ Mutex::Locker locker(m_mutex);
+ BreakpointSP stop_sp;
+ bp_collection::const_iterator end = m_breakpoints.end();
+ bp_collection::const_iterator pos;
+ size_t curr_i = 0;
+ for (pos = m_breakpoints.begin(), curr_i = 0; pos != end; ++pos, ++curr_i)
+ {
+ if (curr_i == i)
+ stop_sp = *pos;
+ }
+ return stop_sp;
+}
+
+void
+BreakpointList::UpdateBreakpoints (ModuleList& module_list, bool added)
+{
+ Mutex::Locker locker(m_mutex);
+ bp_collection::iterator end = m_breakpoints.end();
+ bp_collection::iterator pos;
+ for (pos = m_breakpoints.begin(); pos != end; ++pos)
+ (*pos)->ModulesChanged (module_list, added);
+
+}
+
+void
+BreakpointList::UpdateBreakpointsWhenModuleIsReplaced (ModuleSP old_module_sp, ModuleSP new_module_sp)
+{
+ Mutex::Locker locker(m_mutex);
+ bp_collection::iterator end = m_breakpoints.end();
+ bp_collection::iterator pos;
+ for (pos = m_breakpoints.begin(); pos != end; ++pos)
+ (*pos)->ModuleReplaced (old_module_sp, new_module_sp);
+
+}
+
+void
+BreakpointList::ClearAllBreakpointSites ()
+{
+ Mutex::Locker locker(m_mutex);
+ bp_collection::iterator end = m_breakpoints.end();
+ bp_collection::iterator pos;
+ for (pos = m_breakpoints.begin(); pos != end; ++pos)
+ (*pos)->ClearAllBreakpointSites ();
+
+}
+
+void
+BreakpointList::GetListMutex (Mutex::Locker &locker)
+{
+ return locker.Lock (m_mutex);
+}
diff --git a/source/Breakpoint/BreakpointLocation.cpp b/source/Breakpoint/BreakpointLocation.cpp
new file mode 100644
index 000000000000..1ec726dd52b1
--- /dev/null
+++ b/source/Breakpoint/BreakpointLocation.cpp
@@ -0,0 +1,677 @@
+//===-- BreakpointLocation.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-python.h"
+
+// C Includes
+// C++ Includes
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private-log.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Breakpoint/BreakpointID.h"
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadSpec.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+BreakpointLocation::BreakpointLocation
+(
+ break_id_t loc_id,
+ Breakpoint &owner,
+ const Address &addr,
+ lldb::tid_t tid,
+ bool hardware
+) :
+ StoppointLocation (loc_id, addr.GetOpcodeLoadAddress(&owner.GetTarget()), hardware),
+ m_being_created(true),
+ m_address (addr),
+ m_owner (owner),
+ m_options_ap (),
+ m_bp_site_sp (),
+ m_condition_mutex ()
+{
+ SetThreadID (tid);
+ m_being_created = false;
+}
+
+BreakpointLocation::~BreakpointLocation()
+{
+ ClearBreakpointSite();
+}
+
+lldb::addr_t
+BreakpointLocation::GetLoadAddress () const
+{
+ return m_address.GetOpcodeLoadAddress (&m_owner.GetTarget());
+}
+
+Address &
+BreakpointLocation::GetAddress ()
+{
+ return m_address;
+}
+
+Breakpoint &
+BreakpointLocation::GetBreakpoint ()
+{
+ return m_owner;
+}
+
+bool
+BreakpointLocation::IsEnabled () const
+{
+ if (!m_owner.IsEnabled())
+ return false;
+ else if (m_options_ap.get() != NULL)
+ return m_options_ap->IsEnabled();
+ else
+ return true;
+}
+
+void
+BreakpointLocation::SetEnabled (bool enabled)
+{
+ GetLocationOptions()->SetEnabled(enabled);
+ if (enabled)
+ {
+ ResolveBreakpointSite();
+ }
+ else
+ {
+ ClearBreakpointSite();
+ }
+ SendBreakpointLocationChangedEvent (enabled ? eBreakpointEventTypeEnabled : eBreakpointEventTypeDisabled);
+}
+
+void
+BreakpointLocation::SetThreadID (lldb::tid_t thread_id)
+{
+ if (thread_id != LLDB_INVALID_THREAD_ID)
+ GetLocationOptions()->SetThreadID(thread_id);
+ else
+ {
+ // If we're resetting this to an invalid thread id, then
+ // don't make an options pointer just to do that.
+ if (m_options_ap.get() != NULL)
+ m_options_ap->SetThreadID (thread_id);
+ }
+ SendBreakpointLocationChangedEvent (eBreakpointEventTypeThreadChanged);
+}
+
+lldb::tid_t
+BreakpointLocation::GetThreadID ()
+{
+ if (GetOptionsNoCreate()->GetThreadSpecNoCreate())
+ return GetOptionsNoCreate()->GetThreadSpecNoCreate()->GetTID();
+ else
+ return LLDB_INVALID_THREAD_ID;
+}
+
+void
+BreakpointLocation::SetThreadIndex (uint32_t index)
+{
+ if (index != 0)
+ GetLocationOptions()->GetThreadSpec()->SetIndex(index);
+ else
+ {
+ // If we're resetting this to an invalid thread id, then
+ // don't make an options pointer just to do that.
+ if (m_options_ap.get() != NULL)
+ m_options_ap->GetThreadSpec()->SetIndex(index);
+ }
+ SendBreakpointLocationChangedEvent (eBreakpointEventTypeThreadChanged);
+
+}
+
+uint32_t
+BreakpointLocation::GetThreadIndex() const
+{
+ if (GetOptionsNoCreate()->GetThreadSpecNoCreate())
+ return GetOptionsNoCreate()->GetThreadSpecNoCreate()->GetIndex();
+ else
+ return 0;
+}
+
+void
+BreakpointLocation::SetThreadName (const char *thread_name)
+{
+ if (thread_name != NULL)
+ GetLocationOptions()->GetThreadSpec()->SetName(thread_name);
+ else
+ {
+ // If we're resetting this to an invalid thread id, then
+ // don't make an options pointer just to do that.
+ if (m_options_ap.get() != NULL)
+ m_options_ap->GetThreadSpec()->SetName(thread_name);
+ }
+ SendBreakpointLocationChangedEvent (eBreakpointEventTypeThreadChanged);
+}
+
+const char *
+BreakpointLocation::GetThreadName () const
+{
+ if (GetOptionsNoCreate()->GetThreadSpecNoCreate())
+ return GetOptionsNoCreate()->GetThreadSpecNoCreate()->GetName();
+ else
+ return NULL;
+}
+
+void
+BreakpointLocation::SetQueueName (const char *queue_name)
+{
+ if (queue_name != NULL)
+ GetLocationOptions()->GetThreadSpec()->SetQueueName(queue_name);
+ else
+ {
+ // If we're resetting this to an invalid thread id, then
+ // don't make an options pointer just to do that.
+ if (m_options_ap.get() != NULL)
+ m_options_ap->GetThreadSpec()->SetQueueName(queue_name);
+ }
+ SendBreakpointLocationChangedEvent (eBreakpointEventTypeThreadChanged);
+}
+
+const char *
+BreakpointLocation::GetQueueName () const
+{
+ if (GetOptionsNoCreate()->GetThreadSpecNoCreate())
+ return GetOptionsNoCreate()->GetThreadSpecNoCreate()->GetQueueName();
+ else
+ return NULL;
+}
+
+bool
+BreakpointLocation::InvokeCallback (StoppointCallbackContext *context)
+{
+ if (m_options_ap.get() != NULL && m_options_ap->HasCallback())
+ return m_options_ap->InvokeCallback (context, m_owner.GetID(), GetID());
+ else
+ return m_owner.InvokeCallback (context, GetID());
+}
+
+void
+BreakpointLocation::SetCallback (BreakpointHitCallback callback, void *baton,
+ bool is_synchronous)
+{
+ // The default "Baton" class will keep a copy of "baton" and won't free
+ // or delete it when it goes goes out of scope.
+ GetLocationOptions()->SetCallback(callback, BatonSP (new Baton(baton)), is_synchronous);
+ SendBreakpointLocationChangedEvent (eBreakpointEventTypeCommandChanged);
+}
+
+void
+BreakpointLocation::SetCallback (BreakpointHitCallback callback, const BatonSP &baton_sp,
+ bool is_synchronous)
+{
+ GetLocationOptions()->SetCallback (callback, baton_sp, is_synchronous);
+ SendBreakpointLocationChangedEvent (eBreakpointEventTypeCommandChanged);
+}
+
+
+void
+BreakpointLocation::ClearCallback ()
+{
+ GetLocationOptions()->ClearCallback();
+}
+
+void
+BreakpointLocation::SetCondition (const char *condition)
+{
+ GetLocationOptions()->SetCondition (condition);
+ SendBreakpointLocationChangedEvent (eBreakpointEventTypeConditionChanged);
+}
+
+const char *
+BreakpointLocation::GetConditionText (size_t *hash) const
+{
+ return GetOptionsNoCreate()->GetConditionText(hash);
+}
+
+bool
+BreakpointLocation::ConditionSaysStop (ExecutionContext &exe_ctx, Error &error)
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
+
+ Mutex::Locker evaluation_locker(m_condition_mutex);
+
+ size_t condition_hash;
+ const char *condition_text = GetConditionText(&condition_hash);
+
+ if (!condition_text)
+ {
+ m_user_expression_sp.reset();
+ return false;
+ }
+
+ if (condition_hash != m_condition_hash ||
+ !m_user_expression_sp ||
+ !m_user_expression_sp->MatchesContext(exe_ctx))
+ {
+ m_user_expression_sp.reset(new ClangUserExpression(condition_text,
+ NULL,
+ lldb::eLanguageTypeUnknown,
+ ClangUserExpression::eResultTypeAny));
+
+ StreamString errors;
+
+ if (!m_user_expression_sp->Parse(errors,
+ exe_ctx,
+ eExecutionPolicyOnlyWhenNeeded,
+ true))
+ {
+ error.SetErrorStringWithFormat("Couldn't parse conditional expression:\n%s",
+ errors.GetData());
+ m_user_expression_sp.reset();
+ return false;
+ }
+
+ m_condition_hash = condition_hash;
+ }
+
+ // 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.
+
+ ValueObjectSP result_value_sp;
+ const bool unwind_on_error = true;
+ const bool ignore_breakpoints = true;
+ const bool try_all_threads = true;
+
+ Error expr_error;
+
+ StreamString execution_errors;
+
+ ClangExpressionVariableSP result_variable_sp;
+
+ ExecutionResults result_code =
+ m_user_expression_sp->Execute(execution_errors,
+ exe_ctx,
+ unwind_on_error,
+ ignore_breakpoints,
+ m_user_expression_sp,
+ result_variable_sp,
+ try_all_threads,
+ ClangUserExpression::kDefaultTimeout);
+
+ bool ret;
+
+ if (result_code == eExecutionCompleted)
+ {
+ if (!result_variable_sp)
+ {
+ ret = false;
+ error.SetErrorString("Expression did not return a result");
+ return false;
+ }
+
+ result_value_sp = result_variable_sp->GetValueObject();
+
+ if (result_value_sp)
+ {
+ Scalar scalar_value;
+ if (result_value_sp->ResolveValue (scalar_value))
+ {
+ if (scalar_value.ULongLong(1) == 0)
+ ret = false;
+ else
+ ret = true;
+ if (log)
+ log->Printf("Condition successfully evaluated, result is %s.\n",
+ ret ? "true" : "false");
+ }
+ else
+ {
+ ret = false;
+ error.SetErrorString("Failed to get an integer result from the expression");
+ }
+ }
+ else
+ {
+ ret = false;
+ error.SetErrorString("Failed to get any result from the expression");
+ }
+ }
+ else
+ {
+ ret = false;
+ error.SetErrorStringWithFormat("Couldn't execute expression:\n%s", execution_errors.GetData());
+ }
+
+ return ret;
+}
+
+uint32_t
+BreakpointLocation::GetIgnoreCount ()
+{
+ return GetOptionsNoCreate()->GetIgnoreCount();
+}
+
+void
+BreakpointLocation::SetIgnoreCount (uint32_t n)
+{
+ GetLocationOptions()->SetIgnoreCount(n);
+ SendBreakpointLocationChangedEvent (eBreakpointEventTypeIgnoreChanged);
+}
+
+void
+BreakpointLocation::DecrementIgnoreCount()
+{
+ if (m_options_ap.get() != NULL)
+ {
+ uint32_t loc_ignore = m_options_ap->GetIgnoreCount();
+ if (loc_ignore != 0)
+ m_options_ap->SetIgnoreCount(loc_ignore - 1);
+ }
+}
+
+bool
+BreakpointLocation::IgnoreCountShouldStop()
+{
+ if (m_options_ap.get() != NULL)
+ {
+ uint32_t loc_ignore = m_options_ap->GetIgnoreCount();
+ if (loc_ignore != 0)
+ {
+ m_owner.DecrementIgnoreCount();
+ DecrementIgnoreCount(); // Have to decrement our owners' ignore count, since it won't get a
+ // chance to.
+ return false;
+ }
+ }
+ return true;
+}
+
+const BreakpointOptions *
+BreakpointLocation::GetOptionsNoCreate () const
+{
+ if (m_options_ap.get() != NULL)
+ return m_options_ap.get();
+ else
+ return m_owner.GetOptions ();
+}
+
+BreakpointOptions *
+BreakpointLocation::GetLocationOptions ()
+{
+ // If we make the copy we don't copy the callbacks because that is potentially
+ // expensive and we don't want to do that for the simple case where someone is
+ // just disabling the location.
+ if (m_options_ap.get() == NULL)
+ m_options_ap.reset(BreakpointOptions::CopyOptionsNoCallback(*m_owner.GetOptions ()));
+
+ return m_options_ap.get();
+}
+
+bool
+BreakpointLocation::ValidForThisThread (Thread *thread)
+{
+ return thread->MatchesSpec(GetOptionsNoCreate()->GetThreadSpecNoCreate());
+}
+
+// RETURNS - true if we should stop at this breakpoint, false if we
+// should continue. Note, we don't check the thread spec for the breakpoint
+// here, since if the breakpoint is not for this thread, then the event won't
+// even get reported, so the check is redundant.
+
+bool
+BreakpointLocation::ShouldStop (StoppointCallbackContext *context)
+{
+ bool should_stop = true;
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
+
+ IncrementHitCount();
+
+ if (!IsEnabled())
+ return false;
+
+ if (!IgnoreCountShouldStop())
+ return false;
+
+ if (!m_owner.IgnoreCountShouldStop())
+ return false;
+
+ // We only run synchronous callbacks in ShouldStop:
+ context->is_synchronous = true;
+ should_stop = InvokeCallback (context);
+
+ if (log)
+ {
+ StreamString s;
+ GetDescription (&s, lldb::eDescriptionLevelVerbose);
+ log->Printf ("Hit breakpoint location: %s, %s.\n", s.GetData(), should_stop ? "stopping" : "continuing");
+ }
+
+ return should_stop;
+}
+
+bool
+BreakpointLocation::IsResolved () const
+{
+ return m_bp_site_sp.get() != NULL;
+}
+
+lldb::BreakpointSiteSP
+BreakpointLocation::GetBreakpointSite() const
+{
+ return m_bp_site_sp;
+}
+
+bool
+BreakpointLocation::ResolveBreakpointSite ()
+{
+ if (m_bp_site_sp)
+ return true;
+
+ Process *process = m_owner.GetTarget().GetProcessSP().get();
+ if (process == NULL)
+ return false;
+
+ lldb::break_id_t new_id = process->CreateBreakpointSite (shared_from_this(), false);
+
+ if (new_id == LLDB_INVALID_BREAK_ID)
+ {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
+ if (log)
+ log->Warning ("Tried to add breakpoint site at 0x%" PRIx64 " but it was already present.\n",
+ m_address.GetOpcodeLoadAddress (&m_owner.GetTarget()));
+ return false;
+ }
+
+ return true;
+}
+
+bool
+BreakpointLocation::SetBreakpointSite (BreakpointSiteSP& bp_site_sp)
+{
+ m_bp_site_sp = bp_site_sp;
+ return true;
+}
+
+bool
+BreakpointLocation::ClearBreakpointSite ()
+{
+ if (m_bp_site_sp.get())
+ {
+ m_owner.GetTarget().GetProcessSP()->RemoveOwnerFromBreakpointSite (GetBreakpoint().GetID(),
+ GetID(), m_bp_site_sp);
+ m_bp_site_sp.reset();
+ return true;
+ }
+ return false;
+}
+
+void
+BreakpointLocation::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ SymbolContext sc;
+
+ // If the description level is "initial" then the breakpoint is printing out our initial state,
+ // and we should let it decide how it wants to print our label.
+ if (level != eDescriptionLevelInitial)
+ {
+ s->Indent();
+ BreakpointID::GetCanonicalReference(s, m_owner.GetID(), GetID());
+ }
+
+ if (level == lldb::eDescriptionLevelBrief)
+ return;
+
+ if (level != eDescriptionLevelInitial)
+ s->PutCString(": ");
+
+ if (level == lldb::eDescriptionLevelVerbose)
+ s->IndentMore();
+
+ if (m_address.IsSectionOffset())
+ {
+ m_address.CalculateSymbolContext(&sc);
+
+ if (level == lldb::eDescriptionLevelFull || level == eDescriptionLevelInitial)
+ {
+ s->PutCString("where = ");
+ sc.DumpStopContext (s, m_owner.GetTarget().GetProcessSP().get(), m_address, false, true, false);
+ }
+ else
+ {
+ if (sc.module_sp)
+ {
+ s->EOL();
+ s->Indent("module = ");
+ sc.module_sp->GetFileSpec().Dump (s);
+ }
+
+ if (sc.comp_unit != NULL)
+ {
+ s->EOL();
+ s->Indent("compile unit = ");
+ static_cast<FileSpec*>(sc.comp_unit)->GetFilename().Dump (s);
+
+ if (sc.function != NULL)
+ {
+ s->EOL();
+ s->Indent("function = ");
+ s->PutCString (sc.function->GetMangled().GetName().AsCString("<unknown>"));
+ }
+
+ if (sc.line_entry.line > 0)
+ {
+ s->EOL();
+ s->Indent("location = ");
+ sc.line_entry.DumpStopContext (s, true);
+ }
+
+ }
+ else
+ {
+ // If we don't have a comp unit, see if we have a symbol we can print.
+ if (sc.symbol)
+ {
+ s->EOL();
+ s->Indent("symbol = ");
+ s->PutCString(sc.symbol->GetMangled().GetName().AsCString("<unknown>"));
+ }
+ }
+ }
+ }
+
+ if (level == lldb::eDescriptionLevelVerbose)
+ {
+ s->EOL();
+ s->Indent();
+ }
+
+ if (m_address.IsSectionOffset() && (level == eDescriptionLevelFull || level == eDescriptionLevelInitial))
+ s->Printf (", ");
+ s->Printf ("address = ");
+
+ ExecutionContextScope *exe_scope = NULL;
+ Target *target = &m_owner.GetTarget();
+ if (target)
+ exe_scope = target->GetProcessSP().get();
+ if (exe_scope == NULL)
+ exe_scope = target;
+
+ if (eDescriptionLevelInitial)
+ m_address.Dump(s, exe_scope, Address::DumpStyleLoadAddress, Address::DumpStyleFileAddress);
+ else
+ m_address.Dump(s, exe_scope, Address::DumpStyleLoadAddress, Address::DumpStyleModuleWithFileAddress);
+
+ if (level == lldb::eDescriptionLevelVerbose)
+ {
+ s->EOL();
+ s->Indent();
+ s->Printf("resolved = %s\n", IsResolved() ? "true" : "false");
+
+ s->Indent();
+ s->Printf ("hit count = %-4u\n", GetHitCount());
+
+ if (m_options_ap.get())
+ {
+ s->Indent();
+ m_options_ap->GetDescription (s, level);
+ s->EOL();
+ }
+ s->IndentLess();
+ }
+ else if (level != eDescriptionLevelInitial)
+ {
+ s->Printf(", %sresolved, hit count = %u ",
+ (IsResolved() ? "" : "un"),
+ GetHitCount());
+ if (m_options_ap.get())
+ {
+ m_options_ap->GetDescription (s, level);
+ }
+ }
+}
+
+void
+BreakpointLocation::Dump(Stream *s) const
+{
+ if (s == NULL)
+ return;
+
+ s->Printf("BreakpointLocation %u: tid = %4.4" PRIx64 " load addr = 0x%8.8" PRIx64 " state = %s type = %s breakpoint "
+ "hw_index = %i hit_count = %-4u ignore_count = %-4u",
+ GetID(),
+ GetOptionsNoCreate()->GetThreadSpecNoCreate()->GetTID(),
+ (uint64_t) m_address.GetOpcodeLoadAddress (&m_owner.GetTarget()),
+ (m_options_ap.get() ? m_options_ap->IsEnabled() : m_owner.IsEnabled()) ? "enabled " : "disabled",
+ IsHardware() ? "hardware" : "software",
+ GetHardwareIndex(),
+ GetHitCount(),
+ GetOptionsNoCreate()->GetIgnoreCount());
+}
+
+void
+BreakpointLocation::SendBreakpointLocationChangedEvent (lldb::BreakpointEventType eventKind)
+{
+ if (!m_being_created
+ && !m_owner.IsInternal()
+ && m_owner.GetTarget().EventTypeHasListeners(Target::eBroadcastBitBreakpointChanged))
+ {
+ Breakpoint::BreakpointEventData *data = new Breakpoint::BreakpointEventData (eventKind,
+ m_owner.shared_from_this());
+ data->GetBreakpointLocationCollection().Add (shared_from_this());
+ m_owner.GetTarget().BroadcastEvent (Target::eBroadcastBitBreakpointChanged, data);
+ }
+}
+
diff --git a/source/Breakpoint/BreakpointLocationCollection.cpp b/source/Breakpoint/BreakpointLocationCollection.cpp
new file mode 100644
index 000000000000..ee3f56f928d5
--- /dev/null
+++ b/source/Breakpoint/BreakpointLocationCollection.cpp
@@ -0,0 +1,198 @@
+//===-- BreakpointLocationCollection.cpp ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/BreakpointLocationCollection.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadSpec.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// BreakpointLocationCollection constructor
+//----------------------------------------------------------------------
+BreakpointLocationCollection::BreakpointLocationCollection() :
+ m_break_loc_collection()
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+BreakpointLocationCollection::~BreakpointLocationCollection()
+{
+}
+
+void
+BreakpointLocationCollection::Add(const BreakpointLocationSP &bp_loc)
+{
+ BreakpointLocationSP old_bp_loc = FindByIDPair (bp_loc->GetBreakpoint().GetID(), bp_loc->GetID());
+ if (!old_bp_loc.get())
+ m_break_loc_collection.push_back(bp_loc);
+}
+
+bool
+BreakpointLocationCollection::Remove (lldb::break_id_t bp_id, lldb::break_id_t bp_loc_id)
+{
+ collection::iterator pos = GetIDPairIterator(bp_id, bp_loc_id); // Predicate
+ if (pos != m_break_loc_collection.end())
+ {
+ m_break_loc_collection.erase(pos);
+ return true;
+ }
+ return false;
+
+}
+
+class BreakpointIDPairMatches
+{
+public:
+ BreakpointIDPairMatches (lldb::break_id_t break_id, lldb::break_id_t break_loc_id) :
+ m_break_id(break_id),
+ m_break_loc_id (break_loc_id)
+ {
+ }
+
+ bool operator() (const BreakpointLocationSP &bp_loc) const
+ {
+ return m_break_id == bp_loc->GetBreakpoint().GetID()
+ && m_break_loc_id == bp_loc->GetID();
+ }
+
+private:
+ const lldb::break_id_t m_break_id;
+ const lldb::break_id_t m_break_loc_id;
+};
+
+BreakpointLocationCollection::collection::iterator
+BreakpointLocationCollection::GetIDPairIterator (lldb::break_id_t break_id, lldb::break_id_t break_loc_id)
+{
+ return std::find_if(m_break_loc_collection.begin(), m_break_loc_collection.end(), // Search full range
+ BreakpointIDPairMatches(break_id, break_loc_id)); // Predicate
+}
+
+BreakpointLocationCollection::collection::const_iterator
+BreakpointLocationCollection::GetIDPairConstIterator (lldb::break_id_t break_id, lldb::break_id_t break_loc_id) const
+{
+ return std::find_if(m_break_loc_collection.begin(), m_break_loc_collection.end(), // Search full range
+ BreakpointIDPairMatches(break_id, break_loc_id)); // Predicate
+}
+
+BreakpointLocationSP
+BreakpointLocationCollection::FindByIDPair (lldb::break_id_t break_id, lldb::break_id_t break_loc_id)
+{
+ BreakpointLocationSP stop_sp;
+ collection::iterator pos = GetIDPairIterator(break_id, break_loc_id);
+ if (pos != m_break_loc_collection.end())
+ stop_sp = *pos;
+
+ return stop_sp;
+}
+
+const BreakpointLocationSP
+BreakpointLocationCollection::FindByIDPair (lldb::break_id_t break_id, lldb::break_id_t break_loc_id) const
+{
+ BreakpointLocationSP stop_sp;
+ collection::const_iterator pos = GetIDPairConstIterator(break_id, break_loc_id);
+ if (pos != m_break_loc_collection.end())
+ stop_sp = *pos;
+
+ return stop_sp;
+}
+
+BreakpointLocationSP
+BreakpointLocationCollection::GetByIndex (size_t i)
+{
+ BreakpointLocationSP stop_sp;
+ if (i < m_break_loc_collection.size())
+ stop_sp = m_break_loc_collection[i];
+
+ return stop_sp;
+}
+
+const BreakpointLocationSP
+BreakpointLocationCollection::GetByIndex (size_t i) const
+{
+ BreakpointLocationSP stop_sp;
+ if (i < m_break_loc_collection.size())
+ stop_sp = m_break_loc_collection[i];
+
+ return stop_sp;
+}
+
+bool
+BreakpointLocationCollection::ShouldStop (StoppointCallbackContext *context)
+{
+ bool shouldStop = false;
+ const size_t count = GetSize();
+ for (size_t i = 0; i < count; i++)
+ {
+ if (GetByIndex(i)->ShouldStop(context))
+ shouldStop = true;
+ }
+ return shouldStop;
+}
+
+bool
+BreakpointLocationCollection::ValidForThisThread (Thread *thread)
+{
+ collection::iterator pos,
+ begin = m_break_loc_collection.begin(),
+ end = m_break_loc_collection.end();
+
+ for (pos = begin; pos != end; ++pos)
+ {
+ if ((*pos)->ValidForThisThread (thread))
+ return true;
+ }
+ return false;
+}
+
+bool
+BreakpointLocationCollection::IsInternal () const
+{
+ collection::const_iterator pos,
+ begin = m_break_loc_collection.begin(),
+ end = m_break_loc_collection.end();
+
+ bool is_internal = true;
+
+ for (pos = begin; pos != end; ++pos)
+ {
+ if (!(*pos)->GetBreakpoint().IsInternal ())
+ {
+ is_internal = false;
+ break;
+ }
+ }
+ return is_internal;
+}
+
+void
+BreakpointLocationCollection::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ collection::iterator pos,
+ begin = m_break_loc_collection.begin(),
+ end = m_break_loc_collection.end();
+
+ for (pos = begin; pos != end; ++pos)
+ {
+ if (pos != begin)
+ s->PutChar(' ');
+ (*pos)->GetDescription(s, level);
+ }
+}
diff --git a/source/Breakpoint/BreakpointLocationList.cpp b/source/Breakpoint/BreakpointLocationList.cpp
new file mode 100644
index 000000000000..22a4ff0c68ee
--- /dev/null
+++ b/source/Breakpoint/BreakpointLocationList.cpp
@@ -0,0 +1,305 @@
+//===-- BreakpointLocationList.cpp ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/BreakpointLocationList.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+BreakpointLocationList::BreakpointLocationList(Breakpoint &owner) :
+ m_owner (owner),
+ m_locations(),
+ m_address_to_location (),
+ m_mutex (Mutex::eMutexTypeRecursive),
+ m_next_id (0),
+ m_new_location_recorder (NULL)
+{
+}
+
+BreakpointLocationList::~BreakpointLocationList()
+{
+}
+
+BreakpointLocationSP
+BreakpointLocationList::Create (const Address &addr)
+{
+ Mutex::Locker locker (m_mutex);
+ // The location ID is just the size of the location list + 1
+ lldb::break_id_t bp_loc_id = ++m_next_id;
+ BreakpointLocationSP bp_loc_sp (new BreakpointLocation (bp_loc_id, m_owner, addr));
+ m_locations.push_back (bp_loc_sp);
+ m_address_to_location[addr] = bp_loc_sp;
+ return bp_loc_sp;
+}
+
+bool
+BreakpointLocationList::ShouldStop (StoppointCallbackContext *context, lldb::break_id_t break_id)
+{
+ BreakpointLocationSP bp = FindByID (break_id);
+ if (bp)
+ {
+ // Let the BreakpointLocation decide if it should stop here (could not have
+ // reached it's target hit count yet, or it could have a callback
+ // that decided it shouldn't stop (shared library loads/unloads).
+ return bp->ShouldStop (context);
+ }
+ // We should stop here since this BreakpointLocation isn't valid anymore or it
+ // doesn't exist.
+ return true;
+}
+
+lldb::break_id_t
+BreakpointLocationList::FindIDByAddress (const Address &addr)
+{
+ BreakpointLocationSP bp_loc_sp = FindByAddress (addr);
+ if (bp_loc_sp)
+ {
+ return bp_loc_sp->GetID();
+ }
+ return LLDB_INVALID_BREAK_ID;
+}
+
+BreakpointLocationSP
+BreakpointLocationList::FindByID (lldb::break_id_t break_id) const
+{
+ BreakpointLocationSP bp_loc_sp;
+ Mutex::Locker locker (m_mutex);
+ // We never remove a breakpoint locations, so the ID can be translated into
+ // the location index by subtracting 1
+ uint32_t idx = break_id - 1;
+ if (idx <= m_locations.size())
+ {
+ bp_loc_sp = m_locations[idx];
+ }
+ return bp_loc_sp;
+}
+
+size_t
+BreakpointLocationList::FindInModule (Module *module,
+ BreakpointLocationCollection& bp_loc_list)
+{
+ Mutex::Locker locker (m_mutex);
+ const size_t orig_size = bp_loc_list.GetSize();
+ collection::iterator pos, end = m_locations.end();
+
+ for (pos = m_locations.begin(); pos != end; ++pos)
+ {
+ BreakpointLocationSP break_loc = (*pos);
+ SectionSP section_sp (break_loc->GetAddress().GetSection());
+ if (section_sp && section_sp->GetModule().get() == module)
+ {
+ bp_loc_list.Add (break_loc);
+ }
+ }
+ return bp_loc_list.GetSize() - orig_size;
+}
+
+const BreakpointLocationSP
+BreakpointLocationList::FindByAddress (const Address &addr) const
+{
+ Mutex::Locker locker (m_mutex);
+ BreakpointLocationSP bp_loc_sp;
+ if (!m_locations.empty())
+ {
+ Address so_addr;
+
+ if (addr.IsSectionOffset())
+ {
+ so_addr = addr;
+ }
+ else
+ {
+ // Try and resolve as a load address if possible.
+ m_owner.GetTarget().GetSectionLoadList().ResolveLoadAddress (addr.GetOffset(), so_addr);
+ if (!so_addr.IsValid())
+ {
+ // The address didn't resolve, so just set to passed in addr.
+ so_addr = addr;
+ }
+ }
+
+ addr_map::const_iterator pos = m_address_to_location.find (so_addr);
+ if (pos != m_address_to_location.end())
+ bp_loc_sp = pos->second;
+ }
+
+ return bp_loc_sp;
+}
+
+void
+BreakpointLocationList::Dump (Stream *s) const
+{
+ s->Printf("%p: ", this);
+ //s->Indent();
+ Mutex::Locker locker (m_mutex);
+ s->Printf("BreakpointLocationList with %" PRIu64 " BreakpointLocations:\n", (uint64_t)m_locations.size());
+ s->IndentMore();
+ collection::const_iterator pos, end = m_locations.end();
+ for (pos = m_locations.begin(); pos != end; ++pos)
+ (*pos).get()->Dump(s);
+ s->IndentLess();
+}
+
+
+BreakpointLocationSP
+BreakpointLocationList::GetByIndex (size_t i)
+{
+ Mutex::Locker locker (m_mutex);
+ BreakpointLocationSP bp_loc_sp;
+ if (i < m_locations.size())
+ bp_loc_sp = m_locations[i];
+
+ return bp_loc_sp;
+}
+
+const BreakpointLocationSP
+BreakpointLocationList::GetByIndex (size_t i) const
+{
+ Mutex::Locker locker (m_mutex);
+ BreakpointLocationSP bp_loc_sp;
+ if (i < m_locations.size())
+ bp_loc_sp = m_locations[i];
+
+ return bp_loc_sp;
+}
+
+void
+BreakpointLocationList::ClearAllBreakpointSites ()
+{
+ Mutex::Locker locker (m_mutex);
+ collection::iterator pos, end = m_locations.end();
+ for (pos = m_locations.begin(); pos != end; ++pos)
+ (*pos)->ClearBreakpointSite();
+}
+
+void
+BreakpointLocationList::ResolveAllBreakpointSites ()
+{
+ Mutex::Locker locker (m_mutex);
+ collection::iterator pos, end = m_locations.end();
+
+ for (pos = m_locations.begin(); pos != end; ++pos)
+ {
+ if ((*pos)->IsEnabled())
+ (*pos)->ResolveBreakpointSite();
+ }
+}
+
+uint32_t
+BreakpointLocationList::GetHitCount () const
+{
+ uint32_t hit_count = 0;
+ Mutex::Locker locker (m_mutex);
+ collection::const_iterator pos, end = m_locations.end();
+ for (pos = m_locations.begin(); pos != end; ++pos)
+ hit_count += (*pos)->GetHitCount();
+ return hit_count;
+}
+
+size_t
+BreakpointLocationList::GetNumResolvedLocations() const
+{
+ Mutex::Locker locker (m_mutex);
+ size_t resolve_count = 0;
+ collection::const_iterator pos, end = m_locations.end();
+ for (pos = m_locations.begin(); pos != end; ++pos)
+ {
+ if ((*pos)->IsResolved())
+ ++resolve_count;
+ }
+ return resolve_count;
+}
+
+void
+BreakpointLocationList::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ Mutex::Locker locker (m_mutex);
+ collection::iterator pos, end = m_locations.end();
+
+ for (pos = m_locations.begin(); pos != end; ++pos)
+ {
+ s->Printf(" ");
+ (*pos)->GetDescription(s, level);
+ }
+}
+
+BreakpointLocationSP
+BreakpointLocationList::AddLocation (const Address &addr, bool *new_location)
+{
+ Mutex::Locker locker (m_mutex);
+
+ if (new_location)
+ *new_location = false;
+ BreakpointLocationSP bp_loc_sp (FindByAddress(addr));
+ if (!bp_loc_sp)
+ {
+ bp_loc_sp = Create (addr);
+ if (bp_loc_sp)
+ {
+ bp_loc_sp->ResolveBreakpointSite();
+
+ if (new_location)
+ *new_location = true;
+ if(m_new_location_recorder)
+ {
+ m_new_location_recorder->Add(bp_loc_sp);
+ }
+ }
+ }
+ return bp_loc_sp;
+}
+
+bool
+BreakpointLocationList::RemoveLocation (const lldb::BreakpointLocationSP &bp_loc_sp)
+{
+ if (bp_loc_sp)
+ {
+ Mutex::Locker locker (m_mutex);
+
+ m_address_to_location.erase (bp_loc_sp->GetAddress());
+
+ collection::iterator pos, end = m_locations.end();
+ for (pos = m_locations.begin(); pos != end; ++pos)
+ {
+ if ((*pos).get() == bp_loc_sp.get())
+ {
+ m_locations.erase (pos);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
+
+void
+BreakpointLocationList::StartRecordingNewLocations (BreakpointLocationCollection &new_locations)
+{
+ Mutex::Locker locker (m_mutex);
+ assert (m_new_location_recorder == NULL);
+ m_new_location_recorder = &new_locations;
+}
+
+void
+BreakpointLocationList::StopRecordingNewLocations ()
+{
+ Mutex::Locker locker (m_mutex);
+ m_new_location_recorder = NULL;
+}
+
diff --git a/source/Breakpoint/BreakpointOptions.cpp b/source/Breakpoint/BreakpointOptions.cpp
new file mode 100644
index 000000000000..3a4a117695fc
--- /dev/null
+++ b/source/Breakpoint/BreakpointOptions.cpp
@@ -0,0 +1,298 @@
+//===-- BreakpointOptions.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/BreakpointOptions.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StringList.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadSpec.h"
+#include "lldb/Expression/ClangUserExpression.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+bool
+BreakpointOptions::NullCallback (void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, lldb::user_id_t break_loc_id)
+{
+ return true;
+}
+
+//----------------------------------------------------------------------
+// BreakpointOptions constructor
+//----------------------------------------------------------------------
+BreakpointOptions::BreakpointOptions() :
+ m_callback (BreakpointOptions::NullCallback),
+ m_callback_baton_sp (),
+ m_callback_is_synchronous (false),
+ m_enabled (true),
+ m_one_shot (false),
+ m_ignore_count (0),
+ m_thread_spec_ap (),
+ m_condition_text (),
+ m_condition_text_hash (0)
+{
+}
+
+//----------------------------------------------------------------------
+// BreakpointOptions copy constructor
+//----------------------------------------------------------------------
+BreakpointOptions::BreakpointOptions(const BreakpointOptions& rhs) :
+ m_callback (rhs.m_callback),
+ m_callback_baton_sp (rhs.m_callback_baton_sp),
+ m_callback_is_synchronous (rhs.m_callback_is_synchronous),
+ m_enabled (rhs.m_enabled),
+ m_one_shot (rhs.m_one_shot),
+ m_ignore_count (rhs.m_ignore_count),
+ m_thread_spec_ap ()
+{
+ if (rhs.m_thread_spec_ap.get() != NULL)
+ m_thread_spec_ap.reset (new ThreadSpec(*rhs.m_thread_spec_ap.get()));
+ m_condition_text = rhs.m_condition_text;
+ m_condition_text_hash = rhs.m_condition_text_hash;
+}
+
+//----------------------------------------------------------------------
+// BreakpointOptions assignment operator
+//----------------------------------------------------------------------
+const BreakpointOptions&
+BreakpointOptions::operator=(const BreakpointOptions& rhs)
+{
+ m_callback = rhs.m_callback;
+ m_callback_baton_sp = rhs.m_callback_baton_sp;
+ m_callback_is_synchronous = rhs.m_callback_is_synchronous;
+ m_enabled = rhs.m_enabled;
+ m_one_shot = rhs.m_one_shot;
+ m_ignore_count = rhs.m_ignore_count;
+ if (rhs.m_thread_spec_ap.get() != NULL)
+ m_thread_spec_ap.reset(new ThreadSpec(*rhs.m_thread_spec_ap.get()));
+ m_condition_text = rhs.m_condition_text;
+ m_condition_text_hash = rhs.m_condition_text_hash;
+ return *this;
+}
+
+BreakpointOptions *
+BreakpointOptions::CopyOptionsNoCallback (BreakpointOptions &orig)
+{
+ BreakpointHitCallback orig_callback = orig.m_callback;
+ lldb::BatonSP orig_callback_baton_sp = orig.m_callback_baton_sp;
+ bool orig_is_sync = orig.m_callback_is_synchronous;
+
+ orig.ClearCallback();
+ BreakpointOptions *ret_val = new BreakpointOptions(orig);
+
+ orig.SetCallback (orig_callback, orig_callback_baton_sp, orig_is_sync);
+
+ return ret_val;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+BreakpointOptions::~BreakpointOptions()
+{
+}
+
+//------------------------------------------------------------------
+// Callbacks
+//------------------------------------------------------------------
+void
+BreakpointOptions::SetCallback (BreakpointHitCallback callback, const BatonSP &callback_baton_sp, bool callback_is_synchronous)
+{
+ m_callback_is_synchronous = callback_is_synchronous;
+ m_callback = callback;
+ m_callback_baton_sp = callback_baton_sp;
+}
+
+void
+BreakpointOptions::ClearCallback ()
+{
+ m_callback = BreakpointOptions::NullCallback;
+ m_callback_is_synchronous = false;
+ m_callback_baton_sp.reset();
+}
+
+Baton *
+BreakpointOptions::GetBaton ()
+{
+ return m_callback_baton_sp.get();
+}
+
+const Baton *
+BreakpointOptions::GetBaton () const
+{
+ return m_callback_baton_sp.get();
+}
+
+bool
+BreakpointOptions::InvokeCallback (StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id)
+{
+ if (m_callback && context->is_synchronous == IsCallbackSynchronous())
+ {
+ return m_callback (m_callback_baton_sp ? m_callback_baton_sp->m_data : NULL,
+ context,
+ break_id,
+ break_loc_id);
+ }
+ else
+ return true;
+}
+
+bool
+BreakpointOptions::HasCallback ()
+{
+ return m_callback != BreakpointOptions::NullCallback;
+}
+
+void
+BreakpointOptions::SetCondition (const char *condition)
+{
+ if (!condition)
+ condition = "";
+
+ m_condition_text.assign(condition);
+ std::hash<std::string> hasher;
+ m_condition_text_hash = hasher(m_condition_text);
+}
+
+const char *
+BreakpointOptions::GetConditionText (size_t *hash) const
+{
+ if (!m_condition_text.empty())
+ {
+ if (hash)
+ *hash = m_condition_text_hash;
+
+ return m_condition_text.c_str();
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+const ThreadSpec *
+BreakpointOptions::GetThreadSpecNoCreate () const
+{
+ return m_thread_spec_ap.get();
+}
+
+ThreadSpec *
+BreakpointOptions::GetThreadSpec ()
+{
+ if (m_thread_spec_ap.get() == NULL)
+ m_thread_spec_ap.reset (new ThreadSpec());
+
+ return m_thread_spec_ap.get();
+}
+
+void
+BreakpointOptions::SetThreadID (lldb::tid_t thread_id)
+{
+ GetThreadSpec()->SetTID(thread_id);
+}
+
+void
+BreakpointOptions::GetDescription (Stream *s, lldb::DescriptionLevel level) const
+{
+
+ // Figure out if there are any options not at their default value, and only print
+ // anything if there are:
+
+ if (m_ignore_count != 0 || !m_enabled || m_one_shot || (GetThreadSpecNoCreate() != NULL && GetThreadSpecNoCreate()->HasSpecification ()))
+ {
+ if (level == lldb::eDescriptionLevelVerbose)
+ {
+ s->EOL ();
+ s->IndentMore();
+ s->Indent();
+ s->PutCString("Breakpoint Options:\n");
+ s->IndentMore();
+ s->Indent();
+ }
+ else
+ s->PutCString(" Options: ");
+
+ if (m_ignore_count > 0)
+ s->Printf("ignore: %d ", m_ignore_count);
+ s->Printf("%sabled ", m_enabled ? "en" : "dis");
+
+ if (m_one_shot)
+ s->Printf ("one-shot ");
+
+ if (m_thread_spec_ap.get())
+ m_thread_spec_ap->GetDescription (s, level);
+ else if (level == eDescriptionLevelBrief)
+ s->PutCString ("thread spec: no ");
+ if (level == lldb::eDescriptionLevelFull)
+ {
+ s->IndentLess();
+ s->IndentMore();
+ }
+ }
+
+ if (m_callback_baton_sp.get())
+ {
+ if (level != eDescriptionLevelBrief)
+ {
+ s->EOL();
+ m_callback_baton_sp->GetDescription (s, level);
+ }
+ }
+ if (!m_condition_text.empty())
+ {
+ if (level != eDescriptionLevelBrief)
+ {
+ s->EOL();
+ s->Printf("Condition: %s\n", m_condition_text.c_str());
+ }
+ }
+}
+
+void
+BreakpointOptions::CommandBaton::GetDescription (Stream *s, lldb::DescriptionLevel level) const
+{
+ CommandData *data = (CommandData *)m_data;
+
+ if (level == eDescriptionLevelBrief)
+ {
+ s->Printf (", commands = %s", (data && data->user_source.GetSize() > 0) ? "yes" : "no");
+ return;
+ }
+
+ s->IndentMore ();
+ s->Indent("Breakpoint commands:\n");
+
+ s->IndentMore ();
+ if (data && data->user_source.GetSize() > 0)
+ {
+ const size_t num_strings = data->user_source.GetSize();
+ for (size_t i = 0; i < num_strings; ++i)
+ {
+ s->Indent(data->user_source.GetStringAtIndex(i));
+ s->EOL();
+ }
+ }
+ else
+ {
+ s->PutCString ("No commands.\n");
+ }
+ s->IndentLess ();
+ s->IndentLess ();
+}
+
diff --git a/source/Breakpoint/BreakpointResolver.cpp b/source/Breakpoint/BreakpointResolver.cpp
new file mode 100644
index 000000000000..b22fa1e6dbcc
--- /dev/null
+++ b/source/Breakpoint/BreakpointResolver.cpp
@@ -0,0 +1,61 @@
+//===-- BreakpointResolver.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/BreakpointResolver.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Address.h"
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/SearchFilter.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/lldb-private-log.h"
+
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// BreakpointResolver:
+//----------------------------------------------------------------------
+BreakpointResolver::BreakpointResolver (Breakpoint *bkpt, const unsigned char resolverTy) :
+ m_breakpoint (bkpt),
+ SubclassID (resolverTy)
+{
+}
+
+BreakpointResolver::~BreakpointResolver ()
+{
+
+}
+
+void
+BreakpointResolver::SetBreakpoint (Breakpoint *bkpt)
+{
+ m_breakpoint = bkpt;
+}
+
+void
+BreakpointResolver::ResolveBreakpointInModules (SearchFilter &filter, ModuleList &modules)
+{
+ filter.SearchInModuleList(*this, modules);
+}
+
+void
+BreakpointResolver::ResolveBreakpoint (SearchFilter &filter)
+{
+ filter.Search (*this);
+}
+
diff --git a/source/Breakpoint/BreakpointResolverAddress.cpp b/source/Breakpoint/BreakpointResolverAddress.cpp
new file mode 100644
index 000000000000..1bcef93aedad
--- /dev/null
+++ b/source/Breakpoint/BreakpointResolverAddress.cpp
@@ -0,0 +1,111 @@
+//===-- BreakpointResolverAddress.cpp ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/BreakpointResolverAddress.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private-log.h"
+
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// BreakpointResolverAddress:
+//----------------------------------------------------------------------
+BreakpointResolverAddress::BreakpointResolverAddress
+(
+ Breakpoint *bkpt,
+ const Address &addr
+) :
+ BreakpointResolver (bkpt, BreakpointResolver::AddressResolver),
+ m_addr (addr)
+{
+}
+
+BreakpointResolverAddress::~BreakpointResolverAddress ()
+{
+
+}
+
+void
+BreakpointResolverAddress::ResolveBreakpoint (SearchFilter &filter)
+{
+ // The address breakpoint only takes once, so if we've already set it we're done.
+ if (m_breakpoint->GetNumLocations() > 0)
+ return;
+ else
+ BreakpointResolver::ResolveBreakpoint(filter);
+}
+
+void
+BreakpointResolverAddress::ResolveBreakpointInModules
+(
+ SearchFilter &filter,
+ ModuleList &modules
+)
+{
+ // The address breakpoint only takes once, so if we've already set it we're done.
+ if (m_breakpoint->GetNumLocations() > 0)
+ return;
+ else
+ BreakpointResolver::ResolveBreakpointInModules (filter, modules);
+}
+
+Searcher::CallbackReturn
+BreakpointResolverAddress::SearchCallback
+(
+ SearchFilter &filter,
+ SymbolContext &context,
+ Address *addr,
+ bool containing
+)
+{
+ assert (m_breakpoint != NULL);
+
+ if (filter.AddressPasses (m_addr))
+ {
+ BreakpointLocationSP bp_loc_sp(m_breakpoint->AddLocation(m_addr));
+ if (bp_loc_sp && !m_breakpoint->IsInternal())
+ {
+ StreamString s;
+ bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("Added location: %s\n", s.GetData());
+ }
+ }
+ return Searcher::eCallbackReturnStop;
+}
+
+Searcher::Depth
+BreakpointResolverAddress::GetDepth()
+{
+ return Searcher::eDepthTarget;
+}
+
+void
+BreakpointResolverAddress::GetDescription (Stream *s)
+{
+ s->PutCString ("address = ");
+ m_addr.Dump(s, m_breakpoint->GetTarget().GetProcessSP().get(), Address::DumpStyleLoadAddress, Address::DumpStyleModuleWithFileAddress);
+}
+
+void
+BreakpointResolverAddress::Dump (Stream *s) const
+{
+
+}
diff --git a/source/Breakpoint/BreakpointResolverFileLine.cpp b/source/Breakpoint/BreakpointResolverFileLine.cpp
new file mode 100644
index 000000000000..91a218fdb80a
--- /dev/null
+++ b/source/Breakpoint/BreakpointResolverFileLine.cpp
@@ -0,0 +1,246 @@
+//===-- BreakpointResolverFileLine.cpp --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/BreakpointResolverFileLine.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/lldb-private-log.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// BreakpointResolverFileLine:
+//----------------------------------------------------------------------
+BreakpointResolverFileLine::BreakpointResolverFileLine
+(
+ Breakpoint *bkpt,
+ const FileSpec &file_spec,
+ uint32_t line_no,
+ bool check_inlines,
+ bool skip_prologue
+) :
+ BreakpointResolver (bkpt, BreakpointResolver::FileLineResolver),
+ m_file_spec (file_spec),
+ m_line_number (line_no),
+ m_inlines (check_inlines),
+ m_skip_prologue(skip_prologue)
+{
+}
+
+BreakpointResolverFileLine::~BreakpointResolverFileLine ()
+{
+}
+
+Searcher::CallbackReturn
+BreakpointResolverFileLine::SearchCallback
+(
+ SearchFilter &filter,
+ SymbolContext &context,
+ Address *addr,
+ bool containing
+)
+{
+ SymbolContextList sc_list;
+
+ assert (m_breakpoint != NULL);
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+
+ // There is a tricky bit here. You can have two compilation units that #include the same file, and
+ // in one of them the function at m_line_number is used (and so code and a line entry for it is generated) but in the
+ // other it isn't. If we considered the CU's independently, then in the second inclusion, we'd move the breakpoint
+ // to the next function that actually generated code in the header file. That would end up being confusing.
+ // So instead, we do the CU iterations by hand here, then scan through the complete list of matches, and figure out
+ // the closest line number match, and only set breakpoints on that match.
+
+ // Note also that if file_spec only had a file name and not a directory, there may be many different file spec's in
+ // the resultant list. The closest line match for one will not be right for some totally different file.
+ // So we go through the match list and pull out the sets that have the same file spec in their line_entry
+ // and treat each set separately.
+
+ const size_t num_comp_units = context.module_sp->GetNumCompileUnits();
+ for (size_t i = 0; i < num_comp_units; i++)
+ {
+ CompUnitSP cu_sp (context.module_sp->GetCompileUnitAtIndex (i));
+ if (cu_sp)
+ {
+ if (filter.CompUnitPasses(*cu_sp))
+ cu_sp->ResolveSymbolContext (m_file_spec, m_line_number, m_inlines, false, eSymbolContextEverything, sc_list);
+ }
+ }
+
+ while (sc_list.GetSize() > 0)
+ {
+ SymbolContextList tmp_sc_list;
+ unsigned current_idx = 0;
+ SymbolContext sc;
+ bool first_entry = true;
+
+ FileSpec match_file_spec;
+ uint32_t closest_line_number = UINT32_MAX;
+
+ // Pull out the first entry, and all the others that match its file spec, and stuff them in the tmp list.
+ while (current_idx < sc_list.GetSize())
+ {
+ bool matches;
+
+ sc_list.GetContextAtIndex (current_idx, sc);
+ if (first_entry)
+ {
+ match_file_spec = sc.line_entry.file;
+ matches = true;
+ first_entry = false;
+ }
+ else
+ matches = (sc.line_entry.file == match_file_spec);
+
+ if (matches)
+ {
+ tmp_sc_list.Append (sc);
+ sc_list.RemoveContextAtIndex(current_idx);
+
+ // ResolveSymbolContext will always return a number that is >= the line number you pass in.
+ // So the smaller line number is always better.
+ if (sc.line_entry.line < closest_line_number)
+ closest_line_number = sc.line_entry.line;
+ }
+ else
+ current_idx++;
+ }
+
+ // Okay, we've found the closest line number match, now throw away all the others:
+
+ current_idx = 0;
+ while (current_idx < tmp_sc_list.GetSize())
+ {
+ if (tmp_sc_list.GetContextAtIndex(current_idx, sc))
+ {
+ if (sc.line_entry.line != closest_line_number)
+ tmp_sc_list.RemoveContextAtIndex(current_idx);
+ else
+ current_idx++;
+ }
+ }
+
+ // Next go through and see if there are line table entries that are contiguous, and if so keep only the
+ // first of the contiguous range:
+
+ lldb::addr_t last_end_addr = LLDB_INVALID_ADDRESS;
+ current_idx = 0;
+ while (current_idx < tmp_sc_list.GetSize())
+ {
+ if (tmp_sc_list.GetContextAtIndex(current_idx, sc))
+ {
+ lldb::addr_t start_file_addr = sc.line_entry.range.GetBaseAddress().GetFileAddress();
+ lldb::addr_t end_file_addr = start_file_addr + sc.line_entry.range.GetByteSize();
+
+ if (start_file_addr == last_end_addr)
+ tmp_sc_list.RemoveContextAtIndex(current_idx);
+ else
+ current_idx++;
+
+ last_end_addr = end_file_addr;
+ }
+ }
+
+ // and make breakpoints out of the closest line number match.
+
+ uint32_t tmp_sc_list_size = tmp_sc_list.GetSize();
+
+ for (uint32_t i = 0; i < tmp_sc_list_size; i++)
+ {
+ if (tmp_sc_list.GetContextAtIndex(i, sc))
+ {
+ Address line_start = sc.line_entry.range.GetBaseAddress();
+ if (line_start.IsValid())
+ {
+ if (filter.AddressPasses(line_start))
+ {
+ // If the line number is before the prologue end, move it there...
+ bool skipped_prologue = false;
+ if (m_skip_prologue)
+ {
+ if (sc.function)
+ {
+ Address prologue_addr(sc.function->GetAddressRange().GetBaseAddress());
+ if (prologue_addr.IsValid() && (line_start == prologue_addr))
+ {
+ const uint32_t prologue_byte_size = sc.function->GetPrologueByteSize();
+ if (prologue_byte_size)
+ {
+ prologue_addr.Slide(prologue_byte_size);
+
+ if (filter.AddressPasses(prologue_addr))
+ {
+ skipped_prologue = true;
+ line_start = prologue_addr;
+ }
+ }
+ }
+ }
+ }
+
+ BreakpointLocationSP bp_loc_sp (m_breakpoint->AddLocation(line_start));
+ if (log && bp_loc_sp && !m_breakpoint->IsInternal())
+ {
+ StreamString s;
+ bp_loc_sp->GetDescription (&s, lldb::eDescriptionLevelVerbose);
+ log->Printf ("Added location (skipped prologue: %s): %s \n", skipped_prologue ? "yes" : "no", s.GetData());
+ }
+ }
+ else if (log)
+ {
+ log->Printf ("Breakpoint at file address 0x%" PRIx64 " for %s:%d didn't pass the filter.\n",
+ line_start.GetFileAddress(),
+ m_file_spec.GetFilename().AsCString("<Unknown>"),
+ m_line_number);
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("error: Unable to set breakpoint at file address 0x%" PRIx64 " for %s:%d\n",
+ line_start.GetFileAddress(),
+ m_file_spec.GetFilename().AsCString("<Unknown>"),
+ m_line_number);
+ }
+ }
+ }
+ }
+
+ return Searcher::eCallbackReturnContinue;
+}
+
+Searcher::Depth
+BreakpointResolverFileLine::GetDepth()
+{
+ return Searcher::eDepthModule;
+}
+
+void
+BreakpointResolverFileLine::GetDescription (Stream *s)
+{
+ s->Printf ("file = '%s', line = %u", m_file_spec.GetPath().c_str(), m_line_number);
+}
+
+void
+BreakpointResolverFileLine::Dump (Stream *s) const
+{
+
+}
+
diff --git a/source/Breakpoint/BreakpointResolverFileRegex.cpp b/source/Breakpoint/BreakpointResolverFileRegex.cpp
new file mode 100644
index 000000000000..de974d04894a
--- /dev/null
+++ b/source/Breakpoint/BreakpointResolverFileRegex.cpp
@@ -0,0 +1,134 @@
+//===-- BreakpointResolverFileRegex.cpp --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/BreakpointResolverFileRegex.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/SourceManager.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Target/Target.h"
+#include "lldb/lldb-private-log.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// BreakpointResolverFileRegex:
+//----------------------------------------------------------------------
+BreakpointResolverFileRegex::BreakpointResolverFileRegex
+(
+ Breakpoint *bkpt,
+ RegularExpression &regex
+) :
+ BreakpointResolver (bkpt, BreakpointResolver::FileLineResolver),
+ m_regex (regex)
+{
+}
+
+BreakpointResolverFileRegex::~BreakpointResolverFileRegex ()
+{
+}
+
+Searcher::CallbackReturn
+BreakpointResolverFileRegex::SearchCallback
+(
+ SearchFilter &filter,
+ SymbolContext &context,
+ Address *addr,
+ bool containing
+)
+{
+
+ assert (m_breakpoint != NULL);
+ if (!context.target_sp)
+ return eCallbackReturnContinue;
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+
+ CompileUnit *cu = context.comp_unit;
+ FileSpec cu_file_spec = *(static_cast<FileSpec *>(cu));
+ std::vector<uint32_t> line_matches;
+ context.target_sp->GetSourceManager().FindLinesMatchingRegex(cu_file_spec, m_regex, 1, UINT32_MAX, line_matches);
+ uint32_t num_matches = line_matches.size();
+ for (uint32_t i = 0; i < num_matches; i++)
+ {
+ uint32_t start_idx = 0;
+ bool exact = false;
+ while (1)
+ {
+ LineEntry line_entry;
+
+ // Cycle through all the line entries that might match this one:
+ start_idx = cu->FindLineEntry (start_idx, line_matches[i], NULL, exact, &line_entry);
+ if (start_idx == UINT32_MAX)
+ break;
+ exact = true;
+ start_idx++;
+
+ Address line_start = line_entry.range.GetBaseAddress();
+ if (line_start.IsValid())
+ {
+ if (filter.AddressPasses(line_start))
+ {
+ BreakpointLocationSP bp_loc_sp (m_breakpoint->AddLocation(line_start));
+ if (log && bp_loc_sp && !m_breakpoint->IsInternal())
+ {
+ StreamString s;
+ bp_loc_sp->GetDescription (&s, lldb::eDescriptionLevelVerbose);
+ log->Printf ("Added location: %s\n", s.GetData());
+ }
+ }
+ else if (log)
+ {
+ log->Printf ("Breakpoint at file address 0x%" PRIx64 " for %s:%d didn't pass filter.\n",
+ line_start.GetFileAddress(),
+ cu_file_spec.GetFilename().AsCString("<Unknown>"),
+ line_matches[i]);
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("error: Unable to set breakpoint at file address 0x%" PRIx64 " for %s:%d\n",
+ line_start.GetFileAddress(),
+ cu_file_spec.GetFilename().AsCString("<Unknown>"),
+ line_matches[i]);
+ }
+
+ }
+ }
+ assert (m_breakpoint != NULL);
+
+ return Searcher::eCallbackReturnContinue;
+}
+
+Searcher::Depth
+BreakpointResolverFileRegex::GetDepth()
+{
+ return Searcher::eDepthCompUnit;
+}
+
+void
+BreakpointResolverFileRegex::GetDescription (Stream *s)
+{
+ s->Printf ("source regex = \"%s\"", m_regex.GetText());
+}
+
+void
+BreakpointResolverFileRegex::Dump (Stream *s) const
+{
+
+}
+
diff --git a/source/Breakpoint/BreakpointResolverName.cpp b/source/Breakpoint/BreakpointResolverName.cpp
new file mode 100644
index 000000000000..27f85653d648
--- /dev/null
+++ b/source/Breakpoint/BreakpointResolverName.cpp
@@ -0,0 +1,357 @@
+//===-- BreakpointResolverName.cpp ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/BreakpointResolverName.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Symbol/ClangNamespaceDecl.h"
+#include "lldb/Symbol/Block.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+BreakpointResolverName::BreakpointResolverName (Breakpoint *bkpt,
+ const char *name_cstr,
+ uint32_t name_type_mask,
+ Breakpoint::MatchType type,
+ bool skip_prologue) :
+ BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
+ m_class_name (),
+ m_regex (),
+ m_match_type (type),
+ m_skip_prologue (skip_prologue)
+{
+
+ if (m_match_type == Breakpoint::Regexp)
+ {
+ if (!m_regex.Compile (name_cstr))
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+
+ if (log)
+ log->Warning ("function name regexp: \"%s\" did not compile.", name_cstr);
+ }
+ }
+ else
+ {
+ AddNameLookup (ConstString(name_cstr), name_type_mask);
+ }
+}
+
+BreakpointResolverName::BreakpointResolverName (Breakpoint *bkpt,
+ const char *names[],
+ size_t num_names,
+ uint32_t name_type_mask,
+ bool skip_prologue) :
+ BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
+ m_match_type (Breakpoint::Exact),
+ m_skip_prologue (skip_prologue)
+{
+ for (size_t i = 0; i < num_names; i++)
+ {
+ AddNameLookup (ConstString (names[i]), name_type_mask);
+ }
+}
+
+BreakpointResolverName::BreakpointResolverName (Breakpoint *bkpt,
+ std::vector<std::string> names,
+ uint32_t name_type_mask,
+ bool skip_prologue) :
+ BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
+ m_match_type (Breakpoint::Exact),
+ m_skip_prologue (skip_prologue)
+{
+ for (const std::string& name : names)
+ {
+ AddNameLookup (ConstString (name.c_str(), name.size()), name_type_mask);
+ }
+}
+
+BreakpointResolverName::BreakpointResolverName (Breakpoint *bkpt,
+ RegularExpression &func_regex,
+ bool skip_prologue) :
+ BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
+ m_class_name (NULL),
+ m_regex (func_regex),
+ m_match_type (Breakpoint::Regexp),
+ m_skip_prologue (skip_prologue)
+{
+}
+
+BreakpointResolverName::BreakpointResolverName
+(
+ Breakpoint *bkpt,
+ const char *class_name,
+ const char *method,
+ Breakpoint::MatchType type,
+ bool skip_prologue
+) :
+ BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
+ m_class_name (class_name),
+ m_regex (),
+ m_match_type (type),
+ m_skip_prologue (skip_prologue)
+{
+ LookupInfo lookup;
+ lookup.name.SetCString(method);
+ lookup.lookup_name = lookup.name;
+ lookup.name_type_mask = eFunctionNameTypeMethod;
+ lookup.match_name_after_lookup = false;
+ m_lookups.push_back (lookup);
+}
+
+BreakpointResolverName::~BreakpointResolverName ()
+{
+}
+
+void
+BreakpointResolverName::AddNameLookup (const ConstString &name, uint32_t name_type_mask)
+{
+ ObjCLanguageRuntime::MethodName objc_method(name.GetCString(), false);
+ if (objc_method.IsValid(false))
+ {
+ std::vector<ConstString> objc_names;
+ objc_method.GetFullNames(objc_names, true);
+ for (ConstString objc_name : objc_names)
+ {
+ LookupInfo lookup;
+ lookup.name = name;
+ lookup.lookup_name = objc_name;
+ lookup.name_type_mask = eFunctionNameTypeFull;
+ lookup.match_name_after_lookup = false;
+ m_lookups.push_back (lookup);
+ }
+ }
+ else
+ {
+ LookupInfo lookup;
+ lookup.name = name;
+ Module::PrepareForFunctionNameLookup(lookup.name, name_type_mask, lookup.lookup_name, lookup.name_type_mask, lookup.match_name_after_lookup);
+ m_lookups.push_back (lookup);
+ }
+}
+
+
+void
+BreakpointResolverName::LookupInfo::Prune (SymbolContextList &sc_list, size_t start_idx) const
+{
+ if (match_name_after_lookup && name)
+ {
+ SymbolContext sc;
+ size_t i = start_idx;
+ while (i < sc_list.GetSize())
+ {
+ if (!sc_list.GetContextAtIndex(i, sc))
+ break;
+ ConstString full_name (sc.GetFunctionName());
+ if (full_name && ::strstr(full_name.GetCString(), name.GetCString()) == NULL)
+ {
+ sc_list.RemoveContextAtIndex(i);
+ }
+ else
+ {
+ ++i;
+ }
+ }
+ }
+}
+
+
+// FIXME: Right now we look at the module level, and call the module's "FindFunctions".
+// Greg says he will add function tables, maybe at the CompileUnit level to accelerate function
+// lookup. At that point, we should switch the depth to CompileUnit, and look in these tables.
+
+Searcher::CallbackReturn
+BreakpointResolverName::SearchCallback
+(
+ SearchFilter &filter,
+ SymbolContext &context,
+ Address *addr,
+ bool containing
+)
+{
+ SymbolContextList func_list;
+ //SymbolContextList sym_list;
+
+ uint32_t i;
+ bool new_location;
+ Address break_addr;
+ assert (m_breakpoint != NULL);
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+
+ if (m_class_name)
+ {
+ if (log)
+ log->Warning ("Class/method function specification not supported yet.\n");
+ return Searcher::eCallbackReturnStop;
+ }
+ bool filter_by_cu = (filter.GetFilterRequiredItems() & eSymbolContextCompUnit) != 0;
+ const bool include_symbols = filter_by_cu == false;
+ const bool include_inlines = true;
+ const bool append = true;
+
+ switch (m_match_type)
+ {
+ case Breakpoint::Exact:
+ if (context.module_sp)
+ {
+ for (const LookupInfo &lookup : m_lookups)
+ {
+ const size_t start_func_idx = func_list.GetSize();
+ context.module_sp->FindFunctions (lookup.lookup_name,
+ NULL,
+ lookup.name_type_mask,
+ include_symbols,
+ include_inlines,
+ append,
+ func_list);
+ const size_t end_func_idx = func_list.GetSize();
+
+ if (start_func_idx < end_func_idx)
+ lookup.Prune (func_list, start_func_idx);
+ }
+ }
+ break;
+ case Breakpoint::Regexp:
+ if (context.module_sp)
+ {
+ context.module_sp->FindFunctions (m_regex,
+ !filter_by_cu, // include symbols only if we aren't filterning by CU
+ include_inlines,
+ append,
+ func_list);
+ }
+ break;
+ case Breakpoint::Glob:
+ if (log)
+ log->Warning ("glob is not supported yet.");
+ break;
+ }
+
+ // If the filter specifies a Compilation Unit, remove the ones that don't pass at this point.
+ if (filter_by_cu)
+ {
+ uint32_t num_functions = func_list.GetSize();
+
+ for (size_t idx = 0; idx < num_functions; idx++)
+ {
+ SymbolContext sc;
+ func_list.GetContextAtIndex(idx, sc);
+ if (!sc.comp_unit || !filter.CompUnitPasses(*sc.comp_unit))
+ {
+ func_list.RemoveContextAtIndex(idx);
+ num_functions--;
+ idx--;
+ }
+ }
+ }
+
+ // Remove any duplicates between the funcion list and the symbol list
+ SymbolContext sc;
+ if (func_list.GetSize())
+ {
+ for (i = 0; i < func_list.GetSize(); i++)
+ {
+ if (func_list.GetContextAtIndex(i, sc))
+ {
+ if (sc.block && sc.block->GetInlinedFunctionInfo())
+ {
+ if (!sc.block->GetStartAddress(break_addr))
+ break_addr.Clear();
+ }
+ else if (sc.function)
+ {
+ break_addr = sc.function->GetAddressRange().GetBaseAddress();
+ if (m_skip_prologue && break_addr.IsValid())
+ {
+ const uint32_t prologue_byte_size = sc.function->GetPrologueByteSize();
+ if (prologue_byte_size)
+ break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size);
+ }
+ }
+ else if (sc.symbol)
+ {
+ break_addr = sc.symbol->GetAddress();
+ if (m_skip_prologue && break_addr.IsValid())
+ {
+ const uint32_t prologue_byte_size = sc.symbol->GetPrologueByteSize();
+ if (prologue_byte_size)
+ break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size);
+ }
+ }
+
+ if (break_addr.IsValid())
+ {
+ if (filter.AddressPasses(break_addr))
+ {
+ BreakpointLocationSP bp_loc_sp (m_breakpoint->AddLocation(break_addr, &new_location));
+ if (bp_loc_sp && new_location && !m_breakpoint->IsInternal())
+ {
+ if (log)
+ {
+ StreamString s;
+ bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
+ log->Printf ("Added location: %s\n", s.GetData());
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return Searcher::eCallbackReturnContinue;
+}
+
+Searcher::Depth
+BreakpointResolverName::GetDepth()
+{
+ return Searcher::eDepthModule;
+}
+
+void
+BreakpointResolverName::GetDescription (Stream *s)
+{
+ if (m_match_type == Breakpoint::Regexp)
+ s->Printf("regex = '%s'", m_regex.GetText());
+ else
+ {
+ size_t num_names = m_lookups.size();
+ if (num_names == 1)
+ s->Printf("name = '%s'", m_lookups[0].name.GetCString());
+ else
+ {
+ s->Printf("names = {");
+ for (size_t i = 0; i < num_names - 1; i++)
+ {
+ s->Printf ("'%s', ", m_lookups[i].name.GetCString());
+ }
+ s->Printf ("'%s'}", m_lookups[num_names - 1].name.GetCString());
+ }
+ }
+}
+
+void
+BreakpointResolverName::Dump (Stream *s) const
+{
+
+}
+
diff --git a/source/Breakpoint/BreakpointSite.cpp b/source/Breakpoint/BreakpointSite.cpp
new file mode 100644
index 000000000000..fa5d8c1f9f81
--- /dev/null
+++ b/source/Breakpoint/BreakpointSite.cpp
@@ -0,0 +1,234 @@
+//===-- BreakpointSite.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/BreakpointSite.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Breakpoint/BreakpointSiteList.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+BreakpointSite::BreakpointSite
+(
+ BreakpointSiteList *list,
+ const BreakpointLocationSP& owner,
+ lldb::addr_t addr,
+ bool use_hardware
+) :
+ StoppointLocation(GetNextID(), addr, 0, use_hardware),
+ m_type (eSoftware), // Process subclasses need to set this correctly using SetType()
+ m_saved_opcode(),
+ m_trap_opcode(),
+ m_enabled(false), // Need to create it disabled, so the first enable turns it on.
+ m_owners()
+{
+ m_owners.Add(owner);
+}
+
+BreakpointSite::~BreakpointSite()
+{
+ BreakpointLocationSP bp_loc_sp;
+ const size_t owner_count = m_owners.GetSize();
+ for (size_t i = 0; i < owner_count; i++)
+ {
+ m_owners.GetByIndex(i)->ClearBreakpointSite();
+ }
+}
+
+break_id_t
+BreakpointSite::GetNextID()
+{
+ static break_id_t g_next_id = 0;
+ return ++g_next_id;
+}
+
+// RETURNS - true if we should stop at this breakpoint, false if we
+// should continue.
+
+bool
+BreakpointSite::ShouldStop (StoppointCallbackContext *context)
+{
+ IncrementHitCount();
+ return m_owners.ShouldStop (context);
+}
+
+bool
+BreakpointSite::IsBreakpointAtThisSite (lldb::break_id_t bp_id)
+{
+ const size_t owner_count = m_owners.GetSize();
+ for (size_t i = 0; i < owner_count; i++)
+ {
+ if (m_owners.GetByIndex(i)->GetBreakpoint().GetID() == bp_id)
+ return true;
+ }
+ return false;
+}
+
+void
+BreakpointSite::Dump(Stream *s) const
+{
+ if (s == NULL)
+ return;
+
+ s->Printf("BreakpointSite %u: addr = 0x%8.8" PRIx64 " type = %s breakpoint hw_index = %i hit_count = %-4u",
+ GetID(),
+ (uint64_t)m_addr,
+ IsHardware() ? "hardware" : "software",
+ GetHardwareIndex(),
+ GetHitCount());
+}
+
+void
+BreakpointSite::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ if (level != lldb::eDescriptionLevelBrief)
+ s->Printf ("breakpoint site: %d at 0x%8.8" PRIx64, GetID(), GetLoadAddress());
+ m_owners.GetDescription (s, level);
+}
+
+bool
+BreakpointSite::IsInternal() const
+{
+ return m_owners.IsInternal();
+}
+
+uint8_t *
+BreakpointSite::GetTrapOpcodeBytes()
+{
+ return &m_trap_opcode[0];
+}
+
+const uint8_t *
+BreakpointSite::GetTrapOpcodeBytes() const
+{
+ return &m_trap_opcode[0];
+}
+
+size_t
+BreakpointSite::GetTrapOpcodeMaxByteSize() const
+{
+ return sizeof(m_trap_opcode);
+}
+
+bool
+BreakpointSite::SetTrapOpcode (const uint8_t *trap_opcode, uint32_t trap_opcode_size)
+{
+ if (trap_opcode_size > 0 && trap_opcode_size <= sizeof(m_trap_opcode))
+ {
+ m_byte_size = trap_opcode_size;
+ ::memcpy (m_trap_opcode, trap_opcode, trap_opcode_size);
+ return true;
+ }
+ m_byte_size = 0;
+ return false;
+}
+
+uint8_t *
+BreakpointSite::GetSavedOpcodeBytes()
+{
+ return &m_saved_opcode[0];
+}
+
+const uint8_t *
+BreakpointSite::GetSavedOpcodeBytes() const
+{
+ return &m_saved_opcode[0];
+}
+
+bool
+BreakpointSite::IsEnabled () const
+{
+ return m_enabled;
+}
+
+void
+BreakpointSite::SetEnabled (bool enabled)
+{
+ m_enabled = enabled;
+}
+
+void
+BreakpointSite::AddOwner (const BreakpointLocationSP &owner)
+{
+ m_owners.Add(owner);
+}
+
+size_t
+BreakpointSite::RemoveOwner (lldb::break_id_t break_id, lldb::break_id_t break_loc_id)
+{
+ m_owners.Remove(break_id, break_loc_id);
+ return m_owners.GetSize();
+}
+
+size_t
+BreakpointSite::GetNumberOfOwners ()
+{
+ return m_owners.GetSize();
+}
+
+BreakpointLocationSP
+BreakpointSite::GetOwnerAtIndex (size_t index)
+{
+ return m_owners.GetByIndex (index);
+}
+
+bool
+BreakpointSite::ValidForThisThread (Thread *thread)
+{
+ return m_owners.ValidForThisThread(thread);
+}
+
+bool
+BreakpointSite::IntersectsRange(lldb::addr_t addr, size_t size, lldb::addr_t *intersect_addr, size_t *intersect_size, size_t *opcode_offset) const
+{
+ // We only use software traps for software breakpoints
+ if (!IsHardware())
+ {
+ if (m_byte_size > 0)
+ {
+ const lldb::addr_t bp_end_addr = m_addr + m_byte_size;
+ const lldb::addr_t end_addr = addr + size;
+ // Is the breakpoint end address before the passed in start address?
+ if (bp_end_addr <= addr)
+ return false;
+ // Is the breakpoint start address after passed in end address?
+ if (end_addr <= m_addr)
+ return false;
+ if (intersect_addr || intersect_size || opcode_offset)
+ {
+ if (m_addr < addr)
+ {
+ if (intersect_addr)
+ *intersect_addr = addr;
+ if (intersect_size)
+ *intersect_size = std::min<lldb::addr_t>(bp_end_addr, end_addr) - addr;
+ if (opcode_offset)
+ *opcode_offset = addr - m_addr;
+ }
+ else
+ {
+ if (intersect_addr)
+ *intersect_addr = m_addr;
+ if (intersect_size)
+ *intersect_size = std::min<lldb::addr_t>(bp_end_addr, end_addr) - m_addr;
+ if (opcode_offset)
+ *opcode_offset = 0;
+ }
+ }
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/source/Breakpoint/BreakpointSiteList.cpp b/source/Breakpoint/BreakpointSiteList.cpp
new file mode 100644
index 000000000000..68c4af18ec5e
--- /dev/null
+++ b/source/Breakpoint/BreakpointSiteList.cpp
@@ -0,0 +1,240 @@
+//===-- BreakpointSiteList.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/BreakpointSiteList.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Stream.h"
+#include <algorithm>
+
+using namespace lldb;
+using namespace lldb_private;
+
+BreakpointSiteList::BreakpointSiteList() :
+ m_mutex (Mutex::eMutexTypeRecursive),
+ m_bp_site_list()
+{
+}
+
+BreakpointSiteList::~BreakpointSiteList()
+{
+}
+
+// Add breakpoint site to the list. However, if the element already exists in the
+// list, then we don't add it, and return LLDB_INVALID_BREAK_ID.
+
+lldb::break_id_t
+BreakpointSiteList::Add(const BreakpointSiteSP &bp)
+{
+ lldb::addr_t bp_site_load_addr = bp->GetLoadAddress();
+ Mutex::Locker locker(m_mutex);
+ collection::iterator iter = m_bp_site_list.find (bp_site_load_addr);
+
+ if (iter == m_bp_site_list.end())
+ {
+ m_bp_site_list.insert (iter, collection::value_type (bp_site_load_addr, bp));
+ return bp->GetID();
+ }
+ else
+ {
+ return LLDB_INVALID_BREAK_ID;
+ }
+}
+
+bool
+BreakpointSiteList::ShouldStop (StoppointCallbackContext *context, lldb::break_id_t site_id)
+{
+ BreakpointSiteSP site_sp (FindByID (site_id));
+ if (site_sp)
+ {
+ // Let the BreakpointSite decide if it should stop here (could not have
+ // reached it's target hit count yet, or it could have a callback
+ // that decided it shouldn't stop (shared library loads/unloads).
+ return site_sp->ShouldStop (context);
+ }
+ // We should stop here since this BreakpointSite isn't valid anymore or it
+ // doesn't exist.
+ return true;
+}
+lldb::break_id_t
+BreakpointSiteList::FindIDByAddress (lldb::addr_t addr)
+{
+ BreakpointSiteSP bp = FindByAddress (addr);
+ if (bp)
+ {
+ //DBLogIf(PD_LOG_BREAKPOINTS, "BreakpointSiteList::%s ( addr = 0x%8.8" PRIx64 " ) => %u", __FUNCTION__, (uint64_t)addr, bp->GetID());
+ return bp.get()->GetID();
+ }
+ //DBLogIf(PD_LOG_BREAKPOINTS, "BreakpointSiteList::%s ( addr = 0x%8.8" PRIx64 " ) => NONE", __FUNCTION__, (uint64_t)addr);
+ return LLDB_INVALID_BREAK_ID;
+}
+
+bool
+BreakpointSiteList::Remove (lldb::break_id_t break_id)
+{
+ Mutex::Locker locker(m_mutex);
+ collection::iterator pos = GetIDIterator(break_id); // Predicate
+ if (pos != m_bp_site_list.end())
+ {
+ m_bp_site_list.erase(pos);
+ return true;
+ }
+ return false;
+}
+
+bool
+BreakpointSiteList::RemoveByAddress (lldb::addr_t address)
+{
+ Mutex::Locker locker(m_mutex);
+ collection::iterator pos = m_bp_site_list.find(address);
+ if (pos != m_bp_site_list.end())
+ {
+ m_bp_site_list.erase(pos);
+ return true;
+ }
+ return false;
+}
+
+class BreakpointSiteIDMatches
+{
+public:
+ BreakpointSiteIDMatches (lldb::break_id_t break_id) :
+ m_break_id(break_id)
+ {
+ }
+
+ bool operator() (std::pair <lldb::addr_t, BreakpointSiteSP> val_pair) const
+ {
+ return m_break_id == val_pair.second.get()->GetID();
+ }
+
+private:
+ const lldb::break_id_t m_break_id;
+};
+
+BreakpointSiteList::collection::iterator
+BreakpointSiteList::GetIDIterator (lldb::break_id_t break_id)
+{
+ Mutex::Locker locker(m_mutex);
+ return std::find_if(m_bp_site_list.begin(), m_bp_site_list.end(), // Search full range
+ BreakpointSiteIDMatches(break_id)); // Predicate
+}
+
+BreakpointSiteList::collection::const_iterator
+BreakpointSiteList::GetIDConstIterator (lldb::break_id_t break_id) const
+{
+ Mutex::Locker locker(m_mutex);
+ return std::find_if(m_bp_site_list.begin(), m_bp_site_list.end(), // Search full range
+ BreakpointSiteIDMatches(break_id)); // Predicate
+}
+
+BreakpointSiteSP
+BreakpointSiteList::FindByID (lldb::break_id_t break_id)
+{
+ Mutex::Locker locker(m_mutex);
+ BreakpointSiteSP stop_sp;
+ collection::iterator pos = GetIDIterator(break_id);
+ if (pos != m_bp_site_list.end())
+ stop_sp = pos->second;
+
+ return stop_sp;
+}
+
+const BreakpointSiteSP
+BreakpointSiteList::FindByID (lldb::break_id_t break_id) const
+{
+ Mutex::Locker locker(m_mutex);
+ BreakpointSiteSP stop_sp;
+ collection::const_iterator pos = GetIDConstIterator(break_id);
+ if (pos != m_bp_site_list.end())
+ stop_sp = pos->second;
+
+ return stop_sp;
+}
+
+BreakpointSiteSP
+BreakpointSiteList::FindByAddress (lldb::addr_t addr)
+{
+ BreakpointSiteSP found_sp;
+ Mutex::Locker locker(m_mutex);
+ collection::iterator iter = m_bp_site_list.find(addr);
+ if (iter != m_bp_site_list.end())
+ found_sp = iter->second;
+ return found_sp;
+}
+
+bool
+BreakpointSiteList::BreakpointSiteContainsBreakpoint (lldb::break_id_t bp_site_id, lldb::break_id_t bp_id)
+{
+ Mutex::Locker locker(m_mutex);
+ collection::const_iterator pos = GetIDConstIterator(bp_site_id);
+ if (pos != m_bp_site_list.end())
+ return pos->second->IsBreakpointAtThisSite (bp_id);
+
+ return false;
+}
+
+void
+BreakpointSiteList::Dump (Stream *s) const
+{
+ s->Printf("%p: ", this);
+ //s->Indent();
+ s->Printf("BreakpointSiteList with %u BreakpointSites:\n", (uint32_t)m_bp_site_list.size());
+ s->IndentMore();
+ collection::const_iterator pos;
+ collection::const_iterator end = m_bp_site_list.end();
+ for (pos = m_bp_site_list.begin(); pos != end; ++pos)
+ pos->second.get()->Dump(s);
+ s->IndentLess();
+}
+
+void
+BreakpointSiteList::ForEach (std::function <void(BreakpointSite *)> const &callback)
+{
+ Mutex::Locker locker(m_mutex);
+ for (auto pair : m_bp_site_list)
+ callback (pair.second.get());
+}
+
+bool
+BreakpointSiteList::FindInRange (lldb::addr_t lower_bound, lldb::addr_t upper_bound, BreakpointSiteList &bp_site_list) const
+{
+ if (lower_bound > upper_bound)
+ return false;
+
+ Mutex::Locker locker(m_mutex);
+ collection::const_iterator lower, upper, pos;
+ lower = m_bp_site_list.lower_bound(lower_bound);
+ if (lower == m_bp_site_list.end()
+ || (*lower).first >= upper_bound)
+ return false;
+
+ // This is one tricky bit. The breakpoint might overlap the bottom end of the range. So we grab the
+ // breakpoint prior to the lower bound, and check that that + its byte size isn't in our range.
+ if (lower != m_bp_site_list.begin())
+ {
+ collection::const_iterator prev_pos = lower;
+ prev_pos--;
+ const BreakpointSiteSP &prev_bp = (*prev_pos).second;
+ if (prev_bp->GetLoadAddress() + prev_bp->GetByteSize() > lower_bound)
+ bp_site_list.Add (prev_bp);
+
+ }
+
+ upper = m_bp_site_list.upper_bound(upper_bound);
+
+ for (pos = lower; pos != upper; pos++)
+ {
+ bp_site_list.Add ((*pos).second);
+ }
+ return true;
+}
diff --git a/source/Breakpoint/Stoppoint.cpp b/source/Breakpoint/Stoppoint.cpp
new file mode 100644
index 000000000000..583ab47005f5
--- /dev/null
+++ b/source/Breakpoint/Stoppoint.cpp
@@ -0,0 +1,46 @@
+//===-- Stoppoint.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-private.h"
+#include "lldb/Breakpoint/Stoppoint.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Stoppoint constructor
+//----------------------------------------------------------------------
+Stoppoint::Stoppoint() :
+ m_bid (LLDB_INVALID_BREAK_ID)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+Stoppoint::~Stoppoint()
+{
+}
+
+break_id_t
+Stoppoint::GetID () const
+{
+ return m_bid;
+}
+
+void
+Stoppoint::SetID (break_id_t bid)
+{
+ m_bid = bid;
+}
diff --git a/source/Breakpoint/StoppointCallbackContext.cpp b/source/Breakpoint/StoppointCallbackContext.cpp
new file mode 100644
index 000000000000..2266c3e429c6
--- /dev/null
+++ b/source/Breakpoint/StoppointCallbackContext.cpp
@@ -0,0 +1,39 @@
+//===-- StoppointCallbackContext.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+using namespace lldb_private;
+
+StoppointCallbackContext::StoppointCallbackContext() :
+ event (NULL),
+ exe_ctx_ref (),
+ is_synchronous (false)
+{
+}
+
+StoppointCallbackContext::StoppointCallbackContext(Event *e, const ExecutionContext &exe_ctx, bool synchronously) :
+ event (e),
+ exe_ctx_ref (exe_ctx),
+ is_synchronous(synchronously)
+{
+}
+
+void
+StoppointCallbackContext::Clear()
+{
+ event = NULL;
+ exe_ctx_ref.Clear();
+ is_synchronous = false;
+}
diff --git a/source/Breakpoint/StoppointLocation.cpp b/source/Breakpoint/StoppointLocation.cpp
new file mode 100644
index 000000000000..092caa5a9322
--- /dev/null
+++ b/source/Breakpoint/StoppointLocation.cpp
@@ -0,0 +1,48 @@
+//===-- StoppointLocation.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/StoppointLocation.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// StoppointLocation constructor
+//----------------------------------------------------------------------
+StoppointLocation::StoppointLocation (break_id_t bid, addr_t addr, bool hardware) :
+ m_loc_id(bid),
+ m_addr(addr),
+ m_hw_preferred(hardware),
+ m_hw_index(LLDB_INVALID_INDEX32),
+ m_byte_size(0),
+ m_hit_count(0)
+{
+}
+
+StoppointLocation::StoppointLocation (break_id_t bid, addr_t addr, uint32_t byte_size, bool hardware) :
+ m_loc_id(bid),
+ m_addr(addr),
+ m_hw_preferred(hardware),
+ m_hw_index(LLDB_INVALID_INDEX32),
+ m_byte_size(byte_size),
+ m_hit_count(0)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+StoppointLocation::~StoppointLocation()
+{
+}
diff --git a/source/Breakpoint/Watchpoint.cpp b/source/Breakpoint/Watchpoint.cpp
new file mode 100644
index 000000000000..45559b1901ad
--- /dev/null
+++ b/source/Breakpoint/Watchpoint.cpp
@@ -0,0 +1,489 @@
+//===-- Watchpoint.cpp ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/Watchpoint.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectMemory.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadSpec.h"
+#include "lldb/Expression/ClangUserExpression.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+Watchpoint::Watchpoint (Target& target, lldb::addr_t addr, uint32_t size, const ClangASTType *type, bool hardware) :
+ StoppointLocation (0, addr, size, hardware),
+ m_target(target),
+ m_enabled(false),
+ m_is_hardware(hardware),
+ m_is_watch_variable(false),
+ m_is_ephemeral(false),
+ m_disabled_count(0),
+ m_watch_read(0),
+ m_watch_write(0),
+ m_watch_was_read(0),
+ m_watch_was_written(0),
+ m_ignore_count(0),
+ m_false_alarms(0),
+ m_decl_str(),
+ m_watch_spec_str(),
+ m_type(),
+ m_error(),
+ m_options (),
+ m_being_created(true)
+{
+ if (type && type->IsValid())
+ m_type = *type;
+ else
+ {
+ // If we don't have a known type, then we force it to unsigned int of the right size.
+ ClangASTContext *ast_context = target.GetScratchClangASTContext();
+ m_type = ast_context->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 8 * size);
+ }
+
+ // Set the initial value of the watched variable:
+ if (m_target.GetProcessSP())
+ {
+ ExecutionContext exe_ctx;
+ m_target.GetProcessSP()->CalculateExecutionContext(exe_ctx);
+ CaptureWatchedValue (exe_ctx);
+ }
+ m_being_created = false;
+}
+
+Watchpoint::~Watchpoint()
+{
+}
+
+// This function is used when "baton" doesn't need to be freed
+void
+Watchpoint::SetCallback (WatchpointHitCallback callback, void *baton, bool is_synchronous)
+{
+ // The default "Baton" class will keep a copy of "baton" and won't free
+ // or delete it when it goes goes out of scope.
+ m_options.SetCallback(callback, BatonSP (new Baton(baton)), is_synchronous);
+
+ SendWatchpointChangedEvent (eWatchpointEventTypeCommandChanged);
+}
+
+// This function is used when a baton needs to be freed and therefore is
+// contained in a "Baton" subclass.
+void
+Watchpoint::SetCallback (WatchpointHitCallback callback, const BatonSP &callback_baton_sp, bool is_synchronous)
+{
+ m_options.SetCallback(callback, callback_baton_sp, is_synchronous);
+ SendWatchpointChangedEvent (eWatchpointEventTypeCommandChanged);
+}
+
+void
+Watchpoint::ClearCallback ()
+{
+ m_options.ClearCallback ();
+ SendWatchpointChangedEvent (eWatchpointEventTypeCommandChanged);
+}
+
+void
+Watchpoint::SetDeclInfo (const std::string &str)
+{
+ m_decl_str = str;
+ return;
+}
+
+std::string
+Watchpoint::GetWatchSpec()
+{
+ return m_watch_spec_str;
+}
+
+void
+Watchpoint::SetWatchSpec (const std::string &str)
+{
+ m_watch_spec_str = str;
+ return;
+}
+
+// Override default impl of StoppointLocation::IsHardware() since m_is_hardware
+// member field is more accurate.
+bool
+Watchpoint::IsHardware () const
+{
+ return m_is_hardware;
+}
+
+bool
+Watchpoint::IsWatchVariable() const
+{
+ return m_is_watch_variable;
+}
+
+void
+Watchpoint::SetWatchVariable(bool val)
+{
+ m_is_watch_variable = val;
+}
+
+bool
+Watchpoint::CaptureWatchedValue (const ExecutionContext &exe_ctx)
+{
+ ConstString watch_name("$__lldb__watch_value");
+ m_old_value_sp = m_new_value_sp;
+ Address watch_address(GetLoadAddress());
+ if (!m_type.IsValid())
+ {
+ // Don't know how to report new & old values, since we couldn't make a scalar type for this watchpoint.
+ // This works around an assert in ValueObjectMemory::Create.
+ // FIXME: This should not happen, but if it does in some case we care about,
+ // we can go grab the value raw and print it as unsigned.
+ return false;
+ }
+ m_new_value_sp = ValueObjectMemory::Create (exe_ctx.GetBestExecutionContextScope(), watch_name.AsCString(), watch_address, m_type);
+ m_new_value_sp = m_new_value_sp->CreateConstantValue(watch_name);
+ if (m_new_value_sp && m_new_value_sp->GetError().Success())
+ return true;
+ else
+ return false;
+}
+
+void
+Watchpoint::IncrementFalseAlarmsAndReviseHitCount()
+{
+ ++m_false_alarms;
+ if (m_false_alarms)
+ {
+ if (m_hit_count >= m_false_alarms)
+ {
+ m_hit_count -= m_false_alarms;
+ m_false_alarms = 0;
+ }
+ else
+ {
+ m_false_alarms -= m_hit_count;
+ m_hit_count = 0;
+ }
+ }
+}
+
+// RETURNS - true if we should stop at this breakpoint, false if we
+// should continue.
+
+bool
+Watchpoint::ShouldStop (StoppointCallbackContext *context)
+{
+ IncrementHitCount();
+
+ if (!IsEnabled())
+ return false;
+
+ if (GetHitCount() <= GetIgnoreCount())
+ return false;
+
+ return true;
+}
+
+void
+Watchpoint::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ DumpWithLevel(s, level);
+ return;
+}
+
+void
+Watchpoint::Dump(Stream *s) const
+{
+ DumpWithLevel(s, lldb::eDescriptionLevelBrief);
+}
+
+// If prefix is NULL, we display the watch id and ignore the prefix altogether.
+void
+Watchpoint::DumpSnapshots(Stream *s, const char *prefix) const
+{
+ if (!prefix)
+ {
+ s->Printf("\nWatchpoint %u hit:", GetID());
+ prefix = "";
+ }
+
+ if (m_old_value_sp)
+ {
+ s->Printf("\n%sold value: %s", prefix, m_old_value_sp->GetValueAsCString());
+ }
+ if (m_new_value_sp)
+ {
+ s->Printf("\n%snew value: %s", prefix, m_new_value_sp->GetValueAsCString());
+ }
+}
+
+void
+Watchpoint::DumpWithLevel(Stream *s, lldb::DescriptionLevel description_level) const
+{
+ if (s == NULL)
+ return;
+
+ assert(description_level >= lldb::eDescriptionLevelBrief &&
+ description_level <= lldb::eDescriptionLevelVerbose);
+
+ s->Printf("Watchpoint %u: addr = 0x%8.8" PRIx64 " size = %u state = %s type = %s%s",
+ GetID(),
+ GetLoadAddress(),
+ m_byte_size,
+ IsEnabled() ? "enabled" : "disabled",
+ m_watch_read ? "r" : "",
+ m_watch_write ? "w" : "");
+
+ if (description_level >= lldb::eDescriptionLevelFull) {
+ if (!m_decl_str.empty())
+ s->Printf("\n declare @ '%s'", m_decl_str.c_str());
+ if (!m_watch_spec_str.empty())
+ s->Printf("\n watchpoint spec = '%s'", m_watch_spec_str.c_str());
+
+ // Dump the snapshots we have taken.
+ DumpSnapshots(s, " ");
+
+ if (GetConditionText())
+ s->Printf("\n condition = '%s'", GetConditionText());
+ m_options.GetCallbackDescription(s, description_level);
+ }
+
+ if (description_level >= lldb::eDescriptionLevelVerbose)
+ {
+ s->Printf("\n hw_index = %i hit_count = %-4u ignore_count = %-4u",
+ GetHardwareIndex(),
+ GetHitCount(),
+ GetIgnoreCount());
+ }
+}
+
+bool
+Watchpoint::IsEnabled() const
+{
+ return m_enabled;
+}
+
+// Within StopInfo.cpp, we purposely turn on the ephemeral mode right before temporarily disable the watchpoint
+// in order to perform possible watchpoint actions without triggering further watchpoint events.
+// After the temporary disabled watchpoint is enabled, we then turn off the ephemeral mode.
+
+void
+Watchpoint::TurnOnEphemeralMode()
+{
+ m_is_ephemeral = true;
+}
+
+void
+Watchpoint::TurnOffEphemeralMode()
+{
+ m_is_ephemeral = false;
+ // Leaving ephemeral mode, reset the m_disabled_count!
+ m_disabled_count = 0;
+}
+
+bool
+Watchpoint::IsDisabledDuringEphemeralMode()
+{
+ return m_disabled_count > 1;
+}
+
+void
+Watchpoint::SetEnabled(bool enabled, bool notify)
+{
+ if (!enabled)
+ {
+ if (!m_is_ephemeral)
+ SetHardwareIndex(LLDB_INVALID_INDEX32);
+ else
+ ++m_disabled_count;
+
+ // Don't clear the snapshots for now.
+ // Within StopInfo.cpp, we purposely do disable/enable watchpoint while performing watchpoint actions.
+ }
+ bool changed = enabled != m_enabled;
+ m_enabled = enabled;
+ if (notify && !m_is_ephemeral && changed)
+ SendWatchpointChangedEvent (enabled ? eWatchpointEventTypeEnabled : eWatchpointEventTypeDisabled);
+}
+
+void
+Watchpoint::SetWatchpointType (uint32_t type, bool notify)
+{
+ int old_watch_read = m_watch_read;
+ int old_watch_write = m_watch_write;
+ m_watch_read = (type & LLDB_WATCH_TYPE_READ) != 0;
+ m_watch_write = (type & LLDB_WATCH_TYPE_WRITE) != 0;
+ if (notify && (old_watch_read != m_watch_read || old_watch_write != m_watch_write))
+ SendWatchpointChangedEvent (eWatchpointEventTypeTypeChanged);
+}
+
+bool
+Watchpoint::WatchpointRead () const
+{
+ return m_watch_read != 0;
+}
+bool
+Watchpoint::WatchpointWrite () const
+{
+ return m_watch_write != 0;
+}
+uint32_t
+Watchpoint::GetIgnoreCount () const
+{
+ return m_ignore_count;
+}
+
+void
+Watchpoint::SetIgnoreCount (uint32_t n)
+{
+ bool changed = m_ignore_count != n;
+ m_ignore_count = n;
+ if (changed)
+ SendWatchpointChangedEvent (eWatchpointEventTypeIgnoreChanged);
+}
+
+bool
+Watchpoint::InvokeCallback (StoppointCallbackContext *context)
+{
+ return m_options.InvokeCallback (context, GetID());
+}
+
+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, lldb::eLanguageTypeUnknown, ClangUserExpression::eResultTypeAny));
+ }
+ SendWatchpointChangedEvent (eWatchpointEventTypeConditionChanged);
+}
+
+const char *
+Watchpoint::GetConditionText () const
+{
+ if (m_condition_ap.get())
+ return m_condition_ap->GetUserText();
+ else
+ return NULL;
+}
+
+void
+Watchpoint::SendWatchpointChangedEvent (lldb::WatchpointEventType eventKind)
+{
+ if (!m_being_created
+ && GetTarget().EventTypeHasListeners(Target::eBroadcastBitWatchpointChanged))
+ {
+ WatchpointEventData *data = new Watchpoint::WatchpointEventData (eventKind, shared_from_this());
+ GetTarget().BroadcastEvent (Target::eBroadcastBitWatchpointChanged, data);
+ }
+}
+
+void
+Watchpoint::SendWatchpointChangedEvent (WatchpointEventData *data)
+{
+
+ if (data == NULL)
+ return;
+
+ if (!m_being_created
+ && GetTarget().EventTypeHasListeners(Target::eBroadcastBitWatchpointChanged))
+ GetTarget().BroadcastEvent (Target::eBroadcastBitWatchpointChanged, data);
+ else
+ delete data;
+}
+
+Watchpoint::WatchpointEventData::WatchpointEventData (WatchpointEventType sub_type,
+ const WatchpointSP &new_watchpoint_sp) :
+ EventData (),
+ m_watchpoint_event (sub_type),
+ m_new_watchpoint_sp (new_watchpoint_sp)
+{
+}
+
+Watchpoint::WatchpointEventData::~WatchpointEventData ()
+{
+}
+
+const ConstString &
+Watchpoint::WatchpointEventData::GetFlavorString ()
+{
+ static ConstString g_flavor ("Watchpoint::WatchpointEventData");
+ return g_flavor;
+}
+
+const ConstString &
+Watchpoint::WatchpointEventData::GetFlavor () const
+{
+ return WatchpointEventData::GetFlavorString ();
+}
+
+
+WatchpointSP &
+Watchpoint::WatchpointEventData::GetWatchpoint ()
+{
+ return m_new_watchpoint_sp;
+}
+
+WatchpointEventType
+Watchpoint::WatchpointEventData::GetWatchpointEventType () const
+{
+ return m_watchpoint_event;
+}
+
+void
+Watchpoint::WatchpointEventData::Dump (Stream *s) const
+{
+}
+
+const Watchpoint::WatchpointEventData *
+Watchpoint::WatchpointEventData::GetEventDataFromEvent (const Event *event)
+{
+ if (event)
+ {
+ const EventData *event_data = event->GetData();
+ if (event_data && event_data->GetFlavor() == WatchpointEventData::GetFlavorString())
+ return static_cast <const WatchpointEventData *> (event->GetData());
+ }
+ return NULL;
+}
+
+WatchpointEventType
+Watchpoint::WatchpointEventData::GetWatchpointEventTypeFromEvent (const EventSP &event_sp)
+{
+ const WatchpointEventData *data = GetEventDataFromEvent (event_sp.get());
+
+ if (data == NULL)
+ return eWatchpointEventTypeInvalidType;
+ else
+ return data->GetWatchpointEventType();
+}
+
+WatchpointSP
+Watchpoint::WatchpointEventData::GetWatchpointFromEvent (const EventSP &event_sp)
+{
+ WatchpointSP wp_sp;
+
+ const WatchpointEventData *data = GetEventDataFromEvent (event_sp.get());
+ if (data)
+ wp_sp = data->m_new_watchpoint_sp;
+
+ return wp_sp;
+}
diff --git a/source/Breakpoint/WatchpointList.cpp b/source/Breakpoint/WatchpointList.cpp
new file mode 100644
index 000000000000..6d62dffd22cc
--- /dev/null
+++ b/source/Breakpoint/WatchpointList.cpp
@@ -0,0 +1,306 @@
+//===-- WatchpointList.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/WatchpointList.h"
+#include "lldb/Breakpoint/Watchpoint.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+WatchpointList::WatchpointList() :
+ m_watchpoints (),
+ m_mutex (Mutex::eMutexTypeRecursive),
+ m_next_wp_id (0)
+{
+}
+
+WatchpointList::~WatchpointList()
+{
+}
+
+// Add a watchpoint to the list.
+lldb::watch_id_t
+WatchpointList::Add (const WatchpointSP &wp_sp, bool notify)
+{
+ Mutex::Locker locker (m_mutex);
+ wp_sp->SetID(++m_next_wp_id);
+ m_watchpoints.push_back(wp_sp);
+ if (notify)
+ {
+ if (wp_sp->GetTarget().EventTypeHasListeners(Target::eBroadcastBitWatchpointChanged))
+ wp_sp->GetTarget().BroadcastEvent (Target::eBroadcastBitWatchpointChanged,
+ new Watchpoint::WatchpointEventData (eWatchpointEventTypeAdded, wp_sp));
+ }
+ return wp_sp->GetID();
+}
+
+void
+WatchpointList::Dump (Stream *s) const
+{
+ DumpWithLevel(s, lldb::eDescriptionLevelBrief);
+}
+
+void
+WatchpointList::DumpWithLevel (Stream *s, lldb::DescriptionLevel description_level) const
+{
+ Mutex::Locker locker (m_mutex);
+ s->Printf("%p: ", this);
+ //s->Indent();
+ s->Printf("WatchpointList with %" PRIu64 " Watchpoints:\n",
+ (uint64_t)m_watchpoints.size());
+ s->IndentMore();
+ wp_collection::const_iterator pos, end = m_watchpoints.end();
+ for (pos = m_watchpoints.begin(); pos != end; ++pos)
+ (*pos)->DumpWithLevel(s, description_level);
+ s->IndentLess();
+}
+
+const WatchpointSP
+WatchpointList::FindByAddress (lldb::addr_t addr) const
+{
+ WatchpointSP wp_sp;
+ Mutex::Locker locker (m_mutex);
+ if (!m_watchpoints.empty())
+ {
+ wp_collection::const_iterator pos, end = m_watchpoints.end();
+ for (pos = m_watchpoints.begin(); pos != end; ++pos)
+ if ((*pos)->GetLoadAddress() == addr) {
+ wp_sp = *pos;
+ break;
+ }
+ }
+
+ return wp_sp;
+}
+
+const WatchpointSP
+WatchpointList::FindBySpec (std::string spec) const
+{
+ WatchpointSP wp_sp;
+ Mutex::Locker locker (m_mutex);
+ if (!m_watchpoints.empty())
+ {
+ wp_collection::const_iterator pos, end = m_watchpoints.end();
+ for (pos = m_watchpoints.begin(); pos != end; ++pos)
+ if ((*pos)->GetWatchSpec() == spec) {
+ wp_sp = *pos;
+ break;
+ }
+ }
+
+ return wp_sp;
+}
+
+class WatchpointIDMatches
+{
+public:
+ WatchpointIDMatches (lldb::watch_id_t watch_id) :
+ m_watch_id(watch_id)
+ {
+ }
+
+ bool operator() (const WatchpointSP &wp) const
+ {
+ return m_watch_id == wp->GetID();
+ }
+
+private:
+ const lldb::watch_id_t m_watch_id;
+};
+
+WatchpointList::wp_collection::iterator
+WatchpointList::GetIDIterator (lldb::watch_id_t watch_id)
+{
+ return std::find_if(m_watchpoints.begin(), m_watchpoints.end(), // Search full range
+ WatchpointIDMatches(watch_id)); // Predicate
+}
+
+WatchpointList::wp_collection::const_iterator
+WatchpointList::GetIDConstIterator (lldb::watch_id_t watch_id) const
+{
+ return std::find_if(m_watchpoints.begin(), m_watchpoints.end(), // Search full range
+ WatchpointIDMatches(watch_id)); // Predicate
+}
+
+WatchpointSP
+WatchpointList::FindByID (lldb::watch_id_t watch_id) const
+{
+ WatchpointSP wp_sp;
+ Mutex::Locker locker (m_mutex);
+ wp_collection::const_iterator pos = GetIDConstIterator(watch_id);
+ if (pos != m_watchpoints.end())
+ wp_sp = *pos;
+
+ return wp_sp;
+}
+
+lldb::watch_id_t
+WatchpointList::FindIDByAddress (lldb::addr_t addr)
+{
+ WatchpointSP wp_sp = FindByAddress (addr);
+ if (wp_sp)
+ {
+ return wp_sp->GetID();
+ }
+ return LLDB_INVALID_WATCH_ID;
+}
+
+lldb::watch_id_t
+WatchpointList::FindIDBySpec (std::string spec)
+{
+ WatchpointSP wp_sp = FindBySpec (spec);
+ if (wp_sp)
+ {
+ return wp_sp->GetID();
+ }
+ return LLDB_INVALID_WATCH_ID;
+}
+
+WatchpointSP
+WatchpointList::GetByIndex (uint32_t i)
+{
+ Mutex::Locker locker (m_mutex);
+ WatchpointSP wp_sp;
+ if (i < m_watchpoints.size())
+ {
+ wp_collection::const_iterator pos = m_watchpoints.begin();
+ std::advance(pos, i);
+ wp_sp = *pos;
+ }
+ return wp_sp;
+}
+
+const WatchpointSP
+WatchpointList::GetByIndex (uint32_t i) const
+{
+ Mutex::Locker locker (m_mutex);
+ WatchpointSP wp_sp;
+ if (i < m_watchpoints.size())
+ {
+ wp_collection::const_iterator pos = m_watchpoints.begin();
+ std::advance(pos, i);
+ wp_sp = *pos;
+ }
+ return wp_sp;
+}
+
+std::vector<lldb::watch_id_t>
+WatchpointList::GetWatchpointIDs() const
+{
+ std::vector<lldb::watch_id_t> IDs;
+ wp_collection::const_iterator pos, end = m_watchpoints.end();
+ for (pos = m_watchpoints.begin(); pos != end; ++pos)
+ IDs.push_back((*pos)->GetID());
+ return IDs;
+}
+
+bool
+WatchpointList::Remove (lldb::watch_id_t watch_id, bool notify)
+{
+ Mutex::Locker locker (m_mutex);
+ wp_collection::iterator pos = GetIDIterator(watch_id);
+ if (pos != m_watchpoints.end())
+ {
+ WatchpointSP wp_sp = *pos;
+ if (notify)
+ {
+ if (wp_sp->GetTarget().EventTypeHasListeners(Target::eBroadcastBitWatchpointChanged))
+ wp_sp->GetTarget().BroadcastEvent (Target::eBroadcastBitWatchpointChanged,
+ new Watchpoint::WatchpointEventData (eWatchpointEventTypeRemoved, wp_sp));
+ }
+ m_watchpoints.erase(pos);
+ return true;
+ }
+ return false;
+}
+
+uint32_t
+WatchpointList::GetHitCount () const
+{
+ uint32_t hit_count = 0;
+ Mutex::Locker locker (m_mutex);
+ wp_collection::const_iterator pos, end = m_watchpoints.end();
+ for (pos = m_watchpoints.begin(); pos != end; ++pos)
+ hit_count += (*pos)->GetHitCount();
+ return hit_count;
+}
+
+bool
+WatchpointList::ShouldStop (StoppointCallbackContext *context, lldb::watch_id_t watch_id)
+{
+
+ WatchpointSP wp_sp = FindByID (watch_id);
+ if (wp_sp)
+ {
+ // Let the Watchpoint decide if it should stop here (could not have
+ // reached it's target hit count yet, or it could have a callback
+ // that decided it shouldn't stop.
+ return wp_sp->ShouldStop (context);
+ }
+ // We should stop here since this Watchpoint isn't valid anymore or it
+ // doesn't exist.
+ return true;
+}
+
+void
+WatchpointList::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ Mutex::Locker locker (m_mutex);
+ wp_collection::iterator pos, end = m_watchpoints.end();
+
+ for (pos = m_watchpoints.begin(); pos != end; ++pos)
+ {
+ s->Printf(" ");
+ (*pos)->Dump(s);
+ }
+}
+
+void
+WatchpointList::SetEnabledAll (bool enabled)
+{
+ Mutex::Locker locker(m_mutex);
+
+ wp_collection::iterator pos, end = m_watchpoints.end();
+ for (pos = m_watchpoints.begin(); pos != end; ++pos)
+ (*pos)->SetEnabled (enabled);
+}
+
+void
+WatchpointList::RemoveAll (bool notify)
+{
+ Mutex::Locker locker(m_mutex);
+ if (notify)
+ {
+
+ {
+ wp_collection::iterator pos, end = m_watchpoints.end();
+ for (pos = m_watchpoints.begin(); pos != end; ++pos)
+ {
+ if ((*pos)->GetTarget().EventTypeHasListeners(Target::eBroadcastBitBreakpointChanged))
+ {
+ (*pos)->GetTarget().BroadcastEvent (Target::eBroadcastBitWatchpointChanged,
+ new Watchpoint::WatchpointEventData (eWatchpointEventTypeRemoved,
+ *pos));
+ }
+ }
+ }
+ }
+ m_watchpoints.clear();
+}
+
+void
+WatchpointList::GetListMutex (Mutex::Locker &locker)
+{
+ return locker.Lock (m_mutex);
+}
diff --git a/source/Breakpoint/WatchpointOptions.cpp b/source/Breakpoint/WatchpointOptions.cpp
new file mode 100644
index 000000000000..c2c9696c4ce7
--- /dev/null
+++ b/source/Breakpoint/WatchpointOptions.cpp
@@ -0,0 +1,241 @@
+//===-- WatchpointOptions.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/WatchpointOptions.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StringList.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadSpec.h"
+#include "lldb/Expression/ClangUserExpression.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+bool
+WatchpointOptions::NullCallback (void *baton, StoppointCallbackContext *context, lldb::user_id_t watch_id)
+{
+ return true;
+}
+
+//----------------------------------------------------------------------
+// WatchpointOptions constructor
+//----------------------------------------------------------------------
+WatchpointOptions::WatchpointOptions() :
+ m_callback (WatchpointOptions::NullCallback),
+ m_callback_baton_sp (),
+ m_callback_is_synchronous (false),
+ m_thread_spec_ap ()
+{
+}
+
+//----------------------------------------------------------------------
+// WatchpointOptions copy constructor
+//----------------------------------------------------------------------
+WatchpointOptions::WatchpointOptions(const WatchpointOptions& rhs) :
+ m_callback (rhs.m_callback),
+ m_callback_baton_sp (rhs.m_callback_baton_sp),
+ m_callback_is_synchronous (rhs.m_callback_is_synchronous),
+ m_thread_spec_ap ()
+{
+ if (rhs.m_thread_spec_ap.get() != NULL)
+ m_thread_spec_ap.reset (new ThreadSpec(*rhs.m_thread_spec_ap.get()));
+}
+
+//----------------------------------------------------------------------
+// WatchpointOptions assignment operator
+//----------------------------------------------------------------------
+const WatchpointOptions&
+WatchpointOptions::operator=(const WatchpointOptions& rhs)
+{
+ m_callback = rhs.m_callback;
+ m_callback_baton_sp = rhs.m_callback_baton_sp;
+ m_callback_is_synchronous = rhs.m_callback_is_synchronous;
+ if (rhs.m_thread_spec_ap.get() != NULL)
+ m_thread_spec_ap.reset(new ThreadSpec(*rhs.m_thread_spec_ap.get()));
+ return *this;
+}
+
+WatchpointOptions *
+WatchpointOptions::CopyOptionsNoCallback (WatchpointOptions &orig)
+{
+ WatchpointHitCallback orig_callback = orig.m_callback;
+ lldb::BatonSP orig_callback_baton_sp = orig.m_callback_baton_sp;
+ bool orig_is_sync = orig.m_callback_is_synchronous;
+
+ orig.ClearCallback();
+ WatchpointOptions *ret_val = new WatchpointOptions(orig);
+
+ orig.SetCallback (orig_callback, orig_callback_baton_sp, orig_is_sync);
+
+ return ret_val;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+WatchpointOptions::~WatchpointOptions()
+{
+}
+
+//------------------------------------------------------------------
+// Callbacks
+//------------------------------------------------------------------
+void
+WatchpointOptions::SetCallback (WatchpointHitCallback callback, const BatonSP &callback_baton_sp, bool callback_is_synchronous)
+{
+ m_callback_is_synchronous = callback_is_synchronous;
+ m_callback = callback;
+ m_callback_baton_sp = callback_baton_sp;
+}
+
+void
+WatchpointOptions::ClearCallback ()
+{
+ m_callback = WatchpointOptions::NullCallback;
+ m_callback_is_synchronous = false;
+ m_callback_baton_sp.reset();
+}
+
+Baton *
+WatchpointOptions::GetBaton ()
+{
+ return m_callback_baton_sp.get();
+}
+
+const Baton *
+WatchpointOptions::GetBaton () const
+{
+ return m_callback_baton_sp.get();
+}
+
+bool
+WatchpointOptions::InvokeCallback (StoppointCallbackContext *context,
+ lldb::user_id_t watch_id)
+{
+ if (m_callback && context->is_synchronous == IsCallbackSynchronous())
+ {
+ return m_callback (m_callback_baton_sp ? m_callback_baton_sp->m_data : NULL,
+ context,
+ watch_id);
+ }
+ else
+ return true;
+}
+
+bool
+WatchpointOptions::HasCallback ()
+{
+ return m_callback != WatchpointOptions::NullCallback;
+}
+
+const ThreadSpec *
+WatchpointOptions::GetThreadSpecNoCreate () const
+{
+ return m_thread_spec_ap.get();
+}
+
+ThreadSpec *
+WatchpointOptions::GetThreadSpec ()
+{
+ if (m_thread_spec_ap.get() == NULL)
+ m_thread_spec_ap.reset (new ThreadSpec());
+
+ return m_thread_spec_ap.get();
+}
+
+void
+WatchpointOptions::SetThreadID (lldb::tid_t thread_id)
+{
+ GetThreadSpec()->SetTID(thread_id);
+}
+
+void
+WatchpointOptions::GetCallbackDescription (Stream *s, lldb::DescriptionLevel level) const
+{
+ if (m_callback_baton_sp.get())
+ {
+ s->EOL();
+ m_callback_baton_sp->GetDescription (s, level);
+ }
+}
+void
+WatchpointOptions::GetDescription (Stream *s, lldb::DescriptionLevel level) const
+{
+
+ // Figure out if there are any options not at their default value, and only print
+ // anything if there are:
+
+ if ((GetThreadSpecNoCreate() != NULL && GetThreadSpecNoCreate()->HasSpecification ()))
+ {
+ if (level == lldb::eDescriptionLevelVerbose)
+ {
+ s->EOL ();
+ s->IndentMore();
+ s->Indent();
+ s->PutCString("Watchpoint Options:\n");
+ s->IndentMore();
+ s->Indent();
+ }
+ else
+ s->PutCString(" Options: ");
+
+ if (m_thread_spec_ap.get())
+ m_thread_spec_ap->GetDescription (s, level);
+ else if (level == eDescriptionLevelBrief)
+ s->PutCString ("thread spec: no ");
+ if (level == lldb::eDescriptionLevelFull)
+ {
+ s->IndentLess();
+ s->IndentMore();
+ }
+ }
+
+ GetCallbackDescription(s, level);
+}
+
+void
+WatchpointOptions::CommandBaton::GetDescription (Stream *s, lldb::DescriptionLevel level) const
+{
+ CommandData *data = (CommandData *)m_data;
+
+ if (level == eDescriptionLevelBrief)
+ {
+ s->Printf (", commands = %s", (data && data->user_source.GetSize() > 0) ? "yes" : "no");
+ return;
+ }
+
+ s->IndentMore ();
+ s->Indent("watchpoint commands:\n");
+
+ s->IndentMore ();
+ if (data && data->user_source.GetSize() > 0)
+ {
+ const size_t num_strings = data->user_source.GetSize();
+ for (size_t i = 0; i < num_strings; ++i)
+ {
+ s->Indent(data->user_source.GetStringAtIndex(i));
+ s->EOL();
+ }
+ }
+ else
+ {
+ s->PutCString ("No commands.\n");
+ }
+ s->IndentLess ();
+ s->IndentLess ();
+}
+