1dda28197Spatrick //===-- BreakpointID.cpp --------------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9be691f3bSpatrick #include <cstdio>
10*f6aab3d8Srobert #include <optional>
11061da546Spatrick
12061da546Spatrick #include "lldb/Breakpoint/Breakpoint.h"
13061da546Spatrick #include "lldb/Breakpoint/BreakpointID.h"
14061da546Spatrick #include "lldb/Utility/Status.h"
15061da546Spatrick #include "lldb/Utility/Stream.h"
16061da546Spatrick
17061da546Spatrick using namespace lldb;
18061da546Spatrick using namespace lldb_private;
19061da546Spatrick
BreakpointID(break_id_t bp_id,break_id_t loc_id)20061da546Spatrick BreakpointID::BreakpointID(break_id_t bp_id, break_id_t loc_id)
21061da546Spatrick : m_break_id(bp_id), m_location_id(loc_id) {}
22061da546Spatrick
23061da546Spatrick BreakpointID::~BreakpointID() = default;
24061da546Spatrick
25061da546Spatrick static llvm::StringRef g_range_specifiers[] = {"-", "to", "To", "TO"};
26061da546Spatrick
27061da546Spatrick // Tells whether or not STR is valid to use between two strings representing
28061da546Spatrick // breakpoint IDs, to indicate a range of breakpoint IDs. This is broken out
29061da546Spatrick // into a separate function so that we can easily change or add to the format
30061da546Spatrick // for specifying ID ranges at a later date.
31061da546Spatrick
IsRangeIdentifier(llvm::StringRef str)32061da546Spatrick bool BreakpointID::IsRangeIdentifier(llvm::StringRef str) {
33*f6aab3d8Srobert return llvm::is_contained(g_range_specifiers, str);
34061da546Spatrick }
35061da546Spatrick
IsValidIDExpression(llvm::StringRef str)36061da546Spatrick bool BreakpointID::IsValidIDExpression(llvm::StringRef str) {
37*f6aab3d8Srobert return BreakpointID::ParseCanonicalReference(str).has_value();
38061da546Spatrick }
39061da546Spatrick
GetRangeSpecifiers()40061da546Spatrick llvm::ArrayRef<llvm::StringRef> BreakpointID::GetRangeSpecifiers() {
41*f6aab3d8Srobert return llvm::ArrayRef(g_range_specifiers);
42061da546Spatrick }
43061da546Spatrick
GetDescription(Stream * s,lldb::DescriptionLevel level)44061da546Spatrick void BreakpointID::GetDescription(Stream *s, lldb::DescriptionLevel level) {
45061da546Spatrick if (level == eDescriptionLevelVerbose)
46061da546Spatrick s->Printf("%p BreakpointID:", static_cast<void *>(this));
47061da546Spatrick
48061da546Spatrick if (m_break_id == LLDB_INVALID_BREAK_ID)
49061da546Spatrick s->PutCString("<invalid>");
50061da546Spatrick else if (m_location_id == LLDB_INVALID_BREAK_ID)
51061da546Spatrick s->Printf("%i", m_break_id);
52061da546Spatrick else
53061da546Spatrick s->Printf("%i.%i", m_break_id, m_location_id);
54061da546Spatrick }
55061da546Spatrick
GetCanonicalReference(Stream * s,break_id_t bp_id,break_id_t loc_id)56061da546Spatrick void BreakpointID::GetCanonicalReference(Stream *s, break_id_t bp_id,
57061da546Spatrick break_id_t loc_id) {
58061da546Spatrick if (bp_id == LLDB_INVALID_BREAK_ID)
59061da546Spatrick s->PutCString("<invalid>");
60061da546Spatrick else if (loc_id == LLDB_INVALID_BREAK_ID)
61061da546Spatrick s->Printf("%i", bp_id);
62061da546Spatrick else
63061da546Spatrick s->Printf("%i.%i", bp_id, loc_id);
64061da546Spatrick }
65061da546Spatrick
66*f6aab3d8Srobert std::optional<BreakpointID>
ParseCanonicalReference(llvm::StringRef input)67061da546Spatrick BreakpointID::ParseCanonicalReference(llvm::StringRef input) {
68061da546Spatrick break_id_t bp_id;
69061da546Spatrick break_id_t loc_id = LLDB_INVALID_BREAK_ID;
70061da546Spatrick
71061da546Spatrick if (input.empty())
72*f6aab3d8Srobert return std::nullopt;
73061da546Spatrick
74061da546Spatrick // If it doesn't start with an integer, it's not valid.
75061da546Spatrick if (input.consumeInteger(0, bp_id))
76*f6aab3d8Srobert return std::nullopt;
77061da546Spatrick
78061da546Spatrick // period is optional, but if it exists, it must be followed by a number.
79061da546Spatrick if (input.consume_front(".")) {
80061da546Spatrick if (input.consumeInteger(0, loc_id))
81*f6aab3d8Srobert return std::nullopt;
82061da546Spatrick }
83061da546Spatrick
84061da546Spatrick // And at the end, the entire string must have been consumed.
85061da546Spatrick if (!input.empty())
86*f6aab3d8Srobert return std::nullopt;
87061da546Spatrick
88061da546Spatrick return BreakpointID(bp_id, loc_id);
89061da546Spatrick }
90061da546Spatrick
StringIsBreakpointName(llvm::StringRef str,Status & error)91061da546Spatrick bool BreakpointID::StringIsBreakpointName(llvm::StringRef str, Status &error) {
92061da546Spatrick error.Clear();
93061da546Spatrick if (str.empty())
94061da546Spatrick {
95be691f3bSpatrick error.SetErrorString("Empty breakpoint names are not allowed");
96061da546Spatrick return false;
97061da546Spatrick }
98061da546Spatrick
99061da546Spatrick // First character must be a letter or _
100061da546Spatrick if (!isalpha(str[0]) && str[0] != '_')
101061da546Spatrick {
102061da546Spatrick error.SetErrorStringWithFormat("Breakpoint names must start with a "
103061da546Spatrick "character or underscore: %s",
104061da546Spatrick str.str().c_str());
105061da546Spatrick return false;
106061da546Spatrick }
107061da546Spatrick
108061da546Spatrick // Cannot contain ., -, or space.
109061da546Spatrick if (str.find_first_of(".- ") != llvm::StringRef::npos) {
110061da546Spatrick error.SetErrorStringWithFormat("Breakpoint names cannot contain "
111dda28197Spatrick "'.' or '-' or spaces: \"%s\"",
112061da546Spatrick str.str().c_str());
113061da546Spatrick return false;
114061da546Spatrick }
115061da546Spatrick
116061da546Spatrick return true;
117061da546Spatrick }
118