1 //===-- BreakpointResolverFileRegex.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 "lldb/Breakpoint/BreakpointResolverFileRegex.h" 10 11 #include "lldb/Breakpoint/BreakpointLocation.h" 12 #include "lldb/Core/SourceManager.h" 13 #include "lldb/Symbol/CompileUnit.h" 14 #include "lldb/Target/Target.h" 15 #include "lldb/Utility/Log.h" 16 #include "lldb/Utility/StreamString.h" 17 18 using namespace lldb; 19 using namespace lldb_private; 20 21 // BreakpointResolverFileRegex: 22 BreakpointResolverFileRegex::BreakpointResolverFileRegex( 23 const lldb::BreakpointSP &bkpt, RegularExpression regex, 24 const std::unordered_set<std::string> &func_names, bool exact_match) 25 : BreakpointResolver(bkpt, BreakpointResolver::FileRegexResolver), 26 m_regex(std::move(regex)), m_exact_match(exact_match), 27 m_function_names(func_names) {} 28 29 BreakpointResolverSP BreakpointResolverFileRegex::CreateFromStructuredData( 30 const StructuredData::Dictionary &options_dict, Status &error) { 31 bool success; 32 33 llvm::StringRef regex_string; 34 success = options_dict.GetValueForKeyAsString( 35 GetKey(OptionNames::RegexString), regex_string); 36 if (!success) { 37 error.SetErrorString("BRFR::CFSD: Couldn't find regex entry."); 38 return nullptr; 39 } 40 RegularExpression regex(regex_string); 41 42 bool exact_match; 43 success = options_dict.GetValueForKeyAsBoolean( 44 GetKey(OptionNames::ExactMatch), exact_match); 45 if (!success) { 46 error.SetErrorString("BRFL::CFSD: Couldn't find exact match entry."); 47 return nullptr; 48 } 49 50 // The names array is optional: 51 std::unordered_set<std::string> names_set; 52 StructuredData::Array *names_array; 53 success = options_dict.GetValueForKeyAsArray( 54 GetKey(OptionNames::SymbolNameArray), names_array); 55 if (success && names_array) { 56 size_t num_names = names_array->GetSize(); 57 for (size_t i = 0; i < num_names; i++) { 58 std::optional<llvm::StringRef> maybe_name = 59 names_array->GetItemAtIndexAsString(i); 60 if (!maybe_name) { 61 error.SetErrorStringWithFormat( 62 "BRFR::CFSD: Malformed element %zu in the names array.", i); 63 return nullptr; 64 } 65 names_set.insert(std::string(*maybe_name)); 66 } 67 } 68 69 return std::make_shared<BreakpointResolverFileRegex>( 70 nullptr, std::move(regex), names_set, exact_match); 71 } 72 73 StructuredData::ObjectSP 74 BreakpointResolverFileRegex::SerializeToStructuredData() { 75 StructuredData::DictionarySP options_dict_sp( 76 new StructuredData::Dictionary()); 77 78 options_dict_sp->AddStringItem(GetKey(OptionNames::RegexString), 79 m_regex.GetText()); 80 options_dict_sp->AddBooleanItem(GetKey(OptionNames::ExactMatch), 81 m_exact_match); 82 if (!m_function_names.empty()) { 83 StructuredData::ArraySP names_array_sp(new StructuredData::Array()); 84 for (std::string name : m_function_names) { 85 StructuredData::StringSP item(new StructuredData::String(name)); 86 names_array_sp->AddItem(item); 87 } 88 options_dict_sp->AddItem(GetKey(OptionNames::LineNumber), names_array_sp); 89 } 90 91 return WrapOptionsDict(options_dict_sp); 92 } 93 94 Searcher::CallbackReturn BreakpointResolverFileRegex::SearchCallback( 95 SearchFilter &filter, SymbolContext &context, Address *addr) { 96 97 if (!context.target_sp) 98 return eCallbackReturnContinue; 99 100 CompileUnit *cu = context.comp_unit; 101 FileSpec cu_file_spec = cu->GetPrimaryFile(); 102 std::vector<uint32_t> line_matches; 103 context.target_sp->GetSourceManager().FindLinesMatchingRegex( 104 cu_file_spec, m_regex, 1, UINT32_MAX, line_matches); 105 106 uint32_t num_matches = line_matches.size(); 107 for (uint32_t i = 0; i < num_matches; i++) { 108 SymbolContextList sc_list; 109 // TODO: Handle SourceLocationSpec column information 110 SourceLocationSpec location_spec(cu_file_spec, line_matches[i], 111 /*column=*/std::nullopt, 112 /*check_inlines=*/false, m_exact_match); 113 cu->ResolveSymbolContext(location_spec, eSymbolContextEverything, sc_list); 114 // Find all the function names: 115 if (!m_function_names.empty()) { 116 std::vector<size_t> sc_to_remove; 117 for (size_t i = 0; i < sc_list.GetSize(); i++) { 118 SymbolContext sc_ctx; 119 sc_list.GetContextAtIndex(i, sc_ctx); 120 std::string name( 121 sc_ctx 122 .GetFunctionName( 123 Mangled::NamePreference::ePreferDemangledWithoutArguments) 124 .AsCString()); 125 if (!m_function_names.count(name)) { 126 sc_to_remove.push_back(i); 127 } 128 } 129 130 if (!sc_to_remove.empty()) { 131 std::vector<size_t>::reverse_iterator iter; 132 std::vector<size_t>::reverse_iterator rend = sc_to_remove.rend(); 133 for (iter = sc_to_remove.rbegin(); iter != rend; iter++) { 134 sc_list.RemoveContextAtIndex(*iter); 135 } 136 } 137 } 138 139 const bool skip_prologue = true; 140 141 BreakpointResolver::SetSCMatchesByLine(filter, sc_list, skip_prologue, 142 m_regex.GetText()); 143 } 144 145 return Searcher::eCallbackReturnContinue; 146 } 147 148 lldb::SearchDepth BreakpointResolverFileRegex::GetDepth() { 149 return lldb::eSearchDepthCompUnit; 150 } 151 152 void BreakpointResolverFileRegex::GetDescription(Stream *s) { 153 s->Printf("source regex = \"%s\", exact_match = %d", 154 m_regex.GetText().str().c_str(), m_exact_match); 155 } 156 157 void BreakpointResolverFileRegex::Dump(Stream *s) const {} 158 159 lldb::BreakpointResolverSP 160 BreakpointResolverFileRegex::CopyForBreakpoint(BreakpointSP &breakpoint) { 161 lldb::BreakpointResolverSP ret_sp(new BreakpointResolverFileRegex( 162 breakpoint, m_regex, m_function_names, m_exact_match)); 163 return ret_sp; 164 } 165 166 void BreakpointResolverFileRegex::AddFunctionName(const char *func_name) { 167 m_function_names.insert(func_name); 168 } 169