Index: include/lldb/API/SBFileSpec.h =================================================================== --- include/lldb/API/SBFileSpec.h +++ include/lldb/API/SBFileSpec.h @@ -25,6 +25,8 @@ SBFileSpec(const char *path, bool resolve); + SBFileSpec(const char *path, bool resolve, bool regex); + ~SBFileSpec(); const SBFileSpec &operator=(const lldb::SBFileSpec &rhs); Index: include/lldb/Utility/FileSpec.h =================================================================== --- include/lldb/Utility/FileSpec.h +++ include/lldb/Utility/FileSpec.h @@ -64,7 +64,8 @@ enum PathSyntax { ePathSyntaxPosix, ePathSyntaxWindows, - ePathSyntaxHostNative + ePathSyntaxHostNative, + ePathSyntaxRegex /// Used for regex and behaves like ePatchSyntaxPosix. }; FileSpec(); Index: packages/Python/lldbsuite/test/python_api/breakpoint/TestBreakpointAPI.py =================================================================== --- packages/Python/lldbsuite/test/python_api/breakpoint/TestBreakpointAPI.py +++ packages/Python/lldbsuite/test/python_api/breakpoint/TestBreakpointAPI.py @@ -75,3 +75,33 @@ self.assertTrue(self.dbg.DeleteTarget(target)) self.assertFalse(breakpoint.IsValid()) self.assertFalse(location.IsValid()) + + @add_test_categories(['pyapi']) + def test_target_regex(self): + """Make sure that if an SBTarget gets deleted the associated + Breakpoint's IsValid returns false.""" + + self.build() + exe = os.path.join(os.getcwd(), "a.out") + + # Create a target by the debugger. + target = self.dbg.CreateTarget(exe) + self.assertTrue(target, VALID_TARGET) + + file_list = lldb.SBFileSpecList(); + file_list.Append(lldb.SBFileSpec(".*[m]ain.*\.[c]p*", False, True)) + module_list = lldb.SBFileSpecList(); + module_list.Append(lldb.SBFileSpec(".*a\..*t", False, True)) + + # Now create a breakpoint on main.c by name 'AFunction'. + breakpoint = target.BreakpointCreateByName('AFunction', lldb.eFunctionNameTypeAuto, module_list, file_list) + #print("breakpoint:", breakpoint) + self.assertTrue(breakpoint and + breakpoint.GetNumLocations() == 1, + VALID_BREAKPOINT) + location = breakpoint.GetLocationAtIndex(0) + self.assertTrue(location.IsValid()) + + self.assertTrue(self.dbg.DeleteTarget(target)) + self.assertFalse(breakpoint.IsValid()) + self.assertFalse(location.IsValid()) Index: scripts/interface/SBFileSpec.i =================================================================== --- scripts/interface/SBFileSpec.i +++ scripts/interface/SBFileSpec.i @@ -41,6 +41,8 @@ SBFileSpec (const char *path, bool resolve); + SBFileSpec (const char *path, bool resolve, bool regex); + ~SBFileSpec (); bool Index: source/API/SBFileSpec.cpp =================================================================== --- source/API/SBFileSpec.cpp +++ source/API/SBFileSpec.cpp @@ -37,6 +37,11 @@ SBFileSpec::SBFileSpec(const char *path, bool resolve) : m_opaque_ap(new FileSpec(path, resolve)) {} +SBFileSpec::SBFileSpec(const char *path, bool resolve, bool regex) + : m_opaque_ap(new FileSpec(path, resolve, + regex ? FileSpec::ePathSyntaxRegex + : FileSpec::ePathSyntaxHostNative)) {} + SBFileSpec::~SBFileSpec() {} const SBFileSpec &SBFileSpec::operator=(const SBFileSpec &rhs) { Index: source/Commands/CommandObjectBreakpoint.cpp =================================================================== --- source/Commands/CommandObjectBreakpoint.cpp +++ source/Commands/CommandObjectBreakpoint.cpp @@ -256,6 +256,8 @@ { LLDB_OPT_NOT_10, false, "shlib", 's', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eModuleCompletion, eArgTypeShlibName, "Set the breakpoint only in this shared library. Can repeat this option " "multiple times to specify multiple shared libraries." }, { LLDB_OPT_SET_ALL, false, "hardware", 'H', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Require the breakpoint to use hardware breakpoints." }, + { LLDB_OPT_FILE, false, "source-file-regex", 'z', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eSourceFileCompletion, eArgTypeRegularExpression, "Only files matching pattern." }, + { LLDB_OPT_FILE, false, "module-regex", 'Z', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eSourceFileCompletion, eArgTypeRegularExpression, "Only modules matching pattern." }, { LLDB_OPT_FILE, false, "file", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eSourceFileCompletion, eArgTypeFilename, "Specifies the source file in which to set this breakpoint. Note, by default " "lldb only looks for files that are #included if they use the standard include " "file extensions. To set breakpoints on .c/.cpp/.m/.mm files that are " @@ -560,6 +562,16 @@ m_source_regex_func_names.insert(option_arg); break; + case 'z': + m_filenames.AppendIfUnique( + FileSpec(option_arg, false, FileSpec::ePathSyntaxRegex)); + break; + + case 'Z': + m_modules.AppendIfUnique( + FileSpec(option_arg, false, FileSpec::ePathSyntaxRegex)); + break; + default: error.SetErrorStringWithFormat("unrecognized option '%c'", short_option); Index: source/Core/FileSpecList.cpp =================================================================== --- source/Core/FileSpecList.cpp +++ source/Core/FileSpecList.cpp @@ -10,6 +10,7 @@ #include "lldb/Core/FileSpecList.h" #include "lldb/Utility/ConstString.h" // for ConstString +#include "lldb/Utility/RegularExpression.h" #include "lldb/Utility/Stream.h" #include // for find @@ -90,6 +91,12 @@ bool compare_filename_only = file_spec.GetDirectory().IsEmpty(); for (size_t idx = start_idx; idx < num_files; ++idx) { + if (m_files[idx].GetPathSyntax() == FileSpec::ePathSyntaxRegex) { + RegularExpression regex(m_files[idx].GetPath(false)); + if (regex.Execute(file_spec.GetPath())) + return idx; + continue; + } if (compare_filename_only) { if (ConstString::Equals( m_files[idx].GetFilename(), file_spec.GetFilename(), Index: source/Utility/FileSpec.cpp =================================================================== --- source/Utility/FileSpec.cpp +++ source/Utility/FileSpec.cpp @@ -48,7 +48,8 @@ bool PathSyntaxIsPosix(FileSpec::PathSyntax syntax) { return (syntax == FileSpec::ePathSyntaxPosix || (syntax == FileSpec::ePathSyntaxHostNative && - GetNativeSyntax() == FileSpec::ePathSyntaxPosix)); + GetNativeSyntax() == FileSpec::ePathSyntaxPosix) || + syntax == FileSpec::ePathSyntaxRegex); } const char *GetPathSeparators(FileSpec::PathSyntax syntax) {