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/Core/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 int
35 BreakpointIDList::Size()
36 {
37     return m_breakpoint_ids.size();
38 }
39 
40 BreakpointID &
41 BreakpointIDList::GetBreakpointIDAtIndex (int 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 (int index)
51 {
52     bool success = false;
53     if (index < m_breakpoint_ids.size())
54     {
55         BreakpointIDArray::iterator pos;
56         int i;
57 
58         for (pos = m_breakpoint_ids.begin(), i = 0; i != index && pos != m_breakpoint_ids.end(); ++pos, ++i);
59         assert (i == index);
60         if (pos != m_breakpoint_ids.end())
61         {
62             m_breakpoint_ids.erase (pos);
63             success = true;
64         }
65     }
66     return success;
67 }
68 
69 void
70 BreakpointIDList::Clear()
71 {
72     m_breakpoint_ids.clear ();
73 }
74 
75 bool
76 BreakpointIDList::AddBreakpointID (BreakpointID bp_id)
77 {
78     m_breakpoint_ids.push_back (bp_id);
79 
80     return true;  // We don't do any verification in this function, so always return true.
81 }
82 
83 bool
84 BreakpointIDList::AddBreakpointID (const char *bp_id_str)
85 {
86     BreakpointID temp_bp_id;
87     break_id_t bp_id;
88     break_id_t loc_id;
89 
90     bool success = BreakpointID::ParseCanonicalReference (bp_id_str, &bp_id, &loc_id);
91 
92     if (success)
93     {
94         temp_bp_id.SetID (bp_id, loc_id);
95         m_breakpoint_ids.push_back (temp_bp_id);
96     }
97 
98     return success;
99 }
100 
101 bool
102 BreakpointIDList::FindBreakpointID (BreakpointID &bp_id, int *position)
103 {
104     bool success = false;
105     BreakpointIDArray::iterator tmp_pos;
106 
107     for (int i = 0; i <  m_breakpoint_ids.size(); ++i)
108     {
109         BreakpointID tmp_id = m_breakpoint_ids[i];
110         if (tmp_id.GetBreakpointID() == bp_id.GetBreakpointID()
111             && tmp_id.GetLocationID() == bp_id.GetLocationID())
112         {
113             success = true;
114             *position = i;
115             return true;
116         }
117     }
118 
119     return false;
120 }
121 
122 bool
123 BreakpointIDList::FindBreakpointID (const char *bp_id_str, int *position)
124 {
125     BreakpointID temp_bp_id;
126     break_id_t bp_id;
127     break_id_t loc_id;
128 
129     if (BreakpointID::ParseCanonicalReference (bp_id_str, &bp_id, &loc_id))
130     {
131         temp_bp_id.SetID (bp_id, loc_id);
132         return FindBreakpointID (temp_bp_id, position);
133     }
134     else
135         return false;
136 }
137 
138 void
139 BreakpointIDList::InsertStringArray (const char **string_array, int array_size, CommandReturnObject &result)
140 {
141     if (string_array == NULL)
142         return;
143 
144     for (int i = 0; i < array_size; ++i)
145     {
146         break_id_t bp_id;
147         break_id_t loc_id;
148 
149         if (BreakpointID::ParseCanonicalReference (string_array[i], &bp_id, &loc_id))
150         {
151             if (bp_id != LLDB_INVALID_BREAK_ID)
152             {
153                 BreakpointID temp_bp_id(bp_id, loc_id);
154                 m_breakpoint_ids.push_back (temp_bp_id);
155             }
156             else
157             {
158                 result.AppendErrorWithFormat ("'%s' is not a valid breakpoint ID.\n", string_array[i]);
159                 result.SetStatus (eReturnStatusFailed);
160                 return;
161             }
162         }
163     }
164     result.SetStatus (eReturnStatusSuccessFinishNoResult);
165 }
166 
167 
168 //  This function takes OLD_ARGS, which is usually the result of breaking the command string arguments into
169 //  an array of space-separated strings, and searches through the arguments for any breakpoint ID range specifiers.
170 //  Any string in the array that is not part of an ID range specifier is copied directly into NEW_ARGS.  If any
171 //  ID range specifiers are found, the range is interpreted and a list of canonical breakpoint IDs corresponding to
172 //  all the current breakpoints and locations in the range are added to NEW_ARGS.  When this function is done,
173 //  NEW_ARGS should be a copy of OLD_ARGS, with and ID range specifiers replaced by the members of the range.
174 
175 void
176 BreakpointIDList::FindAndReplaceIDRanges (Args &old_args, Target *target, CommandReturnObject &result,
177                                           Args &new_args)
178 {
179     char *range_start;
180     const char *range_end;
181     const char *current_arg;
182     int num_old_args = old_args.GetArgumentCount();
183 
184     for (int i = 0; i < num_old_args; ++i)
185     {
186         bool is_range = false;
187         current_arg = old_args.GetArgumentAtIndex (i);
188 
189         int range_start_len = 0;
190         int range_end_pos = 0;
191         if (BreakpointIDList::StringContainsIDRangeExpression (current_arg, &range_start_len, &range_end_pos))
192         {
193             is_range = true;
194             range_start = (char *) malloc (range_start_len + 1);
195             strncpy (range_start, current_arg, range_start_len);
196             range_start[range_start_len] = '\0';
197             range_end = current_arg + range_end_pos;
198         }
199         else if ((i + 2 < num_old_args)
200                  && BreakpointID::IsRangeIdentifier (old_args.GetArgumentAtIndex (i+1))
201                  && BreakpointID::IsValidIDExpression (current_arg)
202                  && BreakpointID::IsValidIDExpression (old_args.GetArgumentAtIndex (i+2)))
203         {
204             range_start = (char *) current_arg;
205             range_end = old_args.GetArgumentAtIndex (i+2);
206             is_range = true;
207             i = i+2;
208         }
209 
210         if (is_range)
211         {
212             break_id_t start_bp_id;
213             break_id_t end_bp_id;
214             break_id_t start_loc_id;
215             break_id_t end_loc_id;
216 
217             BreakpointID::ParseCanonicalReference (range_start, &start_bp_id, &start_loc_id);
218             BreakpointID::ParseCanonicalReference (range_end, &end_bp_id, &end_loc_id);
219 
220             if ((start_bp_id == LLDB_INVALID_BREAK_ID)
221                 || (! target->GetBreakpointByID (start_bp_id)))
222             {
223                 new_args.Clear();
224                 result.AppendErrorWithFormat ("'%s' is not a valid breakpoint ID.\n", range_start);
225                 result.SetStatus (eReturnStatusFailed);
226                 return;
227             }
228 
229             if ((end_bp_id == LLDB_INVALID_BREAK_ID)
230                 || (! target->GetBreakpointByID (end_bp_id)))
231             {
232                 new_args.Clear();
233                 result.AppendErrorWithFormat ("'%s' is not a valid breakpoint ID.\n", range_end);
234                 result.SetStatus (eReturnStatusFailed);
235                 return;
236             }
237 
238             // We have valid range starting & ending breakpoint IDs.  Go through all the breakpoints in the
239             // target and find all the breakpoints that fit into this range, and add them to new_args.
240 
241             const BreakpointList& breakpoints = target->GetBreakpointList();
242             size_t num_breakpoints = breakpoints.GetSize();
243             for (int j = 0; j < num_breakpoints; ++j)
244             {
245                 Breakpoint *breakpoint = breakpoints.GetBreakpointByIndex (j).get();
246                 break_id_t cur_bp_id = breakpoint->GetID();
247 
248                 if ((cur_bp_id < start_bp_id) || (cur_bp_id > end_bp_id))
249                     continue;
250 
251                 size_t num_locations = breakpoint->GetNumLocations();
252 
253                 if ((cur_bp_id == start_bp_id) && (start_loc_id != LLDB_INVALID_BREAK_ID))
254                 {
255                     for (int k = 0; k < num_locations; ++k)
256                     {
257                         BreakpointLocation * bp_loc = breakpoint->GetLocationAtIndex(k).get();
258                         if (bp_loc->GetID() >= start_loc_id)
259                         {
260                             StreamString canonical_id_str;
261                             BreakpointID::GetCanonicalReference (&canonical_id_str, cur_bp_id, bp_loc->GetID());
262                             new_args.AppendArgument (canonical_id_str.GetData());
263                         }
264                     }
265                 }
266                 else if ((cur_bp_id == end_bp_id) && (end_loc_id != LLDB_INVALID_BREAK_ID))
267                 {
268                     for (int k = 0; k < num_locations; ++k)
269                     {
270                         BreakpointLocation * bp_loc = breakpoint->GetLocationAtIndex(k).get();
271                         if (bp_loc->GetID() <= end_loc_id)
272                         {
273                             StreamString canonical_id_str;
274                             BreakpointID::GetCanonicalReference (&canonical_id_str, cur_bp_id, bp_loc->GetID());
275                             new_args.AppendArgument (canonical_id_str.GetData());
276                         }
277                     }
278                 }
279                 else
280                 {
281                     StreamString canonical_id_str;
282                     BreakpointID::GetCanonicalReference (&canonical_id_str, cur_bp_id, LLDB_INVALID_BREAK_ID);
283                     new_args.AppendArgument (canonical_id_str.GetData());
284                 }
285             }
286         }
287         else  // else is_range was false
288         {
289             new_args.AppendArgument (current_arg);
290         }
291     }
292 
293     result.SetStatus (eReturnStatusSuccessFinishNoResult);
294     return;
295 }
296 
297 //bool
298 //BreakpointIDList::StringContainsIDRangeExpression (const char *in_string, const char **range_start,
299 //                                                     const **range_end)
300 bool
301 BreakpointIDList::StringContainsIDRangeExpression (const char *in_string, int *range_start_len, int *range_end_pos)
302 {
303     bool is_range_expression = false;
304     std::string arg_str = in_string;
305     std::string::size_type idx;
306     std::string::size_type start_pos = 0;
307 
308     //*range_start = NULL;
309     //*range_end = NULL;
310     *range_start_len = 0;
311     *range_end_pos = 0;
312 
313     int specifiers_size = 0;
314     for (int i = 0; BreakpointID::g_range_specifiers[i] != NULL; ++i)
315         ++specifiers_size;
316 
317     for (int i = 0; i < specifiers_size && !is_range_expression; ++i)
318     {
319         const char *specifier_str = BreakpointID::g_range_specifiers[i];
320         int len = strlen (specifier_str);
321         idx = arg_str.find (BreakpointID::g_range_specifiers[i]);
322         if (idx != std::string::npos)
323         {
324             *range_start_len = idx - start_pos;
325             std::string start_str = arg_str.substr (start_pos, *range_start_len);
326             if (idx + len < arg_str.length())
327             {
328                 *range_end_pos = idx + len;
329                 std::string end_str = arg_str.substr (*range_end_pos);
330                 if (BreakpointID::IsValidIDExpression (start_str.c_str())
331                     && BreakpointID::IsValidIDExpression (end_str.c_str()))
332                 {
333                     is_range_expression = true;
334                     //*range_start = start_str;
335                     //*range_end = end_str;
336                 }
337             }
338         }
339     }
340 
341     if (!is_range_expression)
342     {
343         *range_start_len = 0;
344         *range_end_pos = 0;
345     }
346 
347     return is_range_expression;
348 }
349