xref: /llvm-project/lldb/test/API/functionalities/module_cache/simple_exe/TestModuleCacheSimple.py (revision 1eeeab82c6eb185f5139e633a59c2dbcb15616e4)
1"""Test the LLDB module cache funcionality."""
2
3import glob
4import lldb
5from lldbsuite.test.decorators import *
6from lldbsuite.test.lldbtest import *
7from lldbsuite.test import lldbutil
8import os
9import time
10
11
12class ModuleCacheTestcaseSimple(TestBase):
13    def setUp(self):
14        # Call super's setUp().
15        TestBase.setUp(self)
16        # Find the line number in a(int) to break at.
17        self.cache_dir = os.path.join(self.getBuildDir(), "lldb-module-cache")
18        # Set the lldb module cache directory to a directory inside the build
19        # artifacts directory so no other tests are interfered with.
20        self.runCmd(
21            'settings set symbols.lldb-index-cache-path "%s"' % (self.cache_dir)
22        )
23        self.runCmd("settings set symbols.enable-lldb-index-cache true")
24        self.build()
25
26    def get_module_cache_files(self, basename):
27        module_file_glob = os.path.join(
28            self.cache_dir, "llvmcache-*%s*-symtab-*" % (basename)
29        )
30        return glob.glob(module_file_glob)
31
32    # Doesn't depend on any specific debug information.
33    @no_debug_info_test
34    @skipIfWindows
35    def test(self):
36        """
37        Test module cache functionality for a simple object file.
38
39        This will test that if we enable the module cache, we have a
40        corresponding index cache entry for the symbol table for the
41        executable. It also removes the executable, rebuilds so that the
42        modification time of the binary gets updated, and then creates a new
43        target and should cause the cache to get updated so the cache file
44        should get an updated modification time.
45        """
46        exe = self.getBuildArtifact("a.out")
47
48        # Create a module with no dependencies.
49        target = self.createTestTarget(load_dependent_modules=False)
50
51        # Get the executable module and get the number of symbols to make
52        # sure the symbol table gets parsed and cached. The module cache is
53        # enabled in the setUp() function.
54        main_module = target.GetModuleAtIndex(0)
55        self.assertTrue(main_module.IsValid())
56        # Make sure the symbol table gets loaded and cached
57        main_module.GetNumSymbols()
58        cache_files = self.get_module_cache_files("a.out")
59        self.assertEqual(
60            len(cache_files), 1, "make sure there is only one cache file for 'a.out'"
61        )
62        symtab_cache_path = cache_files[0]
63        exe_mtime_1 = os.path.getmtime(exe)
64        symtab_mtime_1 = os.path.getmtime(symtab_cache_path)
65        # Now remove the executable and sleep for a few seconds to make sure we
66        # get a different creation and modification time for the file since some
67        # OSs store the modification time in seconds since Jan 1, 1970.
68        os.remove(exe)
69        self.assertFalse(
70            os.path.exists(exe), "make sure we were able to remove the executable"
71        )
72        time.sleep(2)
73        # Now rebuild the binary so it has a different content which should
74        # update the UUID to make the cache miss when it tries to load the
75        # symbol table from the binary at the same path.
76        self.build(dictionary={"CFLAGS_EXTRAS": "-DEXTRA_FUNCTION"})
77        self.assertTrue(
78            os.path.exists(exe), "make sure executable exists after rebuild"
79        )
80        # Make sure the modification time has changed or this test will fail.
81        exe_mtime_2 = os.path.getmtime(exe)
82        self.assertNotEqual(
83            exe_mtime_1,
84            exe_mtime_2,
85            "make sure the modification time of the executable has changed",
86        )
87        # Make sure the module cache still has an out of date cache with the
88        # same old modification time.
89        self.assertEqual(
90            symtab_mtime_1,
91            os.path.getmtime(symtab_cache_path),
92            "check that the 'symtab' cache file modification time doesn't match the executable modification time after rebuild",
93        )
94        # Create a new target and get the symbols again, and make sure the cache
95        # gets updated for the symbol table cache
96        target = self.createTestTarget(load_dependent_modules=False)
97        main_module = target.GetModuleAtIndex(0)
98        self.assertTrue(main_module.IsValid())
99        main_module.GetNumSymbols()
100        self.assertTrue(
101            os.path.exists(symtab_cache_path),
102            'make sure "symtab" cache files exists after cache is updated',
103        )
104        symtab_mtime_2 = os.path.getmtime(symtab_cache_path)
105        self.assertNotEqual(
106            symtab_mtime_1,
107            symtab_mtime_2,
108            'make sure modification time of "symtab-..." changed',
109        )
110