[Lldb-commits] [lldb] [lldb-dap] Fix core file stop reason overriden to "entry" (PR #195352)
via lldb-commits
lldb-commits at lists.llvm.org
Fri May 1 13:50:18 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lldb
Author: Wanyi (kusmour)
<details>
<summary>Changes</summary>
# Summary:
There's a behavior change on core file stop reason
It used to report the actual crash (stop) reason:
- reason: "exception" (reflecting the actual crash signal/exception)
- description: crash signals, eg."signal SIGSEGV"
However, the stopped event now always reports:
- reason: "entry"
- The crash reason is lost
## Root Cause
1. `bd0efcaa34b1` (Oct 31, 2025) — "[lldb-dap] Correctly trigger 'entry' stop reasons"
This commit changed CreateThreadStopped in `JSONUtils.cpp`:
Changed `body.try_emplace("reason", "entry")` to `body["reason"] = "entry"`, and this will overwrites it unconditionally.
2. `51e5b6c6acc0` (Feb 3, 2026) — "Migrating 'stopped' event to structured types"
Rewrote the stopped event with an if/else that completely skips the stop reason switch when on_entry=true:
```
if (on_entry) {
body.reason = eStoppedReasonEntry; // thread stop reason never inspected
} else { ... }
```
## The Underlying Design Issue
`stop_at_entry` serves double duty in AttachRequestHandler.cpp:40-41:
```
if (!args.coreFile.empty())
dap.stop_at_entry = true;
```
This flag both (a) `prevents process.Continue()` from being called (correct for core files) and (b) tells `SendThreadStoppedEvent` to use reason "entry" (wrong for core files — should report the actual crash reason).
# Test Plan:
Added DAP test to check for stop reasons
Launch a coredump debug session with local build lldb-dap and observe the stop reason
<img width="262" height="181" alt="image" src="https://github.com/user-attachments/assets/077dced9-2f0a-477a-825f-3b60483a69d3" />
---
Full diff: https://github.com/llvm/llvm-project/pull/195352.diff
4 Files Affected:
- (modified) lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py (+31)
- (modified) lldb/tools/lldb-dap/DAP.h (+1)
- (modified) lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp (+3-1)
- (modified) lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp (+1-1)
``````````diff
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 5a773503c3c63..c48ec020d6e05 100644
--- a/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py
+++ b/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py
@@ -76,6 +76,37 @@ def test_wrong_core_file(self):
# attach may fail for mutilple reasons.
self.assertEqual(error_msg, "Failed to create the process")
+ @skipIfLLVMTargetMissing("X86")
+ def test_core_file_stopped_reason(self):
+ """Test that the stopped event for a core file reports the actual crash
+ reason (e.g. 'exception') rather than 'entry'."""
+ 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()
+ self.attach(program=exe_file, coreFile=core_file)
+ self.dap_server.request_configurationDone()
+ self.dap_server.wait_for_stopped()
+
+ # Core files should report the actual crash reason, not 'entry'.
+ stop_reasons = self.dap_server.thread_stop_reasons
+ self.assertGreater(len(stop_reasons), 0, "Expected at least one stopped thread")
+
+ # Find any thread with a stop reason — the crashing thread should
+ # report 'exception' with a description about the signal.
+ found_exception = False
+ for tid, body in stop_reasons.items():
+ if body.get("reason") == "exception":
+ found_exception = True
+ self.assertIn("description", body)
+ break
+ self.assertTrue(
+ found_exception,
+ f"Expected at least one thread with stop reason 'exception', "
+ f"got: {stop_reasons}",
+ )
+
@skipIfLLVMTargetMissing("X86")
def test_core_file_source_mapping_array(self):
"""Test that sourceMap property is correctly applied when loading a core"""
diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h
index fc402b01376c4..09fcb23395e79 100644
--- a/lldb/tools/lldb-dap/DAP.h
+++ b/lldb/tools/lldb-dap/DAP.h
@@ -121,6 +121,7 @@ struct DAP final : public DAPTransport::MessageHandler {
llvm::once_flag terminated_event_flag;
bool stop_at_entry = false;
bool is_attach = false;
+ bool is_core_file = false;
/// The process event thread normally responds to process exited events by
/// shutting down the entire adapter. When we're restarting, we keep the id of
diff --git a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp
index 9f708e7087e19..8569e033fb90a 100644
--- a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp
@@ -38,8 +38,10 @@ Error AttachRequestHandler::Run(const AttachRequestArguments &args) const {
return err;
dap.SetConfiguration(args.configuration, /*is_attach=*/true);
- if (!args.coreFile.empty())
+ if (!args.coreFile.empty()) {
dap.stop_at_entry = true;
+ dap.is_core_file = true;
+ }
PrintWelcomeMessage();
diff --git a/lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp
index 4b84a047cd148..4174679541fe4 100644
--- a/lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp
@@ -62,7 +62,7 @@ ConfigurationDoneRequestHandler::Run(const ConfigurationDoneArguments &) const {
SendProcessEvent(dap, dap.is_attach ? Attach : Launch);
if (dap.stop_at_entry)
- return SendThreadStoppedEvent(dap, /*on_entry=*/true);
+ return SendThreadStoppedEvent(dap, /*on_entry=*/!dap.is_core_file);
return ToError(process.Continue());
}
``````````
</details>
https://github.com/llvm/llvm-project/pull/195352
More information about the lldb-commits
mailing list