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(g_range_specifiers, str); 34 } 35 36 bool BreakpointID::IsValidIDExpression(llvm::StringRef str) { 37 return BreakpointID::ParseCanonicalReference(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("%p BreakpointID:", static_cast<void *>(this)); 47 48 if (m_break_id == LLDB_INVALID_BREAK_ID) 49 s->PutCString("<invalid>"); 50 else if (m_location_id == LLDB_INVALID_BREAK_ID) 51 s->Printf("%i", m_break_id); 52 else 53 s->Printf("%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("<invalid>"); 60 else if (loc_id == LLDB_INVALID_BREAK_ID) 61 s->Printf("%i", bp_id); 62 else 63 s->Printf("%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(0, 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(".")) { 80 if (input.consumeInteger(0, 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(".- ") != 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