Index: lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp =================================================================== --- lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp +++ 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; Index: lldb/test/API/.lit_test_times.txt =================================================================== --- /dev/null +++ lldb/test/API/.lit_test_times.txt @@ -0,0 +1 @@ +2.777875e+00 functionalities/load_lazy/TestLoadUsingLazyBind.py Index: lldb/test/API/functionalities/load_lazy/Makefile =================================================================== --- /dev/null +++ lldb/test/API/functionalities/load_lazy/Makefile @@ -0,0 +1,18 @@ +CXX_SOURCES := main.cpp +USE_LIBDL := 1 + +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 Index: lldb/test/API/functionalities/load_lazy/TestLoadUsingLazyBind.py =================================================================== --- /dev/null +++ lldb/test/API/functionalities/load_lazy/TestLoadUsingLazyBind.py @@ -0,0 +1,65 @@ +""" +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 + + +class LoadUsingLazyBind(TestBase): + + mydir = TestBase.compute_mydir(__file__) + NO_DEBUG_INFO_TESTCASE = True + + @skipIfRemote + @skipIfWindows # The Windows platform doesn't implement DoLoadImage. + # Failing for unknown reasons on Linux, see + # https://bugs.llvm.org/show_bug.cgi?id=49656. + @skipUnlessDarwin + def test_load_using_lazy_bind(self): + """Test that we load using RTLD_LAZY""" + + self.build() + wd = os.path.realpath(self.getBuildDir()) + + ext = '.so' + if self.platformIsDarwin(): + ext = '.dylib' + + def make_lib_path(name): + libpath = os.path.join(wd, name + ext) + self.assertTrue(os.path.exists(libpath)) + return libpath + + libt1 = make_lib_path('libt1') + libt2_0 = make_lib_path('libt2_0') + libt2_1 = make_lib_path('libt2_1') + + # Overwrite t2_0 with t2_1 to delete the definition of `use`. + shutil.copy(libt2_1, libt2_0) + + # Launch a process and break + (target, process, thread, _) = lldbutil.run_to_source_breakpoint(self, + "break here", + lldb.SBFileSpec("main.cpp")) + + # Load libt1; should fail unless we use RTLD_LAZY + error = lldb.SBError() + lib_spec = lldb.SBFileSpec('libt1' + ext) + paths = lldb.SBStringList() + paths.AppendString(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") + + # Calling `f1()` should return 5. + frame = thread.GetFrameAtIndex(0) + val = frame.EvaluateExpression("f1()") + self.assertTrue(val.IsValid()) + self.assertEquals(val.GetValueAsSigned(-1), 5) Index: lldb/test/API/functionalities/load_lazy/categories =================================================================== --- /dev/null +++ lldb/test/API/functionalities/load_lazy/categories @@ -0,0 +1 @@ +basic_process Index: lldb/test/API/functionalities/load_lazy/main.cpp =================================================================== --- /dev/null +++ lldb/test/API/functionalities/load_lazy/main.cpp @@ -0,0 +1,3 @@ +int main() { + return 0; // break here +} Index: lldb/test/API/functionalities/load_lazy/t1.c =================================================================== --- /dev/null +++ lldb/test/API/functionalities/load_lazy/t1.c @@ -0,0 +1,3 @@ +extern void use(); +int f1() { return 5; } +void f2() { use(); } Index: lldb/test/API/functionalities/load_lazy/t2_0.c =================================================================== --- /dev/null +++ lldb/test/API/functionalities/load_lazy/t2_0.c @@ -0,0 +1 @@ +void use() {}