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