Index: packages/Python/lldbsuite/test/functionalities/breakpoint/move_nearest/Makefile =================================================================== --- /dev/null +++ packages/Python/lldbsuite/test/functionalities/breakpoint/move_nearest/Makefile @@ -0,0 +1,8 @@ +LEVEL = ../../../make + +DYLIB_NAME := foo +DYLIB_CXX_SOURCES := foo.cpp +CXX_SOURCES := main.cpp +CFLAGS_EXTRAS += -fPIC + +include $(LEVEL)/Makefile.rules Index: packages/Python/lldbsuite/test/functionalities/breakpoint/move_nearest/TestMoveNearest.py =================================================================== --- /dev/null +++ packages/Python/lldbsuite/test/functionalities/breakpoint/move_nearest/TestMoveNearest.py @@ -0,0 +1,49 @@ +"""Test that types defined in shared libraries work correctly.""" + +from __future__ import print_function + + +import unittest2 +import lldb +from lldbsuite.test.lldbtest import * +import lldbsuite.test.lldbutil as lldbutil + + +class TestMoveNearest(TestBase): + + mydir = TestBase.compute_mydir(__file__) + NO_DEBUG_INFO_TESTCASE = True + + def setUp(self): + # Call super's setUp(). + TestBase.setUp(self) + # Find the line number to break inside main(). + self.source = 'foo.h' + self.line1 = line_number(self.source, '// !BR1') + self.line2 = line_number(self.source, '// !BR2') + + def tearDown(self): + self.runCmd("settings clear target.move-to-nearest-code") + TestBase.tearDown(self) + + def test(self): + """Test that target.move-to-nearest code setting behaves properly in the + presence of multiple modules""" + + self.build() + target = self.dbg.CreateTarget("a.out") + self.assertTrue(target, VALID_TARGET) + + # Regardless of the setting value the breakpoint should have exactly one + # location + self.runCmd("settings set target.move-to-nearest-code true") + lldbutil.run_break_set_by_file_and_line(self, self.source, self.line1, + loc_exact=True) + lldbutil.run_break_set_by_file_and_line(self, self.source, self.line2, + loc_exact=True) + + self.runCmd("settings set target.move-to-nearest-code false") + lldbutil.run_break_set_by_file_and_line(self, self.source, self.line1, + loc_exact=True) + lldbutil.run_break_set_by_file_and_line(self, self.source, self.line2, + loc_exact=True) Index: packages/Python/lldbsuite/test/functionalities/breakpoint/move_nearest/foo.h =================================================================== --- /dev/null +++ packages/Python/lldbsuite/test/functionalities/breakpoint/move_nearest/foo.h @@ -0,0 +1,5 @@ +LLDB_TEST_API inline int foo1() { return 1; } // !BR1 +LLDB_TEST_API inline int foo2() { return 2; } // !BR2 + +LLDB_TEST_API extern int call_foo1(); +LLDB_TEST_API extern int call_foo2(); Index: packages/Python/lldbsuite/test/functionalities/breakpoint/move_nearest/foo.cpp =================================================================== --- /dev/null +++ packages/Python/lldbsuite/test/functionalities/breakpoint/move_nearest/foo.cpp @@ -0,0 +1,3 @@ +#include "foo.h" + +int call_foo1() { return foo1(); } Index: packages/Python/lldbsuite/test/functionalities/breakpoint/move_nearest/main.cpp =================================================================== --- /dev/null +++ packages/Python/lldbsuite/test/functionalities/breakpoint/move_nearest/main.cpp @@ -0,0 +1,5 @@ +#include "foo.h" + +int call_foo2() { return foo2(); } + +int main() { return call_foo1() + call_foo2(); } Index: source/Breakpoint/BreakpointResolverFileLine.cpp =================================================================== --- source/Breakpoint/BreakpointResolverFileLine.cpp +++ source/Breakpoint/BreakpointResolverFileLine.cpp @@ -17,6 +17,7 @@ #include "lldb/Core/Module.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Function.h" +#include "lldb/Target/Target.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/StreamString.h" @@ -112,40 +113,49 @@ BreakpointResolverFileLine::SearchCallback(SearchFilter &filter, SymbolContext &context, Address *addr, bool containing) { + SymbolContextList sc_list; assert(m_breakpoint != NULL); // There is a tricky bit here. You can have two compilation units that - // #include the same file, and - // in one of them the function at m_line_number is used (and so code and a - // line entry for it is generated) but in the - // other it isn't. If we considered the CU's independently, then in the - // second inclusion, we'd move the breakpoint - // to the next function that actually generated code in the header file. That - // would end up being confusing. - // So instead, we do the CU iterations by hand here, then scan through the - // complete list of matches, and figure out - // the closest line number match, and only set breakpoints on that match. + // #include the same file, and in one of them the function at m_line_number is + // used (and so code and a line entry for it is generated) but in the other it + // isn't. If we considered the CU's independently, then in the second + // inclusion, we'd move the breakpoint to the next function that actually + // generated code in the header file. That would end up being confusing. So + // instead, we do the CU iterations by hand here, then scan through the + // complete list of matches, and figure out the closest line number match, and + // only set breakpoints on that match. // Note also that if file_spec only had a file name and not a directory, there - // may be many different file spec's in - // the resultant list. The closest line match for one will not be right for - // some totally different file. - // So we go through the match list and pull out the sets that have the same - // file spec in their line_entry - // and treat each set separately. - - const size_t num_comp_units = context.module_sp->GetNumCompileUnits(); - for (size_t i = 0; i < num_comp_units; i++) { - CompUnitSP cu_sp(context.module_sp->GetCompileUnitAtIndex(i)); - if (cu_sp) { - if (filter.CompUnitPasses(*cu_sp)) - cu_sp->ResolveSymbolContext(m_file_spec, m_line_number, m_inlines, - m_exact_match, eSymbolContextEverything, - sc_list); + // may be many different file spec's in the resultant list. The closest line + // match for one will not be right for some totally different file. So we go + // through the match list and pull out the sets that have the same file spec + // in their line_entry and treat each set separately. + const ModuleList &target_images = context.target_sp->GetImages(); + std::lock_guard guard(target_images.GetMutex()); + + size_t n_modules = target_images.GetSize(); + for (size_t i = 0; i < n_modules; i++) { + // If this is the last level supplied, then call the callback directly, + // otherwise descend. + ModuleSP module_sp(target_images.GetModuleAtIndexUnlocked(i)); + if (!filter.ModulePasses(module_sp)) + continue; + + const size_t num_comp_units = module_sp->GetNumCompileUnits(); + for (size_t i = 0; i < num_comp_units; i++) { + CompUnitSP cu_sp(module_sp->GetCompileUnitAtIndex(i)); + if (! cu_sp || !filter.CompUnitPasses(*cu_sp)) + continue; + + cu_sp->ResolveSymbolContext(m_file_spec, m_line_number, m_inlines, + m_exact_match, eSymbolContextEverything, + sc_list); } } + StreamString s; s.Printf("for %s:%d ", m_file_spec.GetFilename().AsCString(""), m_line_number); @@ -156,7 +166,7 @@ } Searcher::Depth BreakpointResolverFileLine::GetDepth() { - return Searcher::eDepthModule; + return Searcher::eDepthTarget; } void BreakpointResolverFileLine::GetDescription(Stream *s) {