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