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