xref: /llvm-project/lldb/test/API/source-manager/TestSourceManager.py (revision 0394e08bfbb110d606ace49bd10d951eb904e5d6)
199451b44SJordan Rupprecht"""
299451b44SJordan RupprechtTest lldb core component: SourceManager.
399451b44SJordan Rupprecht
499451b44SJordan RupprechtTest cases:
599451b44SJordan Rupprecht
699451b44SJordan Rupprechto test_display_source_python:
799451b44SJordan Rupprecht  Test display of source using the SBSourceManager API.
899451b44SJordan Rupprechto test_modify_source_file_while_debugging:
999451b44SJordan Rupprecht  Test the caching mechanism of the source manager.
1099451b44SJordan Rupprecht"""
1199451b44SJordan Rupprecht
1271b2ff79SJordan Rupprechtimport os
1351944e78SJonas Devlieghereimport io
1471b2ff79SJordan Rupprechtimport stat
1571b2ff79SJordan Rupprecht
1699451b44SJordan Rupprechtimport lldb
1799451b44SJordan Rupprechtfrom lldbsuite.test.decorators import *
1899451b44SJordan Rupprechtfrom lldbsuite.test.lldbtest import *
1999451b44SJordan Rupprechtfrom lldbsuite.test import lldbutil
2099451b44SJordan Rupprecht
2199451b44SJordan Rupprecht
2299451b44SJordan Rupprechtdef ansi_underline_surround_regex(inner_regex_text):
2399451b44SJordan Rupprecht    # return re.compile(r"\[4m%s\[0m" % inner_regex_text)
2499451b44SJordan Rupprecht    return "4.+\033\\[4m%s\033\\[0m" % inner_regex_text
2599451b44SJordan Rupprecht
262238dcc3SJonas Devlieghere
2799451b44SJordan Rupprechtdef ansi_color_surround_regex(inner_regex_text):
2899451b44SJordan Rupprecht    return "\033\\[3[0-7]m%s\033\\[0m" % inner_regex_text
2999451b44SJordan Rupprecht
3099451b44SJordan Rupprecht
312238dcc3SJonas Devlieghereclass SourceManagerTestCase(TestBase):
3299451b44SJordan Rupprecht    NO_DEBUG_INFO_TESTCASE = True
3399451b44SJordan Rupprecht
3499451b44SJordan Rupprecht    def setUp(self):
3599451b44SJordan Rupprecht        # Call super's setUp().
3699451b44SJordan Rupprecht        TestBase.setUp(self)
3799451b44SJordan Rupprecht        # Find the line number to break inside main().
3899451b44SJordan Rupprecht        self.file = self.getBuildArtifact("main-copy.c")
392238dcc3SJonas Devlieghere        self.line = line_number("main.c", "// Set break point at this line.")
4099451b44SJordan Rupprecht
4151944e78SJonas Devlieghere    def modify_content(self):
4251944e78SJonas Devlieghere        # Read the main.c file content.
4351944e78SJonas Devlieghere        with io.open(self.file, "r", newline="\n") as f:
4451944e78SJonas Devlieghere            original_content = f.read()
4551944e78SJonas Devlieghere            if self.TraceOn():
4651944e78SJonas Devlieghere                print("original content:", original_content)
4751944e78SJonas Devlieghere
4851944e78SJonas Devlieghere        # Modify the in-memory copy of the original source code.
4951944e78SJonas Devlieghere        new_content = original_content.replace("Hello world", "Hello lldb", 1)
5051944e78SJonas Devlieghere
5151944e78SJonas Devlieghere        # Modify the source code file.
5251944e78SJonas Devlieghere        # If the source was read only, the copy will also be read only.
5351944e78SJonas Devlieghere        # Run "chmod u+w" on it first so we can modify it.
5451944e78SJonas Devlieghere        statinfo = os.stat(self.file)
5551944e78SJonas Devlieghere        os.chmod(self.file, statinfo.st_mode | stat.S_IWUSR)
5651944e78SJonas Devlieghere
5751944e78SJonas Devlieghere        with io.open(self.file, "w", newline="\n") as f:
5851944e78SJonas Devlieghere            time.sleep(1)
5951944e78SJonas Devlieghere            f.write(new_content)
6051944e78SJonas Devlieghere            if self.TraceOn():
6151944e78SJonas Devlieghere                print("new content:", new_content)
6251944e78SJonas Devlieghere                print(
6351944e78SJonas Devlieghere                    "os.path.getmtime() after writing new content:",
6451944e78SJonas Devlieghere                    os.path.getmtime(self.file),
6551944e78SJonas Devlieghere                )
6651944e78SJonas Devlieghere
6799451b44SJordan Rupprecht    def get_expected_stop_column_number(self):
6899451b44SJordan Rupprecht        """Return the 1-based column number of the first non-whitespace
6999451b44SJordan Rupprecht        character in the breakpoint source line."""
7099451b44SJordan Rupprecht        stop_line = get_line(self.file, self.line)
7199451b44SJordan Rupprecht        # The number of spaces that must be skipped to get to the first non-
7299451b44SJordan Rupprecht        # whitespace character --- where we expect the debugger breakpoint
7399451b44SJordan Rupprecht        # column to be --- is equal to the number of characters that get
7499451b44SJordan Rupprecht        # stripped off the front when we lstrip it, plus one to specify
7599451b44SJordan Rupprecht        # the character column after the initial whitespace.
7699451b44SJordan Rupprecht        return len(stop_line) - len(stop_line.lstrip()) + 1
7799451b44SJordan Rupprecht
782238dcc3SJonas Devlieghere    def do_display_source_python_api(
792238dcc3SJonas Devlieghere        self, use_color, needle_regex, highlight_source=False
802238dcc3SJonas Devlieghere    ):
8199451b44SJordan Rupprecht        self.build()
8299451b44SJordan Rupprecht        exe = self.getBuildArtifact("a.out")
8399451b44SJordan Rupprecht        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
8499451b44SJordan Rupprecht
8599451b44SJordan Rupprecht        target = self.dbg.CreateTarget(exe)
8699451b44SJordan Rupprecht        self.assertTrue(target, VALID_TARGET)
8799451b44SJordan Rupprecht
8899451b44SJordan Rupprecht        # Launch the process, and do not stop at the entry point.
8999451b44SJordan Rupprecht        args = None
9099451b44SJordan Rupprecht        envp = None
912238dcc3SJonas Devlieghere        process = target.LaunchSimple(args, envp, self.get_process_working_directory())
9299451b44SJordan Rupprecht        self.assertIsNotNone(process)
9399451b44SJordan Rupprecht
9499451b44SJordan Rupprecht        #
9599451b44SJordan Rupprecht        # Exercise Python APIs to display source lines.
9699451b44SJordan Rupprecht        #
9799451b44SJordan Rupprecht
9899451b44SJordan Rupprecht        # Setup whether we should use ansi escape sequences, including color
9999451b44SJordan Rupprecht        # and styles such as underline.
10099451b44SJordan Rupprecht        self.dbg.SetUseColor(use_color)
10199451b44SJordan Rupprecht        # Disable syntax highlighting if needed.
10299451b44SJordan Rupprecht
10399451b44SJordan Rupprecht        self.runCmd("settings set highlight-source " + str(highlight_source).lower())
10499451b44SJordan Rupprecht
10599451b44SJordan Rupprecht        filespec = lldb.SBFileSpec(self.file, False)
10699451b44SJordan Rupprecht        source_mgr = self.dbg.GetSourceManager()
10799451b44SJordan Rupprecht        # Use a string stream as the destination.
10899451b44SJordan Rupprecht        stream = lldb.SBStream()
10999451b44SJordan Rupprecht        column = self.get_expected_stop_column_number()
11099451b44SJordan Rupprecht        context_before = 2
11199451b44SJordan Rupprecht        context_after = 2
11299451b44SJordan Rupprecht        current_line_prefix = "=>"
11399451b44SJordan Rupprecht        source_mgr.DisplaySourceLinesWithLineNumbersAndColumn(
1142238dcc3SJonas Devlieghere            filespec,
1152238dcc3SJonas Devlieghere            self.line,
1162238dcc3SJonas Devlieghere            column,
1172238dcc3SJonas Devlieghere            context_before,
1182238dcc3SJonas Devlieghere            context_after,
1192238dcc3SJonas Devlieghere            current_line_prefix,
1202238dcc3SJonas Devlieghere            stream,
1212238dcc3SJonas Devlieghere        )
12299451b44SJordan Rupprecht
12399451b44SJordan Rupprecht        #    2
12499451b44SJordan Rupprecht        #    3    int main(int argc, char const *argv[]) {
12599451b44SJordan Rupprecht        # => 4        printf("Hello world.\n"); // Set break point at this line.
12699451b44SJordan Rupprecht        #    5        return 0;
12799451b44SJordan Rupprecht        #    6    }
1282238dcc3SJonas Devlieghere        self.expect(
1292238dcc3SJonas Devlieghere            stream.GetData(),
1302238dcc3SJonas Devlieghere            "Source code displayed correctly:\n" + stream.GetData(),
13199451b44SJordan Rupprecht            exe=False,
1322238dcc3SJonas Devlieghere            patterns=["=>", "%d.*Hello world" % self.line, needle_regex],
1332238dcc3SJonas Devlieghere        )
13499451b44SJordan Rupprecht
13599451b44SJordan Rupprecht        # Boundary condition testings for SBStream().  LLDB should not crash!
13699451b44SJordan Rupprecht        stream.Print(None)
13799451b44SJordan Rupprecht        stream.RedirectToFile(None, True)
13899451b44SJordan Rupprecht
1392238dcc3SJonas Devlieghere    @add_test_categories(["pyapi"])
14099451b44SJordan Rupprecht    def test_display_source_python_dumb_terminal(self):
14199451b44SJordan Rupprecht        """Test display of source using the SBSourceManager API, using a
14299451b44SJordan Rupprecht        dumb terminal and thus no color support (the default)."""
14399451b44SJordan Rupprecht        use_color = False
14499451b44SJordan Rupprecht        self.do_display_source_python_api(use_color, r"\s+\^")
14599451b44SJordan Rupprecht
1462238dcc3SJonas Devlieghere    @add_test_categories(["pyapi"])
14799451b44SJordan Rupprecht    def test_display_source_python_ansi_terminal(self):
14899451b44SJordan Rupprecht        """Test display of source using the SBSourceManager API, using a
14999451b44SJordan Rupprecht        dumb terminal and thus no color support (the default)."""
15099451b44SJordan Rupprecht        use_color = True
15199451b44SJordan Rupprecht        underline_regex = ansi_underline_surround_regex(r"printf")
15299451b44SJordan Rupprecht        self.do_display_source_python_api(use_color, underline_regex)
15399451b44SJordan Rupprecht
1542238dcc3SJonas Devlieghere    @add_test_categories(["pyapi"])
15599451b44SJordan Rupprecht    def test_display_source_python_ansi_terminal_syntax_highlighting(self):
15699451b44SJordan Rupprecht        """Test display of source using the SBSourceManager API and check for
15799451b44SJordan Rupprecht        the syntax highlighted output"""
15899451b44SJordan Rupprecht        use_color = True
1592238dcc3SJonas Devlieghere        syntax_highlighting = True
16099451b44SJordan Rupprecht
16199451b44SJordan Rupprecht        # Just pick 'int' as something that should be colored.
16299451b44SJordan Rupprecht        color_regex = ansi_color_surround_regex("int")
16399451b44SJordan Rupprecht        self.do_display_source_python_api(use_color, color_regex, syntax_highlighting)
16499451b44SJordan Rupprecht
16599451b44SJordan Rupprecht        # Same for 'char'.
16699451b44SJordan Rupprecht        color_regex = ansi_color_surround_regex("char")
16799451b44SJordan Rupprecht        self.do_display_source_python_api(use_color, color_regex, syntax_highlighting)
16899451b44SJordan Rupprecht
16999451b44SJordan Rupprecht        # Test that we didn't color unrelated identifiers.
17099451b44SJordan Rupprecht        self.do_display_source_python_api(use_color, r" main\(", syntax_highlighting)
17199451b44SJordan Rupprecht        self.do_display_source_python_api(use_color, r"\);", syntax_highlighting)
17299451b44SJordan Rupprecht
17399451b44SJordan Rupprecht    def test_move_and_then_display_source(self):
17499451b44SJordan Rupprecht        """Test that target.source-map settings work by moving main.c to hidden/main.c."""
17599451b44SJordan Rupprecht        self.build()
17699451b44SJordan Rupprecht        exe = self.getBuildArtifact("a.out")
17799451b44SJordan Rupprecht        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
17899451b44SJordan Rupprecht
17999451b44SJordan Rupprecht        # Move main.c to hidden/main.c.
18099451b44SJordan Rupprecht        hidden = self.getBuildArtifact("hidden")
18199451b44SJordan Rupprecht        lldbutil.mkdir_p(hidden)
18299451b44SJordan Rupprecht        main_c_hidden = os.path.join(hidden, "main-copy.c")
18399451b44SJordan Rupprecht        os.rename(self.file, main_c_hidden)
18499451b44SJordan Rupprecht
18599451b44SJordan Rupprecht        # Set source remapping with invalid replace path and verify we get an
18699451b44SJordan Rupprecht        # error
18799451b44SJordan Rupprecht        self.expect(
18899451b44SJordan Rupprecht            "settings set target.source-map /a/b/c/d/e /q/r/s/t/u",
18999451b44SJordan Rupprecht            error=True,
1902238dcc3SJonas Devlieghere            substrs=['''error: the replacement path doesn't exist: "/q/r/s/t/u"'''],
1912238dcc3SJonas Devlieghere        )
19299451b44SJordan Rupprecht
19399451b44SJordan Rupprecht        # 'make -C' has resolved current directory to its realpath form.
19499451b44SJordan Rupprecht        builddir_real = os.path.realpath(self.getBuildDir())
19599451b44SJordan Rupprecht        hidden_real = os.path.realpath(hidden)
19699451b44SJordan Rupprecht        # Set target.source-map settings.
1972238dcc3SJonas Devlieghere        self.runCmd(
1982238dcc3SJonas Devlieghere            "settings set target.source-map %s %s" % (builddir_real, hidden_real)
1992238dcc3SJonas Devlieghere        )
20099451b44SJordan Rupprecht        # And verify that the settings work.
2012238dcc3SJonas Devlieghere        self.expect(
2022238dcc3SJonas Devlieghere            "settings show target.source-map", substrs=[builddir_real, hidden_real]
2032238dcc3SJonas Devlieghere        )
20499451b44SJordan Rupprecht
20599451b44SJordan Rupprecht        # Display main() and verify that the source mapping has been kicked in.
2062238dcc3SJonas Devlieghere        self.expect(
2072238dcc3SJonas Devlieghere            "source list -n main", SOURCE_DISPLAYED_CORRECTLY, substrs=["Hello world"]
2082238dcc3SJonas Devlieghere        )
20999451b44SJordan Rupprecht
21099451b44SJordan Rupprecht    @skipIf(oslist=["windows"], bugnumber="llvm.org/pr44431")
21199451b44SJordan Rupprecht    def test_modify_source_file_while_debugging(self):
21299451b44SJordan Rupprecht        """Modify a source file while debugging the executable."""
21399451b44SJordan Rupprecht        self.build()
21499451b44SJordan Rupprecht        exe = self.getBuildArtifact("a.out")
21599451b44SJordan Rupprecht        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
21699451b44SJordan Rupprecht
21799451b44SJordan Rupprecht        lldbutil.run_break_set_by_file_and_line(
2182238dcc3SJonas Devlieghere            self, "main-copy.c", self.line, num_expected_locations=1, loc_exact=True
2192238dcc3SJonas Devlieghere        )
22099451b44SJordan Rupprecht
22199451b44SJordan Rupprecht        self.runCmd("run", RUN_SUCCEEDED)
22299451b44SJordan Rupprecht
22399451b44SJordan Rupprecht        # The stop reason of the thread should be breakpoint.
2242238dcc3SJonas Devlieghere        self.expect(
2252238dcc3SJonas Devlieghere            "thread list",
2262238dcc3SJonas Devlieghere            STOPPED_DUE_TO_BREAKPOINT,
2272238dcc3SJonas Devlieghere            substrs=[
2282238dcc3SJonas Devlieghere                "stopped",
2292238dcc3SJonas Devlieghere                "main-copy.c:%d" % self.line,
2302238dcc3SJonas Devlieghere                "stop reason = breakpoint",
2312238dcc3SJonas Devlieghere            ],
2322238dcc3SJonas Devlieghere        )
23399451b44SJordan Rupprecht
23499451b44SJordan Rupprecht        # Display some source code.
23599451b44SJordan Rupprecht        self.expect(
2362238dcc3SJonas Devlieghere            "source list -f main-copy.c -l %d" % self.line,
23799451b44SJordan Rupprecht            SOURCE_DISPLAYED_CORRECTLY,
2382238dcc3SJonas Devlieghere            substrs=["Hello world"],
2392238dcc3SJonas Devlieghere        )
24099451b44SJordan Rupprecht
241bc0a9a17SJim Ingham        # Do the same thing with a file & line spec:
242bc0a9a17SJim Ingham        self.expect(
2432238dcc3SJonas Devlieghere            "source list -y main-copy.c:%d" % self.line,
244bc0a9a17SJim Ingham            SOURCE_DISPLAYED_CORRECTLY,
2452238dcc3SJonas Devlieghere            substrs=["Hello world"],
2462238dcc3SJonas Devlieghere        )
247bc0a9a17SJim Ingham
24899451b44SJordan Rupprecht        # The '-b' option shows the line table locations from the debug information
24999451b44SJordan Rupprecht        # that indicates valid places to set source level breakpoints.
25099451b44SJordan Rupprecht
25199451b44SJordan Rupprecht        # The file to display is implicit in this case.
25299451b44SJordan Rupprecht        self.runCmd("source list -l %d -c 3 -b" % self.line)
25399451b44SJordan Rupprecht        output = self.res.GetOutput().splitlines()[0]
25499451b44SJordan Rupprecht
25599451b44SJordan Rupprecht        # If the breakpoint set command succeeded, we should expect a positive number
25699451b44SJordan Rupprecht        # of breakpoints for the current line, i.e., self.line.
25799451b44SJordan Rupprecht        import re
2582238dcc3SJonas Devlieghere
2592238dcc3SJonas Devlieghere        m = re.search("^\[(\d+)\].*// Set break point at this line.", output)
26099451b44SJordan Rupprecht        if not m:
26199451b44SJordan Rupprecht            self.fail("Fail to display source level breakpoints")
2629c246882SJordan Rupprecht        self.assertGreater(int(m.group(1)), 0)
26399451b44SJordan Rupprecht
26451944e78SJonas Devlieghere        # Modify content
26551944e78SJonas Devlieghere        self.modify_content()
26699451b44SJordan Rupprecht
26751944e78SJonas Devlieghere        # Display the source code again. We should not see the updated line.
26851944e78SJonas Devlieghere        self.expect(
26951944e78SJonas Devlieghere            "source list -f main-copy.c -l %d" % self.line,
27051944e78SJonas Devlieghere            SOURCE_DISPLAYED_CORRECTLY,
27151944e78SJonas Devlieghere            substrs=["Hello world"],
2722238dcc3SJonas Devlieghere        )
27399451b44SJordan Rupprecht
27451944e78SJonas Devlieghere        # clear the source cache.
27551944e78SJonas Devlieghere        self.runCmd("source cache clear")
27651944e78SJonas Devlieghere
27751944e78SJonas Devlieghere        # Display the source code again. Now we should see the updated line.
27899451b44SJordan Rupprecht        self.expect(
2792238dcc3SJonas Devlieghere            "source list -f main-copy.c -l %d" % self.line,
28099451b44SJordan Rupprecht            SOURCE_DISPLAYED_CORRECTLY,
2812238dcc3SJonas Devlieghere            substrs=["Hello lldb"],
2822238dcc3SJonas Devlieghere        )
28399451b44SJordan Rupprecht
28499451b44SJordan Rupprecht    def test_set_breakpoint_with_absolute_path(self):
28599451b44SJordan Rupprecht        self.build()
28699451b44SJordan Rupprecht        hidden = self.getBuildArtifact("hidden")
28799451b44SJordan Rupprecht        lldbutil.mkdir_p(hidden)
28899451b44SJordan Rupprecht        # 'make -C' has resolved current directory to its realpath form.
28999451b44SJordan Rupprecht        builddir_real = os.path.realpath(self.getBuildDir())
29099451b44SJordan Rupprecht        hidden_real = os.path.realpath(hidden)
2912238dcc3SJonas Devlieghere        self.runCmd(
2922238dcc3SJonas Devlieghere            "settings set target.source-map %s %s" % (builddir_real, hidden_real)
2932238dcc3SJonas Devlieghere        )
29499451b44SJordan Rupprecht
29599451b44SJordan Rupprecht        exe = self.getBuildArtifact("a.out")
29699451b44SJordan Rupprecht        main = os.path.join(builddir_real, "hidden", "main-copy.c")
29799451b44SJordan Rupprecht        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
29899451b44SJordan Rupprecht
29999451b44SJordan Rupprecht        lldbutil.run_break_set_by_file_and_line(
3002238dcc3SJonas Devlieghere            self, main, self.line, num_expected_locations=1, loc_exact=False
3012238dcc3SJonas Devlieghere        )
30299451b44SJordan Rupprecht
30399451b44SJordan Rupprecht        self.runCmd("run", RUN_SUCCEEDED)
30499451b44SJordan Rupprecht
30599451b44SJordan Rupprecht        # The stop reason of the thread should be breakpoint.
3062238dcc3SJonas Devlieghere        self.expect(
3072238dcc3SJonas Devlieghere            "thread list",
3082238dcc3SJonas Devlieghere            STOPPED_DUE_TO_BREAKPOINT,
3092238dcc3SJonas Devlieghere            substrs=[
3102238dcc3SJonas Devlieghere                "stopped",
3112238dcc3SJonas Devlieghere                "main-copy.c:%d" % self.line,
3122238dcc3SJonas Devlieghere                "stop reason = breakpoint",
3132238dcc3SJonas Devlieghere            ],
3142238dcc3SJonas Devlieghere        )
315edf410e4SMed Ismail Bennani
316edf410e4SMed Ismail Bennani    def test_artificial_source_location(self):
31739b2979aSPavel Labath        src_file = "artificial_location.cpp"
31839b2979aSPavel Labath        d = {"C_SOURCES": "", "CXX_SOURCES": src_file}
319edf410e4SMed Ismail Bennani        self.build(dictionary=d)
320edf410e4SMed Ismail Bennani
32139b2979aSPavel Labath        target = lldbutil.run_to_breakpoint_make_target(self)
32239b2979aSPavel Labath
32339b2979aSPavel Labath        # Find the instruction with line=0 and put a breakpoint there.
32439b2979aSPavel Labath        sc_list = target.FindFunctions("A::foo")
32539b2979aSPavel Labath        self.assertEqual(len(sc_list), 1)
32639b2979aSPavel Labath        insns = sc_list[0].function.GetInstructions(target)
32739b2979aSPavel Labath        insn0 = next(filter(lambda insn: insn.addr.line_entry.line == 0, insns))
32839b2979aSPavel Labath        bkpt = target.BreakpointCreateBySBAddress(insn0.addr)
32939b2979aSPavel Labath        self.assertGreater(bkpt.GetNumLocations(), 0)
33039b2979aSPavel Labath
33139b2979aSPavel Labath        lldbutil.run_to_breakpoint_do_run(self, target, bkpt)
332edf410e4SMed Ismail Bennani
3332238dcc3SJonas Devlieghere        self.expect(
33466a2ed50SAlex Langford            "process status",
3352238dcc3SJonas Devlieghere            substrs=[
3362238dcc3SJonas Devlieghere                "stop reason = breakpoint",
33766a2ed50SAlex Langford                f"{src_file}:0",
33839b2979aSPavel Labath                "static int foo();",
339*0394e08bSPavel Labath                "note: This address is not associated with a specific line "
340*0394e08bSPavel Labath                "of code. This may be due to compiler optimizations.",
3412238dcc3SJonas Devlieghere            ],
3422238dcc3SJonas Devlieghere        )
343d49caf4aSJonas Devlieghere
344d49caf4aSJonas Devlieghere    def test_source_cache_dump_and_clear(self):
345d49caf4aSJonas Devlieghere        self.build()
346d49caf4aSJonas Devlieghere        exe = self.getBuildArtifact("a.out")
347d49caf4aSJonas Devlieghere        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
348d49caf4aSJonas Devlieghere        lldbutil.run_break_set_by_file_and_line(
349d49caf4aSJonas Devlieghere            self, self.file, self.line, num_expected_locations=1, loc_exact=True
350d49caf4aSJonas Devlieghere        )
351d49caf4aSJonas Devlieghere        self.runCmd("run", RUN_SUCCEEDED)
352d49caf4aSJonas Devlieghere
353d49caf4aSJonas Devlieghere        # Make sure the main source file is in the source cache.
354d49caf4aSJonas Devlieghere        self.expect(
355d49caf4aSJonas Devlieghere            "source cache dump",
356d49caf4aSJonas Devlieghere            substrs=["Modification time", "Lines", "Path", " 7", self.file],
357d49caf4aSJonas Devlieghere        )
358d49caf4aSJonas Devlieghere
359d49caf4aSJonas Devlieghere        # Clear the cache.
360d49caf4aSJonas Devlieghere        self.expect("source cache clear")
361d49caf4aSJonas Devlieghere
362d49caf4aSJonas Devlieghere        # Make sure the main source file is no longer in the source cache.
363d49caf4aSJonas Devlieghere        self.expect("source cache dump", matching=False, substrs=[self.file])
36451944e78SJonas Devlieghere
36551944e78SJonas Devlieghere    def test_source_cache_interactions(self):
36651944e78SJonas Devlieghere        self.build()
36751944e78SJonas Devlieghere        exe = self.getBuildArtifact("a.out")
36851944e78SJonas Devlieghere
36951944e78SJonas Devlieghere        # Create a first target.
37051944e78SJonas Devlieghere        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
371ecbe78c1SJonas Devlieghere        lldbutil.run_break_set_by_symbol(self, "main", num_expected_locations=1)
37251944e78SJonas Devlieghere        self.expect("run", RUN_SUCCEEDED, substrs=["Hello world"])
37351944e78SJonas Devlieghere
37451944e78SJonas Devlieghere        # Create a second target.
37551944e78SJonas Devlieghere        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
376ecbe78c1SJonas Devlieghere        lldbutil.run_break_set_by_symbol(self, "main", num_expected_locations=1)
37751944e78SJonas Devlieghere        self.expect("run", RUN_SUCCEEDED, substrs=["Hello world"])
37851944e78SJonas Devlieghere
37951944e78SJonas Devlieghere        # Modify the source file content.
38051944e78SJonas Devlieghere        self.modify_content()
38151944e78SJonas Devlieghere
38251944e78SJonas Devlieghere        # Clear the source cache. This will wipe the debugger and the process
38351944e78SJonas Devlieghere        # cache for the second process.
38451944e78SJonas Devlieghere        self.runCmd("source cache clear")
38551944e78SJonas Devlieghere
38651944e78SJonas Devlieghere        # Make sure we're seeing the new content from the clean process cache.
387ecbe78c1SJonas Devlieghere        self.expect(
388ecbe78c1SJonas Devlieghere            "next",
38951944e78SJonas Devlieghere            SOURCE_DISPLAYED_CORRECTLY,
39051944e78SJonas Devlieghere            substrs=["Hello lldb"],
39151944e78SJonas Devlieghere        )
39251944e78SJonas Devlieghere
39351944e78SJonas Devlieghere        # Switch back to the first target.
39451944e78SJonas Devlieghere        self.runCmd("target select 0")
39551944e78SJonas Devlieghere
39651944e78SJonas Devlieghere        # Make sure we're seeing the old content from the first target's
39751944e78SJonas Devlieghere        # process cache.
398ecbe78c1SJonas Devlieghere        self.expect(
399ecbe78c1SJonas Devlieghere            "next",
40051944e78SJonas Devlieghere            SOURCE_DISPLAYED_CORRECTLY,
40151944e78SJonas Devlieghere            substrs=["Hello world"],
40251944e78SJonas Devlieghere        )
403