xref: /llvm-project/lldb/test/API/functionalities/load_using_paths/TestLoadUsingPaths.py (revision 9c95617c796f1cd178eaf3001bce543b8acee32f)
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