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 
26 using namespace lldb;
27 using namespace lldb_private;
28 
29 BreakpointResolverName::BreakpointResolverName
30 (
31     Breakpoint *bkpt,
32     const char *func_name,
33     uint32_t func_name_type_mask,
34     Breakpoint::MatchType type,
35     bool skip_prologue
36 ) :
37     BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
38     m_func_name_type_mask (func_name_type_mask),
39     m_class_name (),
40     m_regex (),
41     m_match_type (type),
42     m_skip_prologue (skip_prologue)
43 {
44 
45     if (m_match_type == Breakpoint::Regexp)
46     {
47         if (!m_regex.Compile (func_name))
48         {
49             LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
50 
51             if (log)
52                 log->Warning ("function name regexp: \"%s\" did not compile.", func_name);
53         }
54     }
55     else
56     {
57         m_func_names.push_back(ConstString(func_name));
58     }
59 }
60 
61 BreakpointResolverName::BreakpointResolverName (Breakpoint *bkpt,
62                                                 const char *names[],
63                                                 size_t num_names,
64                                                 uint32_t name_type_mask,
65                                                 bool skip_prologue) :
66     BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
67     m_func_name_type_mask (name_type_mask),
68     m_match_type (Breakpoint::Exact),
69     m_skip_prologue (skip_prologue)
70 {
71     for (size_t i = 0; i < num_names; i++)
72     {
73         m_func_names.push_back (ConstString (names[i]));
74     }
75 }
76 
77 BreakpointResolverName::BreakpointResolverName (Breakpoint *bkpt,
78                                                 std::vector<std::string> names,
79                                                 uint32_t name_type_mask,
80                                                 bool skip_prologue) :
81     BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
82     m_func_name_type_mask (name_type_mask),
83     m_match_type (Breakpoint::Exact),
84     m_skip_prologue (skip_prologue)
85 {
86     size_t num_names = names.size();
87 
88     for (size_t i = 0; i < num_names; i++)
89     {
90         m_func_names.push_back (ConstString (names[i].c_str()));
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_class_name (NULL),
102     m_regex (func_regex),
103     m_match_type (Breakpoint::Regexp),
104     m_skip_prologue (skip_prologue)
105 {
106 }
107 
108 BreakpointResolverName::BreakpointResolverName
109 (
110     Breakpoint *bkpt,
111     const char *class_name,
112     const char *method,
113     Breakpoint::MatchType type,
114     bool skip_prologue
115 ) :
116     BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
117     m_class_name (class_name),
118     m_regex (),
119     m_match_type (type),
120     m_skip_prologue (skip_prologue)
121 {
122     m_func_names.push_back(ConstString(method));
123 }
124 
125 BreakpointResolverName::~BreakpointResolverName ()
126 {
127 }
128 
129 // FIXME: Right now we look at the module level, and call the module's "FindFunctions".
130 // Greg says he will add function tables, maybe at the CompileUnit level to accelerate function
131 // lookup.  At that point, we should switch the depth to CompileUnit, and look in these tables.
132 
133 Searcher::CallbackReturn
134 BreakpointResolverName::SearchCallback
135 (
136     SearchFilter &filter,
137     SymbolContext &context,
138     Address *addr,
139     bool containing
140 )
141 {
142     SymbolContextList func_list;
143     SymbolContextList sym_list;
144 
145     uint32_t i;
146     bool new_location;
147     SymbolContext sc;
148     Address break_addr;
149     assert (m_breakpoint != NULL);
150 
151     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
152 
153     if (m_class_name)
154     {
155         if (log)
156             log->Warning ("Class/method function specification not supported yet.\n");
157         return Searcher::eCallbackReturnStop;
158     }
159 
160     const bool include_symbols = false;
161     const bool include_inlines = true;
162     const bool append = true;
163     bool filter_by_cu = (filter.GetFilterRequiredItems() & eSymbolContextCompUnit) != 0;
164 
165     switch (m_match_type)
166     {
167         case Breakpoint::Exact:
168             if (context.module_sp)
169             {
170                 size_t num_names = m_func_names.size();
171                 for (int i = 0; i < num_names; i++)
172                 {
173                     uint32_t num_functions = context.module_sp->FindFunctions (m_func_names[i],
174                                                                                NULL,
175                                                                                m_func_name_type_mask,
176                                                                                include_symbols,
177                                                                                include_inlines,
178                                                                                append,
179                                                                                func_list);
180                     // If the search filter specifies a Compilation Unit, then we don't need to bother to look in plain
181                     // symbols, since all the ones from a set compilation unit will have been found above already.
182 
183                     if (num_functions == 0 && !filter_by_cu)
184                     {
185                         if (m_func_name_type_mask & (eFunctionNameTypeBase | eFunctionNameTypeFull | eFunctionNameTypeAuto))
186                             context.module_sp->FindSymbolsWithNameAndType (m_func_names[i], eSymbolTypeCode, sym_list);
187                     }
188                 }
189             }
190             break;
191         case Breakpoint::Regexp:
192             if (context.module_sp)
193             {
194                 if (!filter_by_cu)
195                     context.module_sp->FindSymbolsMatchingRegExAndType (m_regex, eSymbolTypeCode, sym_list);
196                 context.module_sp->FindFunctions (m_regex,
197                                                   include_symbols,
198                                                   include_inlines,
199                                                   append,
200                                                   func_list);
201             }
202             break;
203         case Breakpoint::Glob:
204             if (log)
205                 log->Warning ("glob is not supported yet.");
206             break;
207     }
208 
209     // If the filter specifies a Compilation Unit, remove the ones that don't pass at this point.
210     if (filter_by_cu)
211     {
212         uint32_t num_functions = func_list.GetSize();
213 
214         for (size_t idx = 0; idx < num_functions; idx++)
215         {
216             SymbolContext sc;
217             func_list.GetContextAtIndex(idx, sc);
218             if (!sc.comp_unit || !filter.CompUnitPasses(*sc.comp_unit))
219             {
220                 func_list.RemoveContextAtIndex(idx);
221                 num_functions--;
222                 idx--;
223             }
224         }
225     }
226 
227     // Remove any duplicates between the funcion list and the symbol list
228     if (func_list.GetSize())
229     {
230         for (i = 0; i < func_list.GetSize(); i++)
231         {
232             if (func_list.GetContextAtIndex(i, sc) == false)
233                 continue;
234 
235             if (sc.function == NULL)
236                 continue;
237             uint32_t j = 0;
238             while (j < sym_list.GetSize())
239             {
240                 SymbolContext symbol_sc;
241                 if (sym_list.GetContextAtIndex(j, symbol_sc))
242                 {
243                     if (symbol_sc.symbol && symbol_sc.symbol->ValueIsAddress())
244                     {
245                         if (sc.function->GetAddressRange().GetBaseAddress() == symbol_sc.symbol->GetAddress())
246                         {
247                             sym_list.RemoveContextAtIndex(j);
248                             continue;   // Don't increment j
249                         }
250                     }
251                 }
252 
253                 j++;
254             }
255         }
256 
257         for (i = 0; i < func_list.GetSize(); i++)
258         {
259             if (func_list.GetContextAtIndex(i, sc))
260             {
261                 if (sc.block && sc.block->GetInlinedFunctionInfo())
262                 {
263                     if (!sc.block->GetStartAddress(break_addr))
264                         break_addr.Clear();
265                 }
266                 else if (sc.function)
267                 {
268                     break_addr = sc.function->GetAddressRange().GetBaseAddress();
269                     if (m_skip_prologue)
270                     {
271                         if (break_addr.IsValid())
272                         {
273                             const uint32_t prologue_byte_size = sc.function->GetPrologueByteSize();
274                             if (prologue_byte_size)
275                                 break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size);
276                         }
277                     }
278                 }
279 
280                 if (break_addr.IsValid())
281                 {
282                     if (filter.AddressPasses(break_addr))
283                     {
284                         BreakpointLocationSP bp_loc_sp (m_breakpoint->AddLocation(break_addr, &new_location));
285                         if (bp_loc_sp && new_location && !m_breakpoint->IsInternal())
286                         {
287                             if (log)
288                             {
289                                 StreamString s;
290                                 bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
291                                 log->Printf ("Added location: %s\n", s.GetData());
292                             }
293                         }
294                     }
295                 }
296             }
297         }
298     }
299 
300     for (i = 0; i < sym_list.GetSize(); i++)
301     {
302         if (sym_list.GetContextAtIndex(i, sc))
303         {
304             if (sc.symbol && sc.symbol->ValueIsAddress())
305             {
306                 break_addr = sc.symbol->GetAddress();
307 
308                 if (m_skip_prologue)
309                 {
310                     const uint32_t prologue_byte_size = sc.symbol->GetPrologueByteSize();
311                     if (prologue_byte_size)
312                         break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size);
313                 }
314 
315                 if (filter.AddressPasses(break_addr))
316                 {
317                     BreakpointLocationSP bp_loc_sp (m_breakpoint->AddLocation(break_addr, &new_location));
318                     if (bp_loc_sp && new_location && !m_breakpoint->IsInternal())
319                     {
320                         StreamString s;
321                         bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
322                         if (log)
323                             log->Printf ("Added location: %s\n", s.GetData());
324                     }
325                 }
326             }
327         }
328     }
329     return Searcher::eCallbackReturnContinue;
330 }
331 
332 Searcher::Depth
333 BreakpointResolverName::GetDepth()
334 {
335     return Searcher::eDepthModule;
336 }
337 
338 void
339 BreakpointResolverName::GetDescription (Stream *s)
340 {
341     if (m_match_type == Breakpoint::Regexp)
342         s->Printf("regex = '%s'", m_regex.GetText());
343     else
344     {
345         size_t num_names = m_func_names.size();
346         if (num_names == 1)
347             s->Printf("name = '%s'", m_func_names[0].AsCString());
348         else
349         {
350             s->Printf("names = {");
351             for (size_t i = 0; i < num_names - 1; i++)
352             {
353                 s->Printf ("'%s', ", m_func_names[i].AsCString());
354             }
355             s->Printf ("'%s'}", m_func_names[num_names - 1].AsCString());
356         }
357     }
358 }
359 
360 void
361 BreakpointResolverName::Dump (Stream *s) const
362 {
363 
364 }
365 
366