brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.3 KiB · 4f252f9 Raw
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