Home | History | Annotate | Download | only in Breakpoint
      1 //===-- BreakpointIDList.cpp ------------------------------------*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #include "lldb/Breakpoint/BreakpointIDList.h"
     11 
     12 #include "lldb/Breakpoint/Breakpoint.h"
     13 #include "lldb/Breakpoint/BreakpointLocation.h"
     14 #include "lldb/Interpreter/CommandReturnObject.h"
     15 #include "lldb/Interpreter/Args.h"
     16 #include "lldb/Target/Target.h"
     17 
     18 using namespace lldb;
     19 using namespace lldb_private;
     20 
     21 //----------------------------------------------------------------------
     22 // class BreakpointIDList
     23 //----------------------------------------------------------------------
     24 
     25 BreakpointIDList::BreakpointIDList () :
     26 m_invalid_id (LLDB_INVALID_BREAK_ID, LLDB_INVALID_BREAK_ID)
     27 {
     28 }
     29 
     30 BreakpointIDList::~BreakpointIDList ()
     31 {
     32 }
     33 
     34 size_t
     35 BreakpointIDList::GetSize()
     36 {
     37     return m_breakpoint_ids.size();
     38 }
     39 
     40 BreakpointID &
     41 BreakpointIDList::GetBreakpointIDAtIndex (size_t index)
     42 {
     43     if (index < m_breakpoint_ids.size())
     44         return m_breakpoint_ids[index];
     45     else
     46         return m_invalid_id;
     47 }
     48 
     49 bool
     50 BreakpointIDList::RemoveBreakpointIDAtIndex (size_t index)
     51 {
     52     if (index >= m_breakpoint_ids.size())
     53         return false;
     54 
     55     m_breakpoint_ids.erase (m_breakpoint_ids.begin() + index);
     56     return true;
     57 }
     58 
     59 void
     60 BreakpointIDList::Clear()
     61 {
     62     m_breakpoint_ids.clear ();
     63 }
     64 
     65 bool
     66 BreakpointIDList::AddBreakpointID (BreakpointID bp_id)
     67 {
     68     m_breakpoint_ids.push_back (bp_id);
     69 
     70     return true;  // We don't do any verification in this function, so always return true.
     71 }
     72 
     73 bool
     74 BreakpointIDList::AddBreakpointID (const char *bp_id_str)
     75 {
     76     BreakpointID temp_bp_id;
     77     break_id_t bp_id;
     78     break_id_t loc_id;
     79 
     80     bool success = BreakpointID::ParseCanonicalReference (bp_id_str, &bp_id, &loc_id);
     81 
     82     if (success)
     83     {
     84         temp_bp_id.SetID (bp_id, loc_id);
     85         m_breakpoint_ids.push_back (temp_bp_id);
     86     }
     87 
     88     return success;
     89 }
     90 
     91 bool
     92 BreakpointIDList::FindBreakpointID (BreakpointID &bp_id, size_t *position)
     93 {
     94     for (size_t i = 0; i < m_breakpoint_ids.size(); ++i)
     95     {
     96         BreakpointID tmp_id = m_breakpoint_ids[i];
     97         if (tmp_id.GetBreakpointID() == bp_id.GetBreakpointID()
     98             && tmp_id.GetLocationID() == bp_id.GetLocationID())
     99         {
    100             *position = i;
    101             return true;
    102         }
    103     }
    104 
    105     return false;
    106 }
    107 
    108 bool
    109 BreakpointIDList::FindBreakpointID (const char *bp_id_str, size_t *position)
    110 {
    111     BreakpointID temp_bp_id;
    112     break_id_t bp_id;
    113     break_id_t loc_id;
    114 
    115     if (BreakpointID::ParseCanonicalReference (bp_id_str, &bp_id, &loc_id))
    116     {
    117         temp_bp_id.SetID (bp_id, loc_id);
    118         return FindBreakpointID (temp_bp_id, position);
    119     }
    120     else
    121         return false;
    122 }
    123 
    124 void
    125 BreakpointIDList::InsertStringArray (const char **string_array, size_t array_size, CommandReturnObject &result)
    126 {
    127     if (string_array == NULL)
    128         return;
    129 
    130     for (uint32_t i = 0; i < array_size; ++i)
    131     {
    132         break_id_t bp_id;
    133         break_id_t loc_id;
    134 
    135         if (BreakpointID::ParseCanonicalReference (string_array[i], &bp_id, &loc_id))
    136         {
    137             if (bp_id != LLDB_INVALID_BREAK_ID)
    138             {
    139                 BreakpointID temp_bp_id(bp_id, loc_id);
    140                 m_breakpoint_ids.push_back (temp_bp_id);
    141             }
    142             else
    143             {
    144                 result.AppendErrorWithFormat ("'%s' is not a valid breakpoint ID.\n", string_array[i]);
    145                 result.SetStatus (eReturnStatusFailed);
    146                 return;
    147             }
    148         }
    149     }
    150     result.SetStatus (eReturnStatusSuccessFinishNoResult);
    151 }
    152 
    153 
    154 //  This function takes OLD_ARGS, which is usually the result of breaking the command string arguments into
    155 //  an array of space-separated strings, and searches through the arguments for any breakpoint ID range specifiers.
    156 //  Any string in the array that is not part of an ID range specifier is copied directly into NEW_ARGS.  If any
    157 //  ID range specifiers are found, the range is interpreted and a list of canonical breakpoint IDs corresponding to
    158 //  all the current breakpoints and locations in the range are added to NEW_ARGS.  When this function is done,
    159 //  NEW_ARGS should be a copy of OLD_ARGS, with and ID range specifiers replaced by the members of the range.
    160 
    161 void
    162 BreakpointIDList::FindAndReplaceIDRanges (Args &old_args, Target *target, CommandReturnObject &result,
    163                                           Args &new_args)
    164 {
    165     std::string range_start;
    166     const char *range_end;
    167     const char *current_arg;
    168     const size_t num_old_args = old_args.GetArgumentCount();
    169 
    170     for (size_t i = 0; i < num_old_args; ++i)
    171     {
    172         bool is_range = false;
    173         current_arg = old_args.GetArgumentAtIndex (i);
    174 
    175         size_t range_start_len = 0;
    176         size_t range_end_pos = 0;
    177         if (BreakpointIDList::StringContainsIDRangeExpression (current_arg, &range_start_len, &range_end_pos))
    178         {
    179             is_range = true;
    180             range_start.assign (current_arg, range_start_len);
    181             range_end = current_arg + range_end_pos;
    182         }
    183         else if ((i + 2 < num_old_args)
    184                  && BreakpointID::IsRangeIdentifier (old_args.GetArgumentAtIndex (i+1))
    185                  && BreakpointID::IsValidIDExpression (current_arg)
    186                  && BreakpointID::IsValidIDExpression (old_args.GetArgumentAtIndex (i+2)))
    187         {
    188             range_start.assign (current_arg);
    189             range_end = old_args.GetArgumentAtIndex (i+2);
    190             is_range = true;
    191             i = i+2;
    192         }
    193         else
    194         {
    195             // See if user has specified id.*
    196             std::string tmp_str = old_args.GetArgumentAtIndex (i);
    197             size_t pos = tmp_str.find ('.');
    198             if (pos != std::string::npos)
    199             {
    200                 std::string bp_id_str = tmp_str.substr (0, pos);
    201                 if (BreakpointID::IsValidIDExpression (bp_id_str.c_str())
    202                     && tmp_str[pos+1] == '*'
    203                     && tmp_str.length() == (pos + 2))
    204                 {
    205                     break_id_t bp_id;
    206                     break_id_t bp_loc_id;
    207 
    208                     BreakpointID::ParseCanonicalReference (bp_id_str.c_str(), &bp_id, &bp_loc_id);
    209                     BreakpointSP breakpoint_sp = target->GetBreakpointByID (bp_id);
    210                     if (! breakpoint_sp)
    211                     {
    212                         new_args.Clear();
    213                         result.AppendErrorWithFormat ("'%d' is not a valid breakpoint ID.\n", bp_id);
    214                         result.SetStatus (eReturnStatusFailed);
    215                         return;
    216                     }
    217                     const size_t num_locations = breakpoint_sp->GetNumLocations();
    218                     for (size_t j = 0; j < num_locations; ++j)
    219                     {
    220                         BreakpointLocation *bp_loc = breakpoint_sp->GetLocationAtIndex(j).get();
    221                         StreamString canonical_id_str;
    222                         BreakpointID::GetCanonicalReference (&canonical_id_str, bp_id, bp_loc->GetID());
    223                         new_args.AppendArgument (canonical_id_str.GetData());
    224                     }
    225                 }
    226 
    227             }
    228         }
    229 
    230         if (is_range)
    231         {
    232             break_id_t start_bp_id;
    233             break_id_t end_bp_id;
    234             break_id_t start_loc_id;
    235             break_id_t end_loc_id;
    236 
    237             BreakpointID::ParseCanonicalReference (range_start.c_str(), &start_bp_id, &start_loc_id);
    238             BreakpointID::ParseCanonicalReference (range_end, &end_bp_id, &end_loc_id);
    239 
    240             if ((start_bp_id == LLDB_INVALID_BREAK_ID)
    241                 || (! target->GetBreakpointByID (start_bp_id)))
    242             {
    243                 new_args.Clear();
    244                 result.AppendErrorWithFormat ("'%s' is not a valid breakpoint ID.\n", range_start.c_str());
    245                 result.SetStatus (eReturnStatusFailed);
    246                 return;
    247             }
    248 
    249             if ((end_bp_id == LLDB_INVALID_BREAK_ID)
    250                 || (! target->GetBreakpointByID (end_bp_id)))
    251             {
    252                 new_args.Clear();
    253                 result.AppendErrorWithFormat ("'%s' is not a valid breakpoint ID.\n", range_end);
    254                 result.SetStatus (eReturnStatusFailed);
    255                 return;
    256             }
    257 
    258 
    259             if (((start_loc_id == LLDB_INVALID_BREAK_ID)
    260                  && (end_loc_id != LLDB_INVALID_BREAK_ID))
    261                 || ((start_loc_id != LLDB_INVALID_BREAK_ID)
    262                     && (end_loc_id == LLDB_INVALID_BREAK_ID)))
    263             {
    264                 new_args.Clear ();
    265                 result.AppendErrorWithFormat ("Invalid breakpoint id range:  Either both ends of range must specify"
    266                                               " a breakpoint location, or neither can specify a breakpoint location.\n");
    267                 result.SetStatus (eReturnStatusFailed);
    268                 return;
    269             }
    270 
    271             // We have valid range starting & ending breakpoint IDs.  Go through all the breakpoints in the
    272             // target and find all the breakpoints that fit into this range, and add them to new_args.
    273 
    274             // Next check to see if we have location id's.  If so, make sure the start_bp_id and end_bp_id are
    275             // for the same breakpoint; otherwise we have an illegal range: breakpoint id ranges that specify
    276             // bp locations are NOT allowed to cross major bp id numbers.
    277 
    278             if  ((start_loc_id != LLDB_INVALID_BREAK_ID)
    279                 || (end_loc_id != LLDB_INVALID_BREAK_ID))
    280             {
    281                 if (start_bp_id != end_bp_id)
    282                 {
    283                     new_args.Clear();
    284                     result.AppendErrorWithFormat ("Invalid range: Ranges that specify particular breakpoint locations"
    285                                                   " must be within the same major breakpoint; you specified two"
    286                                                   " different major breakpoints, %d and %d.\n",
    287                                                   start_bp_id, end_bp_id);
    288                     result.SetStatus (eReturnStatusFailed);
    289                     return;
    290                 }
    291             }
    292 
    293             const BreakpointList& breakpoints = target->GetBreakpointList();
    294             const size_t num_breakpoints = breakpoints.GetSize();
    295             for (size_t j = 0; j < num_breakpoints; ++j)
    296             {
    297                 Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex (j).get();
    298                 break_id_t cur_bp_id = breakpoint->GetID();
    299 
    300                 if ((cur_bp_id < start_bp_id) || (cur_bp_id > end_bp_id))
    301                     continue;
    302 
    303                 const size_t num_locations = breakpoint->GetNumLocations();
    304 
    305                 if ((cur_bp_id == start_bp_id) && (start_loc_id != LLDB_INVALID_BREAK_ID))
    306                 {
    307                     for (size_t k = 0; k < num_locations; ++k)
    308                     {
    309                         BreakpointLocation * bp_loc = breakpoint->GetLocationAtIndex(k).get();
    310                         if ((bp_loc->GetID() >= start_loc_id) && (bp_loc->GetID() <= end_loc_id))
    311                         {
    312                             StreamString canonical_id_str;
    313                             BreakpointID::GetCanonicalReference (&canonical_id_str, cur_bp_id, bp_loc->GetID());
    314                             new_args.AppendArgument (canonical_id_str.GetData());
    315                         }
    316                     }
    317                 }
    318                 else if ((cur_bp_id == end_bp_id) && (end_loc_id != LLDB_INVALID_BREAK_ID))
    319                 {
    320                     for (size_t k = 0; k < num_locations; ++k)
    321                     {
    322                         BreakpointLocation * bp_loc = breakpoint->GetLocationAtIndex(k).get();
    323                         if (bp_loc->GetID() <= end_loc_id)
    324                         {
    325                             StreamString canonical_id_str;
    326                             BreakpointID::GetCanonicalReference (&canonical_id_str, cur_bp_id, bp_loc->GetID());
    327                             new_args.AppendArgument (canonical_id_str.GetData());
    328                         }
    329                     }
    330                 }
    331                 else
    332                 {
    333                     StreamString canonical_id_str;
    334                     BreakpointID::GetCanonicalReference (&canonical_id_str, cur_bp_id, LLDB_INVALID_BREAK_ID);
    335                     new_args.AppendArgument (canonical_id_str.GetData());
    336                 }
    337             }
    338         }
    339         else  // else is_range was false
    340         {
    341             new_args.AppendArgument (current_arg);
    342         }
    343     }
    344 
    345     result.SetStatus (eReturnStatusSuccessFinishNoResult);
    346     return;
    347 }
    348 
    349 bool
    350 BreakpointIDList::StringContainsIDRangeExpression (const char *in_string,
    351                                                    size_t *range_start_len,
    352                                                    size_t *range_end_pos)
    353 {
    354     bool is_range_expression = false;
    355     std::string arg_str = in_string;
    356     std::string::size_type idx;
    357     std::string::size_type start_pos = 0;
    358 
    359     *range_start_len = 0;
    360     *range_end_pos = 0;
    361 
    362     int specifiers_size = 0;
    363     for (int i = 0; BreakpointID::g_range_specifiers[i] != NULL; ++i)
    364         ++specifiers_size;
    365 
    366     for (int i = 0; i < specifiers_size && !is_range_expression; ++i)
    367     {
    368         const char *specifier_str = BreakpointID::g_range_specifiers[i];
    369         size_t len = strlen (specifier_str);
    370         idx = arg_str.find (BreakpointID::g_range_specifiers[i]);
    371         if (idx != std::string::npos)
    372         {
    373             *range_start_len = idx - start_pos;
    374             std::string start_str = arg_str.substr (start_pos, *range_start_len);
    375             if (idx + len < arg_str.length())
    376             {
    377                 *range_end_pos = idx + len;
    378                 std::string end_str = arg_str.substr (*range_end_pos);
    379                 if (BreakpointID::IsValidIDExpression (start_str.c_str())
    380                     && BreakpointID::IsValidIDExpression (end_str.c_str()))
    381                 {
    382                     is_range_expression = true;
    383                     //*range_start = start_str;
    384                     //*range_end = end_str;
    385                 }
    386             }
    387         }
    388     }
    389 
    390     if (!is_range_expression)
    391     {
    392         *range_start_len = 0;
    393         *range_end_pos = 0;
    394     }
    395 
    396     return is_range_expression;
    397 }
    398