"""Test the LLDB module cache funcionality.""" import glob import lldb from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil import os import time class ModuleCacheTestcaseSimple(TestBase): def setUp(self): # Call super's setUp(). TestBase.setUp(self) # Find the line number in a(int) to break at. self.cache_dir = os.path.join(self.getBuildDir(), "lldb-module-cache") # Set the lldb module cache directory to a directory inside the build # artifacts directory so no other tests are interfered with. self.runCmd( 'settings set symbols.lldb-index-cache-path "%s"' % (self.cache_dir) ) self.runCmd("settings set symbols.enable-lldb-index-cache true") self.build() def get_module_cache_files(self, basename): module_file_glob = os.path.join( self.cache_dir, "llvmcache-*%s*-symtab-*" % (basename) ) return glob.glob(module_file_glob) # Doesn't depend on any specific debug information. @no_debug_info_test @skipIfWindows def test(self): """ Test module cache functionality for a simple object file. This will test that if we enable the module cache, we have a corresponding index cache entry for the symbol table for the executable. It also removes the executable, rebuilds so that the modification time of the binary gets updated, and then creates a new target and should cause the cache to get updated so the cache file should get an updated modification time. """ exe = self.getBuildArtifact("a.out") # Create a module with no dependencies. target = self.createTestTarget(load_dependent_modules=False) # Get the executable module and get the number of symbols to make # sure the symbol table gets parsed and cached. The module cache is # enabled in the setUp() function. main_module = target.GetModuleAtIndex(0) self.assertTrue(main_module.IsValid()) # Make sure the symbol table gets loaded and cached main_module.GetNumSymbols() cache_files = self.get_module_cache_files("a.out") self.assertEqual( len(cache_files), 1, "make sure there is only one cache file for 'a.out'" ) symtab_cache_path = cache_files[0] exe_mtime_1 = os.path.getmtime(exe) symtab_mtime_1 = os.path.getmtime(symtab_cache_path) # Now remove the executable and sleep for a few seconds to make sure we # get a different creation and modification time for the file since some # OSs store the modification time in seconds since Jan 1, 1970. os.remove(exe) self.assertFalse( os.path.exists(exe), "make sure we were able to remove the executable" ) time.sleep(2) # Now rebuild the binary so it has a different content which should # update the UUID to make the cache miss when it tries to load the # symbol table from the binary at the same path. self.build(dictionary={"CFLAGS_EXTRAS": "-DEXTRA_FUNCTION"}) self.assertTrue( os.path.exists(exe), "make sure executable exists after rebuild" ) # Make sure the modification time has changed or this test will fail. exe_mtime_2 = os.path.getmtime(exe) self.assertNotEqual( exe_mtime_1, exe_mtime_2, "make sure the modification time of the executable has changed", ) # Make sure the module cache still has an out of date cache with the # same old modification time. self.assertEqual( symtab_mtime_1, os.path.getmtime(symtab_cache_path), "check that the 'symtab' cache file modification time doesn't match the executable modification time after rebuild", ) # Create a new target and get the symbols again, and make sure the cache # gets updated for the symbol table cache target = self.createTestTarget(load_dependent_modules=False) main_module = target.GetModuleAtIndex(0) self.assertTrue(main_module.IsValid()) main_module.GetNumSymbols() self.assertTrue( os.path.exists(symtab_cache_path), 'make sure "symtab" cache files exists after cache is updated', ) symtab_mtime_2 = os.path.getmtime(symtab_cache_path) self.assertNotEqual( symtab_mtime_1, symtab_mtime_2, 'make sure modification time of "symtab-..." changed', )