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