diff --git a/lldb/packages/Python/lldbsuite/test/decorators.py b/lldb/packages/Python/lldbsuite/test/decorators.py --- a/lldb/packages/Python/lldbsuite/test/decorators.py +++ b/lldb/packages/Python/lldbsuite/test/decorators.py @@ -622,6 +622,10 @@ """Decorate the item to skip tests that should be skipped on any non Darwin platform.""" return skipUnlessPlatform(lldbplatformutil.getDarwinOSTriples())(func) +def skipUnlessLinux(func): + """Decorate the item to skip tests that should be skipped on any non-Linux platform.""" + return skipUnlessPlatform(["linux"])(func) + def skipUnlessTargetAndroid(func): return unittest2.skipUnless(lldbplatformutil.target_is_android(), "requires target to be Android")(func) diff --git a/lldb/test/API/functionalities/module_load_attach/Makefile b/lldb/test/API/functionalities/module_load_attach/Makefile new file mode 100644 --- /dev/null +++ b/lldb/test/API/functionalities/module_load_attach/Makefile @@ -0,0 +1,10 @@ +C_SOURCES := main.c +LD_EXTRAS := -Wl,-rpath "-Wl,$(shell pwd)" +USE_LIBDL := 1 + +feature: + $(MAKE) -f $(MAKEFILE_RULES) \ + DYLIB_ONLY=YES DYLIB_NAME=feature DYLIB_C_SOURCES=feature.c +all: feature + +include Makefile.rules diff --git a/lldb/test/API/functionalities/module_load_attach/TestModuleLoadAttach.py b/lldb/test/API/functionalities/module_load_attach/TestModuleLoadAttach.py new file mode 100644 --- /dev/null +++ b/lldb/test/API/functionalities/module_load_attach/TestModuleLoadAttach.py @@ -0,0 +1,37 @@ +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class TestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + def build_launch_and_attach(self): + self.build() + # launch + exe = self.getBuildArtifact("a.out") + popen = self.spawnSubprocess(exe) + # attach + target = self.dbg.CreateTarget(exe) + self.assertTrue(target, VALID_TARGET) + listener = lldb.SBListener("my.attach.listener") + error = lldb.SBError() + process = target.AttachToProcessWithID(listener, popen.pid, error) + self.assertTrue(error.Success() and process, PROCESS_IS_VALID) + return process + + @skipIfRemote + @skipUnlessLinux + @no_debug_info_test + def test_x(self): + process = self.build_launch_and_attach() + thread = process.GetSelectedThread() + thread.GetSelectedFrame().EvaluateExpression("flip_to_1_to_continue = 1") + # Continue so that dlopen is called. + breakpoint = self.target().BreakpointCreateBySourceRegex( + "// break after dlopen", lldb.SBFileSpec("main.c")) + self.assertNotEqual(breakpoint.GetNumResolvedLocations(), 0) + stopped_threads = lldbutil.continue_to_breakpoint(self.process(), breakpoint) + feature_module = self.dbg.GetSelectedTarget().FindModule(lldb.SBFileSpec("libfeature.so")) + self.assertTrue(feature_module.IsValid()) diff --git a/lldb/test/API/functionalities/module_load_attach/feature.c b/lldb/test/API/functionalities/module_load_attach/feature.c new file mode 100644 --- /dev/null +++ b/lldb/test/API/functionalities/module_load_attach/feature.c @@ -0,0 +1 @@ +extern void feature() {} diff --git a/lldb/test/API/functionalities/module_load_attach/main.c b/lldb/test/API/functionalities/module_load_attach/main.c new file mode 100644 --- /dev/null +++ b/lldb/test/API/functionalities/module_load_attach/main.c @@ -0,0 +1,15 @@ +#include +#include +#include + +volatile int flip_to_1_to_continue = 0; + +int main() { + lldb_enable_attach(); + while (! flip_to_1_to_continue) // Wait for debugger to attach + sleep(1); + // dlopen the feature + void *feature = dlopen("libfeature.so", RTLD_NOW); + assert(feature && "dlopen failed?"); + return 0; // break after dlopen +} diff --git a/lldb/tools/lldb-vscode/lldb-vscode.cpp b/lldb/tools/lldb-vscode/lldb-vscode.cpp --- a/lldb/tools/lldb-vscode/lldb-vscode.cpp +++ b/lldb/tools/lldb-vscode/lldb-vscode.cpp @@ -417,7 +417,8 @@ // of wether the locations were added or removed, the breakpoint // ins't going away, so we the reason is always "changed". if ((event_type & lldb::eBreakpointEventTypeLocationsAdded || - event_type & lldb::eBreakpointEventTypeLocationsRemoved) && + event_type & lldb::eBreakpointEventTypeLocationsRemoved || + event_type & lldb::eBreakpointEventTypeLocationsResolved) && bp.MatchesName(BreakpointBase::GetBreakpointLabel())) { auto bp_event = CreateEventObject("breakpoint"); llvm::json::Object body;