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 append = false;
124     bool filter_by_cu = (filter.GetFilterRequiredItems() & eSymbolContextCompUnit) != 0;
125 
126     switch (m_match_type)
127     {
128         case Breakpoint::Exact:
129             if (context.module_sp)
130             {
131                 uint32_t num_functions = context.module_sp->FindFunctions (m_func_name,
132                                                                            NULL,
133                                                                            m_func_name_type_mask,
134                                                                            include_symbols,
135                                                                            append,
136                                                                            func_list);
137                 // If the search filter specifies a Compilation Unit, then we don't need to bother to look in plain
138                 // symbols, since all the ones from a set compilation unit will have been found above already.
139 
140                 if (num_functions == 0 && !filter_by_cu)
141                 {
142                     if (m_func_name_type_mask & (eFunctionNameTypeBase | eFunctionNameTypeFull | eFunctionNameTypeAuto))
143                         context.module_sp->FindSymbolsWithNameAndType (m_func_name, NULL, eSymbolTypeCode, sym_list);
144                 }
145             }
146             break;
147         case Breakpoint::Regexp:
148             if (context.module_sp)
149             {
150                 if (!filter_by_cu)
151                     context.module_sp->FindSymbolsMatchingRegExAndType (m_regex, eSymbolTypeCode, sym_list);
152                 context.module_sp->FindFunctions (m_regex,
153                                                   include_symbols,
154                                                   append,
155                                                   func_list);
156             }
157             break;
158         case Breakpoint::Glob:
159             if (log)
160                 log->Warning ("glob is not supported yet.");
161             break;
162     }
163 
164     // If the filter specifies a Compilation Unit, remove the ones that don't pass at this point.
165     if (filter_by_cu)
166     {
167         uint32_t num_functions = func_list.GetSize();
168 
169         for (size_t idx = 0; idx < num_functions; idx++)
170         {
171             SymbolContext sc;
172             func_list.GetContextAtIndex(idx, sc);
173             if (!sc.comp_unit || !filter.CompUnitPasses(*sc.comp_unit))
174             {
175                 func_list.RemoveContextAtIndex(idx);
176                 num_functions--;
177                 idx--;
178             }
179         }
180     }
181 
182     // Remove any duplicates between the funcion list and the symbol list
183     if (func_list.GetSize())
184     {
185         for (i = 0; i < func_list.GetSize(); i++)
186         {
187             if (func_list.GetContextAtIndex(i, sc) == false)
188                 continue;
189 
190             if (sc.function == NULL)
191                 continue;
192             uint32_t j = 0;
193             while (j < sym_list.GetSize())
194             {
195                 SymbolContext symbol_sc;
196                 if (sym_list.GetContextAtIndex(j, symbol_sc))
197                 {
198                     if (symbol_sc.symbol && symbol_sc.symbol->GetAddressRangePtr())
199                     {
200                         if (sc.function->GetAddressRange().GetBaseAddress() == symbol_sc.symbol->GetAddressRangePtr()->GetBaseAddress())
201                         {
202                             sym_list.RemoveContextAtIndex(j);
203                             continue;   // Don't increment j
204                         }
205                     }
206                 }
207 
208                 j++;
209             }
210         }
211 
212         for (i = 0; i < func_list.GetSize(); i++)
213         {
214             if (func_list.GetContextAtIndex(i, sc))
215             {
216                 if (sc.block && sc.block->GetInlinedFunctionInfo())
217                 {
218                     if (!sc.block->GetStartAddress(break_addr))
219                         break_addr.Clear();
220                 }
221                 else if (sc.function)
222                 {
223                     break_addr = sc.function->GetAddressRange().GetBaseAddress();
224                     if (m_skip_prologue)
225                     {
226                         if (break_addr.IsValid())
227                         {
228                             const uint32_t prologue_byte_size = sc.function->GetPrologueByteSize();
229                             if (prologue_byte_size)
230                                 break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size);
231                         }
232                     }
233                 }
234 
235                 if (break_addr.IsValid())
236                 {
237                     if (filter.AddressPasses(break_addr))
238                     {
239                         BreakpointLocationSP bp_loc_sp (m_breakpoint->AddLocation(break_addr, &new_location));
240                         if (bp_loc_sp && new_location && !m_breakpoint->IsInternal())
241                         {
242                             if (log)
243                             {
244                                 StreamString s;
245                                 bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
246                                 log->Printf ("Added location: %s\n", s.GetData());
247                             }
248                         }
249                     }
250                 }
251             }
252         }
253     }
254 
255     for (i = 0; i < sym_list.GetSize(); i++)
256     {
257         if (sym_list.GetContextAtIndex(i, sc))
258         {
259             if (sc.symbol && sc.symbol->GetAddressRangePtr())
260             {
261                 break_addr = sc.symbol->GetAddressRangePtr()->GetBaseAddress();
262 
263                 if (m_skip_prologue)
264                 {
265                     const uint32_t prologue_byte_size = sc.symbol->GetPrologueByteSize();
266                     if (prologue_byte_size)
267                         break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size);
268                 }
269 
270                 if (filter.AddressPasses(break_addr))
271                 {
272                     BreakpointLocationSP bp_loc_sp (m_breakpoint->AddLocation(break_addr, &new_location));
273                     if (bp_loc_sp && new_location && !m_breakpoint->IsInternal())
274                     {
275                         StreamString s;
276                         bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
277                         if (log)
278                             log->Printf ("Added location: %s\n", s.GetData());
279                     }
280                 }
281             }
282         }
283     }
284     return Searcher::eCallbackReturnContinue;
285 }
286 
287 Searcher::Depth
288 BreakpointResolverName::GetDepth()
289 {
290     return Searcher::eDepthModule;
291 }
292 
293 void
294 BreakpointResolverName::GetDescription (Stream *s)
295 {
296     if (m_match_type == Breakpoint::Regexp)
297         s->Printf("regex = '%s'", m_regex.GetText());
298     else
299         s->Printf("name = '%s'", m_func_name.AsCString());
300 }
301 
302 void
303 BreakpointResolverName::Dump (Stream *s) const
304 {
305 
306 }
307 
308