1 | //===-- BreakpointID.cpp --------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include <cstdio> |
10 | #include <optional> |
11 | |
12 | #include "lldb/Breakpoint/Breakpoint.h" |
13 | #include "lldb/Breakpoint/BreakpointID.h" |
14 | #include "lldb/Utility/Status.h" |
15 | #include "lldb/Utility/Stream.h" |
16 | |
17 | using namespace lldb; |
18 | using namespace lldb_private; |
19 | |
20 | BreakpointID::BreakpointID(break_id_t bp_id, break_id_t loc_id) |
21 | : m_break_id(bp_id), m_location_id(loc_id) {} |
22 | |
23 | BreakpointID::~BreakpointID() = default; |
24 | |
25 | static llvm::StringRef g_range_specifiers[] = {"-" , "to" , "To" , "TO" }; |
26 | |
27 | // Tells whether or not STR is valid to use between two strings representing |
28 | // breakpoint IDs, to indicate a range of breakpoint IDs. This is broken out |
29 | // into a separate function so that we can easily change or add to the format |
30 | // for specifying ID ranges at a later date. |
31 | |
32 | bool BreakpointID::IsRangeIdentifier(llvm::StringRef str) { |
33 | return llvm::is_contained(Range&: g_range_specifiers, Element: str); |
34 | } |
35 | |
36 | bool BreakpointID::IsValidIDExpression(llvm::StringRef str) { |
37 | return BreakpointID::ParseCanonicalReference(input: str).has_value(); |
38 | } |
39 | |
40 | llvm::ArrayRef<llvm::StringRef> BreakpointID::GetRangeSpecifiers() { |
41 | return llvm::ArrayRef(g_range_specifiers); |
42 | } |
43 | |
44 | void BreakpointID::GetDescription(Stream *s, lldb::DescriptionLevel level) { |
45 | if (level == eDescriptionLevelVerbose) |
46 | s->Printf(format: "%p BreakpointID:" , static_cast<void *>(this)); |
47 | |
48 | if (m_break_id == LLDB_INVALID_BREAK_ID) |
49 | s->PutCString(cstr: "<invalid>" ); |
50 | else if (m_location_id == LLDB_INVALID_BREAK_ID) |
51 | s->Printf(format: "%i" , m_break_id); |
52 | else |
53 | s->Printf(format: "%i.%i" , m_break_id, m_location_id); |
54 | } |
55 | |
56 | void BreakpointID::GetCanonicalReference(Stream *s, break_id_t bp_id, |
57 | break_id_t loc_id) { |
58 | if (bp_id == LLDB_INVALID_BREAK_ID) |
59 | s->PutCString(cstr: "<invalid>" ); |
60 | else if (loc_id == LLDB_INVALID_BREAK_ID) |
61 | s->Printf(format: "%i" , bp_id); |
62 | else |
63 | s->Printf(format: "%i.%i" , bp_id, loc_id); |
64 | } |
65 | |
66 | std::optional<BreakpointID> |
67 | BreakpointID::ParseCanonicalReference(llvm::StringRef input) { |
68 | break_id_t bp_id; |
69 | break_id_t loc_id = LLDB_INVALID_BREAK_ID; |
70 | |
71 | if (input.empty()) |
72 | return std::nullopt; |
73 | |
74 | // If it doesn't start with an integer, it's not valid. |
75 | if (input.consumeInteger(Radix: 0, Result&: bp_id)) |
76 | return std::nullopt; |
77 | |
78 | // period is optional, but if it exists, it must be followed by a number. |
79 | if (input.consume_front(Prefix: "." )) { |
80 | if (input.consumeInteger(Radix: 0, Result&: loc_id)) |
81 | return std::nullopt; |
82 | } |
83 | |
84 | // And at the end, the entire string must have been consumed. |
85 | if (!input.empty()) |
86 | return std::nullopt; |
87 | |
88 | return BreakpointID(bp_id, loc_id); |
89 | } |
90 | |
91 | bool BreakpointID::StringIsBreakpointName(llvm::StringRef str, Status &error) { |
92 | error.Clear(); |
93 | if (str.empty()) |
94 | { |
95 | error.SetErrorString("Empty breakpoint names are not allowed" ); |
96 | return false; |
97 | } |
98 | |
99 | // First character must be a letter or _ |
100 | if (!isalpha(str[0]) && str[0] != '_') |
101 | { |
102 | error.SetErrorStringWithFormat("Breakpoint names must start with a " |
103 | "character or underscore: %s" , |
104 | str.str().c_str()); |
105 | return false; |
106 | } |
107 | |
108 | // Cannot contain ., -, or space. |
109 | if (str.find_first_of(Chars: ".- " ) != llvm::StringRef::npos) { |
110 | error.SetErrorStringWithFormat("Breakpoint names cannot contain " |
111 | "'.' or '-' or spaces: \"%s\"" , |
112 | str.str().c_str()); |
113 | return false; |
114 | } |
115 | |
116 | return true; |
117 | } |
118 | |