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