From 76bb8d6719c2f664a69c4e2e89664c230f807a3b Mon Sep 17 00:00:00 2001 From: Jim Ingham Date: Thu, 28 Apr 2016 01:40:57 +0000 Subject: [PATCH] Add the ability to limit "source regexp" breakpoints to a particular function within a source file. This isn't done, I need to make the name match smarter (right now it requires an exact match which is annoying for methods of a class in a namespace. Also, though we use it in tests all over the place, it doesn't look like we have a test for Source Regexp breakpoints by themselves, I'll add that in a follow-on patch. llvm-svn: 267834 --- lldb/include/lldb/API/SBStringList.h | 3 ++ lldb/include/lldb/API/SBTarget.h | 6 +++ .../lldb/Breakpoint/BreakpointResolverFileRegex.h | 9 +++- lldb/include/lldb/Target/Target.h | 2 + lldb/scripts/interface/SBTarget.i | 6 +++ lldb/source/API/SBStringList.cpp | 10 ++++ lldb/source/API/SBTarget.cpp | 59 +++++++++++----------- .../Breakpoint/BreakpointResolverFileRegex.cpp | 38 +++++++++++++- lldb/source/Commands/CommandObjectBreakpoint.cpp | 12 ++++- lldb/source/Target/Target.cpp | 7 ++- 10 files changed, 118 insertions(+), 34 deletions(-) diff --git a/lldb/include/lldb/API/SBStringList.h b/lldb/include/lldb/API/SBStringList.h index e0e58f7..bc8ff93 100644 --- a/lldb/include/lldb/API/SBStringList.h +++ b/lldb/include/lldb/API/SBStringList.h @@ -45,6 +45,9 @@ public: const char * GetStringAtIndex (size_t idx); + const char * + GetStringAtIndex (size_t idx) const; + void Clear (); diff --git a/lldb/include/lldb/API/SBTarget.h b/lldb/include/lldb/API/SBTarget.h index 3514627..0bcabd0 100644 --- a/lldb/include/lldb/API/SBTarget.h +++ b/lldb/include/lldb/API/SBTarget.h @@ -694,6 +694,12 @@ public: const SBFileSpecList &source_file); lldb::SBBreakpoint + BreakpointCreateBySourceRegex (const char *source_regex, + const SBFileSpecList &module_list, + const SBFileSpecList &source_file, + const SBStringList &func_names); + + lldb::SBBreakpoint BreakpointCreateForException (lldb::LanguageType language, bool catch_bp, bool throw_bp); diff --git a/lldb/include/lldb/Breakpoint/BreakpointResolverFileRegex.h b/lldb/include/lldb/Breakpoint/BreakpointResolverFileRegex.h index a8d7a50..ce67c2d 100644 --- a/lldb/include/lldb/Breakpoint/BreakpointResolverFileRegex.h +++ b/lldb/include/lldb/Breakpoint/BreakpointResolverFileRegex.h @@ -12,9 +12,11 @@ // C Includes // C++ Includes +#include // Other libraries and framework includes // Project includes #include "lldb/Breakpoint/BreakpointResolver.h" +#include "lldb/Core/ConstString.h" namespace lldb_private { @@ -30,6 +32,7 @@ class BreakpointResolverFileRegex : public: BreakpointResolverFileRegex (Breakpoint *bkpt, RegularExpression ®ex, + const std::unordered_set &func_name_set, bool exact_match); ~BreakpointResolverFileRegex() override; @@ -48,6 +51,9 @@ public: void Dump (Stream *s) const override; + + void + AddFunctionName(const char *func_name); /// Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const BreakpointResolverFileRegex *) { return true; } @@ -61,7 +67,8 @@ public: protected: friend class Breakpoint; RegularExpression m_regex; // This is the line expression that we are looking for. - bool m_exact_match; + bool m_exact_match; // If true, then if the source we match is in a comment, we won't set a location there. + std::unordered_set m_function_names; // Limit the search to functions in the comp_unit passed in. private: DISALLOW_COPY_AND_ASSIGN(BreakpointResolverFileRegex); diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index 4f5284a..77125c9 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -797,9 +797,11 @@ public: LazyBool move_to_nearest_code); // Use this to create breakpoint that matches regex against the source lines in files given in source_file_list: + // If function_names is non-empty, also filter by function after the matches are made. lldb::BreakpointSP CreateSourceRegexBreakpoint (const FileSpecList *containingModules, const FileSpecList *source_file_list, + const std::unordered_set &function_names, RegularExpression &source_regex, bool internal, bool request_hardware, diff --git a/lldb/scripts/interface/SBTarget.i b/lldb/scripts/interface/SBTarget.i index b2409eb..6198c35 100644 --- a/lldb/scripts/interface/SBTarget.i +++ b/lldb/scripts/interface/SBTarget.i @@ -676,6 +676,12 @@ public: BreakpointCreateBySourceRegex (const char *source_regex, const lldb::SBFileSpecList &module_list, const lldb::SBFileSpecList &file_list); lldb::SBBreakpoint + BreakpointCreateBySourceRegex (const char *source_regex, + const SBFileSpecList &module_list, + const SBFileSpecList &source_file, + const SBStringList &func_names); + + lldb::SBBreakpoint BreakpointCreateForException (lldb::LanguageType language, bool catch_bp, bool throw_bp); diff --git a/lldb/source/API/SBStringList.cpp b/lldb/source/API/SBStringList.cpp index 129d2f4..f469bc4 100644 --- a/lldb/source/API/SBStringList.cpp +++ b/lldb/source/API/SBStringList.cpp @@ -126,6 +126,16 @@ SBStringList::GetStringAtIndex (size_t idx) return NULL; } +const char * +SBStringList::GetStringAtIndex (size_t idx) const +{ + if (IsValid()) + { + return m_opaque_ap->GetStringAtIndex (idx); + } + return NULL; +} + void SBStringList::Clear () { diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp index 2ef8bcd..220e136 100644 --- a/lldb/source/API/SBTarget.cpp +++ b/lldb/source/API/SBTarget.cpp @@ -22,6 +22,7 @@ #include "lldb/API/SBSourceManager.h" #include "lldb/API/SBProcess.h" #include "lldb/API/SBStream.h" +#include "lldb/API/SBStringList.h" #include "lldb/API/SBSymbolContextList.h" #include "lldb/Breakpoint/BreakpointID.h" #include "lldb/Breakpoint/BreakpointIDList.h" @@ -1124,42 +1125,21 @@ SBTarget::BreakpointCreateBySourceRegex (const char *source_regex, const lldb::SBFileSpec &source_file, const char *module_name) { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); - - SBBreakpoint sb_bp; - TargetSP target_sp(GetSP()); - if (target_sp && source_regex && source_regex[0]) - { - Mutex::Locker api_locker (target_sp->GetAPIMutex()); - RegularExpression regexp(source_regex); - FileSpecList source_file_spec_list; - const bool hardware = false; - const LazyBool move_to_nearest_code = eLazyBoolCalculate; - source_file_spec_list.Append (source_file.ref()); + SBFileSpecList module_spec_list; if (module_name && module_name[0]) { - FileSpecList module_spec_list; module_spec_list.Append (FileSpec (module_name, false)); - - *sb_bp = target_sp->CreateSourceRegexBreakpoint (&module_spec_list, &source_file_spec_list, regexp, false, hardware, move_to_nearest_code); } - else + + SBFileSpecList source_file_list; + if (source_file.IsValid()) { - *sb_bp = target_sp->CreateSourceRegexBreakpoint (NULL, &source_file_spec_list, regexp, false, hardware, move_to_nearest_code); + source_file_list.Append(source_file); } - } - - if (log) - { - char path[PATH_MAX]; - source_file->GetPath (path, sizeof(path)); - log->Printf ("SBTarget(%p)::BreakpointCreateByRegex (source_regex=\"%s\", file=\"%s\", module_name=\"%s\") => SBBreakpoint(%p)", - static_cast(target_sp.get()), source_regex, path, - module_name, static_cast(sb_bp.get())); - } + + return BreakpointCreateBySourceRegex (source_regex, module_spec_list, source_file_list); - return sb_bp; } lldb::SBBreakpoint @@ -1167,6 +1147,15 @@ SBTarget::BreakpointCreateBySourceRegex (const char *source_regex, const SBFileSpecList &module_list, const lldb::SBFileSpecList &source_file_list) { + return BreakpointCreateBySourceRegex(source_regex, module_list, source_file_list, SBStringList()); +} + +lldb::SBBreakpoint +SBTarget::BreakpointCreateBySourceRegex (const char *source_regex, + const SBFileSpecList &module_list, + const lldb::SBFileSpecList &source_file_list, + const SBStringList &func_names) +{ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); SBBreakpoint sb_bp; @@ -1177,7 +1166,19 @@ SBTarget::BreakpointCreateBySourceRegex (const char *source_regex, const bool hardware = false; const LazyBool move_to_nearest_code = eLazyBoolCalculate; RegularExpression regexp(source_regex); - *sb_bp = target_sp->CreateSourceRegexBreakpoint (module_list.get(), source_file_list.get(), regexp, false, hardware, move_to_nearest_code); + std::unordered_set func_names_set; + for (size_t i = 0; i < func_names.GetSize(); i++) + { + func_names_set.insert(func_names.GetStringAtIndex(i)); + } + + *sb_bp = target_sp->CreateSourceRegexBreakpoint (module_list.get(), + source_file_list.get(), + func_names_set, + regexp, + false, + hardware, + move_to_nearest_code); } if (log) diff --git a/lldb/source/Breakpoint/BreakpointResolverFileRegex.cpp b/lldb/source/Breakpoint/BreakpointResolverFileRegex.cpp index e7bce05..ae7f58a 100644 --- a/lldb/source/Breakpoint/BreakpointResolverFileRegex.cpp +++ b/lldb/source/Breakpoint/BreakpointResolverFileRegex.cpp @@ -30,11 +30,13 @@ BreakpointResolverFileRegex::BreakpointResolverFileRegex ( Breakpoint *bkpt, RegularExpression ®ex, + const std::unordered_set &func_names, bool exact_match ) : BreakpointResolver (bkpt, BreakpointResolver::FileLineResolver), m_regex (regex), - m_exact_match (exact_match) + m_exact_match (exact_match), + m_function_names(func_names) { } @@ -68,6 +70,32 @@ BreakpointResolverFileRegex::SearchCallback const bool search_inlines = false; cu->ResolveSymbolContext (cu_file_spec, line_matches[i], search_inlines, m_exact_match, eSymbolContextEverything, sc_list); + // Find all the function names: + if (!m_function_names.empty()) + { + std::vector sc_to_remove; + for (size_t i = 0; i < sc_list.GetSize(); i++) + { + SymbolContext sc_ctx; + sc_list.GetContextAtIndex(i, sc_ctx); + std::string name(sc_ctx.GetFunctionName(Mangled::NamePreference::ePreferDemangledWithoutArguments).AsCString()); + if (!m_function_names.count(name)) + { + sc_to_remove.push_back(i); + } + } + + if (!sc_to_remove.empty()) + { + std::vector::reverse_iterator iter; + std::vector::reverse_iterator rend = sc_to_remove.rend(); + for (iter = sc_to_remove.rbegin(); iter != rend; iter++) + { + sc_list.RemoveContextAtIndex(*iter); + } + } + } + const bool skip_prologue = true; BreakpointResolver::SetSCMatchesByLine (filter, sc_list, skip_prologue, m_regex.GetText()); @@ -98,7 +126,13 @@ BreakpointResolverFileRegex::Dump (Stream *s) const lldb::BreakpointResolverSP BreakpointResolverFileRegex::CopyForBreakpoint (Breakpoint &breakpoint) { - lldb::BreakpointResolverSP ret_sp(new BreakpointResolverFileRegex(&breakpoint, m_regex, m_exact_match)); + lldb::BreakpointResolverSP ret_sp(new BreakpointResolverFileRegex(&breakpoint, m_regex, m_function_names, m_exact_match)); return ret_sp; } +void +BreakpointResolverFileRegex::AddFunctionName(const char *func_name) +{ + m_function_names.insert(func_name); +} + diff --git a/lldb/source/Commands/CommandObjectBreakpoint.cpp b/lldb/source/Commands/CommandObjectBreakpoint.cpp index 8d4ec95..b7ed2a2 100644 --- a/lldb/source/Commands/CommandObjectBreakpoint.cpp +++ b/lldb/source/Commands/CommandObjectBreakpoint.cpp @@ -342,6 +342,10 @@ public: error.SetErrorStringWithFormat ("invalid thread index string '%s'", option_arg); break; + case 'X': + m_source_regex_func_names.insert(option_arg); + break; + default: error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); break; @@ -381,6 +385,7 @@ public: m_all_files = false; m_exception_extra_args.Clear(); m_move_to_nearest_code = eLazyBoolCalculate; + m_source_regex_func_names.clear(); } const OptionDefinition* @@ -423,6 +428,7 @@ public: bool m_all_files; Args m_exception_extra_args; LazyBool m_move_to_nearest_code; + std::unordered_set m_source_regex_func_names; }; protected: @@ -608,6 +614,7 @@ protected: } bp = target->CreateSourceRegexBreakpoint (&(m_options.m_modules), &(m_options.m_filenames), + m_options.m_source_regex_func_names, regexp, internal, m_options.m_hardware, @@ -805,6 +812,9 @@ CommandObjectBreakpointSet::CommandOptions::g_option_table[] = { LLDB_OPT_SET_3, true, "name", 'n', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eSymbolCompletion, eArgTypeFunctionName, "Set the breakpoint by function name. Can be repeated multiple times to make one breakpoint for multiple names" }, + { LLDB_OPT_SET_9, false, "source-regexp-function", 'X', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eSymbolCompletion, eArgTypeFunctionName, + "When used with '-p' limits the source regex to source contained in the named functions. Can be repeated multiple times." }, + { LLDB_OPT_SET_4, true, "fullname", 'F', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eSymbolCompletion, eArgTypeFullName, "Set the breakpoint by fully qualified function names. For C++ this means namespaces and all arguments, and " "for Objective C this means a full function prototype with class and selector. " @@ -855,7 +865,7 @@ CommandObjectBreakpointSet::CommandOptions::g_option_table[] = "Sets Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets."}, { LLDB_OPT_SET_ALL, false, "breakpoint-name", 'N', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBreakpointName, - "Adds this to the list of names for this breakopint."}, + "Adds this to the list of names for this breakpoint."}, { LLDB_OPT_OFFSET_APPLIES, false, "address-slide", 'R', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeAddress, "Add the specified offset to whatever address(es) the breakpoint resolves to. " diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index 6edb145..cae0a8d 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -326,6 +326,7 @@ Target::GetBreakpointByID (break_id_t break_id) BreakpointSP Target::CreateSourceRegexBreakpoint (const FileSpecList *containingModules, const FileSpecList *source_file_spec_list, + const std::unordered_set &function_names, RegularExpression &source_regex, bool internal, bool hardware, @@ -334,7 +335,11 @@ Target::CreateSourceRegexBreakpoint (const FileSpecList *containingModules, SearchFilterSP filter_sp(GetSearchFilterForModuleAndCUList (containingModules, source_file_spec_list)); if (move_to_nearest_code == eLazyBoolCalculate) move_to_nearest_code = GetMoveToNearestCode() ? eLazyBoolYes : eLazyBoolNo; - BreakpointResolverSP resolver_sp(new BreakpointResolverFileRegex(nullptr, source_regex, !static_cast(move_to_nearest_code))); + BreakpointResolverSP resolver_sp(new BreakpointResolverFileRegex(nullptr, + source_regex, + function_names, + !static_cast(move_to_nearest_code))); + return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, true); } -- 2.7.4