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