Author: Alexandre Perez Date: 2026-06-11T05:21:49-07:00 New Revision: f4a027364add48b3522ead105494187ded58047f
URL: https://github.com/llvm/llvm-project/commit/f4a027364add48b3522ead105494187ded58047f DIFF: https://github.com/llvm/llvm-project/commit/f4a027364add48b3522ead105494187ded58047f.diff LOG: [lldb-dap] Support loading core files through attachCommands (#202785) The `attachCommands` attach option lets users bootstrap a session with arbitrary LLDB commands, but a command that loaded a core (e.g. `target create --core`) produced a broken session: `ConfigurationDoneRequestHandler` would call `process.Continue()` on the core and fail, because the non-live-session handling was keyed on the `coreFile` attach argument rather than on the actual resulting process. This teaches `AttachRequestHandler` to detect, after the attach commands run, whether the selected process was loaded from a core via the `SBProcess:: IsLiveDebugSession()` API added in #203111. When it is a core, it sets `stop_at_entry` and clears `is_live_session`, mirroring what the `coreFile` key does. Added: Modified: lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp Removed: ################################################################################ diff --git a/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py b/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py index 7fc275c0c702b..7c1bbad6afaba 100644 --- a/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py +++ b/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py @@ -9,6 +9,51 @@ import lldbdap_testcase import os +# The expected backtrace when loading the bundled linux-x86_64.core. Shared by +# the tests that load this core through diff erent mechanisms (the "coreFile" +# attach key and "attachCommands") so we can assert they behave identically. +EXPECTED_CORE_FRAMES = [ + { + "column": 0, + "id": 524288, + "line": 4, + "moduleId": "01DF54A6-045E-657D-3F8F-FB9CE1118789-14F8BD6D", + "name": "bar", + "source": { + "name": "main.c", + "path": "/home/labath/test/main.c", + "presentationHint": "deemphasize", + }, + "instructionPointerReference": "0x40011C", + }, + { + "column": 0, + "id": 524289, + "line": 10, + "moduleId": "01DF54A6-045E-657D-3F8F-FB9CE1118789-14F8BD6D", + "name": "foo", + "source": { + "name": "main.c", + "path": "/home/labath/test/main.c", + "presentationHint": "deemphasize", + }, + "instructionPointerReference": "0x400142", + }, + { + "column": 0, + "id": 524290, + "line": 16, + "moduleId": "01DF54A6-045E-657D-3F8F-FB9CE1118789-14F8BD6D", + "name": "_start", + "source": { + "name": "main.c", + "path": "/home/labath/test/main.c", + "presentationHint": "deemphasize", + }, + "instructionPointerReference": "0x40015F", + }, +] + class TestDAP_coreFile(lldbdap_testcase.DAPTestCaseBase): @skipIfLLVMTargetMissing("X86") @@ -21,47 +66,7 @@ def test_core_file(self): self.attach(program=exe_file, coreFile=core_file) self.dap_server.request_configurationDone() - expected_frames = [ - { - "column": 0, - "id": 524288, - "line": 4, - "moduleId": "01DF54A6-045E-657D-3F8F-FB9CE1118789-14F8BD6D", - "name": "bar", - "source": { - "name": "main.c", - "path": "/home/labath/test/main.c", - "presentationHint": "deemphasize", - }, - "instructionPointerReference": "0x40011C", - }, - { - "column": 0, - "id": 524289, - "line": 10, - "moduleId": "01DF54A6-045E-657D-3F8F-FB9CE1118789-14F8BD6D", - "name": "foo", - "source": { - "name": "main.c", - "path": "/home/labath/test/main.c", - "presentationHint": "deemphasize", - }, - "instructionPointerReference": "0x400142", - }, - { - "column": 0, - "id": 524290, - "line": 16, - "moduleId": "01DF54A6-045E-657D-3F8F-FB9CE1118789-14F8BD6D", - "name": "_start", - "source": { - "name": "main.c", - "path": "/home/labath/test/main.c", - "presentationHint": "deemphasize", - }, - "instructionPointerReference": "0x40015F", - }, - ] + expected_frames = EXPECTED_CORE_FRAMES self.assertEqual(self.get_stackFrames(), expected_frames) @@ -73,6 +78,51 @@ def test_core_file(self): self.dap_server.request_next(threadId=32259) self.assertEqual(self.get_stackFrames(), expected_frames) + @skipIfLLVMTargetMissing("X86") + def test_core_file_attach_commands(self): + """Loading a core through "attachCommands" (e.g. `target create --core`) + should behave identically to using the "coreFile" attach key: the + session stops with the real crash reason and cannot be resumed.""" + current_dir = os.path.dirname(__file__) + exe_file = os.path.join(current_dir, "linux-x86_64.out") + core_file = os.path.join(current_dir, "linux-x86_64.core") + + self.create_debug_adapter() + # Bootstrap the core target purely through a custom attach command, + # mirroring how the "coreFile" key passes the same program. + self.attach( + program=exe_file, + attachCommands=['target create --core "%s" "%s"' % (core_file, exe_file)], + ) + + # configurationDone must succeed: a core is a non-live session, so the + # adapter must not try to resume it (resuming a core fails). + resp = self.dap_server.request_configurationDone() + self.assertTrue( + resp["success"], + "configurationDone should succeed for a core loaded via attachCommands", + ) + + # The backtrace must match the "coreFile" attach key exactly. + self.assertEqual(self.get_stackFrames(), EXPECTED_CORE_FRAMES) + + # The stop must be reported with the real crash reason, not "entry". + self.dap_server.wait_for_stopped() + found_exception = any( + body.get("reason") == "exception" + for body in self.dap_server.thread_stop_reasons.values() + ) + self.assertTrue( + found_exception, + f"Expected a thread stopped with reason 'exception', got: " + f"{self.dap_server.thread_stop_reasons}", + ) + + # Resuming should have no effect and keep the process stopped. + resp = self.dap_server.request_continue() + self.assertFalse(resp["success"]) + self.assertEqual(self.get_stackFrames(), EXPECTED_CORE_FRAMES) + def test_wrong_core_file(self): exe_file = self.getSourcePath("linux-x86_64.out") wrong_core_file = self.getSourcePath("main.c") diff --git a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp index c4cfbcbd3d73c..b6947c81986f1 100644 --- a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp @@ -109,6 +109,15 @@ Error AttachRequestHandler::Run(const AttachRequestArguments &args) const { if (!dap.target.GetProcess().IsValid()) return make_error<DAPError>( "attachCommands failed to attach to a process"); + + // If the attach commands produced a non-live session (e.g. a core file + // loaded via `target create --core`), report the session's stop reason + // instead of trying to resume it, matching the behavior of the + // `coreFile` attach key. + if (!dap.target.GetProcess().IsLiveDebugSession()) { + dap.stop_at_entry = true; + dap.is_live_session = false; + } } else if (!args.coreFile.empty()) { dap.target.LoadCore(args.coreFile.data(), error); } else if (args.gdbRemotePort != LLDB_DAP_INVALID_PORT) { _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
