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