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