Skip to content

Commit 4378be2

Browse files
committed
[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.
1 parent b248817 commit 4378be2

File tree

2 files changed

+62
-17
lines changed

2 files changed

+62
-17
lines changed

lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,15 @@
99
#include "DAP.h"
1010
#include "EventHelper.h"
1111
#include "JSONUtils.h"
12+
#include "LLDBUtils.h"
1213
#include "RequestHandler.h"
14+
#include "lldb/API/SBFrame.h"
15+
#include "lldb/API/SBInstructionList.h"
16+
#include "lldb/API/SBProcess.h"
17+
#include "lldb/API/SBStream.h"
18+
#include "lldb/API/SBTarget.h"
19+
#include "lldb/API/SBThread.h"
20+
#include "llvm/Support/JSON.h"
1321

1422
namespace lldb_dap {
1523

@@ -74,8 +82,37 @@ namespace lldb_dap {
7482
void SourceRequestHandler::operator()(const llvm::json::Object &request) {
7583
llvm::json::Object response;
7684
FillResponse(request, response);
77-
llvm::json::Object body{{"content", ""}};
78-
response.try_emplace("body", std::move(body));
85+
const auto *arguments = request.getObject("arguments");
86+
const auto *source = arguments->getObject("source");
87+
llvm::json::Object body;
88+
int64_t source_ref = GetUnsigned(
89+
source, "sourceReference", GetUnsigned(arguments, "sourceReference", 0));
90+
91+
if (source_ref) {
92+
lldb::SBProcess process = dap.target.GetProcess();
93+
// Upper 32 bits is the thread index ID
94+
lldb::SBThread thread =
95+
process.GetThreadByIndexID(GetLLDBThreadIndexID(source_ref));
96+
// Lower 32 bits is the frame index
97+
lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(source_ref));
98+
if (!frame.IsValid()) {
99+
response["success"] = false;
100+
response["message"] = "source not found";
101+
} else {
102+
lldb::SBInstructionList insts =
103+
frame.GetSymbol().GetInstructions(dap.target);
104+
lldb::SBStream stream;
105+
insts.GetDescription(stream);
106+
body["content"] = stream.GetData();
107+
body["mimeType"] = "text/x-lldb.disassembly";
108+
response.try_emplace("body", std::move(body));
109+
}
110+
} else {
111+
response["success"] = false;
112+
response["message"] =
113+
"invalid arguments, expected source.sourceReference to be set";
114+
}
115+
79116
dap.SendJSON(llvm::json::Value(std::move(response)));
80117
}
81118

lldb/tools/lldb-dap/JSONUtils.cpp

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@
4545
#include "llvm/Support/ScopedPrinter.h"
4646
#include "llvm/Support/raw_ostream.h"
4747
#include <chrono>
48-
#include <climits>
4948
#include <cstddef>
5049
#include <iomanip>
5150
#include <optional>
@@ -698,14 +697,22 @@ llvm::json::Value CreateSource(llvm::StringRef source_path) {
698697
return llvm::json::Value(std::move(source));
699698
}
700699

701-
static std::optional<llvm::json::Value> CreateSource(lldb::SBFrame &frame) {
700+
static llvm::json::Value CreateSource(lldb::SBFrame &frame,
701+
llvm::StringRef frame_name) {
702702
auto line_entry = frame.GetLineEntry();
703703
// A line entry of 0 indicates the line is compiler generated i.e. no source
704704
// file is associated with the frame.
705705
if (line_entry.GetFileSpec().IsValid() && line_entry.GetLine() != 0)
706706
return CreateSource(line_entry);
707707

708-
return {};
708+
llvm::json::Object source;
709+
EmplaceSafeString(source, "name", frame_name);
710+
source.try_emplace("sourceReference", MakeDAPFrameID(frame));
711+
// If we don't have a filespec then we don't have the original source. Mark
712+
// the source as deemphasized since users will only be able to view assembly
713+
// for these frames.
714+
EmplaceSafeString(source, "presentationHint", "deemphasize");
715+
return std::move(source);
709716
}
710717

711718
// "StackFrame": {
@@ -799,21 +806,22 @@ llvm::json::Value CreateStackFrame(lldb::SBFrame &frame,
799806

800807
EmplaceSafeString(object, "name", frame_name);
801808

802-
auto source = CreateSource(frame);
803-
804-
if (source) {
805-
object.try_emplace("source", *source);
806-
auto line_entry = frame.GetLineEntry();
807-
auto line = line_entry.GetLine();
808-
if (line && line != LLDB_INVALID_LINE_NUMBER)
809-
object.try_emplace("line", line);
810-
else
811-
object.try_emplace("line", 0);
809+
object.try_emplace("source", CreateSource(frame, frame_name));
810+
auto line_entry = frame.GetLineEntry();
811+
if (line_entry.IsValid() &&
812+
(line_entry.GetLine() != 0 ||
813+
line_entry.GetLine() != LLDB_INVALID_LINE_NUMBER)) {
814+
object.try_emplace("line", line_entry.GetLine());
812815
auto column = line_entry.GetColumn();
813816
object.try_emplace("column", column);
814817
} else {
815-
object.try_emplace("line", 0);
816-
object.try_emplace("column", 0);
818+
lldb::addr_t inst_offset = frame.GetPCAddress().GetOffset() -
819+
frame.GetSymbol().GetStartAddress().GetOffset();
820+
lldb::addr_t inst_line =
821+
inst_offset / (frame.GetThread().GetProcess().GetAddressByteSize() / 2);
822+
// lines are base-1 indexed
823+
object.try_emplace("line", inst_line + 1);
824+
object.try_emplace("column", 1);
817825
}
818826

819827
const auto pc = frame.GetPC();

0 commit comments

Comments
 (0)