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