summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointResolverName.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/lldb/source/Breakpoint/BreakpointResolverName.cpp')
-rw-r--r--contrib/llvm/tools/lldb/source/Breakpoint/BreakpointResolverName.cpp410
1 files changed, 410 insertions, 0 deletions
diff --git a/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointResolverName.cpp b/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointResolverName.cpp
new file mode 100644
index 0000000..9ae3fe5
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointResolverName.cpp
@@ -0,0 +1,410 @@
+//===-- BreakpointResolverName.cpp ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/BreakpointResolverName.h"
+
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Symbol/Block.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "Plugins/Language/ObjC/ObjCLanguage.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+BreakpointResolverName::BreakpointResolverName (Breakpoint *bkpt,
+ const char *name_cstr,
+ uint32_t name_type_mask,
+ LanguageType language,
+ Breakpoint::MatchType type,
+ bool skip_prologue) :
+ BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
+ m_class_name (),
+ m_regex (),
+ m_match_type (type),
+ m_language (language),
+ m_skip_prologue (skip_prologue)
+{
+ if (m_match_type == Breakpoint::Regexp)
+ {
+ if (!m_regex.Compile (name_cstr))
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+
+ if (log)
+ log->Warning ("function name regexp: \"%s\" did not compile.", name_cstr);
+ }
+ }
+ else
+ {
+ AddNameLookup (ConstString(name_cstr), name_type_mask);
+ }
+}
+
+BreakpointResolverName::BreakpointResolverName (Breakpoint *bkpt,
+ const char *names[],
+ size_t num_names,
+ uint32_t name_type_mask,
+ LanguageType language,
+ bool skip_prologue) :
+ BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
+ m_match_type (Breakpoint::Exact),
+ m_language (language),
+ m_skip_prologue (skip_prologue)
+{
+ for (size_t i = 0; i < num_names; i++)
+ {
+ AddNameLookup (ConstString (names[i]), name_type_mask);
+ }
+}
+
+BreakpointResolverName::BreakpointResolverName (Breakpoint *bkpt,
+ std::vector<std::string> names,
+ uint32_t name_type_mask,
+ LanguageType language,
+ bool skip_prologue) :
+ BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
+ m_match_type (Breakpoint::Exact),
+ m_language (language),
+ m_skip_prologue (skip_prologue)
+{
+ for (const std::string& name : names)
+ {
+ AddNameLookup (ConstString (name.c_str(), name.size()), name_type_mask);
+ }
+}
+
+BreakpointResolverName::BreakpointResolverName (Breakpoint *bkpt,
+ RegularExpression &func_regex,
+ lldb::LanguageType language,
+ bool skip_prologue) :
+ BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
+ m_class_name (nullptr),
+ m_regex (func_regex),
+ m_match_type (Breakpoint::Regexp),
+ m_language (language),
+ m_skip_prologue (skip_prologue)
+{
+}
+
+BreakpointResolverName::BreakpointResolverName(Breakpoint *bkpt,
+ const char *class_name,
+ const char *method,
+ Breakpoint::MatchType type,
+ bool skip_prologue ) :
+ BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
+ m_class_name (class_name),
+ m_regex (),
+ m_match_type (type),
+ m_language (eLanguageTypeUnknown),
+ m_skip_prologue (skip_prologue)
+{
+ LookupInfo lookup;
+ lookup.name.SetCString(method);
+ lookup.lookup_name = lookup.name;
+ lookup.name_type_mask = eFunctionNameTypeMethod;
+ lookup.match_name_after_lookup = false;
+ m_lookups.push_back (lookup);
+}
+
+BreakpointResolverName::~BreakpointResolverName() = default;
+
+BreakpointResolverName::BreakpointResolverName(const BreakpointResolverName &rhs) :
+ BreakpointResolver(rhs.m_breakpoint, BreakpointResolver::NameResolver),
+ m_lookups(rhs.m_lookups),
+ m_class_name(rhs.m_class_name),
+ m_regex(rhs.m_regex),
+ m_match_type (rhs.m_match_type),
+ m_language (rhs.m_language),
+ m_skip_prologue (rhs.m_skip_prologue)
+{
+}
+
+void
+BreakpointResolverName::AddNameLookup (const ConstString &name, uint32_t name_type_mask)
+{
+ ObjCLanguage::MethodName objc_method(name.GetCString(), false);
+ if (objc_method.IsValid(false))
+ {
+ std::vector<ConstString> objc_names;
+ objc_method.GetFullNames(objc_names, true);
+ for (ConstString objc_name : objc_names)
+ {
+ LookupInfo lookup;
+ lookup.name = name;
+ lookup.lookup_name = objc_name;
+ lookup.name_type_mask = eFunctionNameTypeFull;
+ lookup.match_name_after_lookup = false;
+ m_lookups.push_back (lookup);
+ }
+ }
+ else
+ {
+ LookupInfo lookup;
+ lookup.name = name;
+ Module::PrepareForFunctionNameLookup(lookup.name, name_type_mask, m_language, lookup.lookup_name, lookup.name_type_mask, lookup.match_name_after_lookup);
+ m_lookups.push_back (lookup);
+ }
+}
+
+void
+BreakpointResolverName::LookupInfo::Prune (SymbolContextList &sc_list, size_t start_idx) const
+{
+ if (match_name_after_lookup && name)
+ {
+ SymbolContext sc;
+ size_t i = start_idx;
+ while (i < sc_list.GetSize())
+ {
+ if (!sc_list.GetContextAtIndex(i, sc))
+ break;
+ ConstString full_name (sc.GetFunctionName());
+ if (full_name && ::strstr(full_name.GetCString(), name.GetCString()) == nullptr)
+ {
+ sc_list.RemoveContextAtIndex(i);
+ }
+ else
+ {
+ ++i;
+ }
+ }
+ }
+}
+
+// FIXME: Right now we look at the module level, and call the module's "FindFunctions".
+// Greg says he will add function tables, maybe at the CompileUnit level to accelerate function
+// lookup. At that point, we should switch the depth to CompileUnit, and look in these tables.
+
+Searcher::CallbackReturn
+BreakpointResolverName::SearchCallback(SearchFilter &filter,
+ SymbolContext &context,
+ Address *addr,
+ bool containing)
+{
+ SymbolContextList func_list;
+ //SymbolContextList sym_list;
+
+ uint32_t i;
+ bool new_location;
+ Address break_addr;
+ assert (m_breakpoint != nullptr);
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+
+ if (m_class_name)
+ {
+ if (log)
+ log->Warning ("Class/method function specification not supported yet.\n");
+ return Searcher::eCallbackReturnStop;
+ }
+ bool filter_by_cu = (filter.GetFilterRequiredItems() & eSymbolContextCompUnit) != 0;
+ bool filter_by_language = (m_language != eLanguageTypeUnknown);
+ const bool include_symbols = !filter_by_cu;
+ const bool include_inlines = true;
+ const bool append = true;
+
+ switch (m_match_type)
+ {
+ case Breakpoint::Exact:
+ if (context.module_sp)
+ {
+ for (const LookupInfo &lookup : m_lookups)
+ {
+ const size_t start_func_idx = func_list.GetSize();
+ context.module_sp->FindFunctions(lookup.lookup_name,
+ nullptr,
+ lookup.name_type_mask,
+ include_symbols,
+ include_inlines,
+ append,
+ func_list);
+ const size_t end_func_idx = func_list.GetSize();
+
+ if (start_func_idx < end_func_idx)
+ lookup.Prune (func_list, start_func_idx);
+ }
+ }
+ break;
+ case Breakpoint::Regexp:
+ if (context.module_sp)
+ {
+ context.module_sp->FindFunctions (m_regex,
+ !filter_by_cu, // include symbols only if we aren't filtering by CU
+ include_inlines,
+ append,
+ func_list);
+ }
+ break;
+ case Breakpoint::Glob:
+ if (log)
+ log->Warning ("glob is not supported yet.");
+ break;
+ }
+
+ // If the filter specifies a Compilation Unit, remove the ones that don't pass at this point.
+ if (filter_by_cu || filter_by_language)
+ {
+ uint32_t num_functions = func_list.GetSize();
+
+ for (size_t idx = 0; idx < num_functions; idx++)
+ {
+ bool remove_it = false;
+ SymbolContext sc;
+ func_list.GetContextAtIndex(idx, sc);
+ if (filter_by_cu)
+ {
+ if (!sc.comp_unit || !filter.CompUnitPasses(*sc.comp_unit))
+ remove_it = true;
+ }
+
+ if (filter_by_language)
+ {
+ LanguageType sym_language = sc.GetLanguage();
+ if ((Language::GetPrimaryLanguage(sym_language) !=
+ Language::GetPrimaryLanguage(m_language)) &&
+ (sym_language != eLanguageTypeUnknown))
+ {
+ remove_it = true;
+ }
+ }
+
+ if (remove_it)
+ {
+ func_list.RemoveContextAtIndex(idx);
+ num_functions--;
+ idx--;
+ }
+ }
+ }
+
+ // Remove any duplicates between the function list and the symbol list
+ SymbolContext sc;
+ if (func_list.GetSize())
+ {
+ for (i = 0; i < func_list.GetSize(); i++)
+ {
+ if (func_list.GetContextAtIndex(i, sc))
+ {
+ bool is_reexported = false;
+
+ if (sc.block && sc.block->GetInlinedFunctionInfo())
+ {
+ if (!sc.block->GetStartAddress(break_addr))
+ break_addr.Clear();
+ }
+ else if (sc.function)
+ {
+ break_addr = sc.function->GetAddressRange().GetBaseAddress();
+ if (m_skip_prologue && break_addr.IsValid())
+ {
+ const uint32_t prologue_byte_size = sc.function->GetPrologueByteSize();
+ if (prologue_byte_size)
+ break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size);
+ }
+ }
+ else if (sc.symbol)
+ {
+ if (sc.symbol->GetType() == eSymbolTypeReExported)
+ {
+ const Symbol *actual_symbol = sc.symbol->ResolveReExportedSymbol(m_breakpoint->GetTarget());
+ if (actual_symbol)
+ {
+ is_reexported = true;
+ break_addr = actual_symbol->GetAddress();
+ }
+ }
+ else
+ {
+ break_addr = sc.symbol->GetAddress();
+ }
+
+ if (m_skip_prologue && break_addr.IsValid())
+ {
+ const uint32_t prologue_byte_size = sc.symbol->GetPrologueByteSize();
+ if (prologue_byte_size)
+ break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size);
+ }
+ }
+
+ if (break_addr.IsValid())
+ {
+ if (filter.AddressPasses(break_addr))
+ {
+ BreakpointLocationSP bp_loc_sp (m_breakpoint->AddLocation(break_addr, &new_location));
+ bp_loc_sp->SetIsReExported(is_reexported);
+ if (bp_loc_sp && new_location && !m_breakpoint->IsInternal())
+ {
+ if (log)
+ {
+ StreamString s;
+ bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
+ log->Printf ("Added location: %s\n", s.GetData());
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return Searcher::eCallbackReturnContinue;
+}
+
+Searcher::Depth
+BreakpointResolverName::GetDepth()
+{
+ return Searcher::eDepthModule;
+}
+
+void
+BreakpointResolverName::GetDescription (Stream *s)
+{
+ if (m_match_type == Breakpoint::Regexp)
+ s->Printf("regex = '%s'", m_regex.GetText());
+ else
+ {
+ size_t num_names = m_lookups.size();
+ if (num_names == 1)
+ s->Printf("name = '%s'", m_lookups[0].name.GetCString());
+ else
+ {
+ s->Printf("names = {");
+ for (size_t i = 0; i < num_names - 1; i++)
+ {
+ s->Printf ("'%s', ", m_lookups[i].name.GetCString());
+ }
+ s->Printf ("'%s'}", m_lookups[num_names - 1].name.GetCString());
+ }
+ }
+ if (m_language != eLanguageTypeUnknown)
+ {
+ s->Printf (", language = %s", Language::GetNameForLanguageType(m_language));
+ }
+}
+
+void
+BreakpointResolverName::Dump (Stream *s) const
+{
+}
+
+lldb::BreakpointResolverSP
+BreakpointResolverName::CopyForBreakpoint (Breakpoint &breakpoint)
+{
+ lldb::BreakpointResolverSP ret_sp(new BreakpointResolverName(*this));
+ ret_sp->SetBreakpoint(&breakpoint);
+ return ret_sp;
+}
OpenPOWER on IntegriCloud