Index: include/lldb/Breakpoint/BreakpointResolverFileLine.h =================================================================== --- include/lldb/Breakpoint/BreakpointResolverFileLine.h +++ include/lldb/Breakpoint/BreakpointResolverFileLine.h @@ -32,7 +32,8 @@ const FileSpec &resolver, uint32_t line_no, bool check_inlines, - bool skip_prologue); + bool skip_prologue, + bool exact_match); virtual ~BreakpointResolverFileLine (); @@ -67,6 +68,7 @@ uint32_t m_line_number; // This is the line number that we are looking for. bool m_inlines; // This determines whether the resolver looks for inlined functions or not. bool m_skip_prologue; + bool m_exact_match; private: DISALLOW_COPY_AND_ASSIGN(BreakpointResolverFileLine); Index: include/lldb/Breakpoint/BreakpointResolverFileRegex.h =================================================================== --- include/lldb/Breakpoint/BreakpointResolverFileRegex.h +++ include/lldb/Breakpoint/BreakpointResolverFileRegex.h @@ -29,7 +29,8 @@ { public: BreakpointResolverFileRegex (Breakpoint *bkpt, - RegularExpression ®ex); + RegularExpression ®ex, + bool exact_match); virtual ~BreakpointResolverFileRegex (); @@ -61,6 +62,7 @@ protected: friend class Breakpoint; RegularExpression m_regex; // This is the line expression that we are looking for. + bool m_exact_match; private: DISALLOW_COPY_AND_ASSIGN(BreakpointResolverFileRegex); Index: include/lldb/Target/Target.h =================================================================== --- include/lldb/Target/Target.h +++ include/lldb/Target/Target.h @@ -64,6 +64,9 @@ void SetDefaultArchitecture (const ArchSpec& arch); + bool + GetExactMatch () const; + lldb::DynamicValueType GetPreferDynamicValue() const; @@ -695,7 +698,8 @@ LazyBool check_inlines, LazyBool skip_prologue, bool internal, - bool request_hardware); + bool request_hardware, + LazyBool exact_match); // Use this to create breakpoint that matches regex against the source lines in files given in source_file_list: lldb::BreakpointSP @@ -703,7 +707,8 @@ const FileSpecList *source_file_list, RegularExpression &source_regex, bool internal, - bool request_hardware); + bool request_hardware, + LazyBool exact_match); // Use this to create a breakpoint from a load address lldb::BreakpointSP Index: source/API/SBTarget.cpp =================================================================== --- source/API/SBTarget.cpp +++ source/API/SBTarget.cpp @@ -808,7 +808,8 @@ const LazyBool skip_prologue = eLazyBoolCalculate; const bool internal = false; const bool hardware = false; - *sb_bp = target_sp->CreateBreakpoint (NULL, *sb_file_spec, line, check_inlines, skip_prologue, internal, hardware); + const LazyBool exact_match = eLazyBoolCalculate; + *sb_bp = target_sp->CreateBreakpoint (NULL, *sb_file_spec, line, check_inlines, skip_prologue, internal, hardware, exact_match); } if (log) @@ -1055,6 +1056,7 @@ RegularExpression regexp(source_regex); FileSpecList source_file_spec_list; const bool hardware = false; + const LazyBool exact_match = eLazyBoolCalculate; source_file_spec_list.Append (source_file.ref()); if (module_name && module_name[0]) @@ -1062,11 +1064,11 @@ 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); + *sb_bp = target_sp->CreateSourceRegexBreakpoint (&module_spec_list, &source_file_spec_list, regexp, false, hardware, exact_match); } else { - *sb_bp = target_sp->CreateSourceRegexBreakpoint (NULL, &source_file_spec_list, regexp, false, hardware); + *sb_bp = target_sp->CreateSourceRegexBreakpoint (NULL, &source_file_spec_list, regexp, false, hardware, exact_match); } } @@ -1095,8 +1097,9 @@ { Mutex::Locker api_locker (target_sp->GetAPIMutex()); const bool hardware = false; + const LazyBool exact_match = eLazyBoolCalculate; RegularExpression regexp(source_regex); - *sb_bp = target_sp->CreateSourceRegexBreakpoint (module_list.get(), source_file_list.get(), regexp, false, hardware); + *sb_bp = target_sp->CreateSourceRegexBreakpoint (module_list.get(), source_file_list.get(), regexp, false, hardware, exact_match); } if (log) Index: source/Breakpoint/BreakpointResolverFileLine.cpp =================================================================== --- source/Breakpoint/BreakpointResolverFileLine.cpp +++ source/Breakpoint/BreakpointResolverFileLine.cpp @@ -32,13 +32,15 @@ const FileSpec &file_spec, uint32_t line_no, bool check_inlines, - bool skip_prologue + bool skip_prologue, + bool exact_match ) : BreakpointResolver (bkpt, BreakpointResolver::FileLineResolver), m_file_spec (file_spec), m_line_number (line_no), m_inlines (check_inlines), - m_skip_prologue(skip_prologue) + m_skip_prologue(skip_prologue), + m_exact_match(exact_match) { } @@ -78,7 +80,7 @@ if (cu_sp) { if (filter.CompUnitPasses(*cu_sp)) - cu_sp->ResolveSymbolContext (m_file_spec, m_line_number, m_inlines, false, eSymbolContextEverything, sc_list); + cu_sp->ResolveSymbolContext (m_file_spec, m_line_number, m_inlines, m_exact_match, eSymbolContextEverything, sc_list); } } StreamString s; @@ -116,7 +118,8 @@ m_file_spec, m_line_number, m_inlines, - m_skip_prologue)); + m_skip_prologue, + m_exact_match)); return ret_sp; } Index: source/Breakpoint/BreakpointResolverFileRegex.cpp =================================================================== --- source/Breakpoint/BreakpointResolverFileRegex.cpp +++ source/Breakpoint/BreakpointResolverFileRegex.cpp @@ -29,10 +29,12 @@ BreakpointResolverFileRegex::BreakpointResolverFileRegex ( Breakpoint *bkpt, - RegularExpression ®ex + RegularExpression ®ex, + bool exact_match ) : BreakpointResolver (bkpt, BreakpointResolver::FileLineResolver), - m_regex (regex) + m_regex (regex), + m_exact_match (exact_match) { } @@ -64,9 +66,8 @@ { SymbolContextList sc_list; const bool search_inlines = false; - const bool exact = false; - cu->ResolveSymbolContext (cu_file_spec, line_matches[i], search_inlines, exact, eSymbolContextEverything, sc_list); + cu->ResolveSymbolContext (cu_file_spec, line_matches[i], search_inlines, m_exact_match, eSymbolContextEverything, sc_list); const bool skip_prologue = true; BreakpointResolver::SetSCMatchesByLine (filter, sc_list, skip_prologue, m_regex.GetText()); @@ -97,7 +98,7 @@ lldb::BreakpointResolverSP BreakpointResolverFileRegex::CopyForBreakpoint (Breakpoint &breakpoint) { - lldb::BreakpointResolverSP ret_sp(new BreakpointResolverFileRegex(&breakpoint, m_regex)); + lldb::BreakpointResolverSP ret_sp(new BreakpointResolverFileRegex(&breakpoint, m_regex, m_exact_match)); return ret_sp; } Index: source/Commands/CommandObjectBreakpoint.cpp =================================================================== --- source/Commands/CommandObjectBreakpoint.cpp +++ source/Commands/CommandObjectBreakpoint.cpp @@ -115,7 +115,8 @@ m_exception_language (eLanguageTypeUnknown), m_skip_prologue (eLazyBoolCalculate), m_one_shot (false), - m_all_files (false) + m_all_files (false), + m_exact_match (eLazyBoolCalculate) { } @@ -249,6 +250,11 @@ error.SetErrorStringWithFormat ("invalid line number: %s.", option_arg); break; } + + case 'm': + m_exact_match = eLazyBoolYes; + break; + case 'M': m_func_names.push_back (option_arg); m_func_name_type_mask |= eFunctionNameTypeMethod; @@ -361,6 +367,7 @@ m_breakpoint_names.clear(); m_all_files = false; m_exception_extra_args.Clear(); + m_exact_match = eLazyBoolCalculate; } const OptionDefinition* @@ -400,6 +407,7 @@ bool m_use_dummy; bool m_all_files; Args m_exception_extra_args; + LazyBool m_exact_match; }; @@ -477,7 +485,8 @@ check_inlines, m_options.m_skip_prologue, internal, - m_options.m_hardware).get(); + m_options.m_hardware, + m_options.m_exact_match).get(); } break; @@ -558,7 +567,8 @@ &(m_options.m_filenames), regexp, internal, - m_options.m_hardware).get(); + m_options.m_hardware, + m_options.m_exact_match).get(); } break; case eSetTypeException: @@ -689,6 +699,7 @@ #define LLDB_OPT_FILE ( LLDB_OPT_SET_FROM_TO(1, 9) & ~LLDB_OPT_SET_2 ) #define LLDB_OPT_NOT_10 ( LLDB_OPT_SET_FROM_TO(1, 10) & ~LLDB_OPT_SET_10 ) #define LLDB_OPT_SKIP_PROLOGUE ( LLDB_OPT_SET_1 | LLDB_OPT_SET_FROM_TO(3,8) ) +#define LLDB_OPT_EXACT_MATCH ( LLDB_OPT_SET_1 | LLDB_OPT_SET_9 ) OptionDefinition CommandObjectBreakpointSet::CommandOptions::g_option_table[] = @@ -789,6 +800,9 @@ { LLDB_OPT_SET_ALL, false, "breakpoint-name", 'N', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBreakpointName, "Adds this to the list of names for this breakopint."}, + { LLDB_OPT_EXACT_MATCH, false, "exact-match", 'm', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, + "Don't set the breakpoint if the line number doesn't Match." }, + { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; Index: source/Core/IOHandler.cpp =================================================================== --- source/Core/IOHandler.cpp +++ source/Core/IOHandler.cpp @@ -5326,7 +5326,8 @@ eLazyBoolCalculate, // Check inlines using global setting eLazyBoolCalculate, // Skip prologue using global setting, false, // internal - false); // request_hardware + false, // request_hardware + eLazyBoolCalculate); // exact_match // Make breakpoint one shot bp_sp->GetOptions()->SetOneShot(true); exe_ctx.GetProcessRef().Resume(); @@ -5361,7 +5362,8 @@ eLazyBoolCalculate, // Check inlines using global setting eLazyBoolCalculate, // Skip prologue using global setting, false, // internal - false); // request_hardware + false, // request_hardware + eLazyBoolCalculate); // exact_match } } else if (m_selected_line < GetNumDisassemblyLines()) Index: source/Target/Target.cpp =================================================================== --- source/Target/Target.cpp +++ source/Target/Target.cpp @@ -273,10 +273,13 @@ const FileSpecList *source_file_spec_list, RegularExpression &source_regex, bool internal, - bool hardware) + bool hardware, + LazyBool exact_match) { SearchFilterSP filter_sp(GetSearchFilterForModuleAndCUList (containingModules, source_file_spec_list)); - BreakpointResolverSP resolver_sp(new BreakpointResolverFileRegex (NULL, source_regex)); + if (exact_match == eLazyBoolCalculate) + exact_match = GetExactMatch() ? eLazyBoolYes : eLazyBoolNo; + BreakpointResolverSP resolver_sp(new BreakpointResolverFileRegex (NULL, source_regex, static_cast(exact_match))); return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, true); } @@ -288,7 +291,8 @@ LazyBool check_inlines, LazyBool skip_prologue, bool internal, - bool hardware) + bool hardware, + LazyBool exact_match) { if (check_inlines == eLazyBoolCalculate) { @@ -325,12 +329,15 @@ } if (skip_prologue == eLazyBoolCalculate) skip_prologue = GetSkipPrologue() ? eLazyBoolYes : eLazyBoolNo; + if (exact_match == eLazyBoolCalculate) + exact_match = GetExactMatch() ? eLazyBoolYes : eLazyBoolNo; BreakpointResolverSP resolver_sp(new BreakpointResolverFileLine (NULL, file, line_no, check_inlines, - skip_prologue)); + skip_prologue, + static_cast(exact_match))); return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, true); } @@ -2927,6 +2934,7 @@ g_properties[] = { { "default-arch" , OptionValue::eTypeArch , true , 0 , NULL, NULL, "Default architecture to choose, when there's a choice." }, + { "exact-match" , OptionValue::eTypeBoolean , false, false , NULL, NULL, "Don't set the breakpoint when the resolved line number doesn't match to the original." }, { "expr-prefix" , OptionValue::eTypeFileSpec , false, 0 , NULL, NULL, "Path to a file containing expressions to be prepended to all expressions." }, { "prefer-dynamic-value" , OptionValue::eTypeEnum , false, eDynamicDontRunTarget , NULL, g_dynamic_value_types, "Should printed values be shown as their dynamic value." }, { "enable-synthetic-value" , OptionValue::eTypeBoolean , false, true , NULL, NULL, "Should synthetic values be used by default whenever available." }, @@ -2983,6 +2991,7 @@ enum { ePropertyDefaultArch, + ePropertyExactMatch, ePropertyExprPrefix, ePropertyPreferDynamic, ePropertyEnableSynthetic, @@ -3190,6 +3199,13 @@ return value->SetCurrentValue(arch, true); } +bool +TargetProperties::GetExactMatch() const +{ + const uint32_t idx = ePropertyExactMatch; + return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0); +} + lldb::DynamicValueType TargetProperties::GetPreferDynamicValue() const { Index: test/functionalities/breakpoint/breakpoint_options/Makefile =================================================================== --- /dev/null +++ test/functionalities/breakpoint/breakpoint_options/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make + +C_SOURCES := main.c + +include $(LEVEL)/Makefile.rules Index: test/functionalities/breakpoint/breakpoint_options/TestBreakpointOptions.py =================================================================== --- /dev/null +++ test/functionalities/breakpoint/breakpoint_options/TestBreakpointOptions.py @@ -0,0 +1,71 @@ +""" +Test breakpoint command for different options. +""" + +import os +import unittest2 +import lldb +from lldbtest import * +import lldbutil + +class BreakpointOptionsTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @skipUnlessDarwin + @dsym_test + def test_with_dsym(self): + """Test breakpoint command for different options.""" + self.buildDsym() + self.breakpoint_options_test() + + @dwarf_test + def test_with_dwarf(self): + """Test breakpoint command for different options.""" + self.buildDwarf() + self.breakpoint_options_test() + + def setUp(self): + # Call super's setUp(). + TestBase.setUp(self) + # Find the line number to break inside main(). + self.line = line_number('main.c', '// Set break point at this line.') + + def breakpoint_options_test(self): + """Test breakpoint command for different options.""" + exe = os.path.join(os.getcwd(), "a.out") + self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) + + # This should create a breakpoint with 1 locations. + lldbutil.run_break_set_by_file_and_line (self, "main.c", self.line, extra_options = "-K 1", num_expected_locations = 1) + lldbutil.run_break_set_by_file_and_line (self, "main.c", self.line, extra_options = "-K 0", num_expected_locations = 1) + + # This should create a breakpoint 0 locations. + lldbutil.run_break_set_by_file_and_line (self, "main.c", self.line, extra_options = "-m", num_expected_locations = 0) + + # Run the program. + self.runCmd("run", RUN_SUCCEEDED) + + # Stopped once. + self.expect("thread backtrace", STOPPED_DUE_TO_BREAKPOINT, + substrs = ["stop reason = breakpoint 2."]) + + # Continue the program, there should be another stop. + self.runCmd("process continue") + + # Stopped again. + self.expect("thread backtrace", STOPPED_DUE_TO_BREAKPOINT, + substrs = ["stop reason = breakpoint 1."]) + + # Continue the program, we should exit. + self.runCmd("process continue") + + # We should exit. + self.expect("process status", "Process exited successfully", + patterns = ["^Process [0-9]+ exited with status = 0"]) + +if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() + atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() Index: test/functionalities/breakpoint/breakpoint_options/main.c =================================================================== --- /dev/null +++ test/functionalities/breakpoint/breakpoint_options/main.c @@ -0,0 +1,7 @@ +// Set break point at this line. + +int +main (int argc, char **argv) +{ + return 0; +} Index: test/settings/TestSettings.py =================================================================== --- test/settings/TestSettings.py +++ test/settings/TestSettings.py @@ -450,6 +450,7 @@ "thread-format", "use-external-editor", "target.default-arch", + "target.exact-match", "target.expr-prefix", "target.prefer-dynamic-value", "target.enable-synthetic-value",