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