1 //===-- BreakpointID.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 // C Includes
11 #include <stdio.h>
12 
13 // C++ Includes
14 // Other libraries and framework includes
15 // Project includes
16 #include "lldb/Breakpoint/Breakpoint.h"
17 #include "lldb/Breakpoint/BreakpointID.h"
18 #include "lldb/Core/Error.h"
19 #include "lldb/Core/Stream.h"
20 
21 using namespace lldb;
22 using namespace lldb_private;
23 
24 BreakpointID::BreakpointID(break_id_t bp_id, break_id_t loc_id)
25     : m_break_id(bp_id), m_location_id(loc_id) {}
26 
27 BreakpointID::~BreakpointID() = default;
28 
29 const char *BreakpointID::g_range_specifiers[] = {"-", "to", "To", "TO",
30                                                   nullptr};
31 
32 // Tells whether or not STR is valid to use between two strings representing
33 // breakpoint IDs, to
34 // indicate a range of breakpoint IDs.  This is broken out into a separate
35 // function so that we can
36 // easily change or add to the format for specifying ID ranges at a later date.
37 
38 bool BreakpointID::IsRangeIdentifier(const char *str) {
39   int specifier_count = 0;
40   for (int i = 0; g_range_specifiers[i] != nullptr; ++i)
41     ++specifier_count;
42 
43   for (int i = 0; i < specifier_count; ++i) {
44     if (strcmp(g_range_specifiers[i], str) == 0)
45       return true;
46   }
47 
48   return false;
49 }
50 
51 bool BreakpointID::IsValidIDExpression(const char *str) {
52   break_id_t bp_id;
53   break_id_t loc_id;
54   BreakpointID::ParseCanonicalReference(str, &bp_id, &loc_id);
55 
56   return (bp_id != LLDB_INVALID_BREAK_ID);
57 }
58 
59 void BreakpointID::GetDescription(Stream *s, lldb::DescriptionLevel level) {
60   if (level == eDescriptionLevelVerbose)
61     s->Printf("%p BreakpointID:", static_cast<void *>(this));
62 
63   if (m_break_id == LLDB_INVALID_BREAK_ID)
64     s->PutCString("<invalid>");
65   else if (m_location_id == LLDB_INVALID_BREAK_ID)
66     s->Printf("%i", m_break_id);
67   else
68     s->Printf("%i.%i", m_break_id, m_location_id);
69 }
70 
71 void BreakpointID::GetCanonicalReference(Stream *s, break_id_t bp_id,
72                                          break_id_t loc_id) {
73   if (bp_id == LLDB_INVALID_BREAK_ID)
74     s->PutCString("<invalid>");
75   else if (loc_id == LLDB_INVALID_BREAK_ID)
76     s->Printf("%i", bp_id);
77   else
78     s->Printf("%i.%i", bp_id, loc_id);
79 }
80 
81 bool BreakpointID::ParseCanonicalReference(const char *input,
82                                            break_id_t *break_id_ptr,
83                                            break_id_t *break_loc_id_ptr) {
84   *break_id_ptr = LLDB_INVALID_BREAK_ID;
85   *break_loc_id_ptr = LLDB_INVALID_BREAK_ID;
86 
87   if (input == nullptr || *input == '\0')
88     return false;
89 
90   const char *format = "%i%n.%i%n";
91   int chars_consumed_1 = 0;
92   int chars_consumed_2 = 0;
93   int n_items_parsed = ::sscanf(
94       input, format,
95       break_id_ptr,       // %i   parse the breakpoint ID
96       &chars_consumed_1,  // %n   gets the number of characters parsed so far
97       break_loc_id_ptr,   // %i   parse the breakpoint location ID
98       &chars_consumed_2); // %n   gets the number of characters parsed so far
99 
100   if ((n_items_parsed == 1 && input[chars_consumed_1] == '\0') ||
101       (n_items_parsed == 2 && input[chars_consumed_2] == '\0'))
102     return true;
103 
104   // Badly formatted canonical reference.
105   *break_id_ptr = LLDB_INVALID_BREAK_ID;
106   *break_loc_id_ptr = LLDB_INVALID_BREAK_ID;
107   return false;
108 }
109 
110 bool BreakpointID::StringIsBreakpointName(const char *name, Error &error) {
111   error.Clear();
112 
113   if (name && (name[0] >= 'A' && name[0] <= 'z')) {
114     if (strcspn(name, ".- ") != strlen(name)) {
115       error.SetErrorStringWithFormat("invalid breakpoint name: \"%s\"", name);
116     }
117     return true;
118   } else
119     return false;
120 }
121