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