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