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