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