[Lldb-commits] [lldb] f4a0273 - [lldb-dap] Support loading core files through attachCommands (#202785)

via lldb-commits lldb-commits at lists.llvm.org
Thu Jun 11 05:21:54 PDT 2026


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) {


        


More information about the lldb-commits mailing list