429 lines · cpp
1//===-- BreakpointResolverName.cpp ----------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Breakpoint/BreakpointResolverName.h"10 11#include "lldb/Breakpoint/BreakpointLocation.h"12#include "lldb/Core/Architecture.h"13#include "lldb/Core/Module.h"14#include "lldb/Symbol/Block.h"15#include "lldb/Symbol/Function.h"16#include "lldb/Symbol/Symbol.h"17#include "lldb/Symbol/SymbolContext.h"18#include "lldb/Target/Language.h"19#include "lldb/Target/Target.h"20#include "lldb/Utility/LLDBLog.h"21#include "lldb/Utility/Log.h"22#include "lldb/Utility/StreamString.h"23 24using namespace lldb;25using namespace lldb_private;26 27BreakpointResolverName::BreakpointResolverName(28 const BreakpointSP &bkpt, const char *name_cstr,29 FunctionNameType name_type_mask, LanguageType language,30 Breakpoint::MatchType type, lldb::addr_t offset, bool offset_is_insn_count,31 bool skip_prologue)32 : BreakpointResolver(bkpt, BreakpointResolver::NameResolver, offset,33 offset_is_insn_count),34 m_match_type(type), m_language(language), m_skip_prologue(skip_prologue) {35 if (m_match_type == Breakpoint::Regexp) {36 m_regex = RegularExpression(name_cstr);37 if (!m_regex.IsValid()) {38 Log *log = GetLog(LLDBLog::Breakpoints);39 40 if (log)41 log->Warning("function name regexp: \"%s\" did not compile.",42 name_cstr);43 }44 } else {45 AddNameLookup(ConstString(name_cstr), name_type_mask);46 }47}48 49BreakpointResolverName::BreakpointResolverName(50 const BreakpointSP &bkpt, const char *names[], size_t num_names,51 FunctionNameType name_type_mask, LanguageType language, lldb::addr_t offset,52 bool skip_prologue)53 : BreakpointResolver(bkpt, BreakpointResolver::NameResolver, offset),54 m_match_type(Breakpoint::Exact), m_language(language),55 m_skip_prologue(skip_prologue) {56 for (size_t i = 0; i < num_names; i++) {57 AddNameLookup(ConstString(names[i]), name_type_mask);58 }59}60 61BreakpointResolverName::BreakpointResolverName(62 const BreakpointSP &bkpt, const std::vector<std::string> &names,63 FunctionNameType name_type_mask, LanguageType language, lldb::addr_t offset,64 bool skip_prologue)65 : BreakpointResolver(bkpt, BreakpointResolver::NameResolver, offset),66 m_match_type(Breakpoint::Exact), m_language(language),67 m_skip_prologue(skip_prologue) {68 for (const std::string &name : names) {69 AddNameLookup(ConstString(name.c_str(), name.size()), name_type_mask);70 }71}72 73BreakpointResolverName::BreakpointResolverName(const BreakpointSP &bkpt,74 RegularExpression func_regex,75 lldb::LanguageType language,76 lldb::addr_t offset,77 bool skip_prologue)78 : BreakpointResolver(bkpt, BreakpointResolver::NameResolver, offset),79 m_class_name(nullptr), m_regex(std::move(func_regex)),80 m_match_type(Breakpoint::Regexp), m_language(language),81 m_skip_prologue(skip_prologue) {}82 83BreakpointResolverName::BreakpointResolverName(84 const BreakpointResolverName &rhs)85 : BreakpointResolver(rhs.GetBreakpoint(), BreakpointResolver::NameResolver,86 rhs.GetOffset(), rhs.GetOffsetIsInsnCount()),87 m_lookups(rhs.m_lookups), m_class_name(rhs.m_class_name),88 m_regex(rhs.m_regex), m_match_type(rhs.m_match_type),89 m_language(rhs.m_language), m_skip_prologue(rhs.m_skip_prologue) {}90 91BreakpointResolverSP BreakpointResolverName::CreateFromStructuredData(92 const StructuredData::Dictionary &options_dict, Status &error) {93 LanguageType language = eLanguageTypeUnknown;94 llvm::StringRef language_name;95 bool success = options_dict.GetValueForKeyAsString(96 GetKey(OptionNames::LanguageName), language_name);97 if (success) {98 language = Language::GetLanguageTypeFromString(language_name);99 if (language == eLanguageTypeUnknown) {100 error = Status::FromErrorStringWithFormatv(101 "BRN::CFSD: Unknown language: {0}.", language_name);102 return nullptr;103 }104 }105 106 lldb::offset_t offset = 0;107 success =108 options_dict.GetValueForKeyAsInteger(GetKey(OptionNames::Offset), offset);109 if (!success) {110 error = Status::FromErrorString("BRN::CFSD: Missing offset entry.");111 return nullptr;112 }113 114 bool skip_prologue;115 success = options_dict.GetValueForKeyAsBoolean(116 GetKey(OptionNames::SkipPrologue), skip_prologue);117 if (!success) {118 error = Status::FromErrorString("BRN::CFSD: Missing Skip prologue entry.");119 return nullptr;120 }121 122 llvm::StringRef regex_text;123 success = options_dict.GetValueForKeyAsString(124 GetKey(OptionNames::RegexString), regex_text);125 if (success) {126 return std::make_shared<BreakpointResolverName>(127 nullptr, RegularExpression(regex_text), language, offset,128 skip_prologue);129 }130 StructuredData::Array *names_array;131 success = options_dict.GetValueForKeyAsArray(132 GetKey(OptionNames::SymbolNameArray), names_array);133 if (!success) {134 error = Status::FromErrorString("BRN::CFSD: Missing symbol names entry.");135 return nullptr;136 }137 StructuredData::Array *names_mask_array;138 success = options_dict.GetValueForKeyAsArray(139 GetKey(OptionNames::NameMaskArray), names_mask_array);140 if (!success) {141 error = Status::FromErrorString(142 "BRN::CFSD: Missing symbol names mask entry.");143 return nullptr;144 }145 146 size_t num_elem = names_array->GetSize();147 if (num_elem != names_mask_array->GetSize()) {148 error = Status::FromErrorString(149 "BRN::CFSD: names and names mask arrays have different sizes.");150 return nullptr;151 }152 153 if (num_elem == 0) {154 error = Status::FromErrorString(155 "BRN::CFSD: no name entry in a breakpoint by name breakpoint.");156 return nullptr;157 }158 std::vector<std::string> names;159 std::vector<FunctionNameType> name_masks;160 for (size_t i = 0; i < num_elem; i++) {161 std::optional<llvm::StringRef> maybe_name =162 names_array->GetItemAtIndexAsString(i);163 if (!maybe_name) {164 error =165 Status::FromErrorString("BRN::CFSD: name entry is not a string.");166 return nullptr;167 }168 auto maybe_fnt = names_mask_array->GetItemAtIndexAsInteger<169 std::underlying_type<FunctionNameType>::type>(i);170 if (!maybe_fnt) {171 error = Status::FromErrorString(172 "BRN::CFSD: name mask entry is not an integer.");173 return nullptr;174 }175 names.push_back(std::string(*maybe_name));176 name_masks.push_back(static_cast<FunctionNameType>(*maybe_fnt));177 }178 179 std::shared_ptr<BreakpointResolverName> resolver_sp =180 std::make_shared<BreakpointResolverName>(181 nullptr, names[0].c_str(), name_masks[0], language,182 Breakpoint::MatchType::Exact, offset,183 /*offset_is_insn_count = */ false, skip_prologue);184 for (size_t i = 1; i < num_elem; i++) {185 resolver_sp->AddNameLookup(ConstString(names[i]), name_masks[i]);186 }187 return resolver_sp;188}189 190StructuredData::ObjectSP BreakpointResolverName::SerializeToStructuredData() {191 StructuredData::DictionarySP options_dict_sp(192 new StructuredData::Dictionary());193 194 if (m_regex.IsValid()) {195 options_dict_sp->AddStringItem(GetKey(OptionNames::RegexString),196 m_regex.GetText());197 } else {198 StructuredData::ArraySP names_sp(new StructuredData::Array());199 StructuredData::ArraySP name_masks_sp(new StructuredData::Array());200 for (auto lookup : m_lookups) {201 names_sp->AddItem(std::make_shared<StructuredData::String>(202 lookup.GetName().GetStringRef()));203 name_masks_sp->AddItem(std::make_shared<StructuredData::UnsignedInteger>(204 lookup.GetNameTypeMask()));205 }206 options_dict_sp->AddItem(GetKey(OptionNames::SymbolNameArray), names_sp);207 options_dict_sp->AddItem(GetKey(OptionNames::NameMaskArray), name_masks_sp);208 }209 if (m_language != eLanguageTypeUnknown)210 options_dict_sp->AddStringItem(211 GetKey(OptionNames::LanguageName),212 Language::GetNameForLanguageType(m_language));213 options_dict_sp->AddBooleanItem(GetKey(OptionNames::SkipPrologue),214 m_skip_prologue);215 216 return WrapOptionsDict(options_dict_sp);217}218 219void BreakpointResolverName::AddNameLookup(ConstString name,220 FunctionNameType name_type_mask) {221 222 Module::LookupInfo lookup(name, name_type_mask, m_language);223 m_lookups.emplace_back(lookup);224 225 auto add_variant_funcs = [&](Language *lang) {226 for (Language::MethodNameVariant variant :227 lang->GetMethodNameVariants(name)) {228 // FIXME: Should we be adding variants that aren't of type Full?229 if (variant.GetType() & lldb::eFunctionNameTypeFull) {230 Module::LookupInfo variant_lookup(name, variant.GetType(),231 lang->GetLanguageType());232 variant_lookup.SetLookupName(variant.GetName());233 m_lookups.emplace_back(variant_lookup);234 }235 }236 return IterationAction::Continue;237 };238 239 if (Language *lang = Language::FindPlugin(m_language)) {240 add_variant_funcs(lang);241 } else {242 // Most likely m_language is eLanguageTypeUnknown. We check each language for243 // possible variants or more qualified names and create lookups for those as244 // well.245 Language::ForEach(add_variant_funcs);246 }247}248 249// FIXME: Right now we look at the module level, and call the module's250// "FindFunctions".251// Greg says he will add function tables, maybe at the CompileUnit level to252// accelerate function lookup. At that point, we should switch the depth to253// CompileUnit, and look in these tables.254 255Searcher::CallbackReturn256BreakpointResolverName::SearchCallback(SearchFilter &filter,257 SymbolContext &context, Address *addr) {258 Log *log = GetLog(LLDBLog::Breakpoints);259 260 if (m_class_name) {261 if (log)262 log->Warning("Class/method function specification not supported yet.\n");263 return Searcher::eCallbackReturnStop;264 }265 266 SymbolContextList func_list;267 bool filter_by_cu =268 (filter.GetFilterRequiredItems() & eSymbolContextCompUnit) != 0;269 bool filter_by_language = (m_language != eLanguageTypeUnknown);270 271 ModuleFunctionSearchOptions function_options;272 function_options.include_symbols = !filter_by_cu;273 function_options.include_inlines = true;274 275 switch (m_match_type) {276 case Breakpoint::Exact:277 if (context.module_sp) {278 for (const auto &lookup : m_lookups) {279 const size_t start_func_idx = func_list.GetSize();280 context.module_sp->FindFunctions(lookup, CompilerDeclContext(),281 function_options, func_list);282 283 const size_t end_func_idx = func_list.GetSize();284 285 if (start_func_idx < end_func_idx)286 lookup.Prune(func_list, start_func_idx);287 }288 }289 break;290 case Breakpoint::Regexp:291 if (context.module_sp) {292 context.module_sp->FindFunctions(m_regex, function_options, func_list);293 }294 break;295 case Breakpoint::Glob:296 if (log)297 log->Warning("glob is not supported yet.");298 break;299 }300 301 // If the filter specifies a Compilation Unit, remove the ones that don't302 // pass at this point.303 if (filter_by_cu || filter_by_language) {304 uint32_t num_functions = func_list.GetSize();305 306 for (size_t idx = 0; idx < num_functions; idx++) {307 bool remove_it = false;308 SymbolContext sc;309 func_list.GetContextAtIndex(idx, sc);310 if (filter_by_cu) {311 if (!sc.comp_unit || !filter.CompUnitPasses(*sc.comp_unit))312 remove_it = true;313 }314 315 if (filter_by_language) {316 LanguageType sym_language = sc.GetLanguage();317 if ((Language::GetPrimaryLanguage(sym_language) !=318 Language::GetPrimaryLanguage(m_language)) &&319 (sym_language != eLanguageTypeUnknown)) {320 remove_it = true;321 }322 }323 324 if (remove_it) {325 func_list.RemoveContextAtIndex(idx);326 num_functions--;327 idx--;328 }329 }330 }331 332 BreakpointSP breakpoint_sp = GetBreakpoint();333 Breakpoint &breakpoint = *breakpoint_sp;334 Address break_addr;335 336 // Remove any duplicates between the function list and the symbol list337 for (const SymbolContext &sc : func_list) {338 bool is_reexported = false;339 340 if (sc.block && sc.block->GetInlinedFunctionInfo()) {341 if (!sc.block->GetStartAddress(break_addr))342 break_addr.Clear();343 } else if (sc.function) {344 break_addr = sc.function->GetAddress();345 if (m_skip_prologue && break_addr.IsValid()) {346 const uint32_t prologue_byte_size = sc.function->GetPrologueByteSize();347 if (prologue_byte_size)348 break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size);349 }350 } else if (sc.symbol) {351 if (sc.symbol->GetType() == eSymbolTypeReExported) {352 const Symbol *actual_symbol =353 sc.symbol->ResolveReExportedSymbol(breakpoint.GetTarget());354 if (actual_symbol) {355 is_reexported = true;356 break_addr = actual_symbol->GetAddress();357 }358 } else {359 break_addr = sc.symbol->GetAddress();360 }361 362 if (m_skip_prologue && break_addr.IsValid()) {363 const uint32_t prologue_byte_size = sc.symbol->GetPrologueByteSize();364 if (prologue_byte_size)365 break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size);366 else {367 const Architecture *arch =368 breakpoint.GetTarget().GetArchitecturePlugin();369 if (arch)370 arch->AdjustBreakpointAddress(*sc.symbol, break_addr);371 }372 }373 }374 375 if (!break_addr.IsValid())376 continue;377 378 if (!filter.AddressPasses(break_addr))379 continue;380 381 bool new_location;382 BreakpointLocationSP bp_loc_sp(AddLocation(break_addr, &new_location));383 bp_loc_sp->SetIsReExported(is_reexported);384 if (bp_loc_sp && new_location && !breakpoint.IsInternal()) {385 if (log) {386 StreamString s;387 bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);388 LLDB_LOGF(log, "Added location: %s\n", s.GetData());389 }390 }391 }392 393 return Searcher::eCallbackReturnContinue;394}395 396lldb::SearchDepth BreakpointResolverName::GetDepth() {397 return lldb::eSearchDepthModule;398}399 400void BreakpointResolverName::GetDescription(Stream *s) {401 if (m_match_type == Breakpoint::Regexp)402 s->Printf("regex = '%s'", m_regex.GetText().str().c_str());403 else {404 size_t num_names = m_lookups.size();405 if (num_names == 1)406 s->Printf("name = '%s'", m_lookups[0].GetName().GetCString());407 else {408 s->Printf("names = {");409 for (size_t i = 0; i < num_names; i++) {410 s->Printf("%s'%s'", (i == 0 ? "" : ", "),411 m_lookups[i].GetName().GetCString());412 }413 s->Printf("}");414 }415 }416 if (m_language != eLanguageTypeUnknown) {417 s->Printf(", language = %s", Language::GetNameForLanguageType(m_language));418 }419}420 421void BreakpointResolverName::Dump(Stream *s) const {}422 423lldb::BreakpointResolverSP424BreakpointResolverName::CopyForBreakpoint(BreakpointSP &breakpoint) {425 lldb::BreakpointResolverSP ret_sp(new BreakpointResolverName(*this));426 ret_sp->SetBreakpoint(breakpoint);427 return ret_sp;428}429