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