1254721Semaste//===-- BreakpointIDList.cpp ------------------------------------*- C++ -*-===//
2254721Semaste//
3254721Semaste//                     The LLVM Compiler Infrastructure
4254721Semaste//
5254721Semaste// This file is distributed under the University of Illinois Open Source
6254721Semaste// License. See LICENSE.TXT for details.
7254721Semaste//
8254721Semaste//===----------------------------------------------------------------------===//
9254721Semaste
10254721Semaste#include "lldb/Breakpoint/BreakpointIDList.h"
11254721Semaste
12254721Semaste#include "lldb/Breakpoint/Breakpoint.h"
13254721Semaste#include "lldb/Breakpoint/BreakpointLocation.h"
14254721Semaste#include "lldb/Interpreter/CommandReturnObject.h"
15254721Semaste#include "lldb/Interpreter/Args.h"
16254721Semaste#include "lldb/Target/Target.h"
17254721Semaste
18254721Semasteusing namespace lldb;
19254721Semasteusing namespace lldb_private;
20254721Semaste
21254721Semaste//----------------------------------------------------------------------
22254721Semaste// class BreakpointIDList
23254721Semaste//----------------------------------------------------------------------
24254721Semaste
25254721SemasteBreakpointIDList::BreakpointIDList () :
26254721Semastem_invalid_id (LLDB_INVALID_BREAK_ID, LLDB_INVALID_BREAK_ID)
27254721Semaste{
28254721Semaste}
29254721Semaste
30254721SemasteBreakpointIDList::~BreakpointIDList ()
31254721Semaste{
32254721Semaste}
33254721Semaste
34254721Semastesize_t
35254721SemasteBreakpointIDList::GetSize()
36254721Semaste{
37254721Semaste    return m_breakpoint_ids.size();
38254721Semaste}
39254721Semaste
40254721SemasteBreakpointID &
41254721SemasteBreakpointIDList::GetBreakpointIDAtIndex (size_t index)
42254721Semaste{
43254721Semaste    if (index < m_breakpoint_ids.size())
44254721Semaste        return m_breakpoint_ids[index];
45254721Semaste    else
46254721Semaste        return m_invalid_id;
47254721Semaste}
48254721Semaste
49254721Semastebool
50254721SemasteBreakpointIDList::RemoveBreakpointIDAtIndex (size_t index)
51254721Semaste{
52254721Semaste    if (index >= m_breakpoint_ids.size())
53254721Semaste        return false;
54254721Semaste
55254721Semaste    m_breakpoint_ids.erase (m_breakpoint_ids.begin() + index);
56254721Semaste    return true;
57254721Semaste}
58254721Semaste
59254721Semastevoid
60254721SemasteBreakpointIDList::Clear()
61254721Semaste{
62254721Semaste    m_breakpoint_ids.clear ();
63254721Semaste}
64254721Semaste
65254721Semastebool
66254721SemasteBreakpointIDList::AddBreakpointID (BreakpointID bp_id)
67254721Semaste{
68254721Semaste    m_breakpoint_ids.push_back (bp_id);
69254721Semaste
70254721Semaste    return true;  // We don't do any verification in this function, so always return true.
71254721Semaste}
72254721Semaste
73254721Semastebool
74254721SemasteBreakpointIDList::AddBreakpointID (const char *bp_id_str)
75254721Semaste{
76254721Semaste    BreakpointID temp_bp_id;
77254721Semaste    break_id_t bp_id;
78254721Semaste    break_id_t loc_id;
79254721Semaste
80254721Semaste    bool success = BreakpointID::ParseCanonicalReference (bp_id_str, &bp_id, &loc_id);
81254721Semaste
82254721Semaste    if (success)
83254721Semaste    {
84254721Semaste        temp_bp_id.SetID (bp_id, loc_id);
85254721Semaste        m_breakpoint_ids.push_back (temp_bp_id);
86254721Semaste    }
87254721Semaste
88254721Semaste    return success;
89254721Semaste}
90254721Semaste
91254721Semastebool
92254721SemasteBreakpointIDList::FindBreakpointID (BreakpointID &bp_id, size_t *position)
93254721Semaste{
94254721Semaste    for (size_t i = 0; i < m_breakpoint_ids.size(); ++i)
95254721Semaste    {
96254721Semaste        BreakpointID tmp_id = m_breakpoint_ids[i];
97254721Semaste        if (tmp_id.GetBreakpointID() == bp_id.GetBreakpointID()
98254721Semaste            && tmp_id.GetLocationID() == bp_id.GetLocationID())
99254721Semaste        {
100254721Semaste            *position = i;
101254721Semaste            return true;
102254721Semaste        }
103254721Semaste    }
104254721Semaste
105254721Semaste    return false;
106254721Semaste}
107254721Semaste
108254721Semastebool
109254721SemasteBreakpointIDList::FindBreakpointID (const char *bp_id_str, size_t *position)
110254721Semaste{
111254721Semaste    BreakpointID temp_bp_id;
112254721Semaste    break_id_t bp_id;
113254721Semaste    break_id_t loc_id;
114254721Semaste
115254721Semaste    if (BreakpointID::ParseCanonicalReference (bp_id_str, &bp_id, &loc_id))
116254721Semaste    {
117254721Semaste        temp_bp_id.SetID (bp_id, loc_id);
118254721Semaste        return FindBreakpointID (temp_bp_id, position);
119254721Semaste    }
120254721Semaste    else
121254721Semaste        return false;
122254721Semaste}
123254721Semaste
124254721Semastevoid
125254721SemasteBreakpointIDList::InsertStringArray (const char **string_array, size_t array_size, CommandReturnObject &result)
126254721Semaste{
127254721Semaste    if (string_array == NULL)
128254721Semaste        return;
129254721Semaste
130254721Semaste    for (uint32_t i = 0; i < array_size; ++i)
131254721Semaste    {
132254721Semaste        break_id_t bp_id;
133254721Semaste        break_id_t loc_id;
134254721Semaste
135254721Semaste        if (BreakpointID::ParseCanonicalReference (string_array[i], &bp_id, &loc_id))
136254721Semaste        {
137254721Semaste            if (bp_id != LLDB_INVALID_BREAK_ID)
138254721Semaste            {
139254721Semaste                BreakpointID temp_bp_id(bp_id, loc_id);
140254721Semaste                m_breakpoint_ids.push_back (temp_bp_id);
141254721Semaste            }
142254721Semaste            else
143254721Semaste            {
144254721Semaste                result.AppendErrorWithFormat ("'%s' is not a valid breakpoint ID.\n", string_array[i]);
145254721Semaste                result.SetStatus (eReturnStatusFailed);
146254721Semaste                return;
147254721Semaste            }
148254721Semaste        }
149254721Semaste    }
150254721Semaste    result.SetStatus (eReturnStatusSuccessFinishNoResult);
151254721Semaste}
152254721Semaste
153254721Semaste
154254721Semaste//  This function takes OLD_ARGS, which is usually the result of breaking the command string arguments into
155254721Semaste//  an array of space-separated strings, and searches through the arguments for any breakpoint ID range specifiers.
156254721Semaste//  Any string in the array that is not part of an ID range specifier is copied directly into NEW_ARGS.  If any
157254721Semaste//  ID range specifiers are found, the range is interpreted and a list of canonical breakpoint IDs corresponding to
158254721Semaste//  all the current breakpoints and locations in the range are added to NEW_ARGS.  When this function is done,
159254721Semaste//  NEW_ARGS should be a copy of OLD_ARGS, with and ID range specifiers replaced by the members of the range.
160254721Semaste
161254721Semastevoid
162254721SemasteBreakpointIDList::FindAndReplaceIDRanges (Args &old_args, Target *target, CommandReturnObject &result,
163254721Semaste                                          Args &new_args)
164254721Semaste{
165254721Semaste    std::string range_start;
166254721Semaste    const char *range_end;
167254721Semaste    const char *current_arg;
168254721Semaste    const size_t num_old_args = old_args.GetArgumentCount();
169254721Semaste
170254721Semaste    for (size_t i = 0; i < num_old_args; ++i)
171254721Semaste    {
172254721Semaste        bool is_range = false;
173254721Semaste        current_arg = old_args.GetArgumentAtIndex (i);
174254721Semaste
175254721Semaste        size_t range_start_len = 0;
176254721Semaste        size_t range_end_pos = 0;
177254721Semaste        if (BreakpointIDList::StringContainsIDRangeExpression (current_arg, &range_start_len, &range_end_pos))
178254721Semaste        {
179254721Semaste            is_range = true;
180254721Semaste            range_start.assign (current_arg, range_start_len);
181254721Semaste            range_end = current_arg + range_end_pos;
182254721Semaste        }
183254721Semaste        else if ((i + 2 < num_old_args)
184254721Semaste                 && BreakpointID::IsRangeIdentifier (old_args.GetArgumentAtIndex (i+1))
185254721Semaste                 && BreakpointID::IsValidIDExpression (current_arg)
186254721Semaste                 && BreakpointID::IsValidIDExpression (old_args.GetArgumentAtIndex (i+2)))
187254721Semaste        {
188254721Semaste            range_start.assign (current_arg);
189254721Semaste            range_end = old_args.GetArgumentAtIndex (i+2);
190254721Semaste            is_range = true;
191254721Semaste            i = i+2;
192254721Semaste        }
193254721Semaste        else
194254721Semaste        {
195254721Semaste            // See if user has specified id.*
196254721Semaste            std::string tmp_str = old_args.GetArgumentAtIndex (i);
197254721Semaste            size_t pos = tmp_str.find ('.');
198254721Semaste            if (pos != std::string::npos)
199254721Semaste            {
200254721Semaste                std::string bp_id_str = tmp_str.substr (0, pos);
201254721Semaste                if (BreakpointID::IsValidIDExpression (bp_id_str.c_str())
202254721Semaste                    && tmp_str[pos+1] == '*'
203254721Semaste                    && tmp_str.length() == (pos + 2))
204254721Semaste                {
205254721Semaste                    break_id_t bp_id;
206254721Semaste                    break_id_t bp_loc_id;
207254721Semaste
208254721Semaste                    BreakpointID::ParseCanonicalReference (bp_id_str.c_str(), &bp_id, &bp_loc_id);
209254721Semaste                    BreakpointSP breakpoint_sp = target->GetBreakpointByID (bp_id);
210254721Semaste                    if (! breakpoint_sp)
211254721Semaste                    {
212254721Semaste                        new_args.Clear();
213254721Semaste                        result.AppendErrorWithFormat ("'%d' is not a valid breakpoint ID.\n", bp_id);
214254721Semaste                        result.SetStatus (eReturnStatusFailed);
215254721Semaste                        return;
216254721Semaste                    }
217254721Semaste                    const size_t num_locations = breakpoint_sp->GetNumLocations();
218254721Semaste                    for (size_t j = 0; j < num_locations; ++j)
219254721Semaste                    {
220254721Semaste                        BreakpointLocation *bp_loc = breakpoint_sp->GetLocationAtIndex(j).get();
221254721Semaste                        StreamString canonical_id_str;
222254721Semaste                        BreakpointID::GetCanonicalReference (&canonical_id_str, bp_id, bp_loc->GetID());
223254721Semaste                        new_args.AppendArgument (canonical_id_str.GetData());
224254721Semaste                    }
225254721Semaste                }
226254721Semaste
227254721Semaste            }
228254721Semaste        }
229254721Semaste
230254721Semaste        if (is_range)
231254721Semaste        {
232254721Semaste            break_id_t start_bp_id;
233254721Semaste            break_id_t end_bp_id;
234254721Semaste            break_id_t start_loc_id;
235254721Semaste            break_id_t end_loc_id;
236254721Semaste
237254721Semaste            BreakpointID::ParseCanonicalReference (range_start.c_str(), &start_bp_id, &start_loc_id);
238254721Semaste            BreakpointID::ParseCanonicalReference (range_end, &end_bp_id, &end_loc_id);
239254721Semaste
240254721Semaste            if ((start_bp_id == LLDB_INVALID_BREAK_ID)
241254721Semaste                || (! target->GetBreakpointByID (start_bp_id)))
242254721Semaste            {
243254721Semaste                new_args.Clear();
244254721Semaste                result.AppendErrorWithFormat ("'%s' is not a valid breakpoint ID.\n", range_start.c_str());
245254721Semaste                result.SetStatus (eReturnStatusFailed);
246254721Semaste                return;
247254721Semaste            }
248254721Semaste
249254721Semaste            if ((end_bp_id == LLDB_INVALID_BREAK_ID)
250254721Semaste                || (! target->GetBreakpointByID (end_bp_id)))
251254721Semaste            {
252254721Semaste                new_args.Clear();
253254721Semaste                result.AppendErrorWithFormat ("'%s' is not a valid breakpoint ID.\n", range_end);
254254721Semaste                result.SetStatus (eReturnStatusFailed);
255254721Semaste                return;
256254721Semaste            }
257254721Semaste
258254721Semaste
259254721Semaste            if (((start_loc_id == LLDB_INVALID_BREAK_ID)
260254721Semaste                 && (end_loc_id != LLDB_INVALID_BREAK_ID))
261254721Semaste                || ((start_loc_id != LLDB_INVALID_BREAK_ID)
262254721Semaste                    && (end_loc_id == LLDB_INVALID_BREAK_ID)))
263254721Semaste            {
264254721Semaste                new_args.Clear ();
265254721Semaste                result.AppendErrorWithFormat ("Invalid breakpoint id range:  Either both ends of range must specify"
266254721Semaste                                              " a breakpoint location, or neither can specify a breakpoint location.\n");
267254721Semaste                result.SetStatus (eReturnStatusFailed);
268254721Semaste                return;
269254721Semaste            }
270254721Semaste
271254721Semaste            // We have valid range starting & ending breakpoint IDs.  Go through all the breakpoints in the
272254721Semaste            // target and find all the breakpoints that fit into this range, and add them to new_args.
273254721Semaste
274254721Semaste            // Next check to see if we have location id's.  If so, make sure the start_bp_id and end_bp_id are
275254721Semaste            // for the same breakpoint; otherwise we have an illegal range: breakpoint id ranges that specify
276254721Semaste            // bp locations are NOT allowed to cross major bp id numbers.
277254721Semaste
278254721Semaste            if  ((start_loc_id != LLDB_INVALID_BREAK_ID)
279254721Semaste                || (end_loc_id != LLDB_INVALID_BREAK_ID))
280254721Semaste            {
281254721Semaste                if (start_bp_id != end_bp_id)
282254721Semaste                {
283254721Semaste                    new_args.Clear();
284254721Semaste                    result.AppendErrorWithFormat ("Invalid range: Ranges that specify particular breakpoint locations"
285254721Semaste                                                  " must be within the same major breakpoint; you specified two"
286254721Semaste                                                  " different major breakpoints, %d and %d.\n",
287254721Semaste                                                  start_bp_id, end_bp_id);
288254721Semaste                    result.SetStatus (eReturnStatusFailed);
289254721Semaste                    return;
290254721Semaste                }
291254721Semaste            }
292254721Semaste
293254721Semaste            const BreakpointList& breakpoints = target->GetBreakpointList();
294254721Semaste            const size_t num_breakpoints = breakpoints.GetSize();
295254721Semaste            for (size_t j = 0; j < num_breakpoints; ++j)
296254721Semaste            {
297254721Semaste                Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex (j).get();
298254721Semaste                break_id_t cur_bp_id = breakpoint->GetID();
299254721Semaste
300254721Semaste                if ((cur_bp_id < start_bp_id) || (cur_bp_id > end_bp_id))
301254721Semaste                    continue;
302254721Semaste
303254721Semaste                const size_t num_locations = breakpoint->GetNumLocations();
304254721Semaste
305254721Semaste                if ((cur_bp_id == start_bp_id) && (start_loc_id != LLDB_INVALID_BREAK_ID))
306254721Semaste                {
307254721Semaste                    for (size_t k = 0; k < num_locations; ++k)
308254721Semaste                    {
309254721Semaste                        BreakpointLocation * bp_loc = breakpoint->GetLocationAtIndex(k).get();
310254721Semaste                        if ((bp_loc->GetID() >= start_loc_id) && (bp_loc->GetID() <= end_loc_id))
311254721Semaste                        {
312254721Semaste                            StreamString canonical_id_str;
313254721Semaste                            BreakpointID::GetCanonicalReference (&canonical_id_str, cur_bp_id, bp_loc->GetID());
314254721Semaste                            new_args.AppendArgument (canonical_id_str.GetData());
315254721Semaste                        }
316254721Semaste                    }
317254721Semaste                }
318254721Semaste                else if ((cur_bp_id == end_bp_id) && (end_loc_id != LLDB_INVALID_BREAK_ID))
319254721Semaste                {
320254721Semaste                    for (size_t k = 0; k < num_locations; ++k)
321254721Semaste                    {
322254721Semaste                        BreakpointLocation * bp_loc = breakpoint->GetLocationAtIndex(k).get();
323254721Semaste                        if (bp_loc->GetID() <= end_loc_id)
324254721Semaste                        {
325254721Semaste                            StreamString canonical_id_str;
326254721Semaste                            BreakpointID::GetCanonicalReference (&canonical_id_str, cur_bp_id, bp_loc->GetID());
327254721Semaste                            new_args.AppendArgument (canonical_id_str.GetData());
328254721Semaste                        }
329254721Semaste                    }
330254721Semaste                }
331254721Semaste                else
332254721Semaste                {
333254721Semaste                    StreamString canonical_id_str;
334254721Semaste                    BreakpointID::GetCanonicalReference (&canonical_id_str, cur_bp_id, LLDB_INVALID_BREAK_ID);
335254721Semaste                    new_args.AppendArgument (canonical_id_str.GetData());
336254721Semaste                }
337254721Semaste            }
338254721Semaste        }
339254721Semaste        else  // else is_range was false
340254721Semaste        {
341254721Semaste            new_args.AppendArgument (current_arg);
342254721Semaste        }
343254721Semaste    }
344254721Semaste
345254721Semaste    result.SetStatus (eReturnStatusSuccessFinishNoResult);
346254721Semaste    return;
347254721Semaste}
348254721Semaste
349254721Semastebool
350254721SemasteBreakpointIDList::StringContainsIDRangeExpression (const char *in_string,
351254721Semaste                                                   size_t *range_start_len,
352254721Semaste                                                   size_t *range_end_pos)
353254721Semaste{
354254721Semaste    bool is_range_expression = false;
355254721Semaste    std::string arg_str = in_string;
356254721Semaste    std::string::size_type idx;
357254721Semaste    std::string::size_type start_pos = 0;
358254721Semaste
359254721Semaste    *range_start_len = 0;
360254721Semaste    *range_end_pos = 0;
361254721Semaste
362254721Semaste    int specifiers_size = 0;
363254721Semaste    for (int i = 0; BreakpointID::g_range_specifiers[i] != NULL; ++i)
364254721Semaste        ++specifiers_size;
365254721Semaste
366254721Semaste    for (int i = 0; i < specifiers_size && !is_range_expression; ++i)
367254721Semaste    {
368254721Semaste        const char *specifier_str = BreakpointID::g_range_specifiers[i];
369254721Semaste        size_t len = strlen (specifier_str);
370254721Semaste        idx = arg_str.find (BreakpointID::g_range_specifiers[i]);
371254721Semaste        if (idx != std::string::npos)
372254721Semaste        {
373254721Semaste            *range_start_len = idx - start_pos;
374254721Semaste            std::string start_str = arg_str.substr (start_pos, *range_start_len);
375254721Semaste            if (idx + len < arg_str.length())
376254721Semaste            {
377254721Semaste                *range_end_pos = idx + len;
378254721Semaste                std::string end_str = arg_str.substr (*range_end_pos);
379254721Semaste                if (BreakpointID::IsValidIDExpression (start_str.c_str())
380254721Semaste                    && BreakpointID::IsValidIDExpression (end_str.c_str()))
381254721Semaste                {
382254721Semaste                    is_range_expression = true;
383254721Semaste                    //*range_start = start_str;
384254721Semaste                    //*range_end = end_str;
385254721Semaste                }
386254721Semaste            }
387254721Semaste        }
388254721Semaste    }
389254721Semaste
390254721Semaste    if (!is_range_expression)
391254721Semaste    {
392254721Semaste        *range_start_len = 0;
393254721Semaste        *range_end_pos = 0;
394254721Semaste    }
395254721Semaste
396254721Semaste    return is_range_expression;
397254721Semaste}
398