From cb8c1ee269da72eb6e2c18800cd8ab0a74050785 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Thu, 18 Mar 2021 11:12:17 -0700 Subject: [PATCH] [lldb/PlatformPOSIX] Change LoadImage default to RTLD_LAZY In general, it seems like the debugger should allow programs to load & run with libraries as far as possible, instead of defaulting to being super-picky about unavailable symbols. This is critical on macOS/Darwin, as libswiftCore.dylib may 1) export a version symbol using @available markup and then 2) expect that other exported APIs are only dynamically used once the version symbol is checked. We can't open a version of the library built with a bleeding-edge SDK on an older OS without RTLD_LAXY (or pervasive/expensive @available markup added to dyld APIs). See: https://lists.llvm.org/pipermail/lldb-dev/2021-March/016796.html Differential Revision: https://reviews.llvm.org/D98879 --- .../Plugins/Platform/POSIX/PlatformPOSIX.cpp | 16 ++++++- lldb/test/API/functionalities/load_lazy/Makefile | 17 +++++++ .../load_lazy/TestLoadUsingLazyBind.py | 54 ++++++++++++++++++++++ lldb/test/API/functionalities/load_lazy/categories | 1 + lldb/test/API/functionalities/load_lazy/main.cpp | 3 ++ lldb/test/API/functionalities/load_lazy/t1.c | 3 ++ lldb/test/API/functionalities/load_lazy/t2_0.c | 1 + lldb/test/API/functionalities/load_lazy/t2_1.c | 0 8 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 lldb/test/API/functionalities/load_lazy/Makefile create mode 100644 lldb/test/API/functionalities/load_lazy/TestLoadUsingLazyBind.py create mode 100644 lldb/test/API/functionalities/load_lazy/categories create mode 100644 lldb/test/API/functionalities/load_lazy/main.cpp create mode 100644 lldb/test/API/functionalities/load_lazy/t1.c create mode 100644 lldb/test/API/functionalities/load_lazy/t2_0.c create mode 100644 lldb/test/API/functionalities/load_lazy/t2_1.c diff --git a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp index c8a0060..3e5f145 100644 --- a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp +++ b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp @@ -578,7 +578,19 @@ PlatformPOSIX::MakeLoadImageUtilityFunction(ExecutionContext &exe_ctx, // __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 @@ PlatformPOSIX::MakeLoadImageUtilityFunction(ExecutionContext &exe_ctx, { // 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 @@ PlatformPOSIX::MakeLoadImageUtilityFunction(ExecutionContext &exe_ctx, 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 index 0000000..14eff23 --- /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 index 0000000..18135a1 --- /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 index 0000000..c00c258 --- /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 index 0000000..ba45ee3 --- /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 index 0000000..08eae30 --- /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 index 0000000..9fc1edf --- /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 index 0000000..e69de29 -- 2.7.4