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