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