Fix a bug with setting breakpoints on C++11 inline initialization statements.

If they occurred before the constructor that used them, we would refuse to
set the breakpoint because we thought they were crossing function boundaries.

Differential Revision: https://reviews.llvm.org/D94846
This commit is contained in:
Jim Ingham 2021-01-20 17:58:34 -08:00
parent 34e8fcf63f
commit bff389120f
4 changed files with 95 additions and 0 deletions

View File

@ -187,6 +187,14 @@ void BreakpointResolverFileLine::FilterContexts(SymbolContextList &sc_list,
// is 0, then we can't do this calculation. That can happen if
// GetStartLineSourceInfo gets an error, or if the first line number in
// the function really is 0 - which happens for some languages.
// But only do this calculation if the line number we found in the SC
// was different from the one requested in the source file. If we actually
// found an exact match it must be valid.
if (m_line_number == sc.line_entry.line)
continue;
const int decl_line_is_too_late_fudge = 1;
if (line && m_line_number < line - decl_line_is_too_late_fudge) {
LLDB_LOG(log, "removing symbol context at {0}:{1}", file, line);

View File

@ -0,0 +1,4 @@
C_SOURCES := main.c
CXXFLAGS_EXTRAS := -std=c++11
include Makefile.rules

View File

@ -0,0 +1,52 @@
"""
When using C++11 in place member initialization, show that we
can set and hit breakpoints on initialization lines. This is a
little bit tricky because we try not to move file and line breakpoints
across function boundaries but these lines are outside the source range
of the constructor.
"""
import lldb
import lldbsuite.test.lldbutil as lldbutil
from lldbsuite.test.lldbtest import *
class RenameThisSampleTestTestCase(TestBase):
mydir = TestBase.compute_mydir(__file__)
def test_breakpoints_on_initializers(self):
"""Show we can set breakpoints on initializers appearing both before
and after the constructor body, and hit them."""
self.build()
self.main_source_file = lldb.SBFileSpec("main.cpp")
self.first_initializer_line = line_number("main.cpp", "Set the before constructor breakpoint here")
self.second_initializer_line = line_number("main.cpp", "Set the after constructor breakpoint here")
self.sample_test()
def setUp(self):
# Call super's setUp().
TestBase.setUp(self)
# Set up your test case here. If your test doesn't need any set up then
# remove this method from your TestCase class.
def sample_test(self):
"""You might use the test implementation in several ways, say so here."""
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self,
" Set a breakpoint here to get started", self.main_source_file)
# Now set breakpoints on the two initializer lines we found in the test startup:
bkpt1 = target.BreakpointCreateByLocation(self.main_source_file, self.first_initializer_line)
self.assertEqual(bkpt1.GetNumLocations(), 1)
bkpt2 = target.BreakpointCreateByLocation(self.main_source_file, self.second_initializer_line)
self.assertEqual(bkpt2.GetNumLocations(), 1)
# Now continue, we should stop at the two breakpoints above, first the one before, then
# the one after.
self.assertEqual(len(lldbutil.continue_to_breakpoint(process, bkpt1)), 1, "Hit first breakpoint")
self.assertEqual(len(lldbutil.continue_to_breakpoint(process, bkpt2)), 1, "Hit second breakpoint")

View File

@ -0,0 +1,31 @@
#include <stdio.h>
#include <vector>
class Trivial {
public:
Trivial(int input) : m_int(input) {}
private:
int m_int;
};
class Foo {
private:
Trivial m_trivial = Trivial(100); // Set the before constructor breakpoint here
public:
Foo(int input) {
printf("I have been made!\n");
}
private:
Trivial m_other_trivial = Trivial(200); // Set the after constructor breakpoint here
};
int
main()
{
Foo myFoo(10); // Set a breakpoint here to get started
return 0;
}