1""" 2Test that SBProcess.LoadImageUsingPaths works correctly. 3""" 4 5 6import os 7import lldb 8from lldbsuite.test.decorators import * 9from lldbsuite.test.lldbtest import * 10from lldbsuite.test import lldbutil 11 12 13@skipIfWindows # The Windows platform doesn't implement DoLoadImage. 14class LoadUsingPathsTestCase(TestBase): 15 NO_DEBUG_INFO_TESTCASE = True 16 17 def setUp(self): 18 # Call super's setUp(). 19 TestBase.setUp(self) 20 # Make the hidden directory in the build hierarchy: 21 lldbutil.mkdir_p(self.getBuildArtifact("hidden")) 22 23 # Invoke the default build rule. 24 self.build() 25 26 ext = "so" 27 if self.platformIsDarwin(): 28 ext = "dylib" 29 self.lib_name = "libloadunload." + ext 30 31 self.wd = os.path.realpath(self.getBuildDir()) 32 self.hidden_dir = os.path.join(self.wd, "hidden") 33 self.hidden_lib = os.path.join(self.hidden_dir, self.lib_name) 34 35 @skipIfRemote 36 @skipIfWindows # Windows doesn't have dlopen and friends, dynamic libraries work differently 37 @expectedFlakeyNetBSD 38 @expectedFailureAll(oslist=["linux"], archs=["arm"], bugnumber="llvm.org/pr45894") 39 def test_load_using_paths(self): 40 """Test that we can load a module by providing a set of search paths.""" 41 if self.platformIsDarwin(): 42 dylibName = "libloadunload_d.dylib" 43 else: 44 dylibName = "libloadunload_d.so" 45 46 # The directory with the dynamic library we did not link to. 47 path_dir = os.path.join(self.getBuildDir(), "hidden") 48 49 (target, process, thread, _) = lldbutil.run_to_source_breakpoint( 50 self, "Break here to do the load using paths", lldb.SBFileSpec("main.cpp") 51 ) 52 error = lldb.SBError() 53 lib_spec = lldb.SBFileSpec(self.lib_name) 54 paths = lldb.SBStringList() 55 paths.AppendString(self.wd) 56 paths.AppendString(os.path.join(self.wd, "no_such_dir")) 57 58 out_spec = lldb.SBFileSpec() 59 60 # First try with no correct directories on the path, and make sure that doesn't blow up: 61 token = process.LoadImageUsingPaths(lib_spec, paths, out_spec, error) 62 self.assertEqual( 63 token, lldb.LLDB_INVALID_IMAGE_TOKEN, "Only looked on the provided path." 64 ) 65 # Make sure we got some error back in this case. Since we don't actually know what 66 # the error will look like, let's look for the absence of "unknown reasons". 67 error_str = error.description 68 self.assertNotEqual(len(error_str), 0, "Got an empty error string") 69 self.assertNotIn( 70 "unknown reasons", error_str, "Error string had unknown reasons" 71 ) 72 73 # Now add the correct dir to the paths list and try again: 74 paths.AppendString(self.hidden_dir) 75 token = process.LoadImageUsingPaths(lib_spec, paths, out_spec, error) 76 77 self.assertNotEqual(token, lldb.LLDB_INVALID_IMAGE_TOKEN, "Got a valid token") 78 self.assertEqual( 79 out_spec, lldb.SBFileSpec(self.hidden_lib), "Found the expected library" 80 ) 81 82 # Make sure this really is in the image list: 83 loaded_module = target.FindModule(out_spec) 84 85 self.assertTrue( 86 loaded_module.IsValid(), "The loaded module is in the image list." 87 ) 88 89 # Now see that we can call a function in the loaded module. 90 value = thread.frames[0].EvaluateExpression( 91 "d_function()", lldb.SBExpressionOptions() 92 ) 93 self.assertSuccess(value.GetError(), "Got a value from the expression") 94 ret_val = value.GetValueAsSigned() 95 self.assertEqual(ret_val, 12345, "Got the right value") 96 97 # Make sure the token works to unload it: 98 process.UnloadImage(token) 99 100 # Make sure this really is no longer in the image list: 101 loaded_module = target.FindModule(out_spec) 102 103 self.assertFalse( 104 loaded_module.IsValid(), 105 "The unloaded module is no longer in the image list.", 106 ) 107 108 # Make sure a relative path also works: 109 paths.Clear() 110 paths.AppendString(os.path.join(self.wd, "no_such_dir")) 111 paths.AppendString(self.wd) 112 relative_spec = lldb.SBFileSpec(os.path.join("hidden", self.lib_name)) 113 114 out_spec = lldb.SBFileSpec() 115 token = process.LoadImageUsingPaths(relative_spec, paths, out_spec, error) 116 117 self.assertNotEqual( 118 token, lldb.LLDB_INVALID_IMAGE_TOKEN, "Got a valid token with relative path" 119 ) 120 self.assertEqual( 121 out_spec, 122 lldb.SBFileSpec(self.hidden_lib), 123 "Found the expected library with relative path", 124 ) 125 126 process.UnloadImage(token) 127 128 # Make sure the presence of an empty path doesn't mess anything up: 129 paths.Clear() 130 paths.AppendString("") 131 paths.AppendString(os.path.join(self.wd, "no_such_dir")) 132 paths.AppendString(self.wd) 133 relative_spec = lldb.SBFileSpec(os.path.join("hidden", self.lib_name)) 134 135 out_spec = lldb.SBFileSpec() 136 token = process.LoadImageUsingPaths(relative_spec, paths, out_spec, error) 137 138 self.assertNotEqual( 139 token, 140 lldb.LLDB_INVALID_IMAGE_TOKEN, 141 "Got a valid token with included empty path", 142 ) 143 self.assertEqual( 144 out_spec, 145 lldb.SBFileSpec(self.hidden_lib), 146 "Found the expected library with included empty path", 147 ) 148 149 process.UnloadImage(token) 150 151 # Finally, passing in an absolute path should work like the basename: 152 # This should NOT work because we've taken hidden_dir off the paths: 153 abs_spec = lldb.SBFileSpec(os.path.join(self.hidden_dir, self.lib_name)) 154 155 token = process.LoadImageUsingPaths(lib_spec, paths, out_spec, error) 156 self.assertEqual( 157 token, lldb.LLDB_INVALID_IMAGE_TOKEN, "Only looked on the provided path." 158 ) 159 160 # But it should work when we add the dir: 161 # Now add the correct dir to the paths list and try again: 162 paths.AppendString(self.hidden_dir) 163 token = process.LoadImageUsingPaths(lib_spec, paths, out_spec, error) 164 165 self.assertNotEqual(token, lldb.LLDB_INVALID_IMAGE_TOKEN, "Got a valid token") 166 self.assertEqual( 167 out_spec, lldb.SBFileSpec(self.hidden_lib), "Found the expected library" 168 ) 169