diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp index be08c18b611e9..49edc2cdc5462 100644 --- a/lldb/source/Expression/IRExecutionUnit.cpp +++ b/lldb/source/Expression/IRExecutionUnit.cpp @@ -778,6 +778,14 @@ IRExecutionUnit::FindInSymbols(const std::vector &names, for (size_t i = 0; i < m_preferred_modules.GetSize(); ++i) non_local_images.Remove(m_preferred_modules.GetModuleAtIndex(i)); + // Drop modules the platform considers off-limits to unconstrained symbol + // searches. + for (size_t i = non_local_images.GetSize(); i > 0; --i) { + lldb::ModuleSP module_sp = non_local_images.GetModuleAtIndex(i - 1); + if (target->ModuleIsExcludedForUnconstrainedSearches(module_sp)) + non_local_images.Remove(module_sp); + } + LoadAddressResolver resolver(*target, symbol_was_missing_weak); ModuleFunctionSearchOptions function_options; diff --git a/lldb/test/API/lang/c/libc_calls/Makefile b/lldb/test/API/lang/c/libc_calls/Makefile new file mode 100644 index 0000000000000..10495940055b6 --- /dev/null +++ b/lldb/test/API/lang/c/libc_calls/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules diff --git a/lldb/test/API/lang/c/libc_calls/TestLibcCalls.py b/lldb/test/API/lang/c/libc_calls/TestLibcCalls.py new file mode 100644 index 0000000000000..f25f70b7adb03 --- /dev/null +++ b/lldb/test/API/lang/c/libc_calls/TestLibcCalls.py @@ -0,0 +1,75 @@ +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +# (symbol, function-pointer type) for each libc function in the test. +LIBC_FUNCTIONS = [ + ("memset", "void *(*)(void *, int, unsigned long)"), + ("memcpy", "void *(*)(void *, const void *, unsigned long)"), + ("memmove", "void *(*)(void *, const void *, unsigned long)"), + ("memcmp", "int (*)(const void *, const void *, unsigned long)"), +] + + +class LibcCallsTestCase(TestBase): + NO_DEBUG_INFO_TESTCASE = True + + @skipUnlessDarwin + @skipIfRemote + def test_libc_funcs_do_not_resolve_to_dyld(self): + """The JIT-resolved address of each libc function must not lie in + the private dyld copies of the same name. Calling these functions from + outside of dyld is not supported.""" + + self.build() + lldbutil.run_to_source_breakpoint( + self, "// break here", lldb.SBFileSpec("main.c") + ) + + # Check that dyld is actually loaded. + loaded_module_names = [ + m.GetFileSpec().GetFilename() for m in self.target().module_iter() + ] + self.assertIn("dyld", loaded_module_names, "dyld must be loaded") + + for symbol, fn_type in LIBC_FUNCTIONS: + with self.subTest(symbol=symbol): + # Casting `` through the spelled-out function-pointer + # type gives clang a function type to bind to; the cast + # result is the JIT-resolved address baked in by FindSymbol. + result = self.frame().EvaluateExpression(f"(void *)({fn_type}){symbol}") + self.assertSuccess(result.GetError()) + resolved_addr = result.GetValueAsUnsigned() + self.assertNotEqual(resolved_addr, 0) + + resolved_module_name = ( + self.target() + .ResolveLoadAddress(resolved_addr) + .GetModule() + .GetFileSpec() + .GetFilename() + ) + self.assertNotEqual( + resolved_module_name, "dyld", f"Called dyld version of {symbol}" + ) + + def test_libc_calls_succeed(self): + """Calling memset/memcpy/memmove/memcmp from expressions must + execute without trapping.""" + + self.build() + lldbutil.run_to_source_breakpoint( + self, "// break here", lldb.SBFileSpec("main.c") + ) + + # Call libc functions should work without trapping. + # We use a non-constant length so the compiler is not tempted to lower + # this to a series of read/writes. + self.expect_expr( + """__builtin_memcpy(dst, src, len64); + __builtin_memmove(dst, src, len64); + __builtin_memset(dst, 0, len64); + __builtin_memcmp(src, dst, len64)""", + result_value="0", + ) diff --git a/lldb/test/API/lang/c/libc_calls/main.c b/lldb/test/API/lang/c/libc_calls/main.c new file mode 100644 index 0000000000000..be013dc14f8eb --- /dev/null +++ b/lldb/test/API/lang/c/libc_calls/main.c @@ -0,0 +1,11 @@ +#include "stdio.h" + +char src[64]; +char dst[64]; +unsigned len64 = 64; + +int main(int argc, char **argv) { + // Call a libc function so that we know there is a real libc in our process. + puts("s"); // break here + return 0; +}