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/Module.h"
19 #include "lldb/Core/StreamString.h"
20 #include "lldb/Symbol/ClangNamespaceDecl.h"
21 #include "lldb/Symbol/Block.h"
22 #include "lldb/Symbol/Function.h"
23 #include "lldb/Symbol/Symbol.h"
24 #include "lldb/Symbol/SymbolContext.h"
25 #include "lldb/Target/ObjCLanguageRuntime.h"
26 
27 using namespace lldb;
28 using namespace lldb_private;
29 
30 BreakpointResolverName::BreakpointResolverName
31 (
32     Breakpoint *bkpt,
33     const char *func_name,
34     uint32_t func_name_type_mask,
35     Breakpoint::MatchType type,
36     bool skip_prologue
37 ) :
38     BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
39     m_func_name_type_mask (func_name_type_mask),
40     m_class_name (),
41     m_regex (),
42     m_match_type (type),
43     m_skip_prologue (skip_prologue)
44 {
45 
46     if (m_match_type == Breakpoint::Regexp)
47     {
48         if (!m_regex.Compile (func_name))
49         {
50             Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
51 
52             if (log)
53                 log->Warning ("function name regexp: \"%s\" did not compile.", func_name);
54         }
55     }
56     else
57     {
58         const bool append = true;
59         ObjCLanguageRuntime::MethodName objc_name(func_name, false);
60         if (objc_name.IsValid(false))
61             objc_name.GetFullNames(m_func_names, append);
62         else
63             m_func_names.push_back(ConstString(func_name));
64     }
65 }
66 
67 BreakpointResolverName::BreakpointResolverName (Breakpoint *bkpt,
68                                                 const char *names[],
69                                                 size_t num_names,
70                                                 uint32_t name_type_mask,
71                                                 bool skip_prologue) :
72     BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
73     m_func_name_type_mask (name_type_mask),
74     m_match_type (Breakpoint::Exact),
75     m_skip_prologue (skip_prologue)
76 {
77     const bool append = true;
78     for (size_t i = 0; i < num_names; i++)
79     {
80         ObjCLanguageRuntime::MethodName objc_name(names[i], false);
81         if (objc_name.IsValid(false))
82             objc_name.GetFullNames(m_func_names, append);
83         else
84             m_func_names.push_back (ConstString (names[i]));
85     }
86 }
87 
88 BreakpointResolverName::BreakpointResolverName (Breakpoint *bkpt,
89                                                 std::vector<std::string> names,
90                                                 uint32_t name_type_mask,
91                                                 bool skip_prologue) :
92     BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
93     m_func_name_type_mask (name_type_mask),
94     m_match_type (Breakpoint::Exact),
95     m_skip_prologue (skip_prologue)
96 {
97     size_t num_names = names.size();
98     const bool append = true;
99     for (size_t i = 0; i < num_names; i++)
100     {
101         ObjCLanguageRuntime::MethodName objc_name(names[i].c_str(), false);
102         if (objc_name.IsValid(false))
103             objc_name.GetFullNames(m_func_names, append);
104         else
105             m_func_names.push_back (ConstString (names[i].c_str()));
106     }
107 }
108 
109 BreakpointResolverName::BreakpointResolverName
110 (
111     Breakpoint *bkpt,
112     RegularExpression &func_regex,
113     bool skip_prologue
114 ) :
115     BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
116     m_class_name (NULL),
117     m_regex (func_regex),
118     m_match_type (Breakpoint::Regexp),
119     m_skip_prologue (skip_prologue)
120 {
121 }
122 
123 BreakpointResolverName::BreakpointResolverName
124 (
125     Breakpoint *bkpt,
126     const char *class_name,
127     const char *method,
128     Breakpoint::MatchType type,
129     bool skip_prologue
130 ) :
131     BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
132     m_class_name (class_name),
133     m_regex (),
134     m_match_type (type),
135     m_skip_prologue (skip_prologue)
136 {
137     m_func_names.push_back(ConstString(method));
138 }
139 
140 BreakpointResolverName::~BreakpointResolverName ()
141 {
142 }
143 
144 // FIXME: Right now we look at the module level, and call the module's "FindFunctions".
145 // Greg says he will add function tables, maybe at the CompileUnit level to accelerate function
146 // lookup.  At that point, we should switch the depth to CompileUnit, and look in these tables.
147 
148 Searcher::CallbackReturn
149 BreakpointResolverName::SearchCallback
150 (
151     SearchFilter &filter,
152     SymbolContext &context,
153     Address *addr,
154     bool containing
155 )
156 {
157     SymbolContextList func_list;
158     SymbolContextList sym_list;
159 
160     uint32_t i;
161     bool new_location;
162     SymbolContext sc;
163     Address break_addr;
164     assert (m_breakpoint != NULL);
165 
166     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
167 
168     if (m_class_name)
169     {
170         if (log)
171             log->Warning ("Class/method function specification not supported yet.\n");
172         return Searcher::eCallbackReturnStop;
173     }
174 
175     const bool include_symbols = false;
176     const bool include_inlines = true;
177     const bool append = true;
178     bool filter_by_cu = (filter.GetFilterRequiredItems() & eSymbolContextCompUnit) != 0;
179 
180     switch (m_match_type)
181     {
182         case Breakpoint::Exact:
183             if (context.module_sp)
184             {
185                 size_t num_names = m_func_names.size();
186                 for (int j = 0; j < num_names; j++)
187                 {
188                     size_t num_functions = context.module_sp->FindFunctions (m_func_names[j],
189                                                                              NULL,
190                                                                              m_func_name_type_mask,
191                                                                              include_symbols,
192                                                                              include_inlines,
193                                                                              append,
194                                                                              func_list);
195                     // If the search filter specifies a Compilation Unit, then we don't need to bother to look in plain
196                     // symbols, since all the ones from a set compilation unit will have been found above already.
197 
198                     if (num_functions == 0 && !filter_by_cu)
199                     {
200                         context.module_sp->FindFunctionSymbols (m_func_names[j], m_func_name_type_mask, sym_list);
201                     }
202                 }
203             }
204             break;
205         case Breakpoint::Regexp:
206             if (context.module_sp)
207             {
208                 if (!filter_by_cu)
209                     context.module_sp->FindSymbolsMatchingRegExAndType (m_regex, eSymbolTypeCode, sym_list);
210                 context.module_sp->FindFunctions (m_regex,
211                                                   include_symbols,
212                                                   include_inlines,
213                                                   append,
214                                                   func_list);
215             }
216             break;
217         case Breakpoint::Glob:
218             if (log)
219                 log->Warning ("glob is not supported yet.");
220             break;
221     }
222 
223     // If the filter specifies a Compilation Unit, remove the ones that don't pass at this point.
224     if (filter_by_cu)
225     {
226         uint32_t num_functions = func_list.GetSize();
227 
228         for (size_t idx = 0; idx < num_functions; idx++)
229         {
230             SymbolContext sc;
231             func_list.GetContextAtIndex(idx, sc);
232             if (!sc.comp_unit || !filter.CompUnitPasses(*sc.comp_unit))
233             {
234                 func_list.RemoveContextAtIndex(idx);
235                 num_functions--;
236                 idx--;
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->ValueIsAddress())
258                     {
259                         if (sc.function->GetAddressRange().GetBaseAddress() == symbol_sc.symbol->GetAddress())
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 (m_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->ValueIsAddress())
319             {
320                 break_addr = sc.symbol->GetAddress();
321 
322                 if (m_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
358     {
359         size_t num_names = m_func_names.size();
360         if (num_names == 1)
361             s->Printf("name = '%s'", m_func_names[0].AsCString());
362         else
363         {
364             s->Printf("names = {");
365             for (size_t i = 0; i < num_names - 1; i++)
366             {
367                 s->Printf ("'%s', ", m_func_names[i].AsCString());
368             }
369             s->Printf ("'%s'}", m_func_names[num_names - 1].AsCString());
370         }
371     }
372 }
373 
374 void
375 BreakpointResolverName::Dump (Stream *s) const
376 {
377 
378 }
379 
380