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