[Lldb-commits] [lldb] [lldb-dap] Handle stack frames without a module (PR #136777)
Ely Ronnen via lldb-commits
lldb-commits at lists.llvm.org
Tue Apr 22 15:14:23 PDT 2025
https://github.com/eronnen created https://github.com/llvm/llvm-project/pull/136777
* Fix error in lldb-dap when the stack trace contains a frame without a module by simply showing the first 32 assembly instructions after the PC
>From 93764e39ce2588ea0f86cf8283fa6c82bd89a8de Mon Sep 17 00:00:00 2001
From: Ely Ronnen <elyronnen at gmail.com>
Date: Wed, 23 Apr 2025 00:06:28 +0200
Subject: [PATCH] [lldb-dap] handle stack frames without a module
---
.../lldb-dap/stackTraceMissingModule/Makefile | 2 +
.../TestDAP_stackTraceMissingModule.py | 54 +++++++++++++++++++
.../lldb-dap/stackTraceMissingModule/main.c | 37 +++++++++++++
.../lldb-dap/Handler/SourceRequestHandler.cpp | 14 ++++-
lldb/tools/lldb-dap/JSONUtils.cpp | 10 ++++
5 files changed, 115 insertions(+), 2 deletions(-)
create mode 100644 lldb/test/API/tools/lldb-dap/stackTraceMissingModule/Makefile
create mode 100644 lldb/test/API/tools/lldb-dap/stackTraceMissingModule/TestDAP_stackTraceMissingModule.py
create mode 100644 lldb/test/API/tools/lldb-dap/stackTraceMissingModule/main.c
diff --git a/lldb/test/API/tools/lldb-dap/stackTraceMissingModule/Makefile b/lldb/test/API/tools/lldb-dap/stackTraceMissingModule/Makefile
new file mode 100644
index 0000000000000..c9319d6e6888a
--- /dev/null
+++ b/lldb/test/API/tools/lldb-dap/stackTraceMissingModule/Makefile
@@ -0,0 +1,2 @@
+C_SOURCES := main.c
+include Makefile.rules
diff --git a/lldb/test/API/tools/lldb-dap/stackTraceMissingModule/TestDAP_stackTraceMissingModule.py b/lldb/test/API/tools/lldb-dap/stackTraceMissingModule/TestDAP_stackTraceMissingModule.py
new file mode 100644
index 0000000000000..1eb00f9935a22
--- /dev/null
+++ b/lldb/test/API/tools/lldb-dap/stackTraceMissingModule/TestDAP_stackTraceMissingModule.py
@@ -0,0 +1,54 @@
+"""
+Test lldb-dap stack trace when module is missing
+"""
+
+from lldbsuite.test.decorators import skipUnlessPlatform
+from lldbsuite.test.lldbtest import line_number
+import lldbdap_testcase
+import re
+
+
+class TestDAP_stackTraceMissingModule(lldbdap_testcase.DAPTestCaseBase):
+ @skipUnlessPlatform(["linux"])
+ def test_missingModule(self):
+ """
+ Test that the stack frame without a module still has assembly source.
+ """
+ program = self.getBuildArtifact("a.out")
+ self.build_and_launch(program, commandEscapePrefix="")
+
+ source = "main.c"
+ self.set_source_breakpoints(
+ source,
+ [line_number(source, "// Break here")],
+ )
+ self.continue_to_next_stop()
+
+ # Evaluate expr -- func
+ expr_result = self.dap_server.request_evaluate(
+ expression="expr -f pointer -- func",
+ context="repl",
+ )
+
+ expr_result_address = re.search(
+ r"0x[0-9a-fA-F]+", expr_result["body"]["result"]
+ )
+ self.assertIsNotNone(
+ expr_result_address, "Failed to get address of dynamic allocated func"
+ )
+ func_address = expr_result_address.group(0)
+
+ self.dap_server.request_evaluate(
+ expression=f"breakpoint set --address {func_address}",
+ context="repl",
+ )
+
+ self.continue_to_next_stop()
+
+ frame_without_module = self.get_stackFrames()[0]
+
+ self.assertIn("line", frame_without_module, "Line number missing.")
+ self.assertIn("column", frame_without_module, "Column number missing.")
+ self.assertIn("source", frame_without_module, "Source location missing.")
+ source = frame_without_module["source"]
+ self.assertIn("sourceReference", source, "Source reference missing.")
diff --git a/lldb/test/API/tools/lldb-dap/stackTraceMissingModule/main.c b/lldb/test/API/tools/lldb-dap/stackTraceMissingModule/main.c
new file mode 100644
index 0000000000000..d706231fbd5c2
--- /dev/null
+++ b/lldb/test/API/tools/lldb-dap/stackTraceMissingModule/main.c
@@ -0,0 +1,37 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+extern uint8_t __start_target_section[];
+extern uint8_t __stop_target_section[];
+
+__attribute__((used, section("target_section"))) int target_function(void) {
+ return 42;
+}
+
+typedef int (*target_function_t)(void);
+
+int main(void) {
+ size_t target_function_size = __stop_target_section - __start_target_section;
+ size_t page_size = sysconf(_SC_PAGESIZE);
+ size_t page_aligned_size =
+ (target_function_size + page_size - 1) & ~(page_size - 1);
+
+ void *executable_memory =
+ mmap(NULL, page_aligned_size, PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (executable_memory == MAP_FAILED) {
+ perror("mmap");
+ return 1;
+ }
+
+ memcpy(executable_memory, __start_target_section, target_function_size);
+
+ target_function_t func = (target_function_t)executable_memory;
+ int result = func(); // Break here
+ printf("Result from target function: %d\n", result);
+
+ return 0;
+}
diff --git a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp
index 1a7a13d9f267a..99c3692f15283 100644
--- a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp
@@ -15,6 +15,7 @@
#include "lldb/API/SBInstructionList.h"
#include "lldb/API/SBProcess.h"
#include "lldb/API/SBStream.h"
+#include "lldb/API/SBSymbol.h"
#include "lldb/API/SBTarget.h"
#include "lldb/API/SBThread.h"
#include "llvm/Support/Error.h"
@@ -41,9 +42,18 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const {
if (!frame.IsValid())
return llvm::make_error<DAPError>("source not found");
- lldb::SBInstructionList insts = frame.GetSymbol().GetInstructions(dap.target);
lldb::SBStream stream;
- insts.GetDescription(stream);
+ lldb::SBSymbol symbol = frame.GetSymbol();
+
+ if (symbol.IsValid()) {
+ lldb::SBInstructionList insts = symbol.GetInstructions(dap.target);
+ insts.GetDescription(stream);
+ } else {
+ // No valid symbol, just return the disassembly
+ lldb::SBInstructionList insts =
+ dap.target.ReadInstructions(frame.GetPCAddress(), 32);
+ insts.GetDescription(stream);
+ }
return protocol::SourceResponseBody{/*content=*/stream.GetData(),
/*mimeType=*/"text/x-lldb.disassembly"};
diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp
index 33f10c93d2ada..30d277abce11e 100644
--- a/lldb/tools/lldb-dap/JSONUtils.cpp
+++ b/lldb/tools/lldb-dap/JSONUtils.cpp
@@ -783,6 +783,16 @@ llvm::json::Value CreateStackFrame(lldb::SBFrame &frame,
// Line numbers are 1-based.
object.try_emplace("line", inst_line + 1);
object.try_emplace("column", 1);
+ } else {
+ // No valid line entry or symbol
+ llvm::json::Object source;
+ EmplaceSafeString(source, "name", frame_name);
+ source.try_emplace("sourceReference", MakeDAPFrameID(frame));
+ EmplaceSafeString(source, "presentationHint", "deemphasize");
+ object.try_emplace("source", std::move(source));
+
+ object.try_emplace("line", 1);
+ object.try_emplace("column", 1);
}
const auto pc = frame.GetPC();
More information about the lldb-commits
mailing list