[Lldb-commits] [lldb] [lldb-dap] Add 'source' references to stack frames without source files. (PR #128268)
John Harrison via lldb-commits
lldb-commits at lists.llvm.org
Sat Feb 22 15:17:45 PST 2025
https://github.com/ashgti updated https://github.com/llvm/llvm-project/pull/128268
>From 2f7885cfac5d5049c317de56109eed3bd2579acc Mon Sep 17 00:00:00 2001
From: John Harrison <harjohn at google.com>
Date: Fri, 21 Feb 2025 17:45:17 -0800
Subject: [PATCH 1/4] [lldb-dap] Add 'source' references to stack frames
without source files.
This adds 'source' references to all stack frames. When opening a stack frame users will see the disassembly of the frame if the source is not available.
This works around the odd behavior of navigating frames without the VSCode disassembly view open, which causes 'step' to step in the first frame with a source instead of the active frame.
---
lldb/tools/lldb-dap/JSONUtils.cpp | 38 +++++++++++++++++++------------
lldb/tools/lldb-dap/lldb-dap.cpp | 28 ++++++++++++++++++++---
2 files changed, 48 insertions(+), 18 deletions(-)
diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp
index 6ca4dfb4711a1..ee8fcef6f2503 100644
--- a/lldb/tools/lldb-dap/JSONUtils.cpp
+++ b/lldb/tools/lldb-dap/JSONUtils.cpp
@@ -45,7 +45,6 @@
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/raw_ostream.h"
#include <chrono>
-#include <climits>
#include <cstddef>
#include <iomanip>
#include <optional>
@@ -698,14 +697,22 @@ llvm::json::Value CreateSource(llvm::StringRef source_path) {
return llvm::json::Value(std::move(source));
}
-static std::optional<llvm::json::Value> CreateSource(lldb::SBFrame &frame) {
+static llvm::json::Value CreateSource(lldb::SBFrame &frame,
+ llvm::StringRef frame_name) {
auto line_entry = frame.GetLineEntry();
// A line entry of 0 indicates the line is compiler generated i.e. no source
// file is associated with the frame.
if (line_entry.GetFileSpec().IsValid() && line_entry.GetLine() != 0)
return CreateSource(line_entry);
- return {};
+ llvm::json::Object source;
+ EmplaceSafeString(source, "name", frame_name);
+ source.try_emplace("sourceReference", MakeDAPFrameID(frame));
+ // If we don't have a filespec then we don't have the original source. Mark
+ // the source as deemphasized since users will only be able to view assembly
+ // for these frames.
+ EmplaceSafeString(source, "presentationHint", "deemphasize");
+ return std::move(source);
}
// "StackFrame": {
@@ -799,21 +806,22 @@ llvm::json::Value CreateStackFrame(lldb::SBFrame &frame,
EmplaceSafeString(object, "name", frame_name);
- auto source = CreateSource(frame);
-
- if (source) {
- object.try_emplace("source", *source);
- auto line_entry = frame.GetLineEntry();
- auto line = line_entry.GetLine();
- if (line && line != LLDB_INVALID_LINE_NUMBER)
- object.try_emplace("line", line);
- else
- object.try_emplace("line", 0);
+ object.try_emplace("source", CreateSource(frame, frame_name));
+ auto line_entry = frame.GetLineEntry();
+ if (line_entry.IsValid() &&
+ (line_entry.GetLine() != 0 ||
+ line_entry.GetLine() != LLDB_INVALID_LINE_NUMBER)) {
+ object.try_emplace("line", line_entry.GetLine());
auto column = line_entry.GetColumn();
object.try_emplace("column", column);
} else {
- object.try_emplace("line", 0);
- object.try_emplace("column", 0);
+ lldb::addr_t inst_offset = frame.GetPCAddress().GetOffset() -
+ frame.GetSymbol().GetStartAddress().GetOffset();
+ lldb::addr_t inst_line =
+ inst_offset / (frame.GetThread().GetProcess().GetAddressByteSize() / 2);
+ // lines are base-1 indexed
+ object.try_emplace("line", inst_line + 1);
+ object.try_emplace("column", 1);
}
const auto pc = frame.GetPC();
diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp
index e323990d8b6ed..1da8358eb5224 100644
--- a/lldb/tools/lldb-dap/lldb-dap.cpp
+++ b/lldb/tools/lldb-dap/lldb-dap.cpp
@@ -13,7 +13,9 @@
#include "RunInTerminal.h"
#include "Watchpoint.h"
#include "lldb/API/SBDeclaration.h"
+#include "lldb/API/SBDefines.h"
#include "lldb/API/SBEvent.h"
+#include "lldb/API/SBFile.h"
#include "lldb/API/SBInstruction.h"
#include "lldb/API/SBListener.h"
#include "lldb/API/SBMemoryRegionInfo.h"
@@ -38,9 +40,6 @@
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <array>
-#include <cassert>
-#include <climits>
-#include <cstdarg>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
@@ -3488,6 +3487,29 @@ void request_source(DAP &dap, const llvm::json::Object &request) {
llvm::json::Object response;
FillResponse(request, response);
llvm::json::Object body{{"content", ""}};
+
+ const auto *arguments = request.getObject("arguments");
+ const auto *source = arguments->getObject("source");
+ int64_t source_ref = GetUnsigned(
+ source, "sourceReference", GetUnsigned(arguments, "sourceReference", 0));
+
+ lldb::SBProcess process = dap.target.GetProcess();
+ // Upper 32 bits is the thread index ID
+ lldb::SBThread thread =
+ process.GetThreadByIndexID(GetLLDBThreadIndexID(source_ref));
+ // Lower 32 bits is the frame index
+ lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(source_ref));
+ if (!frame.IsValid()) {
+ response["success"] = false;
+ response["message"] = "source not found";
+ } else {
+ lldb::SBInstructionList insts = frame.GetSymbol().GetInstructions(dap.target);
+ lldb::SBStream stream;
+ insts.GetDescription(stream);
+ body["content"] = stream.GetData();
+ body["mimeType"] = "text/x-lldb.disassembly";
+ }
+
response.try_emplace("body", std::move(body));
dap.SendJSON(llvm::json::Value(std::move(response)));
}
>From da9a1673619935d26a5349d7131f5cc152b84d16 Mon Sep 17 00:00:00 2001
From: John Harrison <harjohn at google.com>
Date: Fri, 21 Feb 2025 18:27:59 -0800
Subject: [PATCH 2/4] Applying clang-format.
---
lldb/tools/lldb-dap/lldb-dap.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp
index 1da8358eb5224..a6db74cd3f860 100644
--- a/lldb/tools/lldb-dap/lldb-dap.cpp
+++ b/lldb/tools/lldb-dap/lldb-dap.cpp
@@ -3503,7 +3503,8 @@ void request_source(DAP &dap, const llvm::json::Object &request) {
response["success"] = false;
response["message"] = "source not found";
} else {
- lldb::SBInstructionList insts = frame.GetSymbol().GetInstructions(dap.target);
+ lldb::SBInstructionList insts =
+ frame.GetSymbol().GetInstructions(dap.target);
lldb::SBStream stream;
insts.GetDescription(stream);
body["content"] = stream.GetData();
>From 585a5700078264d3bf27cab8b317775972f55183 Mon Sep 17 00:00:00 2001
From: John Harrison <ash at greaterthaninfinity.com>
Date: Sat, 22 Feb 2025 13:18:18 -0800
Subject: [PATCH 3/4] Apply suggestions from code review
Co-authored-by: Jonas Devlieghere <jonas at devlieghere.com>
---
lldb/tools/lldb-dap/JSONUtils.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp
index ee8fcef6f2503..86e5852b9a6c9 100644
--- a/lldb/tools/lldb-dap/JSONUtils.cpp
+++ b/lldb/tools/lldb-dap/JSONUtils.cpp
@@ -819,7 +819,7 @@ llvm::json::Value CreateStackFrame(lldb::SBFrame &frame,
frame.GetSymbol().GetStartAddress().GetOffset();
lldb::addr_t inst_line =
inst_offset / (frame.GetThread().GetProcess().GetAddressByteSize() / 2);
- // lines are base-1 indexed
+ // Line numbers are 1-based.
object.try_emplace("line", inst_line + 1);
object.try_emplace("column", 1);
}
>From 12b34ef1268f1bcccc70805349e7c71654ae3398 Mon Sep 17 00:00:00 2001
From: John Harrison <harjohn at google.com>
Date: Sat, 22 Feb 2025 15:16:24 -0800
Subject: [PATCH 4/4] Adding unit tests and included the 'path' on the frames
with disassembly formatted like '<module>`<symbol>' for example
'/usr/lib/system/libsystem_c.dylib`_qsort'.
---
.../test/tools/lldb-dap/dap_server.py | 14 +++
lldb/test/API/tools/lldb-dap/source/Makefile | 3 +
.../tools/lldb-dap/source/TestDAP_source.py | 86 +++++++++++++++++++
lldb/test/API/tools/lldb-dap/source/main.c | 20 +++++
.../lldb-dap/stackTrace/TestDAP_stackTrace.py | 44 +++++++++-
.../test/API/tools/lldb-dap/stackTrace/main.c | 15 ++++
lldb/tools/lldb-dap/JSONUtils.cpp | 46 +++++-----
lldb/tools/lldb-dap/lldb-dap.cpp | 39 +++++----
8 files changed, 228 insertions(+), 39 deletions(-)
create mode 100644 lldb/test/API/tools/lldb-dap/source/Makefile
create mode 100644 lldb/test/API/tools/lldb-dap/source/TestDAP_source.py
create mode 100644 lldb/test/API/tools/lldb-dap/source/main.c
diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py
index 043d82e2e2c7d..2ae6675685d39 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py
@@ -1068,6 +1068,19 @@ def request_stackTrace(
print("[%3u] %s" % (idx, name))
return response
+ def request_source(self, sourceReference):
+ """Request a source from a 'Source' reference."""
+ command_dict = {
+ "command": "source",
+ "type": "request",
+ "arguments": {
+ "source": {"sourceReference": sourceReference},
+ # legacy version of the request
+ "sourceReference": sourceReference,
+ },
+ }
+ return self.send_recv(command_dict)
+
def request_threads(self):
"""Request a list of all threads and combine any information from any
"stopped" events since those contain more information about why a
@@ -1170,6 +1183,7 @@ def request_setInstructionBreakpoints(self, memory_reference=[]):
}
return self.send_recv(command_dict)
+
class DebugAdaptorServer(DebugCommunication):
def __init__(
self,
diff --git a/lldb/test/API/tools/lldb-dap/source/Makefile b/lldb/test/API/tools/lldb-dap/source/Makefile
new file mode 100644
index 0000000000000..10495940055b6
--- /dev/null
+++ b/lldb/test/API/tools/lldb-dap/source/Makefile
@@ -0,0 +1,3 @@
+C_SOURCES := main.c
+
+include Makefile.rules
diff --git a/lldb/test/API/tools/lldb-dap/source/TestDAP_source.py b/lldb/test/API/tools/lldb-dap/source/TestDAP_source.py
new file mode 100644
index 0000000000000..28479ccd11ec9
--- /dev/null
+++ b/lldb/test/API/tools/lldb-dap/source/TestDAP_source.py
@@ -0,0 +1,86 @@
+"""
+Test lldb-dap source request
+"""
+
+
+import os
+
+import lldbdap_testcase
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+
+
+class TestDAP_source(lldbdap_testcase.DAPTestCaseBase):
+ @skipIfWindows
+ def test_stackTrace(self):
+ """
+ Tests the 'source' packet.
+ """
+ program = self.getBuildArtifact("a.out")
+ self.build_and_launch(program)
+ source = "main.c"
+ self.source_path = os.path.join(os.getcwd(), source)
+ self.qsort_call = line_number(source, "qsort call")
+
+ lines = [self.qsort_call]
+ breakpoint_ids = self.set_source_breakpoints(source, lines)
+ self.assertEqual(
+ len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
+ )
+
+ self.continue_to_breakpoints(breakpoint_ids)
+
+ response = self.dap_server.request_source(sourceReference=0)
+ self.assertFalse(response["success"], "verify invalid sourceReference fails")
+
+ (stackFrames, totalFrames) = self.get_stackFrames_and_totalFramesCount()
+ frameCount = len(stackFrames)
+ self.assertGreaterEqual(
+ frameCount, 3, "verify we get frames from system librarys (libc qsort)"
+ )
+ self.assertEqual(
+ totalFrames,
+ frameCount,
+ "verify total frames returns a speculative page size",
+ )
+ expectedFrames = [
+ {
+ "name": "comp",
+ "line": 14,
+ "sourceName": "main.c",
+ "containsSourceReference": False,
+ },
+ {"name": "qsort", "sourceName": "qsort", "containsSourceReference": True},
+ {
+ "name": "main",
+ "line": 25,
+ "sourceName": "main.c",
+ "containsSourceReference": False,
+ },
+ ]
+ for idx, expected in enumerate(expectedFrames):
+ frame = stackFrames[idx]
+ frame_name = self.get_dict_value(frame, ["name"])
+ self.assertRegex(frame_name, expected["name"])
+ source_name = self.get_dict_value(frame, ["source", "name"])
+ self.assertRegex(source_name, expected["sourceName"])
+ if expected["containsSourceReference"]:
+ sourceReference = self.get_dict_value(
+ frame, ["source", "sourceReference"]
+ )
+ response = self.dap_server.request_source(
+ sourceReference=sourceReference
+ )
+ self.assertTrue(response["success"])
+ self.assertGreater(
+ len(self.get_dict_value(response, ["body", "content"])),
+ 0,
+ "verify content returned",
+ )
+ self.assertEqual(
+ self.get_dict_value(response, ["body", "mimeType"]),
+ "text/x-lldb.disassembly",
+ "verify mime type returned",
+ )
+ else:
+ self.assertNotIn("sourceReference", frame["source"])
diff --git a/lldb/test/API/tools/lldb-dap/source/main.c b/lldb/test/API/tools/lldb-dap/source/main.c
new file mode 100644
index 0000000000000..6d8b9461b2998
--- /dev/null
+++ b/lldb/test/API/tools/lldb-dap/source/main.c
@@ -0,0 +1,20 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int comp(const void *first, const void *second) {
+ const int a = *((const int *)first);
+ const int b = *((const int *)second);
+ if (a == b) // qsort call
+ return 0;
+ if (a > b)
+ return 1;
+ return -1;
+}
+
+int main(int argc, char const *argv[]) {
+ int numbers[] = {4, 5, 2, 3, 1, 0, 9, 8, 6, 7};
+ qsort(numbers, sizeof(numbers) / sizeof(int), sizeof(int), comp);
+
+ return 0;
+}
diff --git a/lldb/test/API/tools/lldb-dap/stackTrace/TestDAP_stackTrace.py b/lldb/test/API/tools/lldb-dap/stackTrace/TestDAP_stackTrace.py
index 56ed1ebdf7ab4..4490e6eec2d8e 100644
--- a/lldb/test/API/tools/lldb-dap/stackTrace/TestDAP_stackTrace.py
+++ b/lldb/test/API/tools/lldb-dap/stackTrace/TestDAP_stackTrace.py
@@ -69,8 +69,9 @@ def test_stackTrace(self):
self.recurse_end = line_number(source, "recurse end")
self.recurse_call = line_number(source, "recurse call")
self.recurse_invocation = line_number(source, "recurse invocation")
+ self.qsort_call = line_number(source, "qsort call")
- lines = [self.recurse_end]
+ lines = [self.recurse_end, self.qsort_call]
# Set breakpoint at a point of deepest recuusion
breakpoint_ids = self.set_source_breakpoints(source, lines)
@@ -195,7 +196,7 @@ def test_stackTrace(self):
)
self.verify_stackFrames(startFrame, stackFrames)
- # Verify we get not frames when startFrame is too high
+ # Verify we do not recive frames when startFrame is out of range
startFrame = 1000
levels = 1
stackFrames = self.get_stackFrames(startFrame=startFrame, levels=levels)
@@ -203,6 +204,45 @@ def test_stackTrace(self):
0, len(stackFrames), "verify zero frames with startFrame out of bounds"
)
+ # Verify a stack frame from an external library (libc`qsort) to ensure
+ # frames without source code return a valid source reference.
+ self.continue_to_breakpoints(breakpoint_ids)
+ (stackFrames, totalFrames) = self.get_stackFrames_and_totalFramesCount()
+ frameCount = len(stackFrames)
+ self.assertGreaterEqual(
+ frameCount, 3, "verify we get frames from system librarys (libc qsort)"
+ )
+ self.assertEqual(
+ totalFrames,
+ frameCount,
+ "verify total frames returns a speculative page size",
+ )
+ expectedFrames = [
+ {
+ "name": "comp",
+ "line": 14,
+ "sourceName": "main.c",
+ "containsSourceReference": False,
+ },
+ {"name": "qsort", "sourceName": "qsort", "containsSourceReference": True},
+ {
+ "name": "main",
+ "line": 25,
+ "sourceName": "main.c",
+ "containsSourceReference": False,
+ },
+ ]
+ for idx, expected in enumerate(expectedFrames):
+ frame = stackFrames[idx]
+ frame_name = self.get_dict_value(frame, ["name"])
+ self.assertRegex(frame_name, expected["name"])
+ source_name = self.get_dict_value(frame, ["source", "name"])
+ self.assertRegex(source_name, expected["sourceName"])
+ if expected["containsSourceReference"]:
+ self.assertIn("sourceReference", frame["source"])
+ else:
+ self.assertNotIn("sourceReference", frame["source"])
+
@skipIfWindows
def test_functionNameWithArgs(self):
"""
diff --git a/lldb/test/API/tools/lldb-dap/stackTrace/main.c b/lldb/test/API/tools/lldb-dap/stackTrace/main.c
index 25d81be08e778..2c623ce374b38 100644
--- a/lldb/test/API/tools/lldb-dap/stackTrace/main.c
+++ b/lldb/test/API/tools/lldb-dap/stackTrace/main.c
@@ -1,4 +1,5 @@
#include <stdio.h>
+#include <stdlib.h>
#include <unistd.h>
int recurse(int x) {
@@ -7,7 +8,21 @@ int recurse(int x) {
return recurse(x - 1) + x; // recurse call
}
+int comp(const void *first, const void *second) {
+ const int a = *((const int *)first);
+ const int b = *((const int *)second);
+ if (a == b) // qsort call
+ return 0;
+ if (a > b)
+ return 1;
+ return -1;
+}
+
int main(int argc, char const *argv[]) {
recurse(40); // recurse invocation
+
+ int numbers[] = {4, 5, 2, 3, 1, 0, 9, 8, 6, 7};
+ qsort(numbers, sizeof(numbers) / sizeof(int), sizeof(int), comp);
+
return 0;
}
diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp
index 86e5852b9a6c9..28350981312fc 100644
--- a/lldb/tools/lldb-dap/JSONUtils.cpp
+++ b/lldb/tools/lldb-dap/JSONUtils.cpp
@@ -41,6 +41,7 @@
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/JSON.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/raw_ostream.h"
@@ -50,6 +51,7 @@
#include <optional>
#include <sstream>
#include <string>
+#include <sys/syslimits.h>
#include <utility>
#include <vector>
@@ -697,24 +699,6 @@ llvm::json::Value CreateSource(llvm::StringRef source_path) {
return llvm::json::Value(std::move(source));
}
-static llvm::json::Value CreateSource(lldb::SBFrame &frame,
- llvm::StringRef frame_name) {
- auto line_entry = frame.GetLineEntry();
- // A line entry of 0 indicates the line is compiler generated i.e. no source
- // file is associated with the frame.
- if (line_entry.GetFileSpec().IsValid() && line_entry.GetLine() != 0)
- return CreateSource(line_entry);
-
- llvm::json::Object source;
- EmplaceSafeString(source, "name", frame_name);
- source.try_emplace("sourceReference", MakeDAPFrameID(frame));
- // If we don't have a filespec then we don't have the original source. Mark
- // the source as deemphasized since users will only be able to view assembly
- // for these frames.
- EmplaceSafeString(source, "presentationHint", "deemphasize");
- return std::move(source);
-}
-
// "StackFrame": {
// "type": "object",
// "description": "A Stackframe contains the source location.",
@@ -806,20 +790,38 @@ llvm::json::Value CreateStackFrame(lldb::SBFrame &frame,
EmplaceSafeString(object, "name", frame_name);
- object.try_emplace("source", CreateSource(frame, frame_name));
auto line_entry = frame.GetLineEntry();
- if (line_entry.IsValid() &&
+ // A line entry of 0 indicates the line is compiler generated i.e. no source
+ // file is associated with the frame.
+ if (line_entry.GetFileSpec().IsValid() &&
(line_entry.GetLine() != 0 ||
line_entry.GetLine() != LLDB_INVALID_LINE_NUMBER)) {
+ object.try_emplace("source", CreateSource(line_entry));
object.try_emplace("line", line_entry.GetLine());
auto column = line_entry.GetColumn();
object.try_emplace("column", column);
- } else {
+ } else if (frame.GetSymbol().IsValid()) {
+ // If no source is associated with the frame, use the DAPFrameID to track
+ // the 'source' and generate assembly.
+ llvm::json::Object source;
+ EmplaceSafeString(source, "name", frame_name);
+ char buf[PATH_MAX] = {0};
+ size_t size = frame.GetModule().GetFileSpec().GetPath(buf, PATH_MAX);
+ EmplaceSafeString(source, "path",
+ std::string(buf, size) + '`' + frame_name);
+ source.try_emplace("sourceReference", MakeDAPFrameID(frame));
+ // Markthe source as deemphasized since users will only be able to view
+ // assembly for these frames.
+ EmplaceSafeString(source, "presentationHint", "deemphasize");
+ object.try_emplace("source", std::move(source));
+
+ // Calculate the line of the current PC from the start of the current
+ // symbol.
lldb::addr_t inst_offset = frame.GetPCAddress().GetOffset() -
frame.GetSymbol().GetStartAddress().GetOffset();
lldb::addr_t inst_line =
inst_offset / (frame.GetThread().GetProcess().GetAddressByteSize() / 2);
- // Line numbers are 1-based.
+ // Line numbers are 1-based.
object.try_emplace("line", inst_line + 1);
object.try_emplace("column", 1);
}
diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp
index a6db74cd3f860..fe3ad193f3c84 100644
--- a/lldb/tools/lldb-dap/lldb-dap.cpp
+++ b/lldb/tools/lldb-dap/lldb-dap.cpp
@@ -22,6 +22,8 @@
#include "lldb/API/SBStream.h"
#include "lldb/API/SBStringList.h"
#include "lldb/Host/Config.h"
+#include "lldb/Host/File.h"
+#include "lldb/Host/FileSystem.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
@@ -40,6 +42,7 @@
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <array>
+#include <climits>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
@@ -3493,22 +3496,28 @@ void request_source(DAP &dap, const llvm::json::Object &request) {
int64_t source_ref = GetUnsigned(
source, "sourceReference", GetUnsigned(arguments, "sourceReference", 0));
- lldb::SBProcess process = dap.target.GetProcess();
- // Upper 32 bits is the thread index ID
- lldb::SBThread thread =
- process.GetThreadByIndexID(GetLLDBThreadIndexID(source_ref));
- // Lower 32 bits is the frame index
- lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(source_ref));
- if (!frame.IsValid()) {
- response["success"] = false;
- response["message"] = "source not found";
+ if (source_ref) {
+ lldb::SBProcess process = dap.target.GetProcess();
+ // Upper 32 bits is the thread index ID
+ lldb::SBThread thread =
+ process.GetThreadByIndexID(GetLLDBThreadIndexID(source_ref));
+ // Lower 32 bits is the frame index
+ lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(source_ref));
+ if (!frame.IsValid()) {
+ response["success"] = false;
+ response["message"] = "source not found";
+ } else {
+ lldb::SBInstructionList insts =
+ frame.GetSymbol().GetInstructions(dap.target);
+ lldb::SBStream stream;
+ insts.GetDescription(stream);
+ body["content"] = stream.GetData();
+ body["mimeType"] = "text/x-lldb.disassembly";
+ }
} else {
- lldb::SBInstructionList insts =
- frame.GetSymbol().GetInstructions(dap.target);
- lldb::SBStream stream;
- insts.GetDescription(stream);
- body["content"] = stream.GetData();
- body["mimeType"] = "text/x-lldb.disassembly";
+ response["success"] = false;
+ response["message"] =
+ "invalid arguments, expected source.sourceReference to be set";
}
response.try_emplace("body", std::move(body));
More information about the lldb-commits
mailing list