1 //===-- BreakpointResolverName.cpp ------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 // C Includes
11 // C++ Includes
12 // Other libraries and framework includes
13 // Project includes
14 #include "lldb/Breakpoint/BreakpointResolverName.h"
15 
16 #include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
17 #include "Plugins/Language/ObjC/ObjCLanguage.h"
18 #include "lldb/Breakpoint/BreakpointLocation.h"
19 #include "lldb/Core/Log.h"
20 #include "lldb/Core/Module.h"
21 #include "lldb/Core/StreamString.h"
22 #include "lldb/Symbol/Block.h"
23 #include "lldb/Symbol/Function.h"
24 #include "lldb/Symbol/Symbol.h"
25 #include "lldb/Symbol/SymbolContext.h"
26 
27 using namespace lldb;
28 using namespace lldb_private;
29 
30 BreakpointResolverName::BreakpointResolverName(
31     Breakpoint *bkpt, const char *name_cstr, uint32_t name_type_mask,
32     LanguageType language, Breakpoint::MatchType type, lldb::addr_t offset,
33     bool skip_prologue)
34     : BreakpointResolver(bkpt, BreakpointResolver::NameResolver, offset),
35       m_class_name(), m_regex(), m_match_type(type), m_language(language),
36       m_skip_prologue(skip_prologue) {
37   if (m_match_type == Breakpoint::Regexp) {
38     if (!m_regex.Compile(name_cstr)) {
39       Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
40 
41       if (log)
42         log->Warning("function name regexp: \"%s\" did not compile.",
43                      name_cstr);
44     }
45   } else {
46     AddNameLookup(ConstString(name_cstr), name_type_mask);
47   }
48 }
49 
50 BreakpointResolverName::BreakpointResolverName(
51     Breakpoint *bkpt, const char *names[], size_t num_names,
52     uint32_t name_type_mask, LanguageType language, lldb::addr_t offset,
53     bool skip_prologue)
54     : BreakpointResolver(bkpt, BreakpointResolver::NameResolver, offset),
55       m_match_type(Breakpoint::Exact), m_language(language),
56       m_skip_prologue(skip_prologue) {
57   for (size_t i = 0; i < num_names; i++) {
58     AddNameLookup(ConstString(names[i]), name_type_mask);
59   }
60 }
61 
62 BreakpointResolverName::BreakpointResolverName(
63     Breakpoint *bkpt, std::vector<std::string> names, uint32_t name_type_mask,
64     LanguageType language, lldb::addr_t offset, bool skip_prologue)
65     : BreakpointResolver(bkpt, BreakpointResolver::NameResolver, offset),
66       m_match_type(Breakpoint::Exact), m_language(language),
67       m_skip_prologue(skip_prologue) {
68   for (const std::string &name : names) {
69     AddNameLookup(ConstString(name.c_str(), name.size()), name_type_mask);
70   }
71 }
72 
73 BreakpointResolverName::BreakpointResolverName(Breakpoint *bkpt,
74                                                RegularExpression &func_regex,
75                                                lldb::LanguageType language,
76                                                lldb::addr_t offset,
77                                                bool skip_prologue)
78     : BreakpointResolver(bkpt, BreakpointResolver::NameResolver, offset),
79       m_class_name(nullptr), m_regex(func_regex),
80       m_match_type(Breakpoint::Regexp), m_language(language),
81       m_skip_prologue(skip_prologue) {}
82 
83 BreakpointResolverName::BreakpointResolverName(
84     Breakpoint *bkpt, const char *class_name, const char *method,
85     Breakpoint::MatchType type, lldb::addr_t offset, bool skip_prologue)
86     : BreakpointResolver(bkpt, BreakpointResolver::NameResolver, offset),
87       m_class_name(class_name), m_regex(), m_match_type(type),
88       m_language(eLanguageTypeUnknown), m_skip_prologue(skip_prologue) {
89   Module::LookupInfo lookup;
90   lookup.SetName(ConstString(method));
91   lookup.SetLookupName(lookup.GetName());
92   lookup.SetNameTypeMask(eFunctionNameTypeMethod);
93   m_lookups.push_back(lookup);
94 }
95 
96 BreakpointResolverName::~BreakpointResolverName() = default;
97 
98 BreakpointResolverName::BreakpointResolverName(
99     const BreakpointResolverName &rhs)
100     : BreakpointResolver(rhs.m_breakpoint, BreakpointResolver::NameResolver,
101                          rhs.m_offset),
102       m_lookups(rhs.m_lookups), m_class_name(rhs.m_class_name),
103       m_regex(rhs.m_regex), m_match_type(rhs.m_match_type),
104       m_language(rhs.m_language), m_skip_prologue(rhs.m_skip_prologue) {}
105 
106 void BreakpointResolverName::AddNameLookup(const ConstString &name,
107                                            uint32_t name_type_mask) {
108   ObjCLanguage::MethodName objc_method(name.GetCString(), false);
109   if (objc_method.IsValid(false)) {
110     std::vector<ConstString> objc_names;
111     objc_method.GetFullNames(objc_names, true);
112     for (ConstString objc_name : objc_names) {
113       Module::LookupInfo lookup;
114       lookup.SetName(name);
115       lookup.SetLookupName(objc_name);
116       lookup.SetNameTypeMask(eFunctionNameTypeFull);
117       m_lookups.push_back(lookup);
118     }
119   } else {
120     Module::LookupInfo lookup(name, name_type_mask, m_language);
121     m_lookups.push_back(lookup);
122   }
123 }
124 
125 // FIXME: Right now we look at the module level, and call the module's
126 // "FindFunctions".
127 // Greg says he will add function tables, maybe at the CompileUnit level to
128 // accelerate function
129 // lookup.  At that point, we should switch the depth to CompileUnit, and look
130 // in these tables.
131 
132 Searcher::CallbackReturn
133 BreakpointResolverName::SearchCallback(SearchFilter &filter,
134                                        SymbolContext &context, Address *addr,
135                                        bool containing) {
136   SymbolContextList func_list;
137   // SymbolContextList sym_list;
138 
139   uint32_t i;
140   bool new_location;
141   Address break_addr;
142   assert(m_breakpoint != nullptr);
143 
144   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
145 
146   if (m_class_name) {
147     if (log)
148       log->Warning("Class/method function specification not supported yet.\n");
149     return Searcher::eCallbackReturnStop;
150   }
151   bool filter_by_cu =
152       (filter.GetFilterRequiredItems() & eSymbolContextCompUnit) != 0;
153   bool filter_by_language = (m_language != eLanguageTypeUnknown);
154   const bool include_symbols = !filter_by_cu;
155   const bool include_inlines = true;
156   const bool append = true;
157 
158   switch (m_match_type) {
159   case Breakpoint::Exact:
160     if (context.module_sp) {
161       for (const auto &lookup : m_lookups) {
162         const size_t start_func_idx = func_list.GetSize();
163         context.module_sp->FindFunctions(
164             lookup.GetLookupName(), nullptr, lookup.GetNameTypeMask(),
165             include_symbols, include_inlines, append, func_list);
166 
167         const size_t end_func_idx = func_list.GetSize();
168 
169         if (start_func_idx < end_func_idx)
170           lookup.Prune(func_list, start_func_idx);
171       }
172     }
173     break;
174   case Breakpoint::Regexp:
175     if (context.module_sp) {
176       context.module_sp->FindFunctions(
177           m_regex,
178           !filter_by_cu, // include symbols only if we aren't filtering by CU
179           include_inlines, append, func_list);
180     }
181     break;
182   case Breakpoint::Glob:
183     if (log)
184       log->Warning("glob is not supported yet.");
185     break;
186   }
187 
188   // If the filter specifies a Compilation Unit, remove the ones that don't pass
189   // at this point.
190   if (filter_by_cu || filter_by_language) {
191     uint32_t num_functions = func_list.GetSize();
192 
193     for (size_t idx = 0; idx < num_functions; idx++) {
194       bool remove_it = false;
195       SymbolContext sc;
196       func_list.GetContextAtIndex(idx, sc);
197       if (filter_by_cu) {
198         if (!sc.comp_unit || !filter.CompUnitPasses(*sc.comp_unit))
199           remove_it = true;
200       }
201 
202       if (filter_by_language) {
203         LanguageType sym_language = sc.GetLanguage();
204         if ((Language::GetPrimaryLanguage(sym_language) !=
205              Language::GetPrimaryLanguage(m_language)) &&
206             (sym_language != eLanguageTypeUnknown)) {
207           remove_it = true;
208         }
209       }
210 
211       if (remove_it) {
212         func_list.RemoveContextAtIndex(idx);
213         num_functions--;
214         idx--;
215       }
216     }
217   }
218 
219   // Remove any duplicates between the function list and the symbol list
220   SymbolContext sc;
221   if (func_list.GetSize()) {
222     for (i = 0; i < func_list.GetSize(); i++) {
223       if (func_list.GetContextAtIndex(i, sc)) {
224         bool is_reexported = false;
225 
226         if (sc.block && sc.block->GetInlinedFunctionInfo()) {
227           if (!sc.block->GetStartAddress(break_addr))
228             break_addr.Clear();
229         } else if (sc.function) {
230           break_addr = sc.function->GetAddressRange().GetBaseAddress();
231           if (m_skip_prologue && break_addr.IsValid()) {
232             const uint32_t prologue_byte_size =
233                 sc.function->GetPrologueByteSize();
234             if (prologue_byte_size)
235               break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size);
236           }
237         } else if (sc.symbol) {
238           if (sc.symbol->GetType() == eSymbolTypeReExported) {
239             const Symbol *actual_symbol =
240                 sc.symbol->ResolveReExportedSymbol(m_breakpoint->GetTarget());
241             if (actual_symbol) {
242               is_reexported = true;
243               break_addr = actual_symbol->GetAddress();
244             }
245           } else {
246             break_addr = sc.symbol->GetAddress();
247           }
248 
249           if (m_skip_prologue && break_addr.IsValid()) {
250             const uint32_t prologue_byte_size =
251                 sc.symbol->GetPrologueByteSize();
252             if (prologue_byte_size)
253               break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size);
254           }
255         }
256 
257         if (break_addr.IsValid()) {
258           if (filter.AddressPasses(break_addr)) {
259             BreakpointLocationSP bp_loc_sp(
260                 AddLocation(break_addr, &new_location));
261             bp_loc_sp->SetIsReExported(is_reexported);
262             if (bp_loc_sp && new_location && !m_breakpoint->IsInternal()) {
263               if (log) {
264                 StreamString s;
265                 bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
266                 log->Printf("Added location: %s\n", s.GetData());
267               }
268             }
269           }
270         }
271       }
272     }
273   }
274 
275   return Searcher::eCallbackReturnContinue;
276 }
277 
278 Searcher::Depth BreakpointResolverName::GetDepth() {
279   return Searcher::eDepthModule;
280 }
281 
282 void BreakpointResolverName::GetDescription(Stream *s) {
283   if (m_match_type == Breakpoint::Regexp)
284     s->Printf("regex = '%s'", m_regex.GetText());
285   else {
286     size_t num_names = m_lookups.size();
287     if (num_names == 1)
288       s->Printf("name = '%s'", m_lookups[0].GetName().GetCString());
289     else {
290       s->Printf("names = {");
291       for (size_t i = 0; i < num_names; i++) {
292         s->Printf("%s'%s'", (i == 0 ? "" : ", "),
293                   m_lookups[i].GetName().GetCString());
294       }
295       s->Printf("}");
296     }
297   }
298   if (m_language != eLanguageTypeUnknown) {
299     s->Printf(", language = %s", Language::GetNameForLanguageType(m_language));
300   }
301 }
302 
303 void BreakpointResolverName::Dump(Stream *s) const {}
304 
305 lldb::BreakpointResolverSP
306 BreakpointResolverName::CopyForBreakpoint(Breakpoint &breakpoint) {
307   lldb::BreakpointResolverSP ret_sp(new BreakpointResolverName(*this));
308   ret_sp->SetBreakpoint(&breakpoint);
309   return ret_sp;
310 }
311