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 j = 0; j < num_names; j++)
172                 {
173                     size_t num_functions = context.module_sp->FindFunctions (m_func_names[j],
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                         context.module_sp->FindFunctionSymbols (m_func_names[j], m_func_name_type_mask, sym_list);
186                     }
187                 }
188             }
189             break;
190         case Breakpoint::Regexp:
191             if (context.module_sp)
192             {
193                 if (!filter_by_cu)
194                     context.module_sp->FindSymbolsMatchingRegExAndType (m_regex, eSymbolTypeCode, sym_list);
195                 context.module_sp->FindFunctions (m_regex,
196                                                   include_symbols,
197                                                   include_inlines,
198                                                   append,
199                                                   func_list);
200             }
201             break;
202         case Breakpoint::Glob:
203             if (log)
204                 log->Warning ("glob is not supported yet.");
205             break;
206     }
207 
208     // If the filter specifies a Compilation Unit, remove the ones that don't pass at this point.
209     if (filter_by_cu)
210     {
211         uint32_t num_functions = func_list.GetSize();
212 
213         for (size_t idx = 0; idx < num_functions; idx++)
214         {
215             SymbolContext sc;
216             func_list.GetContextAtIndex(idx, sc);
217             if (!sc.comp_unit || !filter.CompUnitPasses(*sc.comp_unit))
218             {
219                 func_list.RemoveContextAtIndex(idx);
220                 num_functions--;
221                 idx--;
222             }
223         }
224     }
225 
226     // Remove any duplicates between the funcion list and the symbol list
227     if (func_list.GetSize())
228     {
229         for (i = 0; i < func_list.GetSize(); i++)
230         {
231             if (func_list.GetContextAtIndex(i, sc) == false)
232                 continue;
233 
234             if (sc.function == NULL)
235                 continue;
236             uint32_t j = 0;
237             while (j < sym_list.GetSize())
238             {
239                 SymbolContext symbol_sc;
240                 if (sym_list.GetContextAtIndex(j, symbol_sc))
241                 {
242                     if (symbol_sc.symbol && symbol_sc.symbol->ValueIsAddress())
243                     {
244                         if (sc.function->GetAddressRange().GetBaseAddress() == symbol_sc.symbol->GetAddress())
245                         {
246                             sym_list.RemoveContextAtIndex(j);
247                             continue;   // Don't increment j
248                         }
249                     }
250                 }
251 
252                 j++;
253             }
254         }
255 
256         for (i = 0; i < func_list.GetSize(); i++)
257         {
258             if (func_list.GetContextAtIndex(i, sc))
259             {
260                 if (sc.block && sc.block->GetInlinedFunctionInfo())
261                 {
262                     if (!sc.block->GetStartAddress(break_addr))
263                         break_addr.Clear();
264                 }
265                 else if (sc.function)
266                 {
267                     break_addr = sc.function->GetAddressRange().GetBaseAddress();
268                     if (m_skip_prologue)
269                     {
270                         if (break_addr.IsValid())
271                         {
272                             const uint32_t prologue_byte_size = sc.function->GetPrologueByteSize();
273                             if (prologue_byte_size)
274                                 break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size);
275                         }
276                     }
277                 }
278 
279                 if (break_addr.IsValid())
280                 {
281                     if (filter.AddressPasses(break_addr))
282                     {
283                         BreakpointLocationSP bp_loc_sp (m_breakpoint->AddLocation(break_addr, &new_location));
284                         if (bp_loc_sp && new_location && !m_breakpoint->IsInternal())
285                         {
286                             if (log)
287                             {
288                                 StreamString s;
289                                 bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
290                                 log->Printf ("Added location: %s\n", s.GetData());
291                             }
292                         }
293                     }
294                 }
295             }
296         }
297     }
298 
299     for (i = 0; i < sym_list.GetSize(); i++)
300     {
301         if (sym_list.GetContextAtIndex(i, sc))
302         {
303             if (sc.symbol && sc.symbol->ValueIsAddress())
304             {
305                 break_addr = sc.symbol->GetAddress();
306 
307                 if (m_skip_prologue)
308                 {
309                     const uint32_t prologue_byte_size = sc.symbol->GetPrologueByteSize();
310                     if (prologue_byte_size)
311                         break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size);
312                 }
313 
314                 if (filter.AddressPasses(break_addr))
315                 {
316                     BreakpointLocationSP bp_loc_sp (m_breakpoint->AddLocation(break_addr, &new_location));
317                     if (bp_loc_sp && new_location && !m_breakpoint->IsInternal())
318                     {
319                         StreamString s;
320                         bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
321                         if (log)
322                             log->Printf ("Added location: %s\n", s.GetData());
323                     }
324                 }
325             }
326         }
327     }
328     return Searcher::eCallbackReturnContinue;
329 }
330 
331 Searcher::Depth
332 BreakpointResolverName::GetDepth()
333 {
334     return Searcher::eDepthModule;
335 }
336 
337 void
338 BreakpointResolverName::GetDescription (Stream *s)
339 {
340     if (m_match_type == Breakpoint::Regexp)
341         s->Printf("regex = '%s'", m_regex.GetText());
342     else
343     {
344         size_t num_names = m_func_names.size();
345         if (num_names == 1)
346             s->Printf("name = '%s'", m_func_names[0].AsCString());
347         else
348         {
349             s->Printf("names = {");
350             for (size_t i = 0; i < num_names - 1; i++)
351             {
352                 s->Printf ("'%s', ", m_func_names[i].AsCString());
353             }
354             s->Printf ("'%s'}", m_func_names[num_names - 1].AsCString());
355         }
356     }
357 }
358 
359 void
360 BreakpointResolverName::Dump (Stream *s) const
361 {
362 
363 }
364 
365