diff --git a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp --- a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp +++ b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp @@ -578,7 +578,19 @@ // __lldb_dlopen_result for consistency. The wrapper returns a void * but // doesn't use it because UtilityFunctions don't work with void returns at // present. + // + // Use lazy binding so as to not make dlopen()'s success conditional on + // forcing every symbol in the library. + // + // In general, the debugger should allow programs to load & run with + // libraries as far as they can, instead of defaulting to being super-picky + // about unavailable symbols. + // + // The value "1" appears to imply lazy binding (RTLD_LAZY) on both Darwin + // and other POSIX OSes. static const char *dlopen_wrapper_code = R"( + const int RTLD_LAZY = 1; + struct __lldb_dlopen_result { void *image_ptr; const char *error_str; @@ -595,7 +607,7 @@ { // This is the case where the name is the full path: if (!path_strings) { - result_ptr->image_ptr = dlopen(name, 2); + result_ptr->image_ptr = dlopen(name, RTLD_LAZY); if (result_ptr->image_ptr) result_ptr->error_str = nullptr; return nullptr; @@ -609,7 +621,7 @@ buffer[path_len] = '/'; char *target_ptr = buffer+path_len+1; memcpy((void *) target_ptr, (void *) name, name_len + 1); - result_ptr->image_ptr = dlopen(buffer, 2); + result_ptr->image_ptr = dlopen(buffer, RTLD_LAZY); if (result_ptr->image_ptr) { result_ptr->error_str = nullptr; break; diff --git a/lldb/test/API/functionalities/load_lazy/Makefile b/lldb/test/API/functionalities/load_lazy/Makefile new file mode 100644 --- /dev/null +++ b/lldb/test/API/functionalities/load_lazy/Makefile @@ -0,0 +1,17 @@ +CXX_SOURCES := main.cpp + +all: t2_0 t2_1 t1 a.out + +include Makefile.rules + +t1: t2_0 + $(MAKE) VPATH=$(SRCDIR) -f $(MAKEFILE_RULES) \ + DYLIB_ONLY=YES DYLIB_C_SOURCES=t1.c DYLIB_NAME=t1 LD_EXTRAS="-L. -lt2_0" + +t2_0: + $(MAKE) VPATH=$(SRCDIR) -f $(MAKEFILE_RULES) \ + DYLIB_ONLY=YES DYLIB_C_SOURCES=t2_0.c DYLIB_NAME=t2_0 + +t2_1: + $(MAKE) VPATH=$(SRCDIR) -f $(MAKEFILE_RULES) \ + DYLIB_ONLY=YES DYLIB_C_SOURCES=t2_1.c DYLIB_NAME=t2_1 diff --git a/lldb/test/API/functionalities/load_lazy/TestLoadUsingLazyBind.py b/lldb/test/API/functionalities/load_lazy/TestLoadUsingLazyBind.py new file mode 100644 --- /dev/null +++ b/lldb/test/API/functionalities/load_lazy/TestLoadUsingLazyBind.py @@ -0,0 +1,54 @@ +""" +Test that SBProcess.LoadImageUsingPaths uses RTLD_LAZY +""" + + + +import os +import shutil +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +@skipIfRemote +@skipIfWindows # The Windows platform doesn't implement DoLoadImage. +class LoadUsingLazyBind(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + NO_DEBUG_INFO_TESTCASE = True + + def setUp(self): + # Call super's setUp(). + TestBase.setUp(self) + + # Invoke the default build rule. + self.build() + + self.wd = os.path.realpath(self.getBuildDir()) + + self.ext = 'so' + if self.platformIsDarwin(): + self.ext = 'dylib' + + # Overwrite t2_0 with t2_1 to delete the definition of `use`. + shutil.copy(os.path.join(self.wd, 'libt2_1.{}'.format(self.ext)), + os.path.join(self.wd, 'libt2_0.{}'.format(self.ext))) + + @skipIfRemote + @skipIfWindows # The Windows platform doesn't implement DoLoadImage. + def test_load_using_lazy_bind(self): + """Test that we load using RTLD_LAZY""" + + (target, process, thread, _) = lldbutil.run_to_source_breakpoint(self, + "break here", + lldb.SBFileSpec("main.cpp")) + error = lldb.SBError() + lib_spec = lldb.SBFileSpec("libt1.{}".format(self.ext)) + paths = lldb.SBStringList() + paths.AppendString(self.wd) + out_spec = lldb.SBFileSpec() + token = process.LoadImageUsingPaths(lib_spec, paths, out_spec, error) + self.assertNotEqual(token, lldb.LLDB_INVALID_IMAGE_TOKEN, "Got a valid token") diff --git a/lldb/test/API/functionalities/load_lazy/categories b/lldb/test/API/functionalities/load_lazy/categories new file mode 100644 --- /dev/null +++ b/lldb/test/API/functionalities/load_lazy/categories @@ -0,0 +1 @@ +basic_process diff --git a/lldb/test/API/functionalities/load_lazy/main.cpp b/lldb/test/API/functionalities/load_lazy/main.cpp new file mode 100644 --- /dev/null +++ b/lldb/test/API/functionalities/load_lazy/main.cpp @@ -0,0 +1,3 @@ +int main() { + return 0; // break here +} diff --git a/lldb/test/API/functionalities/load_lazy/t1.c b/lldb/test/API/functionalities/load_lazy/t1.c new file mode 100644 --- /dev/null +++ b/lldb/test/API/functionalities/load_lazy/t1.c @@ -0,0 +1,3 @@ +extern void use(); +void f1() {} +void f2() { use(); } diff --git a/lldb/test/API/functionalities/load_lazy/t2_0.c b/lldb/test/API/functionalities/load_lazy/t2_0.c new file mode 100644 --- /dev/null +++ b/lldb/test/API/functionalities/load_lazy/t2_0.c @@ -0,0 +1 @@ +void use() {} diff --git a/lldb/test/API/functionalities/load_lazy/t2_1.c b/lldb/test/API/functionalities/load_lazy/t2_1.c new file mode 100644