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