diff options
Diffstat (limited to 'lldb/source/Breakpoint')
18 files changed, 3553 insertions, 0 deletions
diff --git a/lldb/source/Breakpoint/Breakpoint.cpp b/lldb/source/Breakpoint/Breakpoint.cpp new file mode 100644 index 00000000000..c475cf0f0d7 --- /dev/null +++ b/lldb/source/Breakpoint/Breakpoint.cpp @@ -0,0 +1,516 @@ +//===-- 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/BreakpointResolver.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; +using namespace lldb_private; + +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_target (target), + m_filter_sp (filter_sp), + m_resolver_sp (resolver_sp), + m_options (), + m_locations () +{ +} + +//---------------------------------------------------------------------- +// 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 (Address &addr, bool *new_location) +{ + BreakpointLocationSP bp_loc_sp (m_locations.FindByAddress(addr)); + if (bp_loc_sp) + { + if (new_location) + *new_location = false; + return bp_loc_sp; + } + + bp_loc_sp.reset (new BreakpointLocation (m_locations.GetNextID(), *this, addr)); + m_locations.Add (bp_loc_sp); + bp_loc_sp->ResolveBreakpointSite(); + + if (new_location) + *new_location = true; + return bp_loc_sp; +} + +BreakpointLocationSP +Breakpoint::FindLocationByAddress (Address &addr) +{ + return m_locations.FindByAddress(addr); +} + +break_id_t +Breakpoint::FindLocationIDByAddress (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 (uint32_t index) +{ + return m_locations.GetByIndex(index); +} + +BreakpointLocationSP +Breakpoint::GetLocationSP (BreakpointLocation *bp_loc_ptr) +{ + assert (bp_loc_ptr->GetBreakpoint().GetID() == GetID()); + return m_locations.FindByID(bp_loc_ptr->GetID()); +} + + +// 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 vrs. 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) +{ + m_options.SetEnabled(enable); + if (enable) + m_locations.ResolveAllBreakpointSites(); + else + m_locations.ClearAllBreakpointSites(); +} + +bool +Breakpoint::IsEnabled () +{ + return m_options.IsEnabled(); +} + +void +Breakpoint::SetIgnoreCount (int32_t n) +{ + m_options.SetIgnoreCount(n); +} + +int32_t +Breakpoint::GetIgnoreCount () const +{ + return m_options.GetIgnoreCount(); +} + +void +Breakpoint::SetThreadID (lldb::tid_t thread_id) +{ + m_options.SetThreadID(thread_id); +} + +lldb::tid_t +Breakpoint::GetThreadID () +{ + return m_options.GetThreadID(); +} + +// 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); +} + +// 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) +{ + 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. + + for (int i = 0; i < module_list.GetSize(); i++) + { + bool seen = false; + ModuleSP module_sp (module_list.GetModuleAtIndex (i)); + Module *module = module_sp.get(); + if (!m_filter_sp->ModulePasses (module_sp)) + continue; + + for (int i = 0; i < m_locations.GetSize(); i++) + { + BreakpointLocationSP break_loc = m_locations.GetByIndex(i); + const Section *section = break_loc->GetAddress().GetSection(); + if (section == NULL || section->GetModule() == module) + { + 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.AppendInNeeded (module_sp); + + } + if (new_modules.GetSize() > 0) + { + ResolveBreakpointInModules(new_modules); + } + } + else + { + // Go through the currently set locations and if any have breakpoints in + // the module list, then remove their breakpoint sites. + // FIXME: Think about this... Maybe it's better to delete the locations? + // Are we sure that on load-unload-reload the module pointer will remain + // the same? Or do we need to do an equality on modules that is an + // "equivalence"??? + + for (int i = 0; i < module_list.GetSize(); i++) + { + ModuleSP module_sp (module_list.GetModuleAtIndex (i)); + if (!m_filter_sp->ModulePasses (module_sp)) + continue; + + for (int i = 0; i < m_locations.GetSize(); i++) + { + BreakpointLocationSP break_loc = m_locations.GetByIndex(i); + const Section *section = break_loc->GetAddress().GetSection(); + if (section) + { + if (section->GetModule() == module_sp.get()) + break_loc->ClearBreakpointSite(); + } +// else +// { +// Address temp_addr; +// if (module->ResolveLoadAddress(break_loc->GetLoadAddress(), m_target->GetProcess(), temp_addr)) +// break_loc->ClearBreakpointSite(); +// } + } + } + } +} + +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); + StreamString filter_strm; + + + s->Printf("%i ", GetID()); + GetResolverDescription (s); + GetFilterDescription (&filter_strm); + if (filter_strm.GetString().compare ("No Filter") != 0) + { + s->Printf (", "); + GetFilterDescription (s); + } + + const uint32_t num_locations = GetNumLocations (); + const uint32_t num_resolved_locations = GetNumResolvedLocations (); + + switch (level) + { + case lldb::eDescriptionLevelBrief: + case lldb::eDescriptionLevelFull: + if (num_locations > 0) + { + s->Printf(" with %u location%s", num_locations, num_locations > 1 ? "s" : ""); + if (num_resolved_locations > 0) + s->Printf(" (%u resolved)", num_resolved_locations); + s->PutChar(';'); + } + else + { + s->Printf(" with 0 locations (Pending Breakpoint)."); + } + + if (level == lldb::eDescriptionLevelFull) + { + Baton *baton = GetOptions()->GetBaton(); + if (baton) + { + s->EOL (); + s->Indent(); + baton->GetDescription(s, level); + } + } + break; + + case lldb::eDescriptionLevelVerbose: + // Verbose mode does a debug dump of the breakpoint + Dump (s); + Baton *baton = GetOptions()->GetBaton(); + if (baton) + { + s->EOL (); + s->Indent(); + baton->GetDescription(s, level); + } + break; + } + + if (show_locations) + { + s->EOL(); + s->IndentMore(); + for (int i = 0; i < GetNumLocations(); ++i) + { + BreakpointLocation *loc = GetLocationAtIndex(i).get(); + loc->GetDescription(s, level); + s->EOL(); + } + s->IndentLess(); + + } +} + +Breakpoint::BreakpointEventData::BreakpointEventData (Breakpoint::BreakpointEventData::EventSubType sub_type, BreakpointSP &new_breakpoint_sp) : + EventData (), + m_sub_type (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; +} + +Breakpoint::BreakpointEventData::EventSubType +Breakpoint::BreakpointEventData::GetSubType () const +{ + return m_sub_type; +} + +void +Breakpoint::BreakpointEventData::Dump (Stream *s) const +{ +} + +Breakpoint::BreakpointEventData * +Breakpoint::BreakpointEventData::GetEventDataFromEvent (const EventSP &event_sp) +{ + if (event_sp) + { + EventData *event_data = event_sp->GetData(); + if (event_data && event_data->GetFlavor() == BreakpointEventData::GetFlavorString()) + return static_cast <BreakpointEventData *> (event_sp->GetData()); + } + return NULL; +} + +Breakpoint::BreakpointEventData::EventSubType +Breakpoint::BreakpointEventData::GetSubTypeFromEvent (const EventSP &event_sp) +{ + BreakpointEventData *data = GetEventDataFromEvent (event_sp); + + if (data == NULL) + return eBreakpointInvalidType; + else + return data->GetSubType(); +} + +BreakpointSP +Breakpoint::BreakpointEventData::GetBreakpointFromEvent (const EventSP &event_sp) +{ + BreakpointEventData *data = GetEventDataFromEvent (event_sp); + + if (data == NULL) + { + BreakpointSP ret_val; + return ret_val; + } + else + return data->GetBreakpoint(); +} + + +void +Breakpoint::GetResolverDescription (Stream *s) +{ + if (m_resolver_sp) + m_resolver_sp->GetDescription (s); +} + +void +Breakpoint::GetFilterDescription (Stream *s) +{ + m_filter_sp->GetDescription (s); +} + +const BreakpointSP +Breakpoint::GetSP () +{ + return m_target.GetBreakpointList().FindBreakpointByID (GetID()); +} diff --git a/lldb/source/Breakpoint/BreakpointID.cpp b/lldb/source/Breakpoint/BreakpointID.cpp new file mode 100644 index 00000000000..691e5c07523 --- /dev/null +++ b/lldb/source/Breakpoint/BreakpointID.cpp @@ -0,0 +1,120 @@ +//===-- 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 +// C++ Includes +// Other libraries and framework includes +// Project includes + +#include "lldb/Breakpoint/BreakpointID.h" +#include "lldb/Breakpoint/Breakpoint.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/lldb/source/Breakpoint/BreakpointIDList.cpp b/lldb/source/Breakpoint/BreakpointIDList.cpp new file mode 100644 index 00000000000..895f1b1e3f4 --- /dev/null +++ b/lldb/source/Breakpoint/BreakpointIDList.cpp @@ -0,0 +1,348 @@ +//===-- 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/Core/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 () +{ +} + +int +BreakpointIDList::Size() +{ + return m_breakpoint_ids.size(); +} + +BreakpointID & +BreakpointIDList::GetBreakpointIDAtIndex (int index) +{ + if (index < m_breakpoint_ids.size()) + return m_breakpoint_ids[index]; + else + return m_invalid_id; +} + +bool +BreakpointIDList::RemoveBreakpointIDAtIndex (int index) +{ + bool success = false; + if (index < m_breakpoint_ids.size()) + { + BreakpointIDArray::iterator pos; + int i; + + for (pos = m_breakpoint_ids.begin(), i = 0; i != index && pos != m_breakpoint_ids.end(); ++pos, ++i); + assert (i == index); + if (pos != m_breakpoint_ids.end()) + { + m_breakpoint_ids.erase (pos); + success = true; + } + } + return success; +} + +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, int *position) +{ + bool success = false; + BreakpointIDArray::iterator tmp_pos; + + for (int 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()) + { + success = true; + *position = i; + return true; + } + } + + return false; +} + +bool +BreakpointIDList::FindBreakpointID (const char *bp_id_str, int *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, int array_size, CommandReturnObject &result) +{ + if (string_array == NULL) + return; + + for (int 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) +{ + char *range_start; + const char *range_end; + const char *current_arg; + int num_old_args = old_args.GetArgumentCount(); + + for (int i = 0; i < num_old_args; ++i) + { + bool is_range = false; + current_arg = old_args.GetArgumentAtIndex (i); + + int range_start_len = 0; + int range_end_pos = 0; + if (BreakpointIDList::StringContainsIDRangeExpression (current_arg, &range_start_len, &range_end_pos)) + { + is_range = true; + range_start = (char *) malloc (range_start_len + 1); + strncpy (range_start, current_arg, range_start_len); + range_start[range_start_len] = '\0'; + 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 = (char *) current_arg; + range_end = old_args.GetArgumentAtIndex (i+2); + is_range = true; + i = i+2; + } + + 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, &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); + 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; + } + + // 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. + + const BreakpointList& breakpoints = target->GetBreakpointList(); + size_t num_breakpoints = breakpoints.GetSize(); + for (int j = 0; j < num_breakpoints; ++j) + { + Breakpoint *breakpoint = breakpoints.GetBreakpointByIndex (j).get(); + break_id_t cur_bp_id = breakpoint->GetID(); + + if ((cur_bp_id < start_bp_id) || (cur_bp_id > end_bp_id)) + continue; + + size_t num_locations = breakpoint->GetNumLocations(); + + if ((cur_bp_id == start_bp_id) && (start_loc_id != LLDB_INVALID_BREAK_ID)) + { + for (int k = 0; k < num_locations; ++k) + { + BreakpointLocation * bp_loc = breakpoint->GetLocationAtIndex(k).get(); + if (bp_loc->GetID() >= start_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 (int 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, const char **range_start, +// const **range_end) +bool +BreakpointIDList::StringContainsIDRangeExpression (const char *in_string, int *range_start_len, int *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 = NULL; + //*range_end = NULL; + *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]; + int 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/lldb/source/Breakpoint/BreakpointList.cpp b/lldb/source/Breakpoint/BreakpointList.cpp new file mode 100644 index 00000000000..c10aa770b82 --- /dev/null +++ b/lldb/source/Breakpoint/BreakpointList.cpp @@ -0,0 +1,198 @@ +//===-- 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 + +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) +{ + Mutex::Locker locker(m_mutex); + // Internal breakpoint IDs are negative, normal ones are positive + bp->SetID (m_is_internal ? --m_next_break_id : ++m_next_break_id); + m_breakpoints.push_back(bp); + return bp->GetID(); +} + +bool +BreakpointList::Remove (break_id_t break_id) +{ + Mutex::Locker locker(m_mutex); + bp_collection::iterator pos = GetBreakpointIDIterator(break_id); // Predicate + if (pos != m_breakpoints.end()) + { + m_breakpoints.erase(pos); + 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 () +{ + Mutex::Locker locker(m_mutex); + ClearAllBreakpointSites (); + + 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: ", (int)sizeof(void*) * 2, 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::GetBreakpointByIndex (uint32_t i) +{ + Mutex::Locker locker(m_mutex); + BreakpointSP stop_sp; + bp_collection::iterator end = m_breakpoints.end(); + bp_collection::iterator pos; + uint32_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::GetBreakpointByIndex (uint32_t i) const +{ + Mutex::Locker locker(m_mutex); + BreakpointSP stop_sp; + bp_collection::const_iterator end = m_breakpoints.end(); + bp_collection::const_iterator pos; + uint32_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::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 (); + +} diff --git a/lldb/source/Breakpoint/BreakpointLocation.cpp b/lldb/source/Breakpoint/BreakpointLocation.cpp new file mode 100644 index 00000000000..5c0e81df381 --- /dev/null +++ b/lldb/source/Breakpoint/BreakpointLocation.cpp @@ -0,0 +1,389 @@ +//===-- BreakpointLocation.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 +#include <string> + +// Other libraries and framework includes +// Project includes +#include "lldb/Breakpoint/BreakpointLocation.h" +#include "lldb/Breakpoint/BreakpointID.h" +#include "lldb/Breakpoint/StoppointCallbackContext.h" +#include "lldb/Core/Log.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Process.h" +#include "lldb/Core/StreamString.h" +#include "lldb/lldb-private-log.h" +#include "lldb/Target/Thread.h" + +using namespace lldb; +using namespace lldb_private; + +BreakpointLocation::BreakpointLocation +( + break_id_t loc_id, + Breakpoint &owner, + Address &addr, + lldb::tid_t tid, + bool hardware +) : + StoppointLocation (loc_id, addr.GetLoadAddress(owner.GetTarget().GetProcessSP().get()), tid, hardware), + m_address (addr), + m_owner (owner), + m_options_ap (), + m_bp_site_sp () +{ +} + +BreakpointLocation::~BreakpointLocation() +{ + ClearBreakpointSite(); +} + +lldb::addr_t +BreakpointLocation::GetLoadAddress () +{ + return m_address.GetLoadAddress(m_owner.GetTarget().GetProcessSP().get()); +} + +Address & +BreakpointLocation::GetAddress () +{ + return m_address; +} + +Breakpoint & +BreakpointLocation::GetBreakpoint () +{ + return m_owner; +} + +bool +BreakpointLocation::IsEnabled () +{ + 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(); + } +} + +void +BreakpointLocation::SetThreadID (lldb::tid_t thread_id) +{ + GetLocationOptions()->SetThreadID(thread_id); +} + +lldb::tid_t +BreakpointLocation::GetThreadID () +{ + return GetOptionsNoCopy()->GetThreadID(); +} + +bool +BreakpointLocation::InvokeCallback (StoppointCallbackContext *context) +{ + bool owner_result; + + owner_result = m_owner.InvokeCallback (context, GetID()); + if (owner_result == false) + return false; + else if (m_options_ap.get() != NULL) + return m_options_ap->InvokeCallback (context, m_owner.GetID(), GetID()); + else + return true; +} + +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); +} + +void +BreakpointLocation::SetCallback (BreakpointHitCallback callback, const BatonSP &baton_sp, + bool is_synchronous) +{ + GetLocationOptions()->SetCallback (callback, baton_sp, is_synchronous); +} + +void +BreakpointLocation::ClearCallback () +{ + GetLocationOptions()->ClearCallback(); +} + +int32_t +BreakpointLocation::GetIgnoreCount () +{ + return GetOptionsNoCopy()->GetIgnoreCount(); +} + +void +BreakpointLocation::SetIgnoreCount (int32_t n) +{ + GetLocationOptions()->SetIgnoreCount(n); +} + +BreakpointOptions * +BreakpointLocation::GetOptionsNoCopy () +{ + if (m_options_ap.get() != NULL) + return m_options_ap.get(); + else + return m_owner.GetOptions (); +} + +BreakpointOptions * +BreakpointLocation::GetLocationOptions () +{ + if (m_options_ap.get() == NULL) + m_options_ap.reset(new BreakpointOptions (*m_owner.GetOptions ())); + + return m_options_ap.get(); +} + +// RETURNS - true if we should stop at this breakpoint, false if we +// should continue. + +bool +BreakpointLocation::ShouldStop (StoppointCallbackContext *context) +{ + bool should_stop = true; + + m_hit_count++; + + if (!IsEnabled()) + return false; + + if (GetThreadID() != LLDB_INVALID_THREAD_ID + && context->context.thread->GetID() != GetThreadID()) + return false; + + if (m_hit_count <= GetIgnoreCount()) + return false; + + // Tell if the callback is synchronous here. + context->is_synchronous = true; + should_stop = InvokeCallback (context); + + if (should_stop) + { + Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS); + if (log) + { + StreamString s; + GetDescription (&s, lldb::eDescriptionLevelVerbose); + log->Printf ("Hit breakpoint location: %s\n", s.GetData()); + } + } + return should_stop; +} + +bool +BreakpointLocation::IsResolved () const +{ + return m_bp_site_sp.get() != NULL; +} + +bool +BreakpointLocation::ResolveBreakpointSite () +{ + if (m_bp_site_sp) + return true; + + Process* process = m_owner.GetTarget().GetProcessSP().get(); + if (process == NULL) + return false; + + BreakpointLocationSP myself_sp(m_owner.GetLocationSP (this)); + + lldb::user_id_t new_id = process->CreateBreakpointSite (myself_sp, false); + + if (new_id == LLDB_INVALID_UID) + { + Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS); + if (log) + log->Warning ("Tried to add breakpoint site at 0x%llx but it was already present.\n", + m_address.GetLoadAddress(process)); + 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; + s->Indent(); + BreakpointID::GetCanonicalReference(s, m_owner.GetID(), GetID()); + + if (level == lldb::eDescriptionLevelBrief) + return; + + s->PutCString(": "); + + if (level == lldb::eDescriptionLevelVerbose) + s->IndentMore(); + + if (m_address.IsSectionOffset()) + { + m_address.CalculateSymbolContext(&sc); + + if (level == lldb::eDescriptionLevelFull) + { + s->PutCString("where = "); + sc.DumpStopContext (s, m_owner.GetTarget().GetProcessSP().get(), m_address); + } + 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 = "); + dynamic_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); + } + + } + 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(); + } + s->Printf ("%saddress = ", (level == lldb::eDescriptionLevelFull && m_address.IsSectionOffset()) ? ", " : ""); + ExecutionContextScope *exe_scope = NULL; + Target *target = &m_owner.GetTarget(); + if (target) + exe_scope = target->GetProcessSP().get(); + if (exe_scope == NULL) + exe_scope = target; + + 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("enabled = %s\n", IsEnabled() ? "true" : "false"); + + s->Indent(); + s->Printf ("hit count = %-4u\n", GetHitCount()); + + if (m_options_ap.get()) + { + Baton *baton = m_options_ap->GetBaton(); + if (baton) + { + s->Indent(); + baton->GetDescription (s, level); + s->EOL(); + } + } + s->IndentLess(); + } + else + { + s->Printf(", %sresolved, %s, hit count = %u", + (IsResolved() ? "" : "un"), + (IsEnabled() ? "enabled" : "disabled"), + GetHitCount()); + } +} + +void +BreakpointLocation::Dump(Stream *s) const +{ + if (s == NULL) + return; + + s->Printf("BreakpointLocation %u: tid = %4.4x load addr = 0x%8.8llx state = %s type = %s breakpoint hw_index = %i hit_count = %-4u ignore_count = %-4u", + GetID(), + m_tid, + (uint64_t) m_address.GetLoadAddress(m_owner.GetTarget().GetProcessSP().get()), + (m_options_ap.get() ? m_options_ap->IsEnabled() : m_owner.IsEnabled()) ? "enabled " : "disabled", + IsHardware() ? "hardware" : "software", + GetHardwareIndex(), + GetHitCount(), + m_options_ap.get() ? m_options_ap->GetIgnoreCount() : m_owner.GetIgnoreCount()); +} diff --git a/lldb/source/Breakpoint/BreakpointLocationCollection.cpp b/lldb/source/Breakpoint/BreakpointLocationCollection.cpp new file mode 100644 index 00000000000..7b574263003 --- /dev/null +++ b/lldb/source/Breakpoint/BreakpointLocationCollection.cpp @@ -0,0 +1,161 @@ +//===-- 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/BreakpointLocation.h" +#include "lldb/Breakpoint/BreakpointLocationList.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::user_id_t bp_id, lldb::user_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::user_id_t break_id, lldb::user_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::user_id_t m_break_id; + const lldb::user_id_t m_break_loc_id; +}; + +BreakpointLocationCollection::collection::iterator +BreakpointLocationCollection::GetIDPairIterator (lldb::user_id_t break_id, lldb::user_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::user_id_t break_id, lldb::user_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::user_id_t break_id, lldb::user_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::user_id_t break_id, lldb::user_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 (uint32_t i) +{ + BreakpointLocationSP stop_sp; + if (i >= 0 && i < m_break_loc_collection.size()) + stop_sp = m_break_loc_collection[i]; + + return stop_sp; +} + +const BreakpointLocationSP +BreakpointLocationCollection::GetByIndex (uint32_t i) const +{ + BreakpointLocationSP stop_sp; + if (i >= 0 && i < m_break_loc_collection.size()) + stop_sp = m_break_loc_collection[i]; + + return stop_sp; +} + +bool +BreakpointLocationCollection::ShouldStop (StoppointCallbackContext *context) +{ + bool shouldStop = false; + + for (int i = 0; i < GetSize(); i++) { + bool one_result = GetByIndex(i)->ShouldStop(context); + if (one_result) + shouldStop = true; + } + return shouldStop; +} + +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/lldb/source/Breakpoint/BreakpointLocationList.cpp b/lldb/source/Breakpoint/BreakpointLocationList.cpp new file mode 100644 index 00000000000..d86a8cf4c47 --- /dev/null +++ b/lldb/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/Core/ModuleList.h" +#include "lldb/Target/Target.h" + +using namespace lldb; +using namespace lldb_private; + +BreakpointLocationList::BreakpointLocationList() : + m_locations(), + m_address_to_location (), + m_mutex (Mutex::eMutexTypeRecursive), + m_next_id (0) +{ +} + +BreakpointLocationList::~BreakpointLocationList() +{ +} + +lldb::user_id_t +BreakpointLocationList::Add (BreakpointLocationSP &bp_loc_sp) +{ + if (bp_loc_sp) + { + Mutex::Locker locker (m_mutex); + m_locations.push_back (bp_loc_sp); + m_address_to_location[bp_loc_sp->GetAddress()] = bp_loc_sp; + return bp_loc_sp->GetID(); + } + return LLDB_INVALID_BREAK_ID; +} + +bool +BreakpointLocationList::ShouldStop (StoppointCallbackContext *context, lldb::user_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::user_id_t +BreakpointLocationList::FindIDByAddress (Address &addr) +{ + BreakpointLocationSP bp_loc_sp = FindByAddress (addr); + if (bp_loc_sp) + { + return bp_loc_sp->GetID(); + } + return LLDB_INVALID_BREAK_ID; +} + +bool +BreakpointLocationList::Remove (lldb::user_id_t break_id) +{ + Mutex::Locker locker (m_mutex); + collection::iterator pos = GetIDIterator(break_id); // Predicate + if (pos != m_locations.end()) + { + m_address_to_location.erase ((*pos)->GetAddress()); + m_locations.erase(pos); + return true; + } + return false; +} + + +class BreakpointLocationIDMatches +{ +public: + BreakpointLocationIDMatches (lldb::user_id_t break_id) : + m_break_id(break_id) + { + } + + bool operator() (const BreakpointLocationSP &bp_loc_sp) const + { + return m_break_id == bp_loc_sp->GetID(); + } + +private: + const lldb::user_id_t m_break_id; +}; + +class BreakpointLocationAddressMatches +{ +public: + BreakpointLocationAddressMatches (Address& addr) : + m_addr(addr) + { + } + + bool operator() (const BreakpointLocationSP& bp_loc_sp) const + { + return Address::CompareFileAddress(m_addr, bp_loc_sp->GetAddress()) == 0; + } + +private: + const Address &m_addr; +}; + +BreakpointLocationList::collection::iterator +BreakpointLocationList::GetIDIterator (lldb::user_id_t break_id) +{ + Mutex::Locker locker (m_mutex); + return std::find_if (m_locations.begin(), + m_locations.end(), + BreakpointLocationIDMatches(break_id)); +} + +BreakpointLocationList::collection::const_iterator +BreakpointLocationList::GetIDConstIterator (lldb::user_id_t break_id) const +{ + Mutex::Locker locker (m_mutex); + return std::find_if (m_locations.begin(), + m_locations.end(), + BreakpointLocationIDMatches(break_id)); +} + +BreakpointLocationSP +BreakpointLocationList::FindByID (lldb::user_id_t break_id) +{ + Mutex::Locker locker (m_mutex); + BreakpointLocationSP stop_sp; + collection::iterator pos = GetIDIterator(break_id); + if (pos != m_locations.end()) + stop_sp = *pos; + + return stop_sp; +} + +const BreakpointLocationSP +BreakpointLocationList::FindByID (lldb::user_id_t break_id) const +{ + Mutex::Locker locker (m_mutex); + BreakpointLocationSP stop_sp; + collection::const_iterator pos = GetIDConstIterator(break_id); + if (pos != m_locations.end()) + stop_sp = *pos; + + return stop_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) + { + bool seen = false; + BreakpointLocationSP break_loc = (*pos); + const Section *section = break_loc->GetAddress().GetSection(); + if (section) + { + if (section->GetModule() == module) + { + if (!seen) + { + seen = true; + bp_loc_list.Add (break_loc); + } + + } + } + } + return bp_loc_list.GetSize() - orig_size; +} + + +static int +FindLocationByAddress (Address *addr_ptr, const BreakpointLocationSP *bp_loc_sp_ptr) +{ + return Address::CompareModulePointerAndOffset(*addr_ptr, (*bp_loc_sp_ptr)->GetAddress()); +} + +const BreakpointLocationSP +BreakpointLocationList::FindByAddress (Address &addr) const +{ + Mutex::Locker locker (m_mutex); + BreakpointLocationSP stop_sp; + if (!m_locations.empty()) + { + addr_map::const_iterator pos = m_address_to_location.find (addr); + if (pos != m_address_to_location.end()) + stop_sp = pos->second; + } + + return stop_sp; +} + +void +BreakpointLocationList::Dump (Stream *s) const +{ + s->Printf("%.*p: ", (int)sizeof(void*) * 2, this); + s->Indent(); + Mutex::Locker locker (m_mutex); + s->Printf("BreakpointLocationList with %zu BreakpointLocations:\n", 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 (uint32_t i) +{ + Mutex::Locker locker (m_mutex); + BreakpointLocationSP stop_sp; + if (i >= 0 && i < m_locations.size()) + stop_sp = m_locations[i]; + + return stop_sp; +} + +const BreakpointLocationSP +BreakpointLocationList::GetByIndex (uint32_t i) const +{ + Mutex::Locker locker (m_mutex); + BreakpointLocationSP stop_sp; + if (i >= 0 && i < m_locations.size()) + stop_sp = m_locations[i]; + + return stop_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) + (*pos)->ResolveBreakpointSite(); +} + +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; +} + +break_id_t +BreakpointLocationList::GetNextID() +{ + return ++m_next_id; +} + +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); + } +} + diff --git a/lldb/source/Breakpoint/BreakpointOptions.cpp b/lldb/source/Breakpoint/BreakpointOptions.cpp new file mode 100644 index 00000000000..4f664c4692f --- /dev/null +++ b/lldb/source/Breakpoint/BreakpointOptions.cpp @@ -0,0 +1,180 @@ +//===-- 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/Breakpoint/StoppointCallbackContext.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_is_synchronous (false), + m_callback_baton_sp (), + m_enabled (true), + m_ignore_count (0), + m_thread_id (LLDB_INVALID_THREAD_ID) +{ +} + +//---------------------------------------------------------------------- +// 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_ignore_count (rhs.m_ignore_count), + m_thread_id (rhs.m_thread_id) +{ +} + +//---------------------------------------------------------------------- +// 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_ignore_count = rhs.m_ignore_count; + m_thread_id = rhs.m_thread_id; + return *this; +} + +//---------------------------------------------------------------------- +// 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 = NULL; + m_callback_baton_sp.reset(); +} + +Baton * +BreakpointOptions::GetBaton () +{ + 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; +} + +//------------------------------------------------------------------ +// Enabled/Ignore Count +//------------------------------------------------------------------ +bool +BreakpointOptions::IsEnabled () const +{ + return m_enabled; +} + +void +BreakpointOptions::SetEnabled (bool enabled) +{ + m_enabled = enabled; +} + +int32_t +BreakpointOptions::GetIgnoreCount () const +{ + return m_ignore_count; +} + +void +BreakpointOptions::SetIgnoreCount (int32_t n) +{ + m_ignore_count = n; +} + +void +BreakpointOptions::SetThreadID (lldb::tid_t thread_id) +{ + m_thread_id = thread_id; +} + +lldb::tid_t +BreakpointOptions::GetThreadID () const +{ + return m_thread_id; +} + + + +void +BreakpointOptions::CommandBaton::GetDescription (Stream *s, lldb::DescriptionLevel level) const +{ + s->Indent("Breakpoint commands:\n"); + CommandData *data = (CommandData *)m_data; + + 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 (); +} + diff --git a/lldb/source/Breakpoint/BreakpointResolver.cpp b/lldb/source/Breakpoint/BreakpointResolver.cpp new file mode 100644 index 00000000000..e0fbfde7932 --- /dev/null +++ b/lldb/source/Breakpoint/BreakpointResolver.cpp @@ -0,0 +1,60 @@ +//===-- 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) : + m_breakpoint (bkpt) +{ +} + +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/lldb/source/Breakpoint/BreakpointResolverAddress.cpp b/lldb/source/Breakpoint/BreakpointResolverAddress.cpp new file mode 100644 index 00000000000..034ef601dc4 --- /dev/null +++ b/lldb/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), + 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 breakpoint: "); + m_addr.Dump(s, m_breakpoint->GetTarget().GetProcessSP().get(), Address::DumpStyleLoadAddress, Address::DumpStyleModuleWithFileAddress); +} + +void +BreakpointResolverAddress::Dump (Stream *s) const +{ + +} diff --git a/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp b/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp new file mode 100644 index 00000000000..86e05964485 --- /dev/null +++ b/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp @@ -0,0 +1,122 @@ +//===-- 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/StreamString.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 +) : + BreakpointResolver (bkpt), + m_file_spec (file_spec), + m_line_number (line_no), + m_inlines (check_inlines) +{ +} + +BreakpointResolverFileLine::~BreakpointResolverFileLine () +{ +} + +Searcher::CallbackReturn +BreakpointResolverFileLine::SearchCallback +( + SearchFilter &filter, + SymbolContext &context, + Address *addr, + bool containing +) +{ + SymbolContextList sc_list; + uint32_t sc_list_size; + CompileUnit *cu = context.comp_unit; + + assert (m_breakpoint != NULL); + Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS); + + sc_list_size = cu->ResolveSymbolContext (m_file_spec, m_line_number, m_inlines, false, eSymbolContextEverything, sc_list); + for (int i = 0; i < sc_list_size; i++) + { + SymbolContext sc; + if (sc_list.GetContextAtIndex(i, sc)) + { + Address line_start = sc.line_entry.range.GetBaseAddress(); + if (line_start.IsValid()) + { + 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 ("error: Unable to set breakpoint at file address 0x%llx for %s:%d\n", + line_start.GetFileAddress(), + m_file_spec.GetFilename().AsCString("<Unknown>"), + m_line_number); + } + } + else + { +#if 0 + s << "error: Breakpoint at '" << pos->c_str() << "' isn't resolved yet: \n"; + if (sc.line_entry.address.Dump(&s, Address::DumpStyleSectionNameOffset)) + s.EOL(); + if (sc.line_entry.address.Dump(&s, Address::DumpStyleSectionPointerOffset)) + s.EOL(); + if (sc.line_entry.address.Dump(&s, Address::DumpStyleFileAddress)) + s.EOL(); + if (sc.line_entry.address.Dump(&s, Address::DumpStyleLoadAddress)) + s.EOL(); +#endif + } + } + return Searcher::eCallbackReturnContinue; +} + +Searcher::Depth +BreakpointResolverFileLine::GetDepth() +{ + return Searcher::eDepthCompUnit; +} + +void +BreakpointResolverFileLine::GetDescription (Stream *s) +{ + s->Printf ("File and line breakpoint - file: \"%s\" line: %u", m_file_spec.GetFilename().AsCString(), m_line_number); +} + +void +BreakpointResolverFileLine::Dump (Stream *s) const +{ + +} + diff --git a/lldb/source/Breakpoint/BreakpointResolverName.cpp b/lldb/source/Breakpoint/BreakpointResolverName.cpp new file mode 100644 index 00000000000..b04bb8aef48 --- /dev/null +++ b/lldb/source/Breakpoint/BreakpointResolverName.cpp @@ -0,0 +1,252 @@ +//===-- 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/StreamString.h" +#include "lldb/lldb-private-log.h" + +using namespace lldb; +using namespace lldb_private; + +BreakpointResolverName::BreakpointResolverName +( + Breakpoint *bkpt, + const char *func_name, + Breakpoint::MatchType type +) : + BreakpointResolver (bkpt), + m_func_name (func_name), + m_class_name (NULL), + m_regex (), + m_match_type (type) +{ + if (m_match_type == Breakpoint::Regexp) + { + if (!m_regex.Compile (m_func_name.AsCString())) + { + Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS); + + if (log) + log->Warning ("function name regexp: \"%s\" did not compile.", m_func_name.AsCString()); + } + } +} + +BreakpointResolverName::BreakpointResolverName +( + Breakpoint *bkpt, + RegularExpression &func_regex +) : + BreakpointResolver (bkpt), + m_func_name (NULL), + m_class_name (NULL), + m_regex (func_regex), + m_match_type (Breakpoint::Regexp) +{ + +} + +BreakpointResolverName::BreakpointResolverName +( + Breakpoint *bkpt, + const char *class_name, + const char *method, + Breakpoint::MatchType type +) : + BreakpointResolver (bkpt), + m_func_name (method), + m_class_name (class_name), + m_regex (), + m_match_type (type) +{ + +} + +BreakpointResolverName::~BreakpointResolverName () +{ +} + +// 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; + + bool skip_prologue = true; + uint32_t i; + bool new_location; + SymbolContext sc; + 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; + } + + switch (m_match_type) + { + case Breakpoint::Exact: + if (context.module_sp) + { + context.module_sp->FindSymbolsWithNameAndType (m_func_name, eSymbolTypeCode, sym_list); + context.module_sp->FindFunctions (m_func_name, false, func_list); + } + break; + case Breakpoint::Regexp: + if (context.module_sp) + { + context.module_sp->FindSymbolsMatchingRegExAndType (m_regex, eSymbolTypeCode, sym_list); + context.module_sp->FindFunctions (m_regex, true, func_list); + } + break; + case Breakpoint::Glob: + if (log) + log->Warning ("glob is not supported yet."); + break; + } + + // Remove any duplicates between the funcion list and the symbol list + if (func_list.GetSize()) + { + for (i = 0; i < func_list.GetSize(); i++) + { + if (func_list.GetContextAtIndex(i, sc) == false) + continue; + + if (sc.function == NULL) + continue; + uint32_t j = 0; + while (j < sym_list.GetSize()) + { + SymbolContext symbol_sc; + if (sym_list.GetContextAtIndex(j, symbol_sc)) + { + if (symbol_sc.symbol && symbol_sc.symbol->GetAddressRangePtr()) + { + if (sc.function->GetAddressRange().GetBaseAddress() == symbol_sc.symbol->GetAddressRangePtr()->GetBaseAddress()) + { + sym_list.RemoveContextAtIndex(j); + continue; // Don't increment j + } + } + } + + j++; + } + } + + for (i = 0; i < func_list.GetSize(); i++) + { + if (func_list.GetContextAtIndex(i, sc)) + { + if (sc.function) + { + break_addr = sc.function->GetAddressRange().GetBaseAddress(); + if (skip_prologue) + { + const uint32_t prologue_byte_size = sc.function->GetPrologueByteSize(); + if (prologue_byte_size) + break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size); + } + + 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()); + } + } + } + } + } + } + } + + for (i = 0; i < sym_list.GetSize(); i++) + { + if (sym_list.GetContextAtIndex(i, sc)) + { + if (sc.symbol && sc.symbol->GetAddressRangePtr()) + { + break_addr = sc.symbol->GetAddressRangePtr()->GetBaseAddress(); + + if (skip_prologue) + { + const uint32_t prologue_byte_size = sc.symbol->GetPrologueByteSize(); + if (prologue_byte_size) + break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size); + } + + 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()) + { + StreamString s; + bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose); + if (log) + log->Printf ("Added location: %s\n", s.GetData()); + } + } + } + } + } + return Searcher::eCallbackReturnContinue; +} + +Searcher::Depth +BreakpointResolverName::GetDepth() +{ + return Searcher::eDepthModule; +} + +void +BreakpointResolverName::GetDescription (Stream *s) +{ + s->PutCString("Breakpoint by name: "); + + if (m_match_type == Breakpoint::Regexp) + s->Printf("'%s' (regular expression)", m_regex.GetText()); + else + s->Printf("'%s'", m_func_name.AsCString()); +} + +void +BreakpointResolverName::Dump (Stream *s) const +{ + +} + diff --git a/lldb/source/Breakpoint/BreakpointSite.cpp b/lldb/source/Breakpoint/BreakpointSite.cpp new file mode 100644 index 00000000000..cd0920d07c7 --- /dev/null +++ b/lldb/source/Breakpoint/BreakpointSite.cpp @@ -0,0 +1,221 @@ +//===-- 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/BreakpointLocation.h" +#include "lldb/Breakpoint/BreakpointSiteList.h" + +using namespace lldb; +using namespace lldb_private; + +BreakpointSite::BreakpointSite +( + BreakpointSiteList *list, + BreakpointLocationSP& owner, + lldb::addr_t addr, + lldb::tid_t tid, + bool use_hardware +) : + StoppointLocation(GetNextID(), addr, tid, 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; + for (int i = 0; i < m_owners.GetSize(); 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) +{ + m_hit_count++; + return m_owners.ShouldStop (context); +} + +bool +BreakpointSite::IsBreakpointAtThisSite (lldb::break_id_t bp_id) +{ + for (int i = 0; i < m_owners.GetSize(); 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: tid = %4.4x addr = 0x%8.8llx type = %s breakpoint hw_index = %i hit_count = %-4u", + GetID(), + m_tid, + (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 ", GetID()); + m_owners.GetDescription (s, level); +} + +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, size_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 (BreakpointLocationSP &owner) +{ + m_owners.Add(owner); +} + +uint32_t +BreakpointSite::RemoveOwner (lldb::user_id_t break_id, lldb::user_id_t break_loc_id) +{ + m_owners.Remove(break_id, break_loc_id); + return m_owners.GetSize(); +} + +uint32_t +BreakpointSite::GetNumberOfOwners () +{ + return m_owners.GetSize(); +} + +BreakpointLocationSP +BreakpointSite::GetOwnerAtIndex (uint32_t index) +{ + return m_owners.GetByIndex (index); +} + +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/lldb/source/Breakpoint/BreakpointSiteList.cpp b/lldb/source/Breakpoint/BreakpointSiteList.cpp new file mode 100644 index 00000000000..19e18bb749a --- /dev/null +++ b/lldb/source/Breakpoint/BreakpointSiteList.cpp @@ -0,0 +1,229 @@ +//===-- 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" + +using namespace lldb; +using namespace lldb_private; + +BreakpointSiteList::BreakpointSiteList() : + 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::user_id_t +BreakpointSiteList::Add(const BreakpointSiteSP &bp) +{ + lldb::addr_t bp_site_load_addr = bp->GetLoadAddress(); + 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::user_id_t break_id) +{ + BreakpointSiteSP bp = FindByID (break_id); + if (bp) + { + // 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 bp->ShouldStop (context); + } + // We should stop here since this BreakpointSite isn't valid anymore or it + // doesn't exist. + return true; +} +lldb::user_id_t +BreakpointSiteList::FindIDByAddress (lldb::addr_t addr) +{ + BreakpointSiteSP bp = FindByAddress (addr); + if (bp) + { + //DBLogIf(PD_LOG_BREAKPOINTS, "BreakpointSiteList::%s ( addr = 0x%8.8llx ) => %u", __FUNCTION__, (uint64_t)addr, bp->GetID()); + return bp.get()->GetID(); + } + //DBLogIf(PD_LOG_BREAKPOINTS, "BreakpointSiteList::%s ( addr = 0x%8.8llx ) => NONE", __FUNCTION__, (uint64_t)addr); + return LLDB_INVALID_BREAK_ID; +} + +bool +BreakpointSiteList::Remove (lldb::user_id_t break_id) +{ + 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) +{ + 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::user_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::user_id_t m_break_id; +}; + +BreakpointSiteList::collection::iterator +BreakpointSiteList::GetIDIterator (lldb::user_id_t break_id) +{ + 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::user_id_t break_id) const +{ + 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::user_id_t break_id) +{ + 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::user_id_t break_id) const +{ + 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; + + collection::iterator iter = m_bp_site_list.find(addr); + if (iter != m_bp_site_list.end()) + found_sp = iter->second; + return found_sp; +} + +void +BreakpointSiteList::Dump (Stream *s) const +{ + s->Printf("%.*p: ", (int)sizeof(void*) * 2, 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(); +} + + +BreakpointSiteSP +BreakpointSiteList::GetByIndex (uint32_t i) +{ + BreakpointSiteSP stop_sp; + collection::iterator end = m_bp_site_list.end(); + collection::iterator pos; + uint32_t curr_i = 0; + for (pos = m_bp_site_list.begin(), curr_i = 0; pos != end; ++pos, ++curr_i) + { + if (curr_i == i) + stop_sp = pos->second; + } + return stop_sp; +} + +const BreakpointSiteSP +BreakpointSiteList::GetByIndex (uint32_t i) const +{ + BreakpointSiteSP stop_sp; + collection::const_iterator end = m_bp_site_list.end(); + collection::const_iterator pos; + uint32_t curr_i = 0; + for (pos = m_bp_site_list.begin(), curr_i = 0; pos != end; ++pos, ++curr_i) + { + if (curr_i == i) + stop_sp = pos->second; + } + return stop_sp; +} + +void +BreakpointSiteList::SetEnabledForAll (const bool enabled, const lldb::user_id_t except_id) +{ + collection::iterator end = m_bp_site_list.end(); + collection::iterator pos; + for (pos = m_bp_site_list.begin(); pos != end; ++pos) + { + if (except_id != LLDB_INVALID_BREAK_ID && except_id != pos->second->GetID()) + pos->second->SetEnabled (enabled); + else + pos->second->SetEnabled (!enabled); + } +} + +const BreakpointSiteList::collection * +BreakpointSiteList::GetMap () +{ + return &m_bp_site_list; +} diff --git a/lldb/source/Breakpoint/Stoppoint.cpp b/lldb/source/Breakpoint/Stoppoint.cpp new file mode 100644 index 00000000000..583ab47005f --- /dev/null +++ b/lldb/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/lldb/source/Breakpoint/StoppointCallbackContext.cpp b/lldb/source/Breakpoint/StoppointCallbackContext.cpp new file mode 100644 index 00000000000..86620621c76 --- /dev/null +++ b/lldb/source/Breakpoint/StoppointCallbackContext.cpp @@ -0,0 +1,38 @@ +//===-- 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), + context() +{ +} + +StoppointCallbackContext::StoppointCallbackContext(Event *e, Process* p, Thread *t, StackFrame *f, bool synchronously) : + event (e), + context (p, t, f), + is_synchronous(synchronously) +{ +} + +void +StoppointCallbackContext::Clear() +{ + event = NULL; + context.Clear(); + is_synchronous = false; +} diff --git a/lldb/source/Breakpoint/StoppointLocation.cpp b/lldb/source/Breakpoint/StoppointLocation.cpp new file mode 100644 index 00000000000..999ad536ab8 --- /dev/null +++ b/lldb/source/Breakpoint/StoppointLocation.cpp @@ -0,0 +1,120 @@ +//===-- 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, tid_t tid, bool hardware) : + m_loc_id(bid), + m_tid(tid), + m_byte_size(0), + m_addr(addr), + m_hit_count(0), + m_hw_preferred(hardware), + m_hw_index(LLDB_INVALID_INDEX32) +{ +} + +StoppointLocation::StoppointLocation (break_id_t bid, addr_t addr, tid_t tid, size_t size, bool hardware) : + m_loc_id(bid), + m_tid(tid), + m_byte_size(size), + m_addr(addr), + m_hit_count(0), + m_hw_preferred(hardware), + m_hw_index(LLDB_INVALID_INDEX32) +{ +} + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +StoppointLocation::~StoppointLocation() +{ +} + + +size_t +StoppointLocation::GetByteSize () const +{ + return m_byte_size; +} + +addr_t +StoppointLocation::GetLoadAddress() const +{ + return m_addr; +} + +tid_t +StoppointLocation::GetThreadID() const +{ + return m_tid; +} + +uint32_t +StoppointLocation::GetHitCount () const +{ + return m_hit_count; +} + +bool +StoppointLocation::HardwarePreferred () const +{ + return m_hw_preferred; +} + +bool +StoppointLocation::IsHardware () const +{ + return m_hw_index != LLDB_INVALID_INDEX32; +} + +uint32_t +StoppointLocation::GetHardwareIndex () const +{ + return m_hw_index; +} + +void +StoppointLocation::SetHardwareIndex (uint32_t hw_index) +{ + m_hw_index = hw_index; +} + +// RETURNS - true if we should stop at this breakpoint, false if we +// should continue. + +bool +StoppointLocation::ShouldStop (StoppointCallbackContext *context) +{ + return true; +} + +break_id_t +StoppointLocation::GetID() const +{ + return m_loc_id; +} + +void +StoppointLocation::Dump (Stream *stream) const +{ + +} diff --git a/lldb/source/Breakpoint/WatchpointLocation.cpp b/lldb/source/Breakpoint/WatchpointLocation.cpp new file mode 100644 index 00000000000..f765ef43202 --- /dev/null +++ b/lldb/source/Breakpoint/WatchpointLocation.cpp @@ -0,0 +1,137 @@ +//===-- WatchpointLocation.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/WatchpointLocation.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Stream.h" + +using namespace lldb; +using namespace lldb_private; + +WatchpointLocation::WatchpointLocation (lldb::addr_t addr, lldb::tid_t tid, bool hardware) : + StoppointLocation (GetNextID(), addr, tid, hardware), + m_enabled(0), + m_watch_read(0), + m_watch_write(0), + m_watch_was_read(0), + m_watch_was_written(0), + m_ignore_count(0), + m_callback(NULL), + m_callback_baton(NULL) +{ +} + +WatchpointLocation::~WatchpointLocation() +{ +} + +break_id_t +WatchpointLocation::GetNextID() +{ + static break_id_t g_next_ID = 0; + return ++g_next_ID; +} + +bool +WatchpointLocation::SetCallback (WatchpointHitCallback callback, void *callback_baton) +{ + m_callback = callback; + m_callback_baton = callback_baton; + return true; +} + + +// RETURNS - true if we should stop at this breakpoint, false if we +// should continue. + +bool +WatchpointLocation::BreakpointWasHit (StoppointCallbackContext *context) +{ + m_hit_count++; + + if (m_hit_count > m_ignore_count) + { + uint32_t access = 0; + if (m_watch_was_read) + access |= LLDB_WATCH_TYPE_READ; + if (m_watch_was_written) + access |= LLDB_WATCH_TYPE_WRITE; + return m_callback(m_callback_baton, context, GetID(), access); + } + return false; +} + +void +WatchpointLocation::Dump(Stream *s) const +{ + if (s == NULL) + return; + + s->Printf("WatchpointLocation %u: tid = %4.4x addr = 0x%8.8llx size = %zu state = %s type = %s watchpoint (%s%s) hw_index = %i hit_count = %-4u ignore_count = %-4u callback = %8p baton = %8p", + GetID(), + m_tid, + (uint64_t)m_addr, + m_byte_size, + m_enabled ? "enabled " : "disabled", + IsHardware() ? "hardware" : "software", + m_watch_read ? "r" : "", + m_watch_write ? "w" : "", + GetHardwareIndex(), + GetHitCount(), + GetIgnoreCount(), + m_callback, + m_callback_baton); +} + +bool +WatchpointLocation::IsEnabled() const +{ + return m_enabled; +} + +void +WatchpointLocation::SetEnabled(uint32_t enabled) +{ + if (!enabled) + SetHardwareIndex(LLDB_INVALID_INDEX32); + m_enabled = enabled; +} + +void +WatchpointLocation::SetWatchpointType (uint32_t type) +{ + m_watch_read = (type & LLDB_WATCH_TYPE_READ) != 0; + m_watch_write = (type & LLDB_WATCH_TYPE_WRITE) != 0; +} + +bool +WatchpointLocation::WatchpointRead () const +{ + return m_watch_read != 0; +} +bool +WatchpointLocation::WatchpointWrite () const +{ + return m_watch_write != 0; +} +int32_t +WatchpointLocation::GetIgnoreCount () const +{ + return m_ignore_count; +} + +void +WatchpointLocation::SetIgnoreCount (int32_t n) +{ + m_ignore_count = n; +} |