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