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