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 
110 BreakpointResolverName::BreakpointResolverName
111 (
112     Breakpoint *bkpt,
113     const char *class_name,
114     const char *method,
115     Breakpoint::MatchType type,
116     bool skip_prologue
117 ) :
118     BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
119     m_func_name (method),
120     m_class_name (class_name),
121     m_regex (),
122     m_match_type (type),
123     m_skip_prologue (skip_prologue)
124 {
125 
126 }
127 
128 BreakpointResolverName::~BreakpointResolverName ()
129 {
130 }
131 
132 // FIXME: Right now we look at the module level, and call the module's "FindFunctions".
133 // Greg says he will add function tables, maybe at the CompileUnit level to accelerate function
134 // lookup.  At that point, we should switch the depth to CompileUnit, and look in these tables.
135 
136 Searcher::CallbackReturn
137 BreakpointResolverName::SearchCallback
138 (
139     SearchFilter &filter,
140     SymbolContext &context,
141     Address *addr,
142     bool containing
143 )
144 {
145     SymbolContextList func_list;
146     SymbolContextList sym_list;
147 
148     uint32_t i;
149     bool new_location;
150     SymbolContext sc;
151     Address break_addr;
152     assert (m_breakpoint != NULL);
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 (context.module_sp->FindFunctions (m_func_name,
171                                                       m_func_name_type_mask,
172                                                       include_symbols,
173                                                       append,
174                                                       func_list) == 0)
175                 {
176                     if (m_func_name_type_mask & (eFunctionNameTypeBase | eFunctionNameTypeFull))
177                         context.module_sp->FindSymbolsWithNameAndType (m_func_name, eSymbolTypeCode, sym_list);
178                 }
179             }
180             break;
181         case Breakpoint::Regexp:
182             if (context.module_sp)
183             {
184                 context.module_sp->FindSymbolsMatchingRegExAndType (m_regex, eSymbolTypeCode, sym_list);
185                 context.module_sp->FindFunctions (m_regex,
186                                                   include_symbols,
187                                                   append,
188                                                   func_list);
189             }
190             break;
191         case Breakpoint::Glob:
192             if (log)
193                 log->Warning ("glob is not supported yet.");
194             break;
195     }
196 
197     if (!m_basename_filter.empty())
198     {
199         // Filter out any matches whose names don't contain the basename filter
200         const char *basename_filter = m_basename_filter.c_str();
201         if (func_list.GetSize())
202         {
203             bool remove = false;
204             for (i = 0; i < func_list.GetSize(); remove = false)
205             {
206                 if (func_list.GetContextAtIndex(i, sc) == false)
207                     remove = true;
208                 else if (sc.function == NULL)
209                     remove = true;
210                 else
211                 {
212                     const InlineFunctionInfo* inlined_info = NULL;
213 
214                     if (sc.block)
215                         inlined_info = sc.block->GetInlinedFunctionInfo();
216 
217                     if (inlined_info)
218                     {
219                         if (::strstr (inlined_info->GetName().AsCString(), basename_filter) == NULL)
220                             remove = true;
221                     }
222                     else if (::strstr (sc.function->GetName().AsCString(), basename_filter) == NULL)
223                         remove = true;
224                 }
225 
226                 if (remove)
227                 {
228                     func_list.RemoveContextAtIndex(i);
229                     continue;
230                 }
231                 i++;
232             }
233         }
234 
235         if (sym_list.GetSize())
236         {
237             bool remove = false;
238             for (i = 0; i < sym_list.GetSize(); remove = false)
239             {
240                 if (sym_list.GetContextAtIndex(i, sc) == false)
241                     remove = true;
242                 else if (sc.symbol == NULL)
243                     remove = true;
244                 else if (::strstr (sc.symbol->GetName().AsCString(), basename_filter) == NULL)
245                     remove = true;
246 
247                 if (remove)
248                 {
249                     sym_list.RemoveContextAtIndex(i);
250                     continue;
251                 }
252                 i++;
253             }
254         }
255     }
256 
257     // Remove any duplicates between the funcion list and the symbol list
258     if (func_list.GetSize())
259     {
260         for (i = 0; i < func_list.GetSize(); i++)
261         {
262             if (func_list.GetContextAtIndex(i, sc) == false)
263                 continue;
264 
265             if (sc.function == NULL)
266                 continue;
267             uint32_t j = 0;
268             while (j < sym_list.GetSize())
269             {
270                 SymbolContext symbol_sc;
271                 if (sym_list.GetContextAtIndex(j, symbol_sc))
272                 {
273                     if (symbol_sc.symbol && symbol_sc.symbol->GetAddressRangePtr())
274                     {
275                         if (sc.function->GetAddressRange().GetBaseAddress() == symbol_sc.symbol->GetAddressRangePtr()->GetBaseAddress())
276                         {
277                             sym_list.RemoveContextAtIndex(j);
278                             continue;   // Don't increment j
279                         }
280                     }
281                 }
282 
283                 j++;
284             }
285         }
286 
287         for (i = 0; i < func_list.GetSize(); i++)
288         {
289             if (func_list.GetContextAtIndex(i, sc))
290             {
291                 if (sc.block && sc.block->GetInlinedFunctionInfo())
292                 {
293                     if (!sc.block->GetStartAddress(break_addr))
294                         break_addr.Clear();
295                 }
296                 else if (sc.function)
297                 {
298                     break_addr = sc.function->GetAddressRange().GetBaseAddress();
299                     if (m_skip_prologue)
300                     {
301                         if (break_addr.IsValid())
302                         {
303                             const uint32_t prologue_byte_size = sc.function->GetPrologueByteSize();
304                             if (prologue_byte_size)
305                                 break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size);
306                         }
307                     }
308                 }
309 
310                 if (break_addr.IsValid())
311                 {
312                     if (filter.AddressPasses(break_addr))
313                     {
314                         BreakpointLocationSP bp_loc_sp (m_breakpoint->AddLocation(break_addr, &new_location));
315                         if (bp_loc_sp && new_location && !m_breakpoint->IsInternal())
316                         {
317                             if (log)
318                             {
319                                 StreamString s;
320                                 bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
321                                 log->Printf ("Added location: %s\n", s.GetData());
322                             }
323                         }
324                     }
325                 }
326             }
327         }
328     }
329 
330     for (i = 0; i < sym_list.GetSize(); i++)
331     {
332         if (sym_list.GetContextAtIndex(i, sc))
333         {
334             if (sc.symbol && sc.symbol->GetAddressRangePtr())
335             {
336                 break_addr = sc.symbol->GetAddressRangePtr()->GetBaseAddress();
337 
338                 if (m_skip_prologue)
339                 {
340                     const uint32_t prologue_byte_size = sc.symbol->GetPrologueByteSize();
341                     if (prologue_byte_size)
342                         break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size);
343                 }
344 
345                 if (filter.AddressPasses(break_addr))
346                 {
347                     BreakpointLocationSP bp_loc_sp (m_breakpoint->AddLocation(break_addr, &new_location));
348                     if (bp_loc_sp && new_location && !m_breakpoint->IsInternal())
349                     {
350                         StreamString s;
351                         bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
352                         if (log)
353                             log->Printf ("Added location: %s\n", s.GetData());
354                     }
355                 }
356             }
357         }
358     }
359     return Searcher::eCallbackReturnContinue;
360 }
361 
362 Searcher::Depth
363 BreakpointResolverName::GetDepth()
364 {
365     return Searcher::eDepthModule;
366 }
367 
368 void
369 BreakpointResolverName::GetDescription (Stream *s)
370 {
371     if (m_match_type == Breakpoint::Regexp)
372         s->Printf("regex = '%s'", m_regex.GetText());
373     else if (m_basename_filter.empty())
374         s->Printf("name = '%s'", m_func_name.AsCString());
375     else
376         s->Printf("name = '%s'", m_basename_filter.c_str());
377 }
378 
379 void
380 BreakpointResolverName::Dump (Stream *s) const
381 {
382 
383 }
384 
385