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/StreamString.h"
19 #include "lldb/Target/Target.h"
20 
21 using namespace lldb;
22 using namespace lldb_private;
23 
24 BreakpointResolverName::BreakpointResolverName
25 (
26     Breakpoint *bkpt,
27     const char *func_name,
28     uint32_t func_name_type_mask,
29     Breakpoint::MatchType type,
30     bool skip_prologue
31 ) :
32     BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
33     m_func_name (),
34     m_basename_filter (),
35     m_func_name_type_mask (func_name_type_mask),
36     m_class_name (),
37     m_regex (),
38     m_match_type (type),
39     m_skip_prologue (skip_prologue)
40 {
41     if (func_name_type_mask == eFunctionNameTypeAuto)
42     {
43         if ((::strchr (func_name, '(' ) != NULL) ||
44             (::strstr (func_name, "-[") == func_name) ||
45             (::strstr (func_name, "+[") == func_name))
46         {
47             // We have a name that contains an open parens, or starts with
48             // "+[" or "-[", so this looks like a complete function prototype
49             m_func_name_type_mask = eFunctionNameTypeFull;
50         }
51         else
52         {
53             // We don't have a full function name, but we might have a partial
54             // function basename with namespaces or classes
55             if (::strstr (func_name, "::") != NULL)
56             {
57                 // Keep the full name in "m_basename_filter"
58                 m_basename_filter = func_name;
59                 // Now set "m_func_name" to just the function basename
60                 m_func_name.SetCString(m_basename_filter.c_str() + m_basename_filter.rfind("::") + 2);
61                 // We have a name with a double colon which means we have a
62                 // function name that is a C++ method or a function in a C++
63                 // namespace
64                 m_func_name_type_mask = eFunctionNameTypeBase | eFunctionNameTypeMethod;
65             }
66             else if (::strstr (func_name, ":") != NULL)
67             {
68                 // Single colon => selector
69                 m_func_name_type_mask = eFunctionNameTypeSelector;
70             }
71             else
72             {
73                 // just a  basename by default
74                 m_func_name_type_mask = eFunctionNameTypeBase;
75             }
76         }
77     }
78 
79     if (!m_func_name)
80         m_func_name.SetCString(func_name);
81 
82     if (m_match_type == Breakpoint::Regexp)
83     {
84         if (!m_regex.Compile (m_func_name.AsCString()))
85         {
86             LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
87 
88             if (log)
89                 log->Warning ("function name regexp: \"%s\" did not compile.", m_func_name.AsCString());
90         }
91     }
92 }
93 
94 BreakpointResolverName::BreakpointResolverName
95 (
96     Breakpoint *bkpt,
97     RegularExpression &func_regex,
98     bool skip_prologue
99 ) :
100     BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
101     m_func_name (NULL),
102     m_class_name (NULL),
103     m_regex (func_regex),
104     m_match_type (Breakpoint::Regexp),
105     m_skip_prologue (skip_prologue)
106 {
107 }
108 
109 BreakpointResolverName::BreakpointResolverName
110 (
111     Breakpoint *bkpt,
112     const char *class_name,
113     const char *method,
114     Breakpoint::MatchType type,
115     bool skip_prologue
116 ) :
117     BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
118     m_func_name (method),
119     m_class_name (class_name),
120     m_regex (),
121     m_match_type (type),
122     m_skip_prologue (skip_prologue)
123 {
124 
125 }
126 
127 BreakpointResolverName::~BreakpointResolverName ()
128 {
129 }
130 
131 // FIXME: Right now we look at the module level, and call the module's "FindFunctions".
132 // Greg says he will add function tables, maybe at the CompileUnit level to accelerate function
133 // lookup.  At that point, we should switch the depth to CompileUnit, and look in these tables.
134 
135 Searcher::CallbackReturn
136 BreakpointResolverName::SearchCallback
137 (
138     SearchFilter &filter,
139     SymbolContext &context,
140     Address *addr,
141     bool containing
142 )
143 {
144     SymbolContextList func_list;
145     SymbolContextList sym_list;
146 
147     uint32_t i;
148     bool new_location;
149     SymbolContext sc;
150     Address break_addr;
151     assert (m_breakpoint != NULL);
152 
153     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
154 
155     if (m_class_name)
156     {
157         if (log)
158             log->Warning ("Class/method function specification not supported yet.\n");
159         return Searcher::eCallbackReturnStop;
160     }
161 
162     const bool include_symbols = false;
163     const bool append = false;
164     bool filter_by_cu = (filter.GetFilterRequiredItems() & eSymbolContextCompUnit) != 0;
165 
166     switch (m_match_type)
167     {
168         case Breakpoint::Exact:
169             if (context.module_sp)
170             {
171                 uint32_t num_functions = context.module_sp->FindFunctions (m_func_name,
172                                                       m_func_name_type_mask,
173                                                       include_symbols,
174                                                       append,
175                                                       func_list);
176                 // If the search filter specifies a Compilation Unit, then we don't need to bother to look in plain
177                 // symbols, since all the ones from a set compilation unit will have been found above already.
178 
179                 if (num_functions == 0 && !filter_by_cu)
180                 {
181                     if (m_func_name_type_mask & (eFunctionNameTypeBase | eFunctionNameTypeFull))
182                         context.module_sp->FindSymbolsWithNameAndType (m_func_name, eSymbolTypeCode, sym_list);
183                 }
184             }
185             break;
186         case Breakpoint::Regexp:
187             if (context.module_sp)
188             {
189                 if (!filter_by_cu)
190                     context.module_sp->FindSymbolsMatchingRegExAndType (m_regex, eSymbolTypeCode, sym_list);
191                 context.module_sp->FindFunctions (m_regex,
192                                                   include_symbols,
193                                                   append,
194                                                   func_list);
195             }
196             break;
197         case Breakpoint::Glob:
198             if (log)
199                 log->Warning ("glob is not supported yet.");
200             break;
201     }
202 
203     // If the filter specifies a Compilation Unit, remove the ones that don't pass at this point.
204     if (filter_by_cu)
205     {
206         uint32_t num_functions = func_list.GetSize();
207 
208         for (size_t idx = 0; idx < num_functions; idx++)
209         {
210             SymbolContext sc;
211             func_list.GetContextAtIndex(idx, sc);
212             if (!sc.comp_unit || !filter.CompUnitPasses(*sc.comp_unit))
213             {
214                 func_list.RemoveContextAtIndex(idx);
215                 num_functions--;
216                 idx--;
217             }
218         }
219     }
220 
221 
222     if (!m_basename_filter.empty())
223     {
224         // Filter out any matches whose names don't contain the basename filter
225         const char *basename_filter = m_basename_filter.c_str();
226         if (func_list.GetSize())
227         {
228             bool remove = false;
229             for (i = 0; i < func_list.GetSize(); remove = false)
230             {
231                 if (func_list.GetContextAtIndex(i, sc) == false)
232                     remove = true;
233                 else if (sc.function == NULL)
234                     remove = true;
235                 else
236                 {
237                     const InlineFunctionInfo* inlined_info = NULL;
238 
239                     if (sc.block)
240                         inlined_info = sc.block->GetInlinedFunctionInfo();
241 
242                     if (inlined_info)
243                     {
244                         if (::strstr (inlined_info->GetName().AsCString(), basename_filter) == NULL)
245                             remove = true;
246                     }
247                     else if (::strstr (sc.function->GetName().AsCString(), basename_filter) == NULL)
248                         remove = true;
249                 }
250 
251                 if (remove)
252                 {
253                     func_list.RemoveContextAtIndex(i);
254                     continue;
255                 }
256                 i++;
257             }
258         }
259 
260         if (sym_list.GetSize())
261         {
262             bool remove = false;
263             for (i = 0; i < sym_list.GetSize(); remove = false)
264             {
265                 if (sym_list.GetContextAtIndex(i, sc) == false)
266                     remove = true;
267                 else if (sc.symbol == NULL)
268                     remove = true;
269                 else if (::strstr (sc.symbol->GetName().AsCString(), basename_filter) == NULL)
270                     remove = true;
271 
272                 if (remove)
273                 {
274                     sym_list.RemoveContextAtIndex(i);
275                     continue;
276                 }
277                 i++;
278             }
279         }
280     }
281 
282     // Remove any duplicates between the funcion list and the symbol list
283     if (func_list.GetSize())
284     {
285         for (i = 0; i < func_list.GetSize(); i++)
286         {
287             if (func_list.GetContextAtIndex(i, sc) == false)
288                 continue;
289 
290             if (sc.function == NULL)
291                 continue;
292             uint32_t j = 0;
293             while (j < sym_list.GetSize())
294             {
295                 SymbolContext symbol_sc;
296                 if (sym_list.GetContextAtIndex(j, symbol_sc))
297                 {
298                     if (symbol_sc.symbol && symbol_sc.symbol->GetAddressRangePtr())
299                     {
300                         if (sc.function->GetAddressRange().GetBaseAddress() == symbol_sc.symbol->GetAddressRangePtr()->GetBaseAddress())
301                         {
302                             sym_list.RemoveContextAtIndex(j);
303                             continue;   // Don't increment j
304                         }
305                     }
306                 }
307 
308                 j++;
309             }
310         }
311 
312         for (i = 0; i < func_list.GetSize(); i++)
313         {
314             if (func_list.GetContextAtIndex(i, sc))
315             {
316                 if (sc.block && sc.block->GetInlinedFunctionInfo())
317                 {
318                     if (!sc.block->GetStartAddress(break_addr))
319                         break_addr.Clear();
320                 }
321                 else if (sc.function)
322                 {
323                     break_addr = sc.function->GetAddressRange().GetBaseAddress();
324                     if (m_skip_prologue)
325                     {
326                         if (break_addr.IsValid())
327                         {
328                             const uint32_t prologue_byte_size = sc.function->GetPrologueByteSize();
329                             if (prologue_byte_size)
330                                 break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size);
331                         }
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                         if (bp_loc_sp && new_location && !m_breakpoint->IsInternal())
341                         {
342                             if (log)
343                             {
344                                 StreamString s;
345                                 bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
346                                 log->Printf ("Added location: %s\n", s.GetData());
347                             }
348                         }
349                     }
350                 }
351             }
352         }
353     }
354 
355     for (i = 0; i < sym_list.GetSize(); i++)
356     {
357         if (sym_list.GetContextAtIndex(i, sc))
358         {
359             if (sc.symbol && sc.symbol->GetAddressRangePtr())
360             {
361                 break_addr = sc.symbol->GetAddressRangePtr()->GetBaseAddress();
362 
363                 if (m_skip_prologue)
364                 {
365                     const uint32_t prologue_byte_size = sc.symbol->GetPrologueByteSize();
366                     if (prologue_byte_size)
367                         break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size);
368                 }
369 
370                 if (filter.AddressPasses(break_addr))
371                 {
372                     BreakpointLocationSP bp_loc_sp (m_breakpoint->AddLocation(break_addr, &new_location));
373                     if (bp_loc_sp && new_location && !m_breakpoint->IsInternal())
374                     {
375                         StreamString s;
376                         bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
377                         if (log)
378                             log->Printf ("Added location: %s\n", s.GetData());
379                     }
380                 }
381             }
382         }
383     }
384     return Searcher::eCallbackReturnContinue;
385 }
386 
387 Searcher::Depth
388 BreakpointResolverName::GetDepth()
389 {
390     return Searcher::eDepthModule;
391 }
392 
393 void
394 BreakpointResolverName::GetDescription (Stream *s)
395 {
396     if (m_match_type == Breakpoint::Regexp)
397         s->Printf("regex = '%s'", m_regex.GetText());
398     else if (m_basename_filter.empty())
399         s->Printf("name = '%s'", m_func_name.AsCString());
400     else
401         s->Printf("name = '%s'", m_basename_filter.c_str());
402 }
403 
404 void
405 BreakpointResolverName::Dump (Stream *s) const
406 {
407 
408 }
409 
410