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