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     switch (m_match_type)
159     {
160         case Breakpoint::Exact:
161             if (context.module_sp)
162             {
163                 if (m_func_name_type_mask & (eFunctionNameTypeBase | eFunctionNameTypeFull))
164                     context.module_sp->FindSymbolsWithNameAndType (m_func_name, eSymbolTypeCode, sym_list);
165                 context.module_sp->FindFunctions (m_func_name, m_func_name_type_mask, false, func_list);
166             }
167             break;
168         case Breakpoint::Regexp:
169             if (context.module_sp)
170             {
171                 context.module_sp->FindSymbolsMatchingRegExAndType (m_regex, eSymbolTypeCode, sym_list);
172                 context.module_sp->FindFunctions (m_regex, true, func_list);
173             }
174             break;
175         case Breakpoint::Glob:
176             if (log)
177                 log->Warning ("glob is not supported yet.");
178             break;
179     }
180 
181     if (!m_basename_filter.empty())
182     {
183         // Filter out any matches whose names don't contain the basename filter
184         const char *basename_filter = m_basename_filter.c_str();
185         if (func_list.GetSize())
186         {
187             bool remove = false;
188             for (i = 0; i < func_list.GetSize(); remove = false)
189             {
190                 if (func_list.GetContextAtIndex(i, sc) == false)
191                     remove = true;
192                 else if (sc.function == NULL)
193                     remove = true;
194                 else
195                 {
196                     const InlineFunctionInfo* inlined_info = NULL;
197 
198                     if (sc.block)
199                         inlined_info = sc.block->GetInlinedFunctionInfo();
200 
201                     if (inlined_info)
202                     {
203                         if (::strstr (inlined_info->GetName().AsCString(), basename_filter) == NULL)
204                             remove = true;
205                     }
206                     else if (::strstr (sc.function->GetName().AsCString(), basename_filter) == NULL)
207                         remove = true;
208                 }
209 
210                 if (remove)
211                 {
212                     func_list.RemoveContextAtIndex(i);
213                     continue;
214                 }
215                 i++;
216             }
217         }
218 
219         if (sym_list.GetSize())
220         {
221             bool remove = false;
222             for (i = 0; i < sym_list.GetSize(); remove = false)
223             {
224                 if (sym_list.GetContextAtIndex(i, sc) == false)
225                     remove = true;
226                 else if (sc.symbol == NULL)
227                     remove = true;
228                 else if (::strstr (sc.symbol->GetName().AsCString(), basename_filter) == NULL)
229                     remove = true;
230 
231                 if (remove)
232                 {
233                     sym_list.RemoveContextAtIndex(i);
234                     continue;
235                 }
236                 i++;
237             }
238         }
239     }
240 
241     // Remove any duplicates between the funcion list and the symbol list
242     if (func_list.GetSize())
243     {
244         for (i = 0; i < func_list.GetSize(); i++)
245         {
246             if (func_list.GetContextAtIndex(i, sc) == false)
247                 continue;
248 
249             if (sc.function == NULL)
250                 continue;
251             uint32_t j = 0;
252             while (j < sym_list.GetSize())
253             {
254                 SymbolContext symbol_sc;
255                 if (sym_list.GetContextAtIndex(j, symbol_sc))
256                 {
257                     if (symbol_sc.symbol && symbol_sc.symbol->GetAddressRangePtr())
258                     {
259                         if (sc.function->GetAddressRange().GetBaseAddress() == symbol_sc.symbol->GetAddressRangePtr()->GetBaseAddress())
260                         {
261                             sym_list.RemoveContextAtIndex(j);
262                             continue;   // Don't increment j
263                         }
264                     }
265                 }
266 
267                 j++;
268             }
269         }
270 
271         for (i = 0; i < func_list.GetSize(); i++)
272         {
273             if (func_list.GetContextAtIndex(i, sc))
274             {
275                 if (sc.block && sc.block->GetInlinedFunctionInfo())
276                 {
277                     if (!sc.block->GetStartAddress(break_addr))
278                         break_addr.Clear();
279                 }
280                 else if (sc.function)
281                 {
282                     break_addr = sc.function->GetAddressRange().GetBaseAddress();
283                     if (skip_prologue)
284                     {
285                         if (break_addr.IsValid())
286                         {
287                             const uint32_t prologue_byte_size = sc.function->GetPrologueByteSize();
288                             if (prologue_byte_size)
289                                 break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size);
290                         }
291                     }
292                 }
293 
294                 if (break_addr.IsValid())
295                 {
296                     if (filter.AddressPasses(break_addr))
297                     {
298                         BreakpointLocationSP bp_loc_sp (m_breakpoint->AddLocation(break_addr, &new_location));
299                         if (bp_loc_sp && new_location && !m_breakpoint->IsInternal())
300                         {
301                             if (log)
302                             {
303                                 StreamString s;
304                                 bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
305                                 log->Printf ("Added location: %s\n", s.GetData());
306                             }
307                         }
308                     }
309                 }
310             }
311         }
312     }
313 
314     for (i = 0; i < sym_list.GetSize(); i++)
315     {
316         if (sym_list.GetContextAtIndex(i, sc))
317         {
318             if (sc.symbol && sc.symbol->GetAddressRangePtr())
319             {
320                 break_addr = sc.symbol->GetAddressRangePtr()->GetBaseAddress();
321 
322                 if (skip_prologue)
323                 {
324                     const uint32_t prologue_byte_size = sc.symbol->GetPrologueByteSize();
325                     if (prologue_byte_size)
326                         break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size);
327                 }
328 
329                 if (filter.AddressPasses(break_addr))
330                 {
331                     BreakpointLocationSP bp_loc_sp (m_breakpoint->AddLocation(break_addr, &new_location));
332                     if (bp_loc_sp && new_location && !m_breakpoint->IsInternal())
333                     {
334                         StreamString s;
335                         bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
336                         if (log)
337                             log->Printf ("Added location: %s\n", s.GetData());
338                     }
339                 }
340             }
341         }
342     }
343     return Searcher::eCallbackReturnContinue;
344 }
345 
346 Searcher::Depth
347 BreakpointResolverName::GetDepth()
348 {
349     return Searcher::eDepthModule;
350 }
351 
352 void
353 BreakpointResolverName::GetDescription (Stream *s)
354 {
355     if (m_match_type == Breakpoint::Regexp)
356         s->Printf("regex = '%s'", m_regex.GetText());
357     else if (m_basename_filter.empty())
358         s->Printf("name = '%s'", m_func_name.AsCString());
359     else
360         s->Printf("name = '%s'", m_basename_filter.c_str());
361 }
362 
363 void
364 BreakpointResolverName::Dump (Stream *s) const
365 {
366 
367 }
368 
369