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 "lldb/Breakpoint/BreakpointLocation.h"
17 #include "lldb/Core/Log.h"
18 #include "lldb/Core/Module.h"
19 #include "lldb/Core/StreamString.h"
20 #include "lldb/Symbol/Block.h"
21 #include "lldb/Symbol/Function.h"
22 #include "lldb/Symbol/Symbol.h"
23 #include "lldb/Symbol/SymbolContext.h"
24 #include "Plugins/Language/ObjC/ObjCLanguage.h"
25 
26 using namespace lldb;
27 using namespace lldb_private;
28 
29 BreakpointResolverName::BreakpointResolverName (Breakpoint *bkpt,
30                                                 const char *name_cstr,
31                                                 uint32_t name_type_mask,
32                                                 LanguageType language,
33                                                 Breakpoint::MatchType type,
34                                                 lldb::addr_t offset,
35                                                 bool skip_prologue) :
36     BreakpointResolver (bkpt, BreakpointResolver::NameResolver, offset),
37     m_class_name (),
38     m_regex (),
39     m_match_type (type),
40     m_language (language),
41     m_skip_prologue (skip_prologue)
42 {
43     if (m_match_type == Breakpoint::Regexp)
44     {
45         if (!m_regex.Compile (name_cstr))
46         {
47             Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
48 
49             if (log)
50                 log->Warning ("function name regexp: \"%s\" did not compile.", name_cstr);
51         }
52     }
53     else
54     {
55         AddNameLookup (ConstString(name_cstr), name_type_mask);
56     }
57 }
58 
59 BreakpointResolverName::BreakpointResolverName (Breakpoint *bkpt,
60                                                 const char *names[],
61                                                 size_t num_names,
62                                                 uint32_t name_type_mask,
63                                                 LanguageType language,
64                                                 lldb::addr_t offset,
65                                                 bool skip_prologue) :
66     BreakpointResolver (bkpt, BreakpointResolver::NameResolver, offset),
67     m_match_type (Breakpoint::Exact),
68     m_language (language),
69     m_skip_prologue (skip_prologue)
70 {
71     for (size_t i = 0; i < num_names; i++)
72     {
73         AddNameLookup (ConstString (names[i]), name_type_mask);
74     }
75 }
76 
77 BreakpointResolverName::BreakpointResolverName (Breakpoint *bkpt,
78                                                 std::vector<std::string> names,
79                                                 uint32_t name_type_mask,
80                                                 LanguageType language,
81                                                 lldb::addr_t offset,
82                                                 bool skip_prologue) :
83     BreakpointResolver (bkpt, BreakpointResolver::NameResolver, offset),
84     m_match_type (Breakpoint::Exact),
85     m_language (language),
86     m_skip_prologue (skip_prologue)
87 {
88     for (const std::string& name : names)
89     {
90         AddNameLookup (ConstString (name.c_str(), name.size()), name_type_mask);
91     }
92 }
93 
94 BreakpointResolverName::BreakpointResolverName (Breakpoint *bkpt,
95                                                 RegularExpression &func_regex,
96                                                 lldb::LanguageType language,
97                                                 lldb::addr_t offset,
98                                                 bool skip_prologue) :
99     BreakpointResolver (bkpt, BreakpointResolver::NameResolver, offset),
100     m_class_name (nullptr),
101     m_regex (func_regex),
102     m_match_type (Breakpoint::Regexp),
103     m_language (language),
104     m_skip_prologue (skip_prologue)
105 {
106 }
107 
108 BreakpointResolverName::BreakpointResolverName
109 (
110     Breakpoint *bkpt,
111     const char *class_name,
112     const char *method,
113     Breakpoint::MatchType type,
114     lldb::addr_t offset,
115     bool skip_prologue
116 ) :
117     BreakpointResolver (bkpt, BreakpointResolver::NameResolver, offset),
118     m_class_name (class_name),
119     m_regex (),
120     m_match_type (type),
121     m_language (eLanguageTypeUnknown),
122     m_skip_prologue (skip_prologue)
123 {
124     LookupInfo lookup;
125     lookup.name.SetCString(method);
126     lookup.lookup_name = lookup.name;
127     lookup.name_type_mask = eFunctionNameTypeMethod;
128     lookup.match_name_after_lookup = false;
129     m_lookups.push_back (lookup);
130 }
131 
132 BreakpointResolverName::~BreakpointResolverName() = default;
133 
134 BreakpointResolverName::BreakpointResolverName(const BreakpointResolverName &rhs) :
135     BreakpointResolver(rhs.m_breakpoint, BreakpointResolver::NameResolver, rhs.m_offset),
136     m_lookups(rhs.m_lookups),
137     m_class_name(rhs.m_class_name),
138     m_regex(rhs.m_regex),
139     m_match_type (rhs.m_match_type),
140     m_language (rhs.m_language),
141     m_skip_prologue (rhs.m_skip_prologue)
142 {
143 }
144 
145 void
146 BreakpointResolverName::AddNameLookup (const ConstString &name, uint32_t name_type_mask)
147 {
148     ObjCLanguage::MethodName objc_method(name.GetCString(), false);
149     if (objc_method.IsValid(false))
150     {
151         std::vector<ConstString> objc_names;
152         objc_method.GetFullNames(objc_names, true);
153         for (ConstString objc_name : objc_names)
154         {
155             LookupInfo lookup;
156             lookup.name = name;
157             lookup.lookup_name = objc_name;
158             lookup.name_type_mask = eFunctionNameTypeFull;
159             lookup.match_name_after_lookup = false;
160             m_lookups.push_back (lookup);
161         }
162     }
163     else
164     {
165         LookupInfo lookup;
166         lookup.name = name;
167         Module::PrepareForFunctionNameLookup(lookup.name, name_type_mask, m_language, lookup.lookup_name, lookup.name_type_mask, lookup.match_name_after_lookup);
168         m_lookups.push_back (lookup);
169     }
170 }
171 
172 void
173 BreakpointResolverName::LookupInfo::Prune (SymbolContextList &sc_list, size_t start_idx) const
174 {
175     if (match_name_after_lookup && name)
176     {
177         SymbolContext sc;
178         size_t i = start_idx;
179         while (i < sc_list.GetSize())
180         {
181             if (!sc_list.GetContextAtIndex(i, sc))
182                 break;
183             ConstString full_name (sc.GetFunctionName());
184             if (full_name && ::strstr(full_name.GetCString(), name.GetCString()) == nullptr)
185             {
186                 sc_list.RemoveContextAtIndex(i);
187             }
188             else
189             {
190                 ++i;
191             }
192         }
193     }
194 }
195 
196 // FIXME: Right now we look at the module level, and call the module's "FindFunctions".
197 // Greg says he will add function tables, maybe at the CompileUnit level to accelerate function
198 // lookup.  At that point, we should switch the depth to CompileUnit, and look in these tables.
199 
200 Searcher::CallbackReturn
201 BreakpointResolverName::SearchCallback(SearchFilter &filter,
202                                        SymbolContext &context,
203                                        Address *addr,
204                                        bool containing)
205 {
206     SymbolContextList func_list;
207     //SymbolContextList sym_list;
208 
209     uint32_t i;
210     bool new_location;
211     Address break_addr;
212     assert (m_breakpoint != nullptr);
213 
214     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
215 
216     if (m_class_name)
217     {
218         if (log)
219             log->Warning ("Class/method function specification not supported yet.\n");
220         return Searcher::eCallbackReturnStop;
221     }
222     bool filter_by_cu = (filter.GetFilterRequiredItems() & eSymbolContextCompUnit) != 0;
223     bool filter_by_language = (m_language != eLanguageTypeUnknown);
224     const bool include_symbols = !filter_by_cu;
225     const bool include_inlines = true;
226     const bool append = true;
227 
228     switch (m_match_type)
229     {
230         case Breakpoint::Exact:
231             if (context.module_sp)
232             {
233                 for (const LookupInfo &lookup : m_lookups)
234                 {
235                     const size_t start_func_idx = func_list.GetSize();
236                     context.module_sp->FindFunctions(lookup.lookup_name,
237                                                      nullptr,
238                                                      lookup.name_type_mask,
239                                                      include_symbols,
240                                                      include_inlines,
241                                                      append,
242                                                      func_list);
243                     const size_t end_func_idx = func_list.GetSize();
244 
245                     if (start_func_idx < end_func_idx)
246                         lookup.Prune (func_list, start_func_idx);
247                 }
248             }
249             break;
250         case Breakpoint::Regexp:
251             if (context.module_sp)
252             {
253                 context.module_sp->FindFunctions (m_regex,
254                                                   !filter_by_cu, // include symbols only if we aren't filtering by CU
255                                                   include_inlines,
256                                                   append,
257                                                   func_list);
258             }
259             break;
260         case Breakpoint::Glob:
261             if (log)
262                 log->Warning ("glob is not supported yet.");
263             break;
264     }
265 
266     // If the filter specifies a Compilation Unit, remove the ones that don't pass at this point.
267     if (filter_by_cu || filter_by_language)
268     {
269         uint32_t num_functions = func_list.GetSize();
270 
271         for (size_t idx = 0; idx < num_functions; idx++)
272         {
273             bool remove_it = false;
274             SymbolContext sc;
275             func_list.GetContextAtIndex(idx, sc);
276             if (filter_by_cu)
277             {
278                 if (!sc.comp_unit || !filter.CompUnitPasses(*sc.comp_unit))
279                     remove_it = true;
280             }
281 
282             if (filter_by_language)
283             {
284                 LanguageType sym_language = sc.GetLanguage();
285                 if ((Language::GetPrimaryLanguage(sym_language) !=
286                      Language::GetPrimaryLanguage(m_language)) &&
287                     (sym_language != eLanguageTypeUnknown))
288                 {
289                     remove_it = true;
290                 }
291             }
292 
293             if  (remove_it)
294             {
295                 func_list.RemoveContextAtIndex(idx);
296                 num_functions--;
297                 idx--;
298             }
299         }
300     }
301 
302     // Remove any duplicates between the function list and the symbol list
303     SymbolContext sc;
304     if (func_list.GetSize())
305     {
306         for (i = 0; i < func_list.GetSize(); i++)
307         {
308             if (func_list.GetContextAtIndex(i, sc))
309             {
310                 bool is_reexported = false;
311 
312                 if (sc.block && sc.block->GetInlinedFunctionInfo())
313                 {
314                     if (!sc.block->GetStartAddress(break_addr))
315                         break_addr.Clear();
316                 }
317                 else if (sc.function)
318                 {
319                     break_addr = sc.function->GetAddressRange().GetBaseAddress();
320                     if (m_skip_prologue && break_addr.IsValid())
321                     {
322                         const uint32_t prologue_byte_size = sc.function->GetPrologueByteSize();
323                         if (prologue_byte_size)
324                             break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size);
325                     }
326                 }
327                 else if (sc.symbol)
328                 {
329                     if (sc.symbol->GetType() == eSymbolTypeReExported)
330                     {
331                         const Symbol *actual_symbol = sc.symbol->ResolveReExportedSymbol(m_breakpoint->GetTarget());
332                         if (actual_symbol)
333                         {
334                             is_reexported = true;
335                             break_addr = actual_symbol->GetAddress();
336                         }
337                     }
338                     else
339                     {
340                         break_addr = sc.symbol->GetAddress();
341                     }
342 
343                     if (m_skip_prologue && break_addr.IsValid())
344                     {
345                         const uint32_t prologue_byte_size = sc.symbol->GetPrologueByteSize();
346                         if (prologue_byte_size)
347                             break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size);
348                     }
349                 }
350 
351                 if (break_addr.IsValid())
352                 {
353                     if (filter.AddressPasses(break_addr))
354                     {
355                         BreakpointLocationSP bp_loc_sp (AddLocation(break_addr, &new_location));
356                         bp_loc_sp->SetIsReExported(is_reexported);
357                         if (bp_loc_sp && new_location && !m_breakpoint->IsInternal())
358                         {
359                             if (log)
360                             {
361                                 StreamString s;
362                                 bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
363                                 log->Printf ("Added location: %s\n", s.GetData());
364                             }
365                         }
366                     }
367                 }
368             }
369         }
370     }
371 
372     return Searcher::eCallbackReturnContinue;
373 }
374 
375 Searcher::Depth
376 BreakpointResolverName::GetDepth()
377 {
378     return Searcher::eDepthModule;
379 }
380 
381 void
382 BreakpointResolverName::GetDescription (Stream *s)
383 {
384     if (m_match_type == Breakpoint::Regexp)
385         s->Printf("regex = '%s'", m_regex.GetText());
386     else
387     {
388         size_t num_names = m_lookups.size();
389         if (num_names == 1)
390             s->Printf("name = '%s'", m_lookups[0].name.GetCString());
391         else
392         {
393             s->Printf("names = {");
394             for (size_t i = 0; i < num_names - 1; i++)
395             {
396                 s->Printf ("'%s', ", m_lookups[i].name.GetCString());
397             }
398             s->Printf ("'%s'}", m_lookups[num_names - 1].name.GetCString());
399         }
400     }
401     if (m_language != eLanguageTypeUnknown)
402     {
403         s->Printf (", language = %s", Language::GetNameForLanguageType(m_language));
404     }
405 }
406 
407 void
408 BreakpointResolverName::Dump (Stream *s) const
409 {
410 }
411 
412 lldb::BreakpointResolverSP
413 BreakpointResolverName::CopyForBreakpoint (Breakpoint &breakpoint)
414 {
415     lldb::BreakpointResolverSP ret_sp(new BreakpointResolverName(*this));
416     ret_sp->SetBreakpoint(&breakpoint);
417     return ret_sp;
418 }
419